2022-10-25 10:06:53

by John Garry

[permalink] [raw]
Subject: [PATCH RFC v3 00/22] blk-mq/libata/scsi: SCSI driver tagging improvements Part I

Currently SCSI low-level drivers are required to manage tags for commands
which do not come via the block layer - libata internal commands would be
an example of one of these. We want to make blk-mq manage these tags also.

There was some work to provide "reserved commands" support in such series
as https://lore.kernel.org/linux-scsi/[email protected]/

This was based on allocating a request for the lifetime of the "internal"
command.

This series tries to solve that problem by not just allocating the request
but also sending it as a request through the block layer. Reasons to do
this:
- Normal flow of a request and also commonality for regular scsi command
lifetime
- We don't leave request and scsi_cmnd fields dangling as when we just
allocate and free the request for the lifetime of the "internal" command
- For poll mode support we can only poll in block layer, so could not send
internal commands on poll mode queues if we did not do this, which is a
problem
- Can get rid of duplicated code like libsas internal command timeout
handling

Series part I contains core SCSI midlayer, libata, and libsas changes to
queue libsas "slow" tasks as requests.

Series part II of this series focused on changing libata to queue internal
commands as requests.

Testing:
QEMU with AHCI with disk and cdrom attached, hisi_sas, pm8001.

Branch containing all patches is at:
https://github.com/hisilicon/kernel-dev/commits/private-topic-sas-6.1-block

v2 was here:
https://lore.kernel.org/linux-scsi/[email protected]/

Hannes Reinecke (1):
scsi: core: Implement reserved command handling

John Garry (21):
blk-mq: Don't get budget for reserved requests
scsi: core: Add scsi_get_dev()
scsi: core: Add support to send reserved commands
scsi: core: Add support for reserved command timeout handling
scsi: libsas: Improve sas_ex_discover_expander() error handling
scsi: libsas: Notify LLDD expander found before calling sas_rphy_add()
scsi: scsi_transport_sas: Alloc sdev for expander
scsi: libsas: Add sas_alloc_slow_task_rq()
scsi: libsas: Add sas_queuecommand_internal()
scsi: libsas: Add sas_internal_timeout()
scsi: core: Use SCSI_SCAN_RESCAN in __scsi_add_device()
scsi: scsi_transport_sas: Allocate end device target id in the rphy
alloc
ata: libata-scsi: Add ata_scsi_setup_sdev()
scsi: libsas: Add sas_ata_setup_device()
ata: libata-scsi: Allocate sdev early in port probe
scsi: libsas drivers: Reserve tags
scsi: libsas: Queue SMP commands as requests
scsi: libsas: Queue TMF commands as requests
scsi: core: Add scsi_alloc_request_hwq()
scsi: libsas: Queue internal abort commands as requests
scsi: libsas: Delete sas_task_slow.timer

block/blk-mq.c | 4 +-
drivers/ata/libata-eh.c | 1 +
drivers/ata/libata-scsi.c | 49 ++++++++----
drivers/ata/libata.h | 1 +
drivers/scsi/aic94xx/aic94xx_init.c | 3 +
drivers/scsi/hisi_sas/hisi_sas_main.c | 40 +++++-----
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 3 +
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 3 +
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 7 ++
drivers/scsi/hosts.c | 16 ++++
drivers/scsi/isci/init.c | 3 +
drivers/scsi/libsas/sas_ata.c | 20 +++++
drivers/scsi/libsas/sas_expander.c | 101 ++++++++++++++-----------
drivers/scsi/libsas/sas_init.c | 61 ++++++++++++++-
drivers/scsi/libsas/sas_internal.h | 5 ++
drivers/scsi/libsas/sas_scsi_host.c | 93 ++++++++++++-----------
drivers/scsi/mvsas/mv_init.c | 7 ++
drivers/scsi/pm8001/pm8001_init.c | 8 +-
drivers/scsi/scsi_error.c | 3 +
drivers/scsi/scsi_lib.c | 42 +++++++++-
drivers/scsi/scsi_scan.c | 29 ++++++-
drivers/scsi/scsi_transport_sas.c | 34 ++++++---
include/linux/libata.h | 2 +
include/scsi/libsas.h | 8 +-
include/scsi/scsi_cmnd.h | 3 +
include/scsi/scsi_host.h | 21 ++++-
26 files changed, 424 insertions(+), 143 deletions(-)

--
2.35.3



2022-10-25 10:08:09

by John Garry

[permalink] [raw]
Subject: [PATCH RFC v3 10/22] scsi: libsas: Add sas_queuecommand_internal()

Add a callback for scsi host template reserved_queuecommand callback, and
plug it into libsas LLDDs.

Signed-off-by: John Garry <[email protected]>
---
drivers/scsi/aic94xx/aic94xx_init.c | 1 +
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 1 +
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 1 +
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 1 +
drivers/scsi/isci/init.c | 1 +
drivers/scsi/libsas/sas_scsi_host.c | 13 +++++++++++++
drivers/scsi/mvsas/mv_init.c | 1 +
drivers/scsi/pm8001/pm8001_init.c | 1 +
include/scsi/libsas.h | 1 +
9 files changed, 21 insertions(+)

diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 954d0c5ae2e2..e9d2ee5434c2 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -60,6 +60,7 @@ static struct scsi_host_template aic94xx_sht = {
.compat_ioctl = sas_ioctl,
#endif
.track_queue_depth = 1,
+ .reserved_queuecommand = sas_queuecommand_internal,
};

static int asd_map_memio(struct asd_ha_struct *asd_ha)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index d643c5a49aa9..6cf660b1212e 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1760,6 +1760,7 @@ static struct scsi_host_template sht_v1_hw = {
#endif
.shost_groups = host_v1_hw_groups,
.host_reset = hisi_sas_host_reset,
+ .reserved_queuecommand = sas_queuecommand_internal,
};

static const struct hisi_sas_hw hisi_sas_v1_hw = {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index cded42f4ca44..d2bf23ad0833 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -3578,6 +3578,7 @@ static struct scsi_host_template sht_v2_hw = {
.host_reset = hisi_sas_host_reset,
.map_queues = map_queues_v2_hw,
.host_tagset = 1,
+ .reserved_queuecommand = sas_queuecommand_internal,
};

static const struct hisi_sas_hw hisi_sas_v2_hw = {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 0c3fcb807806..ff56072c7a33 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -3245,6 +3245,7 @@ static struct scsi_host_template sht_v3_hw = {
.tag_alloc_policy = BLK_TAG_ALLOC_RR,
.host_reset = hisi_sas_host_reset,
.host_tagset = 1,
+ .reserved_queuecommand = sas_queuecommand_internal,
};

static const struct hisi_sas_hw hisi_sas_v3_hw = {
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index e294d5d961eb..e970f4b77ed3 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -177,6 +177,7 @@ static struct scsi_host_template isci_sht = {
#endif
.shost_groups = isci_host_groups,
.track_queue_depth = 1,
+ .reserved_queuecommand = sas_queuecommand_internal,
};

static struct sas_domain_function_template isci_transport_ops = {
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index a36fa1c128a8..04e8c0575021 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -158,6 +158,19 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
return task;
}

+int sas_queuecommand_internal(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
+{
+ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+ struct sas_internal *i = to_sas_internal(ha->core.shost->transportt);
+ struct request *rq = blk_mq_rq_from_pdu(cmnd);
+ struct sas_task *task = rq->end_io_data;
+
+ ASSIGN_SAS_TASK(cmnd, task);
+
+ return i->dft->lldd_execute_task(task, GFP_KERNEL);
+}
+EXPORT_SYMBOL_GPL(sas_queuecommand_internal);
+
int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{
struct sas_internal *i = to_sas_internal(host->transportt);
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index cfe84473a515..228ab00e180f 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -54,6 +54,7 @@ static struct scsi_host_template mvs_sht = {
#endif
.shost_groups = mvst_host_groups,
.track_queue_depth = 1,
+ .reserved_queuecommand = sas_queuecommand_internal,
};

static struct sas_domain_function_template mvs_transport_ops = {
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index a1df61205b20..1a12c3f97f53 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -123,6 +123,7 @@ static struct scsi_host_template pm8001_sht = {
.track_queue_depth = 1,
.cmd_per_lun = 32,
.map_queues = pm8001_map_queues,
+ .reserved_queuecommand = sas_queuecommand_internal,
};

/*
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 4c4d8c91b1c1..64035f83c5bd 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -739,6 +739,7 @@ int sas_discover_sata(struct domain_device *);
int sas_discover_end_dev(struct domain_device *);

void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *);
+int sas_queuecommand_internal(struct Scsi_Host *shost, struct scsi_cmnd *cmnd);

void sas_init_dev(struct domain_device *);

--
2.35.3


2022-10-25 10:09:01

by John Garry

[permalink] [raw]
Subject: [PATCH RFC v3 21/22] scsi: libsas: Queue internal abort commands as requests

Like what we did for SMP commands, send internal abort commands through
the block layer.

At this point we can delete special handling in sas_task_abort() for SAS
"internal" commands, as every slow task now has a request associated.

Function sas_task_internal_timedout() is no longer referenced, so delete
it.

Signed-off-by: John Garry <[email protected]>
---
drivers/scsi/hisi_sas/hisi_sas_main.c | 36 +++++++++----------
drivers/scsi/libsas/sas_expander.c | 2 +-
drivers/scsi/libsas/sas_init.c | 12 +++++--
drivers/scsi/libsas/sas_internal.h | 3 +-
drivers/scsi/libsas/sas_scsi_host.c | 52 ++++++---------------------
include/scsi/libsas.h | 1 -
6 files changed, 38 insertions(+), 68 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index fe2752d24fe8..65475775c844 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -465,7 +465,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
struct hisi_sas_port *port;
struct hisi_hba *hisi_hba;
struct hisi_sas_slot *slot;
- struct request *rq = NULL;
+ struct request *rq;
struct device *dev;
int rc;

@@ -485,6 +485,21 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)

hisi_hba = dev_to_hisi_hba(device);
dev = hisi_hba->dev;
+ rq = sas_task_find_rq(task);
+ if (rq) {
+ unsigned int dq_index;
+ u32 blk_tag;
+
+ blk_tag = blk_mq_unique_tag(rq);
+ 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];
+ }

switch (task->task_proto) {
case SAS_PROTOCOL_SSP:
@@ -519,22 +534,6 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)

return -ECOMM;
}
-
- rq = sas_task_find_rq(task);
- if (rq) {
- unsigned int dq_index;
- u32 blk_tag;
-
- blk_tag = blk_mq_unique_tag(rq);
- 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];
- }
break;
case SAS_PROTOCOL_INTERNAL_ABORT:
if (!hisi_hba->hw->prep_abort)
@@ -543,13 +542,10 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
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",
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index cc41127ea5cc..e852f1565fe7 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -50,7 +50,7 @@ static int smp_execute_task_sg(struct domain_device *dev,
break;
}

- task = sas_alloc_slow_task_rq(dev, GFP_KERNEL);
+ task = sas_alloc_slow_task_rq(dev, GFP_KERNEL, -1U);
if (!task) {
res = -ENOMEM;
break;
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 5f9e71a54799..c3f602bd2c4c 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -56,7 +56,7 @@ struct sas_task *sas_alloc_slow_task(gfp_t flags)
return task;
}

-struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device, gfp_t flags)
+struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device, gfp_t flags, unsigned int qid)
{
struct sas_ha_struct *sas_ha = device->port->ha;
struct Scsi_Host *shost = sas_ha->core.shost;
@@ -86,8 +86,14 @@ struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device, gfp_t flag
task->dev = device;
task->task_done = sas_task_complete_internal;

- rq = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN,
- BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
+ if (qid == -1U) {
+ rq = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN,
+ BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
+ } else {
+ rq = scsi_alloc_request_hwq(sdev->request_queue, REQ_OP_DRV_IN,
+ BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT,
+ qid);
+ }
if (IS_ERR(rq)) {
sas_free_task(task);
return NULL;
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 9b58948c57c2..af4a4bf88830 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -54,7 +54,8 @@ void sas_free_event(struct asd_sas_event *event);

struct sas_task *sas_alloc_task(gfp_t flags);
struct sas_task *sas_alloc_slow_task(gfp_t flags);
-struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device, gfp_t flags);
+struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device, gfp_t flags,
+ unsigned int qid);
void sas_free_task(struct sas_task *task);

int sas_register_ports(struct sas_ha_struct *sas_ha);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index e6ee8dd56a45..a93e019a7dbf 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -920,23 +920,6 @@ void sas_task_complete_internal(struct sas_task *task)
scsi_done(scmd);
}

-void sas_task_internal_timedout(struct timer_list *t)
-{
- struct sas_task_slow *slow = from_timer(slow, t, timer);
- struct sas_task *task = slow->task;
- bool is_completed = true;
- unsigned long flags;
-
- 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);
-}
enum blk_eh_timer_return sas_internal_timeout(struct scsi_cmnd *scmd)
{
struct sas_task *task = TO_SAS_TASK(scmd);
@@ -978,28 +961,23 @@ static int sas_execute_internal_abort(struct domain_device *device,
int res, retry;

for (retry = 0; retry < TASK_RETRY; retry++) {
- task = sas_alloc_slow_task(GFP_KERNEL);
+ struct request *rq;
+
+ task = sas_alloc_slow_task_rq(device, GFP_KERNEL, qid);
if (!task)
return -ENOMEM;

task->dev = device;
task->task_proto = SAS_PROTOCOL_INTERNAL_ABORT;
- task->task_done = sas_task_internal_done;
- task->slow_task->timer.function = sas_task_internal_timedout;
- task->slow_task->timer.expires = jiffies + TASK_TIMEOUT;
- add_timer(&task->slow_task->timer);
+ task->task_done = sas_task_complete_internal;

task->abort_task.tag = tag;
task->abort_task.type = type;
- task->abort_task.qid = qid;

- res = i->dft->lldd_execute_task(task, GFP_KERNEL);
- if (res) {
- del_timer_sync(&task->slow_task->timer);
- pr_err("Executing internal abort failed %016llx (%d)\n",
- SAS_ADDR(device->sas_addr), res);
- break;
- }
+ rq = scsi_cmd_to_rq(task->uldd_task);
+ rq->timeout = TASK_TIMEOUT;
+
+ blk_execute_rq_nowait(rq, true);

wait_for_completion(&task->slow_task->completion);
res = TMF_RESP_FUNC_FAILED;
@@ -1069,7 +1047,7 @@ int sas_execute_tmf(struct domain_device *device, void *parameter,
for (retry = 0; retry < TASK_RETRY; retry++) {
struct request *rq;

- task = sas_alloc_slow_task_rq(device, GFP_KERNEL);
+ task = sas_alloc_slow_task_rq(device, GFP_KERNEL, -1U);
if (!task)
return -ENOMEM;

@@ -1251,17 +1229,7 @@ void sas_task_abort(struct sas_task *task)
{
struct scsi_cmnd *sc = task->uldd_task;

- /* Escape for libsas internal commands */
- if (!sc) {
- struct sas_task_slow *slow = task->slow_task;
-
- if (!slow)
- return;
- if (!del_timer(&slow->timer))
- return;
- slow->timer.function(&slow->timer);
- return;
- }
+ WARN_ON_ONCE(!sc);

if (dev_is_sata(task->dev) && !task->slow_task)
sas_ata_task_abort(task);
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index f02156ccd376..60543d8b01d4 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -565,7 +565,6 @@ enum sas_internal_abort {

struct sas_internal_abort_task {
enum sas_internal_abort type;
- unsigned int qid;
u16 tag;
};

--
2.35.3


2022-10-25 10:11:38

by John Garry

[permalink] [raw]
Subject: [PATCH RFC v3 20/22] scsi: core: Add scsi_alloc_request_hwq()

Add a variant of scsi_alloc_request() which allocates a request for a
specific hw queue.

Signed-off-by: John Garry <[email protected]>
---
drivers/scsi/scsi_lib.c | 12 ++++++++++++
include/scsi/scsi_cmnd.h | 3 +++
2 files changed, 15 insertions(+)

diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 08015c42c326..a622be13bc48 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1143,6 +1143,18 @@ struct request *scsi_alloc_request(struct request_queue *q, blk_opf_t opf,
}
EXPORT_SYMBOL_GPL(scsi_alloc_request);

+struct request *scsi_alloc_request_hwq(struct request_queue *q,
+ unsigned int op, blk_mq_req_flags_t flags, unsigned int hwq)
+{
+ struct request *rq;
+
+ rq = blk_mq_alloc_request_hctx(q, op, flags, hwq);
+ if (!IS_ERR(rq))
+ scsi_initialize_rq(rq);
+ return rq;
+}
+EXPORT_SYMBOL_GPL(scsi_alloc_request_hwq);
+
/*
* Only called when the request isn't completed by SCSI, and not freed by
* SCSI
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 7d3622db38ed..1fd98d1e9c73 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -389,4 +389,7 @@ extern void scsi_build_sense(struct scsi_cmnd *scmd, int desc,
struct request *scsi_alloc_request(struct request_queue *q, blk_opf_t opf,
blk_mq_req_flags_t flags);

+struct request *scsi_alloc_request_hwq(struct request_queue *q,
+ unsigned int op, blk_mq_req_flags_t flags, unsigned int hwq);
+
#endif /* _SCSI_SCSI_CMND_H */
--
2.35.3


2022-10-25 10:11:45

by John Garry

[permalink] [raw]
Subject: [PATCH RFC v3 14/22] ata: libata-scsi: Add ata_scsi_setup_sdev()

Add a function to setup the sdev associated with an ata_device.

Currently in libata to create the sdev we call __scsi_add_device() to
create the sdev and execute the scan. However if we want to move to a
2-step process where we allocate the sdev early in the port probe, then
we need a separate function just to allocate the sdev.

We add a ata_port_operations callback .setup_scsi_device for when the
driver needs a custom setup. This is essentially for libsas, which does
not use the same options for sdev parent and id.

Signed-off-by: John Garry <[email protected]>
---
drivers/ata/libata-scsi.c | 26 ++++++++++++++++++++++++++
drivers/ata/libata.h | 1 +
include/linux/libata.h | 2 ++
3 files changed, 29 insertions(+)

diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index e2ebb0b065e2..efdba852e363 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -4253,6 +4253,32 @@ static void ata_scsi_assign_ofnode(struct ata_device *dev, struct ata_port *ap)
}
#endif

+int ata_scsi_setup_sdev(struct ata_device *dev)
+{
+ u64 lun = 0;
+ int channel = 0;
+ uint id = 0;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ struct Scsi_Host *shost = ap->scsi_host;
+ struct device *parent = &shost->shost_gendev;
+ struct scsi_device *sdev;
+
+ if (ap->ops->setup_scsi_device)
+ return ap->ops->setup_scsi_device(dev);
+
+ if (ata_is_host_link(link))
+ id = dev->devno;
+ else
+ channel = link->pmp;
+ sdev = scsi_get_dev(parent, channel, id, lun);
+ if (!sdev)
+ return -ENODEV;
+ dev->sdev = sdev;
+ ata_scsi_assign_ofnode(dev, ap);
+ return 0;
+}
+
void ata_scsi_scan_host(struct ata_port *ap, int sync)
{
int tries = 5;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 2c5c8273af01..0c2df1e60768 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -112,6 +112,7 @@ extern struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev);
extern int ata_scsi_add_hosts(struct ata_host *host,
struct scsi_host_template *sht);
+extern int ata_scsi_setup_sdev(struct ata_device *dev);
extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_set_sense(struct ata_device *dev,
diff --git a/include/linux/libata.h b/include/linux/libata.h
index fe990176e6ee..827d5838cd23 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -968,6 +968,8 @@ struct ata_port_operations {
void (*phy_reset)(struct ata_port *ap);
void (*eng_timeout)(struct ata_port *ap);

+ int (*setup_scsi_device)(struct ata_device *dev);
+
/*
* ->inherits must be the last field and all the preceding
* fields must be pointers.
--
2.35.3


2022-10-25 10:11:50

by John Garry

[permalink] [raw]
Subject: [PATCH RFC v3 17/22] scsi: libsas drivers: Reserve tags

Reserve 2x tags for libsas reserved tag handling, which should be
enough.

Continue to carve out a region of tags for driver internal management
until each sas_task always has a request.

Signed-off-by: John Garry <[email protected]>
---
drivers/scsi/aic94xx/aic94xx_init.c | 1 +
drivers/scsi/hisi_sas/hisi_sas_main.c | 4 ++++
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 1 +
drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 1 +
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 5 +++++
drivers/scsi/isci/init.c | 1 +
drivers/scsi/mvsas/mv_init.c | 5 +++++
drivers/scsi/pm8001/pm8001_init.c | 6 +++++-
8 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 06c86d7a777a..70b735cedeb3 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -62,6 +62,7 @@ static struct scsi_host_template aic94xx_sht = {
.track_queue_depth = 1,
.reserved_queuecommand = sas_queuecommand_internal,
.reserved_timedout = sas_internal_timeout,
+ .nr_reserved_cmds = 2,
};

static int asd_map_memio(struct asd_ha_struct *asd_ha)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 54860d252466..fe2752d24fe8 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -2442,6 +2442,10 @@ int hisi_sas_probe(struct platform_device *pdev,
shost->can_queue = HISI_SAS_MAX_COMMANDS;
shost->cmd_per_lun = HISI_SAS_MAX_COMMANDS;
} else {
+ /*
+ * Intentionally use HISI_SAS_UNRESERVED_IPTT for .can_queue until
+ * every sas_task we're sent has a request associated.
+ */
shost->can_queue = HISI_SAS_UNRESERVED_IPTT;
shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT;
}
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index 9f71cc72cd80..438e8a963782 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1762,6 +1762,7 @@ static struct scsi_host_template sht_v1_hw = {
.host_reset = hisi_sas_host_reset,
.reserved_queuecommand = sas_queuecommand_internal,
.reserved_timedout = sas_internal_timeout,
+ .nr_reserved_cmds = 2,
};

static const struct hisi_sas_hw hisi_sas_v1_hw = {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 483a03ed6253..b733eb18864c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -3580,6 +3580,7 @@ static struct scsi_host_template sht_v2_hw = {
.host_tagset = 1,
.reserved_queuecommand = sas_queuecommand_internal,
.reserved_timedout = sas_internal_timeout,
+ .nr_reserved_cmds = 2,
};

static const struct hisi_sas_hw hisi_sas_v2_hw = {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 02d96fba510f..d703af7985b0 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -3247,6 +3247,7 @@ static struct scsi_host_template sht_v3_hw = {
.host_tagset = 1,
.reserved_queuecommand = sas_queuecommand_internal,
.reserved_timedout = sas_internal_timeout,
+ .nr_reserved_cmds = 2,
};

static const struct hisi_sas_hw hisi_sas_v3_hw = {
@@ -4859,6 +4860,10 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
shost->max_lun = ~0;
shost->max_channel = 1;
shost->max_cmd_len = 16;
+ /*
+ * Intentionally use HISI_SAS_UNRESERVED_IPTT for .can_queue until
+ * every sas_task we're sent has a request associated.
+ */
shost->can_queue = HISI_SAS_UNRESERVED_IPTT;
shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT;

diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 9c7869bf6cde..c07d89451bb6 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -179,6 +179,7 @@ static struct scsi_host_template isci_sht = {
.track_queue_depth = 1,
.reserved_queuecommand = sas_queuecommand_internal,
.reserved_timedout = sas_internal_timeout,
+ .nr_reserved_cmds = 2,
};

static struct sas_domain_function_template isci_transport_ops = {
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 7fed0259e1f5..07e6c5d6c46d 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -56,6 +56,7 @@ static struct scsi_host_template mvs_sht = {
.track_queue_depth = 1,
.reserved_queuecommand = sas_queuecommand_internal,
.reserved_timedout = sas_internal_timeout,
+ .nr_reserved_cmds = 2,
};

static struct sas_domain_function_template mvs_transport_ops = {
@@ -470,6 +471,10 @@ static void mvs_post_sas_ha_init(struct Scsi_Host *shost,
else
can_queue = MVS_CHIP_SLOT_SZ;

+ /*
+ * Carve out MVS_RSVD_SLOTS slots internally until every sas_task we're sent
+ * has a request associated.
+ */
can_queue -= MVS_RSVD_SLOTS;

shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG);
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index ce9509792bc0..e37e8898afaa 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -125,6 +125,7 @@ static struct scsi_host_template pm8001_sht = {
.map_queues = pm8001_map_queues,
.reserved_queuecommand = sas_queuecommand_internal,
.reserved_timedout = sas_internal_timeout,
+ .nr_reserved_cmds = 2,
};

/*
@@ -1214,7 +1215,10 @@ static int pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha)

max_out_io = pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io;
ccb_count = min_t(int, PM8001_MAX_CCB, max_out_io);
-
+ /*
+ * Intentionally use ccb_count - PM8001_RESERVE_SLOT for .can_queue
+ * until every sas_task we're sent has a request associated.
+ */
shost->can_queue = ccb_count - PM8001_RESERVE_SLOT;

pm8001_ha->rsvd_tags = bitmap_zalloc(PM8001_RESERVE_SLOT, GFP_KERNEL);
--
2.35.3


2022-10-25 10:27:46

by John Garry

[permalink] [raw]
Subject: [PATCH RFC v3 03/22] scsi: core: Implement reserved command handling

From: Hannes Reinecke <[email protected]>

Quite some drivers are using management commands internally, which
typically use the same hardware tag pool (ie they are being allocated
from the same hardware resources) as the 'normal' I/O commands.
These commands are set aside before allocating the block-mq tag bitmap,
so they'll never show up as busy in the tag map.
The block-layer, OTOH, already has 'reserved_tags' to handle precisely
this situation.
So this patch adds a new field 'nr_reserved_cmds' to the SCSI host
template to instruct the block layer to set aside a tag space for these
management commands by using reserved tags.

Signed-off-by: Hannes Reinecke <[email protected]>
#jpg: Set tag_set->queue_depth = shost->can_queue, and not
= shost->can_queue + shost->nr_reserved_cmds;
Signed-off-by: John Garry <[email protected]>
---
drivers/scsi/hosts.c | 3 +++
drivers/scsi/scsi_lib.c | 2 ++
include/scsi/scsi_host.h | 15 ++++++++++++++-
3 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 12346e2297fd..db89afc37bc9 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -489,6 +489,9 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
if (sht->virt_boundary_mask)
shost->virt_boundary_mask = sht->virt_boundary_mask;

+ if (sht->nr_reserved_cmds)
+ shost->nr_reserved_cmds = sht->nr_reserved_cmds;
+
device_initialize(&shost->shost_gendev);
dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
shost->shost_gendev.bus = &scsi_bus_type;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 39d4fd124375..a8c4e7c037ae 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1978,6 +1978,8 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
tag_set->nr_hw_queues = shost->nr_hw_queues ? : 1;
tag_set->nr_maps = shost->nr_maps ? : 1;
tag_set->queue_depth = shost->can_queue;
+ tag_set->reserved_tags = shost->nr_reserved_cmds;
+
tag_set->cmd_size = cmd_size;
tag_set->numa_node = dev_to_node(shost->dma_dev);
tag_set->flags = BLK_MQ_F_SHOULD_MERGE;
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 750ccf126377..91678c77398e 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -360,10 +360,17 @@ struct scsi_host_template {
/*
* This determines if we will use a non-interrupt driven
* or an interrupt driven scheme. It is set to the maximum number
- * of simultaneous commands a single hw queue in HBA will accept.
+ * of simultaneous commands a single hw queue in HBA will accept
+ * including reserved commands.
*/
int can_queue;

+ /*
+ * This determines how many commands the HBA will set aside
+ * for reserved commands.
+ */
+ int nr_reserved_cmds;
+
/*
* In many instances, especially where disconnect / reconnect are
* supported, our host also has an ID on the SCSI bus. If this is
@@ -611,6 +618,12 @@ struct Scsi_Host {
*/
unsigned nr_hw_queues;
unsigned nr_maps;
+
+ /*
+ * Number of reserved commands to allocate, if any.
+ */
+ unsigned int nr_reserved_cmds;
+
unsigned active_mode:2;

/*
--
2.35.3


2022-10-25 11:18:00

by John Garry

[permalink] [raw]
Subject: Re: [PATCH RFC v3 00/22] blk-mq/libata/scsi: SCSI driver tagging improvements Part I

On 25/10/2022 11:17, John Garry wrote:

Hi all,

I meant to say that this is just an update for where I got to here. I am
actually changing employer soon, but will continue in upstream linux
storage domain. So I don't want people to think that I am just throwing
some stuff over the wall for the community to deal with. I would still
like people to check this.

Thanks,
John

> Currently SCSI low-level drivers are required to manage tags for commands
> which do not come via the block layer - libata internal commands would be
> an example of one of these. We want to make blk-mq manage these tags also.
>
> There was some work to provide "reserved commands" support in such series
> as https://lore.kernel.org/linux-scsi/[email protected]/
>
> This was based on allocating a request for the lifetime of the "internal"
> command.
>
> This series tries to solve that problem by not just allocating the request
> but also sending it as a request through the block layer. Reasons to do
> this:
> - Normal flow of a request and also commonality for regular scsi command
> lifetime
> - We don't leave request and scsi_cmnd fields dangling as when we just
> allocate and free the request for the lifetime of the "internal" command
> - For poll mode support we can only poll in block layer, so could not send
> internal commands on poll mode queues if we did not do this, which is a
> problem
> - Can get rid of duplicated code like libsas internal command timeout
> handling
>
> Series part I contains core SCSI midlayer, libata, and libsas changes to
> queue libsas "slow" tasks as requests.
>
> Series part II of this series focused on changing libata to queue internal
> commands as requests.
>
> Testing:
> QEMU with AHCI with disk and cdrom attached, hisi_sas, pm8001.
>
> Branch containing all patches is at:
> https://github.com/hisilicon/kernel-dev/commits/private-topic-sas-6.1-block
>
> v2 was here:
> https://lore.kernel.org/linux-scsi/[email protected]/
>
> Hannes Reinecke (1):
> scsi: core: Implement reserved command handling
>
> John Garry (21):
> blk-mq: Don't get budget for reserved requests
> scsi: core: Add scsi_get_dev()
> scsi: core: Add support to send reserved commands
> scsi: core: Add support for reserved command timeout handling
> scsi: libsas: Improve sas_ex_discover_expander() error handling
> scsi: libsas: Notify LLDD expander found before calling sas_rphy_add()
> scsi: scsi_transport_sas: Alloc sdev for expander
> scsi: libsas: Add sas_alloc_slow_task_rq()
> scsi: libsas: Add sas_queuecommand_internal()
> scsi: libsas: Add sas_internal_timeout()
> scsi: core: Use SCSI_SCAN_RESCAN in __scsi_add_device()
> scsi: scsi_transport_sas: Allocate end device target id in the rphy
> alloc
> ata: libata-scsi: Add ata_scsi_setup_sdev()
> scsi: libsas: Add sas_ata_setup_device()
> ata: libata-scsi: Allocate sdev early in port probe
> scsi: libsas drivers: Reserve tags
> scsi: libsas: Queue SMP commands as requests
> scsi: libsas: Queue TMF commands as requests
> scsi: core: Add scsi_alloc_request_hwq()
> scsi: libsas: Queue internal abort commands as requests
> scsi: libsas: Delete sas_task_slow.timer
>
> block/blk-mq.c | 4 +-
> drivers/ata/libata-eh.c | 1 +
> drivers/ata/libata-scsi.c | 49 ++++++++----
> drivers/ata/libata.h | 1 +
> drivers/scsi/aic94xx/aic94xx_init.c | 3 +
> drivers/scsi/hisi_sas/hisi_sas_main.c | 40 +++++-----
> drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 3 +
> drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 3 +
> drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 7 ++
> drivers/scsi/hosts.c | 16 ++++
> drivers/scsi/isci/init.c | 3 +
> drivers/scsi/libsas/sas_ata.c | 20 +++++
> drivers/scsi/libsas/sas_expander.c | 101 ++++++++++++++-----------
> drivers/scsi/libsas/sas_init.c | 61 ++++++++++++++-
> drivers/scsi/libsas/sas_internal.h | 5 ++
> drivers/scsi/libsas/sas_scsi_host.c | 93 ++++++++++++-----------
> drivers/scsi/mvsas/mv_init.c | 7 ++
> drivers/scsi/pm8001/pm8001_init.c | 8 +-
> drivers/scsi/scsi_error.c | 3 +
> drivers/scsi/scsi_lib.c | 42 +++++++++-
> drivers/scsi/scsi_scan.c | 29 ++++++-
> drivers/scsi/scsi_transport_sas.c | 34 ++++++---
> include/linux/libata.h | 2 +
> include/scsi/libsas.h | 8 +-
> include/scsi/scsi_cmnd.h | 3 +
> include/scsi/scsi_host.h | 21 ++++-
> 26 files changed, 424 insertions(+), 143 deletions(-)
>


2022-10-27 01:43:07

by Damien Le Moal

[permalink] [raw]
Subject: Re: [PATCH RFC v3 03/22] scsi: core: Implement reserved command handling

On 10/25/22 19:17, John Garry wrote:
> From: Hannes Reinecke <[email protected]>
>
> Quite some drivers are using management commands internally, which
> typically use the same hardware tag pool (ie they are being allocated
> from the same hardware resources) as the 'normal' I/O commands.
> These commands are set aside before allocating the block-mq tag bitmap,
> so they'll never show up as busy in the tag map.
> The block-layer, OTOH, already has 'reserved_tags' to handle precisely
> this situation.
> So this patch adds a new field 'nr_reserved_cmds' to the SCSI host
> template to instruct the block layer to set aside a tag space for these
> management commands by using reserved tags.
>
> Signed-off-by: Hannes Reinecke <[email protected]>
> #jpg: Set tag_set->queue_depth = shost->can_queue, and not
> = shost->can_queue + shost->nr_reserved_cmds;
> Signed-off-by: John Garry <[email protected]>
> ---
> drivers/scsi/hosts.c | 3 +++
> drivers/scsi/scsi_lib.c | 2 ++
> include/scsi/scsi_host.h | 15 ++++++++++++++-
> 3 files changed, 19 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
> index 12346e2297fd..db89afc37bc9 100644
> --- a/drivers/scsi/hosts.c
> +++ b/drivers/scsi/hosts.c
> @@ -489,6 +489,9 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
> if (sht->virt_boundary_mask)
> shost->virt_boundary_mask = sht->virt_boundary_mask;
>
> + if (sht->nr_reserved_cmds)
> + shost->nr_reserved_cmds = sht->nr_reserved_cmds;
> +

Nit: the if is not really necessary I think. But it does not hurt.

> device_initialize(&shost->shost_gendev);
> dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
> shost->shost_gendev.bus = &scsi_bus_type;
> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
> index 39d4fd124375..a8c4e7c037ae 100644
> --- a/drivers/scsi/scsi_lib.c
> +++ b/drivers/scsi/scsi_lib.c
> @@ -1978,6 +1978,8 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
> tag_set->nr_hw_queues = shost->nr_hw_queues ? : 1;
> tag_set->nr_maps = shost->nr_maps ? : 1;
> tag_set->queue_depth = shost->can_queue;
> + tag_set->reserved_tags = shost->nr_reserved_cmds;
> +

Why the blank line ?

> tag_set->cmd_size = cmd_size;
> tag_set->numa_node = dev_to_node(shost->dma_dev);
> tag_set->flags = BLK_MQ_F_SHOULD_MERGE;
> diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
> index 750ccf126377..91678c77398e 100644
> --- a/include/scsi/scsi_host.h
> +++ b/include/scsi/scsi_host.h
> @@ -360,10 +360,17 @@ struct scsi_host_template {
> /*
> * This determines if we will use a non-interrupt driven
> * or an interrupt driven scheme. It is set to the maximum number
> - * of simultaneous commands a single hw queue in HBA will accept.
> + * of simultaneous commands a single hw queue in HBA will accept
> + * including reserved commands.
> */
> int can_queue;
>
> + /*
> + * This determines how many commands the HBA will set aside
> + * for reserved commands.
> + */
> + int nr_reserved_cmds;
> +
> /*
> * In many instances, especially where disconnect / reconnect are
> * supported, our host also has an ID on the SCSI bus. If this is
> @@ -611,6 +618,12 @@ struct Scsi_Host {
> */
> unsigned nr_hw_queues;
> unsigned nr_maps;
> +
> + /*
> + * Number of reserved commands to allocate, if any.
> + */
> + unsigned int nr_reserved_cmds;
> +
> unsigned active_mode:2;
>
> /*

--
Damien Le Moal
Western Digital Research


2022-10-27 08:25:20

by Hannes Reinecke

[permalink] [raw]
Subject: Re: [PATCH RFC v3 03/22] scsi: core: Implement reserved command handling

On 10/27/22 03:18, Damien Le Moal wrote:
> On 10/25/22 19:17, John Garry wrote:
>> From: Hannes Reinecke <[email protected]>
>>
>> Quite some drivers are using management commands internally, which
>> typically use the same hardware tag pool (ie they are being allocated
>> from the same hardware resources) as the 'normal' I/O commands.
>> These commands are set aside before allocating the block-mq tag bitmap,
>> so they'll never show up as busy in the tag map.
>> The block-layer, OTOH, already has 'reserved_tags' to handle precisely
>> this situation.
>> So this patch adds a new field 'nr_reserved_cmds' to the SCSI host
>> template to instruct the block layer to set aside a tag space for these
>> management commands by using reserved tags.
>>
>> Signed-off-by: Hannes Reinecke <[email protected]>
>> #jpg: Set tag_set->queue_depth = shost->can_queue, and not
>> = shost->can_queue + shost->nr_reserved_cmds;
>> Signed-off-by: John Garry <[email protected]>
>> ---
>> drivers/scsi/hosts.c | 3 +++
>> drivers/scsi/scsi_lib.c | 2 ++
>> include/scsi/scsi_host.h | 15 ++++++++++++++-
>> 3 files changed, 19 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
>> index 12346e2297fd..db89afc37bc9 100644
>> --- a/drivers/scsi/hosts.c
>> +++ b/drivers/scsi/hosts.c
>> @@ -489,6 +489,9 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
>> if (sht->virt_boundary_mask)
>> shost->virt_boundary_mask = sht->virt_boundary_mask;
>>
>> + if (sht->nr_reserved_cmds)
>> + shost->nr_reserved_cmds = sht->nr_reserved_cmds;
>> +
>
> Nit: the if is not really necessary I think. But it does not hurt.
>
Yes, we do.
Not all HBAs are able to figure out the number of reserved commands
upfront; some modify that based on the PCI device used etc.
So I'd keep it for now.

Cheers,

Hannes
--
Dr. Hannes Reinecke Kernel Storage Architect
[email protected] +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman


2022-10-27 08:58:27

by John Garry

[permalink] [raw]
Subject: Re: [PATCH RFC v3 03/22] scsi: core: Implement reserved command handling

On 27/10/2022 08:51, Hannes Reinecke wrote:
>>>
>>> Signed-off-by: Hannes Reinecke <[email protected]>
>>> #jpg: Set tag_set->queue_depth = shost->can_queue, and not
>>> = shost->can_queue + shost->nr_reserved_cmds;
>>> Signed-off-by: John Garry <[email protected]>
>>> ---
>>>   drivers/scsi/hosts.c     |  3 +++
>>>   drivers/scsi/scsi_lib.c  |  2 ++
>>>   include/scsi/scsi_host.h | 15 ++++++++++++++-
>>>   3 files changed, 19 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
>>> index 12346e2297fd..db89afc37bc9 100644
>>> --- a/drivers/scsi/hosts.c
>>> +++ b/drivers/scsi/hosts.c
>>> @@ -489,6 +489,9 @@ struct Scsi_Host *scsi_host_alloc(struct
>>> scsi_host_template *sht, int privsize)
>>>       if (sht->virt_boundary_mask)
>>>           shost->virt_boundary_mask = sht->virt_boundary_mask;
>>> +    if (sht->nr_reserved_cmds)
>>> +        shost->nr_reserved_cmds = sht->nr_reserved_cmds;
>>> +
>>
>> Nit: the if is not really necessary I think. But it does not hurt.
>>
> Yes, we do.
> Not all HBAs are able to figure out the number of reserved commands
> upfront; some modify that based on the PCI device used etc.
> So I'd keep it for now.

I think logically Damien is right as in the shost alloc
shost->nr_reserved_cmds is initially zero, so:

if (sht->nr_reserved_cmds)
shost->nr_reserved_cmds = sht->nr_reserved_cmds;

is same as simply:

shost->nr_reserved_cmds = sht->nr_reserved_cmds;

However I am just copying the coding style.

Thanks,
John

2022-10-27 09:33:54

by John Garry

[permalink] [raw]
Subject: Re: [PATCH RFC v3 03/22] scsi: core: Implement reserved command handling


>
>> device_initialize(&shost->shost_gendev);
>> dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
>> shost->shost_gendev.bus = &scsi_bus_type;
>> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
>> index 39d4fd124375..a8c4e7c037ae 100644
>> --- a/drivers/scsi/scsi_lib.c
>> +++ b/drivers/scsi/scsi_lib.c
>> @@ -1978,6 +1978,8 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
>> tag_set->nr_hw_queues = shost->nr_hw_queues ? : 1;
>> tag_set->nr_maps = shost->nr_maps ? : 1;
>> tag_set->queue_depth = shost->can_queue;
>> + tag_set->reserved_tags = shost->nr_reserved_cmds;
>> +
> Why the blank line ?
>

I don't think that it is required, I can remedy.

>> tag_set->cmd_size = cmd_size;

Thanks,
John

2022-10-29 01:49:11

by chenxiang (M)

[permalink] [raw]
Subject: Re: [PATCH RFC v3 21/22] scsi: libsas: Queue internal abort commands as requests

Hi John,

For internal abort commands, it allocates and deliver requests through
sdev->request_queue.

Is it possible that we still need to send internal abort commands even
if sdev is freed?

I notices that in sas_destruct_devices, it calls sas_rphy_delete() to
remove target, and then call i->dft->lldd_dev_gone()

which will call internal abort commands.



在 2022/10/25 18:18, John Garry 写道:
> Like what we did for SMP commands, send internal abort commands through
> the block layer.
>
> At this point we can delete special handling in sas_task_abort() for SAS
> "internal" commands, as every slow task now has a request associated.
>
> Function sas_task_internal_timedout() is no longer referenced, so delete
> it.
>
> Signed-off-by: John Garry <[email protected]>
> ---
> drivers/scsi/hisi_sas/hisi_sas_main.c | 36 +++++++++----------
> drivers/scsi/libsas/sas_expander.c | 2 +-
> drivers/scsi/libsas/sas_init.c | 12 +++++--
> drivers/scsi/libsas/sas_internal.h | 3 +-
> drivers/scsi/libsas/sas_scsi_host.c | 52 ++++++---------------------
> include/scsi/libsas.h | 1 -
> 6 files changed, 38 insertions(+), 68 deletions(-)
>
> diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
> index fe2752d24fe8..65475775c844 100644
> --- a/drivers/scsi/hisi_sas/hisi_sas_main.c
> +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
> @@ -465,7 +465,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
> struct hisi_sas_port *port;
> struct hisi_hba *hisi_hba;
> struct hisi_sas_slot *slot;
> - struct request *rq = NULL;
> + struct request *rq;
> struct device *dev;
> int rc;
>
> @@ -485,6 +485,21 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
>
> hisi_hba = dev_to_hisi_hba(device);
> dev = hisi_hba->dev;
> + rq = sas_task_find_rq(task);
> + if (rq) {
> + unsigned int dq_index;
> + u32 blk_tag;
> +
> + blk_tag = blk_mq_unique_tag(rq);
> + 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];
> + }
>
> switch (task->task_proto) {
> case SAS_PROTOCOL_SSP:
> @@ -519,22 +534,6 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
>
> return -ECOMM;
> }
> -
> - rq = sas_task_find_rq(task);
> - if (rq) {
> - unsigned int dq_index;
> - u32 blk_tag;
> -
> - blk_tag = blk_mq_unique_tag(rq);
> - 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];
> - }
> break;
> case SAS_PROTOCOL_INTERNAL_ABORT:
> if (!hisi_hba->hw->prep_abort)
> @@ -543,13 +542,10 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
> 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",
> diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
> index cc41127ea5cc..e852f1565fe7 100644
> --- a/drivers/scsi/libsas/sas_expander.c
> +++ b/drivers/scsi/libsas/sas_expander.c
> @@ -50,7 +50,7 @@ static int smp_execute_task_sg(struct domain_device *dev,
> break;
> }
>
> - task = sas_alloc_slow_task_rq(dev, GFP_KERNEL);
> + task = sas_alloc_slow_task_rq(dev, GFP_KERNEL, -1U);
> if (!task) {
> res = -ENOMEM;
> break;
> diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
> index 5f9e71a54799..c3f602bd2c4c 100644
> --- a/drivers/scsi/libsas/sas_init.c
> +++ b/drivers/scsi/libsas/sas_init.c
> @@ -56,7 +56,7 @@ struct sas_task *sas_alloc_slow_task(gfp_t flags)
> return task;
> }
>
> -struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device, gfp_t flags)
> +struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device, gfp_t flags, unsigned int qid)
> {
> struct sas_ha_struct *sas_ha = device->port->ha;
> struct Scsi_Host *shost = sas_ha->core.shost;
> @@ -86,8 +86,14 @@ struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device, gfp_t flag
> task->dev = device;
> task->task_done = sas_task_complete_internal;
>
> - rq = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN,
> - BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
> + if (qid == -1U) {
> + rq = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN,
> + BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
> + } else {
> + rq = scsi_alloc_request_hwq(sdev->request_queue, REQ_OP_DRV_IN,
> + BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT,
> + qid);
> + }
> if (IS_ERR(rq)) {
> sas_free_task(task);
> return NULL;
> diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
> index 9b58948c57c2..af4a4bf88830 100644
> --- a/drivers/scsi/libsas/sas_internal.h
> +++ b/drivers/scsi/libsas/sas_internal.h
> @@ -54,7 +54,8 @@ void sas_free_event(struct asd_sas_event *event);
>
> struct sas_task *sas_alloc_task(gfp_t flags);
> struct sas_task *sas_alloc_slow_task(gfp_t flags);
> -struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device, gfp_t flags);
> +struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device, gfp_t flags,
> + unsigned int qid);
> void sas_free_task(struct sas_task *task);
>
> int sas_register_ports(struct sas_ha_struct *sas_ha);
> diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
> index e6ee8dd56a45..a93e019a7dbf 100644
> --- a/drivers/scsi/libsas/sas_scsi_host.c
> +++ b/drivers/scsi/libsas/sas_scsi_host.c
> @@ -920,23 +920,6 @@ void sas_task_complete_internal(struct sas_task *task)
> scsi_done(scmd);
> }
>
> -void sas_task_internal_timedout(struct timer_list *t)
> -{
> - struct sas_task_slow *slow = from_timer(slow, t, timer);
> - struct sas_task *task = slow->task;
> - bool is_completed = true;
> - unsigned long flags;
> -
> - 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);
> -}
> enum blk_eh_timer_return sas_internal_timeout(struct scsi_cmnd *scmd)
> {
> struct sas_task *task = TO_SAS_TASK(scmd);
> @@ -978,28 +961,23 @@ static int sas_execute_internal_abort(struct domain_device *device,
> int res, retry;
>
> for (retry = 0; retry < TASK_RETRY; retry++) {
> - task = sas_alloc_slow_task(GFP_KERNEL);
> + struct request *rq;
> +
> + task = sas_alloc_slow_task_rq(device, GFP_KERNEL, qid);
> if (!task)
> return -ENOMEM;
>
> task->dev = device;
> task->task_proto = SAS_PROTOCOL_INTERNAL_ABORT;
> - task->task_done = sas_task_internal_done;
> - task->slow_task->timer.function = sas_task_internal_timedout;
> - task->slow_task->timer.expires = jiffies + TASK_TIMEOUT;
> - add_timer(&task->slow_task->timer);
> + task->task_done = sas_task_complete_internal;
>
> task->abort_task.tag = tag;
> task->abort_task.type = type;
> - task->abort_task.qid = qid;
>
> - res = i->dft->lldd_execute_task(task, GFP_KERNEL);
> - if (res) {
> - del_timer_sync(&task->slow_task->timer);
> - pr_err("Executing internal abort failed %016llx (%d)\n",
> - SAS_ADDR(device->sas_addr), res);
> - break;
> - }
> + rq = scsi_cmd_to_rq(task->uldd_task);
> + rq->timeout = TASK_TIMEOUT;
> +
> + blk_execute_rq_nowait(rq, true);
>
> wait_for_completion(&task->slow_task->completion);
> res = TMF_RESP_FUNC_FAILED;
> @@ -1069,7 +1047,7 @@ int sas_execute_tmf(struct domain_device *device, void *parameter,
> for (retry = 0; retry < TASK_RETRY; retry++) {
> struct request *rq;
>
> - task = sas_alloc_slow_task_rq(device, GFP_KERNEL);
> + task = sas_alloc_slow_task_rq(device, GFP_KERNEL, -1U);
> if (!task)
> return -ENOMEM;
>
> @@ -1251,17 +1229,7 @@ void sas_task_abort(struct sas_task *task)
> {
> struct scsi_cmnd *sc = task->uldd_task;
>
> - /* Escape for libsas internal commands */
> - if (!sc) {
> - struct sas_task_slow *slow = task->slow_task;
> -
> - if (!slow)
> - return;
> - if (!del_timer(&slow->timer))
> - return;
> - slow->timer.function(&slow->timer);
> - return;
> - }
> + WARN_ON_ONCE(!sc);
>
> if (dev_is_sata(task->dev) && !task->slow_task)
> sas_ata_task_abort(task);
> diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
> index f02156ccd376..60543d8b01d4 100644
> --- a/include/scsi/libsas.h
> +++ b/include/scsi/libsas.h
> @@ -565,7 +565,6 @@ enum sas_internal_abort {
>
> struct sas_internal_abort_task {
> enum sas_internal_abort type;
> - unsigned int qid;
> u16 tag;
> };
>


2022-11-02 10:26:08

by John Garry

[permalink] [raw]
Subject: Re: [PATCH RFC v3 21/22] scsi: libsas: Queue internal abort commands as requests

On 29/10/2022 02:15, chenxiang (M) wrote:
> Hi John,
>
> For internal abort commands, it allocates and deliver requests through
> sdev->request_queue.
>
> Is it possible that we still need to send internal abort commands even
> if sdev is freed?
>
> I  notices that in sas_destruct_devices, it calls sas_rphy_delete() to
> remove target, and then call i->dft->lldd_dev_gone()
>
> which will call internal abort commands.

Good question. I did not properly check the removal path and, indeed,
the sdev would be gone when we call lldd_dev_gone ->
internal_task_abort_dev, so that should fail to execute.

However I do wonder why we really need to call internal_task_abort_dev
in the lldd_dev_gone callback. At the point lldd_dev_gone is called all
IO should be complete - indeed, it is now accounted for as requests
associated with the sdev. If it is really required to be called (HW
requirement?) then maybe it could be relocated to sdev/starget teardown
callback.

Thanks,
John

>
>
>
> 在 2022/10/25 18:18, John Garry 写道:
>> Like what we did for SMP commands, send internal abort commands through
>> the block layer.
>>
>> At this point we can delete special handling in sas_task_abort() for SAS
>> "internal" commands, as every slow task now has a request associated.
>>
>> Function sas_task_internal_timedout() is no longer referenced, so delete
>> it.
>>
>> Signed-off-by: John Garry <[email protected]>
>> ---
>>   drivers/scsi/hisi_sas/hisi_sas_main.c | 36 +++++++++----------
>>   drivers/scsi/libsas/sas_expander.c    |  2 +-
>>   drivers/scsi/libsas/sas_init.c        | 12 +++++--
>>   drivers/scsi/libsas/sas_internal.h    |  3 +-
>>   drivers/scsi/libsas/sas_scsi_host.c   | 52 ++++++---------------------
>>   include/scsi/libsas.h                 |  1 -
>>   6 files changed, 38 insertions(+), 68 deletions(-)
>>
>> diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c
>> b/drivers/scsi/hisi_sas/hisi_sas_main.c
>> index fe2752d24fe8..65475775c844 100644
>> --- a/drivers/scsi/hisi_sas/hisi_sas_main.c
>> +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
>> @@ -465,7 +465,7 @@ static int hisi_sas_queue_command(struct sas_task
>> *task, gfp_t gfp_flags)
>>       struct hisi_sas_port *port;
>>       struct hisi_hba *hisi_hba;
>>       struct hisi_sas_slot *slot;
>> -    struct request *rq = NULL;
>> +    struct request *rq;
>>       struct device *dev;
>>       int rc;
>> @@ -485,6 +485,21 @@ static int hisi_sas_queue_command(struct sas_task
>> *task, gfp_t gfp_flags)
>>       hisi_hba = dev_to_hisi_hba(device);
>>       dev = hisi_hba->dev;
>> +    rq = sas_task_find_rq(task);
>> +    if (rq) {
>> +        unsigned int dq_index;
>> +        u32 blk_tag;
>> +
>> +        blk_tag = blk_mq_unique_tag(rq);
>> +        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];
>> +    }
>>       switch (task->task_proto) {
>>       case SAS_PROTOCOL_SSP:
>> @@ -519,22 +534,6 @@ static int hisi_sas_queue_command(struct sas_task
>> *task, gfp_t gfp_flags)
>>                   return -ECOMM;
>>           }
>> -
>> -        rq = sas_task_find_rq(task);
>> -        if (rq) {
>> -            unsigned int dq_index;
>> -            u32 blk_tag;
>> -
>> -            blk_tag = blk_mq_unique_tag(rq);
>> -            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];
>> -        }
>>           break;
>>       case SAS_PROTOCOL_INTERNAL_ABORT:
>>           if (!hisi_hba->hw->prep_abort)
>> @@ -543,13 +542,10 @@ static int hisi_sas_queue_command(struct
>> sas_task *task, gfp_t gfp_flags)
>>           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",
>> diff --git a/drivers/scsi/libsas/sas_expander.c
>> b/drivers/scsi/libsas/sas_expander.c
>> index cc41127ea5cc..e852f1565fe7 100644
>> --- a/drivers/scsi/libsas/sas_expander.c
>> +++ b/drivers/scsi/libsas/sas_expander.c
>> @@ -50,7 +50,7 @@ static int smp_execute_task_sg(struct domain_device
>> *dev,
>>               break;
>>           }
>> -        task = sas_alloc_slow_task_rq(dev, GFP_KERNEL);
>> +        task = sas_alloc_slow_task_rq(dev, GFP_KERNEL, -1U);
>>           if (!task) {
>>               res = -ENOMEM;
>>               break;
>> diff --git a/drivers/scsi/libsas/sas_init.c
>> b/drivers/scsi/libsas/sas_init.c
>> index 5f9e71a54799..c3f602bd2c4c 100644
>> --- a/drivers/scsi/libsas/sas_init.c
>> +++ b/drivers/scsi/libsas/sas_init.c
>> @@ -56,7 +56,7 @@ struct sas_task *sas_alloc_slow_task(gfp_t flags)
>>       return task;
>>   }
>> -struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device,
>> gfp_t flags)
>> +struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device,
>> gfp_t flags, unsigned int qid)
>>   {
>>       struct sas_ha_struct *sas_ha = device->port->ha;
>>       struct Scsi_Host *shost = sas_ha->core.shost;
>> @@ -86,8 +86,14 @@ struct sas_task *sas_alloc_slow_task_rq(struct
>> domain_device *device, gfp_t flag
>>       task->dev = device;
>>       task->task_done = sas_task_complete_internal;
>> -    rq = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN,
>> -                BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
>> +    if (qid == -1U) {
>> +        rq = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN,
>> +                    BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
>> +    } else {
>> +        rq = scsi_alloc_request_hwq(sdev->request_queue, REQ_OP_DRV_IN,
>> +                    BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT,
>> +                    qid);
>> +    }
>>       if (IS_ERR(rq)) {
>>           sas_free_task(task);
>>           return NULL;
>> diff --git a/drivers/scsi/libsas/sas_internal.h
>> b/drivers/scsi/libsas/sas_internal.h
>> index 9b58948c57c2..af4a4bf88830 100644
>> --- a/drivers/scsi/libsas/sas_internal.h
>> +++ b/drivers/scsi/libsas/sas_internal.h
>> @@ -54,7 +54,8 @@ void sas_free_event(struct asd_sas_event *event);
>>   struct sas_task *sas_alloc_task(gfp_t flags);
>>   struct sas_task *sas_alloc_slow_task(gfp_t flags);
>> -struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device,
>> gfp_t flags);
>> +struct sas_task *sas_alloc_slow_task_rq(struct domain_device *device,
>> gfp_t flags,
>> +                      unsigned int qid);
>>   void sas_free_task(struct sas_task *task);
>>   int  sas_register_ports(struct sas_ha_struct *sas_ha);
>> diff --git a/drivers/scsi/libsas/sas_scsi_host.c
>> b/drivers/scsi/libsas/sas_scsi_host.c
>> index e6ee8dd56a45..a93e019a7dbf 100644
>> --- a/drivers/scsi/libsas/sas_scsi_host.c
>> +++ b/drivers/scsi/libsas/sas_scsi_host.c
>> @@ -920,23 +920,6 @@ void sas_task_complete_internal(struct sas_task
>> *task)
>>       scsi_done(scmd);
>>   }
>> -void sas_task_internal_timedout(struct timer_list *t)
>> -{
>> -    struct sas_task_slow *slow = from_timer(slow, t, timer);
>> -    struct sas_task *task = slow->task;
>> -    bool is_completed = true;
>> -    unsigned long flags;
>> -
>> -    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);
>> -}
>>   enum blk_eh_timer_return sas_internal_timeout(struct scsi_cmnd *scmd)
>>   {
>>       struct sas_task *task = TO_SAS_TASK(scmd);
>> @@ -978,28 +961,23 @@ static int sas_execute_internal_abort(struct
>> domain_device *device,
>>       int res, retry;
>>       for (retry = 0; retry < TASK_RETRY; retry++) {
>> -        task = sas_alloc_slow_task(GFP_KERNEL);
>> +        struct request *rq;
>> +
>> +        task = sas_alloc_slow_task_rq(device, GFP_KERNEL, qid);
>>           if (!task)
>>               return -ENOMEM;
>>           task->dev = device;
>>           task->task_proto = SAS_PROTOCOL_INTERNAL_ABORT;
>> -        task->task_done = sas_task_internal_done;
>> -        task->slow_task->timer.function = sas_task_internal_timedout;
>> -        task->slow_task->timer.expires = jiffies + TASK_TIMEOUT;
>> -        add_timer(&task->slow_task->timer);
>> +        task->task_done = sas_task_complete_internal;
>>           task->abort_task.tag = tag;
>>           task->abort_task.type = type;
>> -        task->abort_task.qid = qid;
>> -        res = i->dft->lldd_execute_task(task, GFP_KERNEL);
>> -        if (res) {
>> -            del_timer_sync(&task->slow_task->timer);
>> -            pr_err("Executing internal abort failed %016llx (%d)\n",
>> -                   SAS_ADDR(device->sas_addr), res);
>> -            break;
>> -        }
>> +        rq = scsi_cmd_to_rq(task->uldd_task);
>> +        rq->timeout = TASK_TIMEOUT;
>> +
>> +        blk_execute_rq_nowait(rq, true);
>>           wait_for_completion(&task->slow_task->completion);
>>           res = TMF_RESP_FUNC_FAILED;
>> @@ -1069,7 +1047,7 @@ int sas_execute_tmf(struct domain_device
>> *device, void *parameter,
>>       for (retry = 0; retry < TASK_RETRY; retry++) {
>>           struct request *rq;
>> -        task = sas_alloc_slow_task_rq(device, GFP_KERNEL);
>> +        task = sas_alloc_slow_task_rq(device, GFP_KERNEL, -1U);
>>           if (!task)
>>               return -ENOMEM;
>> @@ -1251,17 +1229,7 @@ void sas_task_abort(struct sas_task *task)
>>   {
>>       struct scsi_cmnd *sc = task->uldd_task;
>> -    /* Escape for libsas internal commands */
>> -    if (!sc) {
>> -        struct sas_task_slow *slow = task->slow_task;
>> -
>> -        if (!slow)
>> -            return;
>> -        if (!del_timer(&slow->timer))
>> -            return;
>> -        slow->timer.function(&slow->timer);
>> -        return;
>> -    }
>> +    WARN_ON_ONCE(!sc);
>>       if (dev_is_sata(task->dev) && !task->slow_task)
>>           sas_ata_task_abort(task);
>> diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
>> index f02156ccd376..60543d8b01d4 100644
>> --- a/include/scsi/libsas.h
>> +++ b/include/scsi/libsas.h
>> @@ -565,7 +565,6 @@ enum sas_internal_abort {
>>   struct sas_internal_abort_task {
>>       enum sas_internal_abort type;
>> -    unsigned int qid;
>>       u16 tag;
>>   };
>
>
>


2022-11-03 03:41:44

by chenxiang (M)

[permalink] [raw]
Subject: Re: [PATCH RFC v3 21/22] scsi: libsas: Queue internal abort commands as requests



在 2022/11/2 18:04, John Garry 写道:
> On 29/10/2022 02:15, chenxiang (M) wrote:
>> Hi John,
>>
>> For internal abort commands, it allocates and deliver requests
>> through sdev->request_queue.
>>
>> Is it possible that we still need to send internal abort commands
>> even if sdev is freed?
>>
>> I notices that in sas_destruct_devices, it calls sas_rphy_delete()
>> to remove target, and then call i->dft->lldd_dev_gone()
>>
>> which will call internal abort commands.
>
> Good question. I did not properly check the removal path and, indeed,
> the sdev would be gone when we call lldd_dev_gone ->
> internal_task_abort_dev, so that should fail to execute.
>
> However I do wonder why we really need to call internal_task_abort_dev
> in the lldd_dev_gone callback. At the point lldd_dev_gone is called
> all IO should be complete - indeed, it is now accounted for as
> requests associated with the sdev. If it is really required to be
> called (HW requirement?) then maybe it could be relocated to
> sdev/starget teardown callback.

Call internal abort in lldd_dev_gone callback comes from the commit
(40f2702b57eb16ef "scsi: hisi_sas: add internal abort in
hisi_sas_dev_gone()"), and it seems not descript why adding it.
But those internal IOs are sent to SAS controller to do something in it,
and it is not depend on scsi device. Like SMP IO, it allocates
scsi_device for expander, why not allocate a scsi_device for controller?

>
> Thanks,
> John
>
>>
>>
>>
>> 在 2022/10/25 18:18, John Garry 写道:
>>> Like what we did for SMP commands, send internal abort commands through
>>> the block layer.
>>>
>>> At this point we can delete special handling in sas_task_abort() for
>>> SAS
>>> "internal" commands, as every slow task now has a request associated.
>>>
>>> Function sas_task_internal_timedout() is no longer referenced, so
>>> delete
>>> it.
>>>
>>> Signed-off-by: John Garry <[email protected]>
>>> ---
>>> drivers/scsi/hisi_sas/hisi_sas_main.c | 36 +++++++++----------
>>> drivers/scsi/libsas/sas_expander.c | 2 +-
>>> drivers/scsi/libsas/sas_init.c | 12 +++++--
>>> drivers/scsi/libsas/sas_internal.h | 3 +-
>>> drivers/scsi/libsas/sas_scsi_host.c | 52
>>> ++++++---------------------
>>> include/scsi/libsas.h | 1 -
>>> 6 files changed, 38 insertions(+), 68 deletions(-)
>>>
>>> diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c
>>> b/drivers/scsi/hisi_sas/hisi_sas_main.c
>>> index fe2752d24fe8..65475775c844 100644
>>> --- a/drivers/scsi/hisi_sas/hisi_sas_main.c
>>> +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
>>> @@ -465,7 +465,7 @@ static int hisi_sas_queue_command(struct
>>> sas_task *task, gfp_t gfp_flags)
>>> struct hisi_sas_port *port;
>>> struct hisi_hba *hisi_hba;
>>> struct hisi_sas_slot *slot;
>>> - struct request *rq = NULL;
>>> + struct request *rq;
>>> struct device *dev;
>>> int rc;
>>> @@ -485,6 +485,21 @@ static int hisi_sas_queue_command(struct
>>> sas_task *task, gfp_t gfp_flags)
>>> hisi_hba = dev_to_hisi_hba(device);
>>> dev = hisi_hba->dev;
>>> + rq = sas_task_find_rq(task);
>>> + if (rq) {
>>> + unsigned int dq_index;
>>> + u32 blk_tag;
>>> +
>>> + blk_tag = blk_mq_unique_tag(rq);
>>> + 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];
>>> + }
>>> switch (task->task_proto) {
>>> case SAS_PROTOCOL_SSP:
>>> @@ -519,22 +534,6 @@ static int hisi_sas_queue_command(struct
>>> sas_task *task, gfp_t gfp_flags)
>>> return -ECOMM;
>>> }
>>> -
>>> - rq = sas_task_find_rq(task);
>>> - if (rq) {
>>> - unsigned int dq_index;
>>> - u32 blk_tag;
>>> -
>>> - blk_tag = blk_mq_unique_tag(rq);
>>> - 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];
>>> - }
>>> break;
>>> case SAS_PROTOCOL_INTERNAL_ABORT:
>>> if (!hisi_hba->hw->prep_abort)
>>> @@ -543,13 +542,10 @@ static int hisi_sas_queue_command(struct
>>> sas_task *task, gfp_t gfp_flags)
>>> 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",
>>> diff --git a/drivers/scsi/libsas/sas_expander.c
>>> b/drivers/scsi/libsas/sas_expander.c
>>> index cc41127ea5cc..e852f1565fe7 100644
>>> --- a/drivers/scsi/libsas/sas_expander.c
>>> +++ b/drivers/scsi/libsas/sas_expander.c
>>> @@ -50,7 +50,7 @@ static int smp_execute_task_sg(struct
>>> domain_device *dev,
>>> break;
>>> }
>>> - task = sas_alloc_slow_task_rq(dev, GFP_KERNEL);
>>> + task = sas_alloc_slow_task_rq(dev, GFP_KERNEL, -1U);
>>> if (!task) {
>>> res = -ENOMEM;
>>> break;
>>> diff --git a/drivers/scsi/libsas/sas_init.c
>>> b/drivers/scsi/libsas/sas_init.c
>>> index 5f9e71a54799..c3f602bd2c4c 100644
>>> --- a/drivers/scsi/libsas/sas_init.c
>>> +++ b/drivers/scsi/libsas/sas_init.c
>>> @@ -56,7 +56,7 @@ struct sas_task *sas_alloc_slow_task(gfp_t flags)
>>> return task;
>>> }
>>> -struct sas_task *sas_alloc_slow_task_rq(struct domain_device
>>> *device, gfp_t flags)
>>> +struct sas_task *sas_alloc_slow_task_rq(struct domain_device
>>> *device, gfp_t flags, unsigned int qid)
>>> {
>>> struct sas_ha_struct *sas_ha = device->port->ha;
>>> struct Scsi_Host *shost = sas_ha->core.shost;
>>> @@ -86,8 +86,14 @@ struct sas_task *sas_alloc_slow_task_rq(struct
>>> domain_device *device, gfp_t flag
>>> task->dev = device;
>>> task->task_done = sas_task_complete_internal;
>>> - rq = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN,
>>> - BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
>>> + if (qid == -1U) {
>>> + rq = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN,
>>> + BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
>>> + } else {
>>> + rq = scsi_alloc_request_hwq(sdev->request_queue,
>>> REQ_OP_DRV_IN,
>>> + BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT,
>>> + qid);
>>> + }
>>> if (IS_ERR(rq)) {
>>> sas_free_task(task);
>>> return NULL;
>>> diff --git a/drivers/scsi/libsas/sas_internal.h
>>> b/drivers/scsi/libsas/sas_internal.h
>>> index 9b58948c57c2..af4a4bf88830 100644
>>> --- a/drivers/scsi/libsas/sas_internal.h
>>> +++ b/drivers/scsi/libsas/sas_internal.h
>>> @@ -54,7 +54,8 @@ void sas_free_event(struct asd_sas_event *event);
>>> struct sas_task *sas_alloc_task(gfp_t flags);
>>> struct sas_task *sas_alloc_slow_task(gfp_t flags);
>>> -struct sas_task *sas_alloc_slow_task_rq(struct domain_device
>>> *device, gfp_t flags);
>>> +struct sas_task *sas_alloc_slow_task_rq(struct domain_device
>>> *device, gfp_t flags,
>>> + unsigned int qid);
>>> void sas_free_task(struct sas_task *task);
>>> int sas_register_ports(struct sas_ha_struct *sas_ha);
>>> diff --git a/drivers/scsi/libsas/sas_scsi_host.c
>>> b/drivers/scsi/libsas/sas_scsi_host.c
>>> index e6ee8dd56a45..a93e019a7dbf 100644
>>> --- a/drivers/scsi/libsas/sas_scsi_host.c
>>> +++ b/drivers/scsi/libsas/sas_scsi_host.c
>>> @@ -920,23 +920,6 @@ void sas_task_complete_internal(struct sas_task
>>> *task)
>>> scsi_done(scmd);
>>> }
>>> -void sas_task_internal_timedout(struct timer_list *t)
>>> -{
>>> - struct sas_task_slow *slow = from_timer(slow, t, timer);
>>> - struct sas_task *task = slow->task;
>>> - bool is_completed = true;
>>> - unsigned long flags;
>>> -
>>> - 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);
>>> -}
>>> enum blk_eh_timer_return sas_internal_timeout(struct scsi_cmnd *scmd)
>>> {
>>> struct sas_task *task = TO_SAS_TASK(scmd);
>>> @@ -978,28 +961,23 @@ static int sas_execute_internal_abort(struct
>>> domain_device *device,
>>> int res, retry;
>>> for (retry = 0; retry < TASK_RETRY; retry++) {
>>> - task = sas_alloc_slow_task(GFP_KERNEL);
>>> + struct request *rq;
>>> +
>>> + task = sas_alloc_slow_task_rq(device, GFP_KERNEL, qid);
>>> if (!task)
>>> return -ENOMEM;
>>> task->dev = device;
>>> task->task_proto = SAS_PROTOCOL_INTERNAL_ABORT;
>>> - task->task_done = sas_task_internal_done;
>>> - task->slow_task->timer.function = sas_task_internal_timedout;
>>> - task->slow_task->timer.expires = jiffies + TASK_TIMEOUT;
>>> - add_timer(&task->slow_task->timer);
>>> + task->task_done = sas_task_complete_internal;
>>> task->abort_task.tag = tag;
>>> task->abort_task.type = type;
>>> - task->abort_task.qid = qid;
>>> - res = i->dft->lldd_execute_task(task, GFP_KERNEL);
>>> - if (res) {
>>> - del_timer_sync(&task->slow_task->timer);
>>> - pr_err("Executing internal abort failed %016llx (%d)\n",
>>> - SAS_ADDR(device->sas_addr), res);
>>> - break;
>>> - }
>>> + rq = scsi_cmd_to_rq(task->uldd_task);
>>> + rq->timeout = TASK_TIMEOUT;
>>> +
>>> + blk_execute_rq_nowait(rq, true);
>>> wait_for_completion(&task->slow_task->completion);
>>> res = TMF_RESP_FUNC_FAILED;
>>> @@ -1069,7 +1047,7 @@ int sas_execute_tmf(struct domain_device
>>> *device, void *parameter,
>>> for (retry = 0; retry < TASK_RETRY; retry++) {
>>> struct request *rq;
>>> - task = sas_alloc_slow_task_rq(device, GFP_KERNEL);
>>> + task = sas_alloc_slow_task_rq(device, GFP_KERNEL, -1U);
>>> if (!task)
>>> return -ENOMEM;
>>> @@ -1251,17 +1229,7 @@ void sas_task_abort(struct sas_task *task)
>>> {
>>> struct scsi_cmnd *sc = task->uldd_task;
>>> - /* Escape for libsas internal commands */
>>> - if (!sc) {
>>> - struct sas_task_slow *slow = task->slow_task;
>>> -
>>> - if (!slow)
>>> - return;
>>> - if (!del_timer(&slow->timer))
>>> - return;
>>> - slow->timer.function(&slow->timer);
>>> - return;
>>> - }
>>> + WARN_ON_ONCE(!sc);
>>> if (dev_is_sata(task->dev) && !task->slow_task)
>>> sas_ata_task_abort(task);
>>> diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
>>> index f02156ccd376..60543d8b01d4 100644
>>> --- a/include/scsi/libsas.h
>>> +++ b/include/scsi/libsas.h
>>> @@ -565,7 +565,6 @@ enum sas_internal_abort {
>>> struct sas_internal_abort_task {
>>> enum sas_internal_abort type;
>>> - unsigned int qid;
>>> u16 tag;
>>> };
>>
>>
>>
>
> .
>