You can subscribe to this list here.
| 2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(19) |
Nov
(18) |
Dec
(34) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2007 |
Jan
(14) |
Feb
(14) |
Mar
(3) |
Apr
(10) |
May
(10) |
Jun
(17) |
Jul
(15) |
Aug
(24) |
Sep
(24) |
Oct
(11) |
Nov
(13) |
Dec
(15) |
| 2008 |
Jan
(10) |
Feb
(46) |
Mar
(20) |
Apr
(42) |
May
(44) |
Jun
(22) |
Jul
(59) |
Aug
(8) |
Sep
(15) |
Oct
(52) |
Nov
(30) |
Dec
(38) |
| 2009 |
Jan
(27) |
Feb
(27) |
Mar
(47) |
Apr
(85) |
May
(74) |
Jun
(41) |
Jul
(70) |
Aug
(64) |
Sep
(97) |
Oct
(147) |
Nov
(67) |
Dec
(48) |
| 2010 |
Jan
(68) |
Feb
(33) |
Mar
(53) |
Apr
(98) |
May
(55) |
Jun
(71) |
Jul
(99) |
Aug
(132) |
Sep
(291) |
Oct
(220) |
Nov
(344) |
Dec
(300) |
| 2011 |
Jan
(57) |
Feb
(25) |
Mar
(59) |
Apr
(104) |
May
(60) |
Jun
(155) |
Jul
(143) |
Aug
(43) |
Sep
(53) |
Oct
(20) |
Nov
(35) |
Dec
(103) |
| 2012 |
Jan
(62) |
Feb
(43) |
Mar
(29) |
Apr
(80) |
May
(75) |
Jun
(61) |
Jul
(52) |
Aug
(58) |
Sep
(33) |
Oct
(32) |
Nov
(69) |
Dec
(37) |
| 2013 |
Jan
(77) |
Feb
(28) |
Mar
(52) |
Apr
(18) |
May
(37) |
Jun
(21) |
Jul
(22) |
Aug
(55) |
Sep
(29) |
Oct
(74) |
Nov
(50) |
Dec
(44) |
| 2014 |
Jan
(77) |
Feb
(62) |
Mar
(81) |
Apr
(99) |
May
(59) |
Jun
(95) |
Jul
(55) |
Aug
(34) |
Sep
(78) |
Oct
(33) |
Nov
(48) |
Dec
(51) |
| 2015 |
Jan
(56) |
Feb
(120) |
Mar
(37) |
Apr
(15) |
May
(22) |
Jun
(196) |
Jul
(54) |
Aug
(33) |
Sep
(32) |
Oct
(42) |
Nov
(149) |
Dec
(61) |
| 2016 |
Jan
(15) |
Feb
(26) |
Mar
(37) |
Apr
(27) |
May
(14) |
Jun
(11) |
Jul
(13) |
Aug
(64) |
Sep
(2) |
Oct
(36) |
Nov
(18) |
Dec
(46) |
| 2017 |
Jan
(6) |
Feb
(1) |
Mar
(2) |
Apr
(50) |
May
(42) |
Jun
(11) |
Jul
(4) |
Aug
(12) |
Sep
(11) |
Oct
(21) |
Nov
(15) |
Dec
(42) |
| 2018 |
Jan
(33) |
Feb
(27) |
Mar
(20) |
Apr
(5) |
May
(4) |
Jun
(1) |
Jul
(42) |
Aug
(29) |
Sep
(11) |
Oct
(40) |
Nov
(312) |
Dec
(18) |
| 2019 |
Jan
(44) |
Feb
(98) |
Mar
(125) |
Apr
(160) |
May
(123) |
Jun
(33) |
Jul
(56) |
Aug
(81) |
Sep
(24) |
Oct
(23) |
Nov
(52) |
Dec
(86) |
| 2020 |
Jan
(6) |
Feb
(17) |
Mar
(62) |
Apr
(21) |
May
(118) |
Jun
(42) |
Jul
(52) |
Aug
(62) |
Sep
(20) |
Oct
(5) |
Nov
(23) |
Dec
(111) |
| 2021 |
Jan
(31) |
Feb
(8) |
Mar
(26) |
Apr
(13) |
May
(54) |
Jun
(31) |
Jul
(17) |
Aug
(10) |
Sep
(83) |
Oct
(8) |
Nov
(21) |
Dec
(33) |
| 2022 |
Jan
(67) |
Feb
(11) |
Mar
(4) |
Apr
(46) |
May
(12) |
Jun
(17) |
Jul
(19) |
Aug
(7) |
Sep
(53) |
Oct
(14) |
Nov
(29) |
Dec
(22) |
| 2023 |
Jan
(20) |
Feb
(4) |
Mar
(37) |
Apr
(25) |
May
(15) |
Jun
(20) |
Jul
(38) |
Aug
(1) |
Sep
(1) |
Oct
(34) |
Nov
|
Dec
(8) |
| 2024 |
Jan
(15) |
Feb
(10) |
Mar
|
Apr
(4) |
May
(23) |
Jun
|
Jul
(8) |
Aug
(2) |
Sep
(18) |
Oct
(1) |
Nov
(18) |
Dec
(15) |
| 2025 |
Jan
(5) |
Feb
(1) |
Mar
(7) |
Apr
(4) |
May
(18) |
Jun
(7) |
Jul
|
Aug
(17) |
Sep
(13) |
Oct
(15) |
Nov
(5) |
Dec
(37) |
|
From: Gleb C. <lna...@ya...> - 2025-12-12 10:56:14
|
Commit: d11040a GitHub URL: https://github.com/SCST-project/scst/commit/d11040a0b19886aabffa6796e2931922a5c71d9b Author: Gleb Chesnokov Date: 2025-12-12T13:55:53+03:00 Log Message: ----------- scst_lib: Use bdev_fput() to release bdev files See also upstream commit 22650a99821d ("fs,block: yield devices early") # v6.9. Modified Paths: -------------- scst/src/scst_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) =================================================================== diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index eb7f70d..d9e9f6d 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -6135,7 +6135,7 @@ void scst_release_bdev(struct scst_bdev_descriptor *bdev_desc) struct file *bdev_file = bdev_desc->priv; if (bdev_file) - fput(bdev_file); + bdev_fput(bdev_file); #endif bdev_desc->bdev = NULL; |
|
From: Gleb C. <lna...@ya...> - 2025-12-11 09:19:51
|
Commit: 1a7cfc8 GitHub URL: https://github.com/SCST-project/scst/commit/1a7cfc8e6801b2e03d0d54c363de318f8e1d9570 Author: Tony Battersby Date: 2025-12-11T12:19:22+03:00 Log Message: ----------- scst_cmd_set_sn: remove lockless fast path The lockless fast path for scst_cmd_set_sn() can cause commands to lockup in state EXEC_CHECK_SN when there are multiple scst_tgts accessing the same scst_device, for example two initiators connected to the two ports of a dual-port QLogic FC HBA in target mode both reading from the same shared disk. The multithreaded_init_done value is too low-level for this; it does not take the higher-level configuration into account. - Remove the lockless fast path. - Remove multithreaded_init_done, which enabled/disabled the lockless fast path. - Push the locking down into scst_cmd_set_sn(), which will now apply regardless of set_sn_on_restart_cmd, which matters for mixed-driver (e.g. iSCSI+qla2xxx) target-mode setups. - Remove a bunch of comments explaining the rules for the lockless fast path. Fixes: https://github.com/SCST-project/scst/issues/333 Signed-off-by: Tony Battersby <to...@cy...> Modified Paths: -------------- scst/include/scst.h | 13 +--- scst/src/scst_targ.c | 48 ++++----------- scst_local/scst_local.c | 1 - 3 files changed, 12 insertions(+), 50 deletions(-) =================================================================== diff --git a/scst/include/scst.h b/scst/include/scst.h index 360c212..137ede9 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -755,12 +755,6 @@ struct scst_tgt_template { /* True, if this target doesn't need "enabled" attribute */ unsigned enabled_attr_not_needed:1; - /* - * True, if this target adapter can call scst_cmd_init_done() from - * several threads at the same time. - */ - unsigned multithreaded_init_done:1; - /* * True, if this target driver supports T10-PI (DIF), i.e. sending and * receiving DIF PI tags. If false, SCST will not allow to add @@ -2033,10 +2027,7 @@ struct scst_order_data { atomic_t *cur_sn_slot; atomic_t sn_slots[15]; - /* - * Used to serialized scst_cmd_init_done() if the corresponding - * session's target template has multithreaded_init_done set - */ + /* Used to serialize scst_cmd_init_done(). */ spinlock_t init_done_lock; }; @@ -3590,8 +3581,6 @@ void scst_cmd_init_done(struct scst_cmd *cmd, enum scst_exec_context pref_contex * SCST done the command's preprocessing preprocessing_done() function * should be called. The second argument sets preferred command execution * context. See SCST_CONTEXT_* constants for details. - * - * See comment for scst_cmd_init_done() for the serialization requirements. */ static inline void scst_cmd_init_stage1_done(struct scst_cmd *cmd, enum scst_exec_context pref_context, int set_sn) diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index a015fc6..b0a3d55 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -783,20 +783,6 @@ out_redirect: * initialization and also that the command is ready for execution. The * second argument sets the preferred command execution context. See also * SCST_CONTEXT_* constants for more information. - * - * !!IMPORTANT!! - * - * If cmd->set_sn_on_restart_cmd has not been set, this function, as well - * as scst_cmd_init_stage1_done() and scst_restart_cmd(), must not be - * called simultaneously for the same session (more precisely, for the same - * session/LUN, i.e. tgt_dev), i.e. they must be somehow externally - * serialized. This is needed to have lock free fast path in - * scst_cmd_set_sn(). For majority of targets those functions are naturally - * serialized by the single source of commands. Only some, like iSCSI - * immediate commands with multiple connections per session or scst_local, - * are exceptions. For it, some mutex/lock must be used for the - * serialization. Or, alternatively, multithreaded_init_done can be set in - * the target's template. */ void scst_cmd_init_done(struct scst_cmd *cmd, enum scst_exec_context pref_context) { @@ -1618,9 +1604,6 @@ static int scst_preprocessing_done(struct scst_cmd *cmd) * * The second argument sets completion status * (see SCST_PREPROCESS_STATUS_* constants for details) - * - * See also comment for scst_cmd_init_done() for the serialization - * requirements. */ void scst_restart_cmd(struct scst_cmd *cmd, int status, enum scst_exec_context pref_context) { @@ -1652,10 +1635,8 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status, enum scst_exec_context p } else { scst_set_cmd_state(cmd, SCST_CMD_STATE_TGT_PRE_EXEC); } - if (cmd->set_sn_on_restart_cmd) { - EXTRACHECKS_BUG_ON(cmd->tgtt->multithreaded_init_done); + if (cmd->set_sn_on_restart_cmd) scst_cmd_set_sn(cmd); - } #ifdef CONFIG_SCST_TEST_IO_IN_SIRQ if (cmd->op_flags & SCST_TEST_IO_IN_SIRQ_ALLOWED) break; @@ -3848,7 +3829,7 @@ static void scst_cmd_set_sn(struct scst_cmd *cmd) EXTRACHECKS_BUG_ON(cmd->sn_set || cmd->hq_cmd_inced); - /* Optimized for lockless fast path of sequence of SIMPLE commands */ + /* Optimized for fast path of sequence of SIMPLE commands */ scst_check_debug_sn(cmd); @@ -3870,6 +3851,8 @@ static void scst_cmd_set_sn(struct scst_cmd *cmd) } } + spin_lock_irqsave(&order_data->init_done_lock, flags); + again: switch (cmd->queue_type) { case SCST_CMD_QUEUE_SIMPLE: @@ -3927,7 +3910,7 @@ ordered: } else { order_data->prev_cmd_ordered = 1; - spin_lock_irqsave(&order_data->sn_lock, flags); + spin_lock(&order_data->sn_lock); /* irqs already off */ /* * If no commands are going to reach @@ -3948,7 +3931,7 @@ ordered: scst_inc_expected_sn_idle(order_data); } } - spin_unlock_irqrestore(&order_data->sn_lock, flags); + spin_unlock(&order_data->sn_lock); } cmd->sn = order_data->curr_sn; @@ -3957,9 +3940,9 @@ ordered: case SCST_CMD_QUEUE_HEAD_OF_QUEUE: TRACE_SN("HQ cmd %p (op %s)", cmd, scst_get_opcode_name(cmd)); - spin_lock_irqsave(&order_data->sn_lock, flags); + spin_lock(&order_data->sn_lock); /* irqs already off */ order_data->hq_cmd_count++; - spin_unlock_irqrestore(&order_data->sn_lock, flags); + spin_unlock(&order_data->sn_lock); cmd->hq_cmd_inced = 1; goto out; @@ -3977,6 +3960,7 @@ ordered: order_data->cur_sn_slot - order_data->sn_slots); out: + spin_unlock_irqrestore(&order_data->init_done_lock, flags); TRACE_EXIT(); } @@ -4226,18 +4210,8 @@ static int __scst_init_cmd(struct scst_cmd *cmd) if (cmd->completed) goto out; - if (!cmd->set_sn_on_restart_cmd) { - if (!cmd->tgtt->multithreaded_init_done) { - scst_cmd_set_sn(cmd); - } else { - struct scst_order_data *order_data = cmd->cur_order_data; - unsigned long flags; - - spin_lock_irqsave(&order_data->init_done_lock, flags); - scst_cmd_set_sn(cmd); - spin_unlock_irqrestore(&order_data->init_done_lock, flags); - } - } + if (!cmd->set_sn_on_restart_cmd) + scst_cmd_set_sn(cmd); } else if (res < 0) { TRACE_DBG("Finishing cmd %p", cmd); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_lun_not_supported)); diff --git a/scst_local/scst_local.c b/scst_local/scst_local.c index 897f3aa..070ad4f 100644 --- a/scst_local/scst_local.c +++ b/scst_local/scst_local.c @@ -1352,7 +1352,6 @@ static struct scst_tgt_template scst_local_targ_tmpl = { .name = "scst_local", .sg_tablesize = 0xffff, .xmit_response_atomic = 1, - .multithreaded_init_done = 1, .enabled_attr_not_needed = 1, .tgtt_attrs = scst_local_tgtt_attrs, .tgt_attrs = scst_local_tgt_attrs, |
|
From: Gleb C. <lna...@ya...> - 2025-12-10 18:45:26
|
Commit: cb6cdf3 GitHub URL: https://github.com/SCST-project/scst/commit/cb6cdf3a82807158315b34a17942041f011491e7 Author: Gleb Chesnokov Date: 2025-12-10T21:42:47+03:00 Log Message: ----------- qla2x00t, qla2x00t-32gbit: Port to Linux kernel v6.19 Support for the following changes in the Linux kernel v6.19: - 383d89699c50 ("treewide: Drop pci_save_state() after pci_restore_state()") Modified Paths: -------------- qla2x00t-32gbit/qla_os.c | 2 ++ qla2x00t/qla_os.c | 2 ++ 2 files changed, 4 insertions(+) =================================================================== diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index 827412a..319d6ba 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -8029,10 +8029,12 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) pci_restore_state(pdev); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 19, 0) /* pci_restore_state() clears the saved_state flag of the device * save restored state which resets saved_state flag */ pci_save_state(pdev); +#endif if (ha->mem_only) rc = pci_enable_device_mem(pdev); diff --git a/qla2x00t/qla_os.c b/qla2x00t/qla_os.c index f4ce570..db3dc93 100644 --- a/qla2x00t/qla_os.c +++ b/qla2x00t/qla_os.c @@ -4692,10 +4692,12 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) pci_restore_state(pdev); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 19, 0) /* pci_restore_state() clears the saved_state flag of the device * save restored state which resets saved_state flag */ pci_save_state(pdev); +#endif if (ha->mem_only) rc = pci_enable_device_mem(pdev); |
|
From: Gleb C. <lna...@ya...> - 2025-12-10 18:45:07
|
Commit: 12c870a GitHub URL: https://github.com/SCST-project/scst/commit/12c870abe9c1e4ca34fbceb59b285ecd76fa7f4d Author: Gleb Chesnokov Date: 2025-12-10T21:42:47+03:00 Log Message: ----------- qla2x00t-32gbit: Fix improper freeing of purex item In qla2xxx_process_purls_iocb(), an item is allocated via qla27xx_copy_multiple_pkt(), which internally calls qla24xx_alloc_purex_item(). The qla24xx_alloc_purex_item() function may return a pre-allocated item from a per-adapter pool for small allocations, instead of dynamically allocating memory with kzalloc(). An error handling path in qla2xxx_process_purls_iocb() incorrectly uses kfree() to release the item. If the item was from the pre-allocated pool, calling kfree() on it is a bug that can lead to memory corruption. Fix this by using the correct deallocation function, qla24xx_free_purex_item(), which properly handles both dynamically allocated and pre-allocated items. Fixes: 875386b98857 ("scsi: qla2xxx: Add Unsolicited LS Request and Response Support for NVMe") Signed-off-by: Zilin Guan <zi...@se...> Reviewed-by: Himanshu Madhani <hma...@gm...> Link: https://patch.msgid.link/202...@se... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit 78b1a242fe61 upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_nvme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_nvme.c b/qla2x00t-32gbit/qla_nvme.c index 1fd13db..c6ef8e7 100644 --- a/qla2x00t-32gbit/qla_nvme.c +++ b/qla2x00t-32gbit/qla_nvme.c @@ -1257,7 +1257,7 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp) a.reason = FCNVME_RJT_RC_LOGIC; a.explanation = FCNVME_RJT_EXP_NONE; xmt_reject = true; - kfree(item); + qla24xx_free_purex_item(item); goto out; } |
|
From: Gleb C. <lna...@ya...> - 2025-12-10 18:44:46
|
Commit: b5777ff GitHub URL: https://github.com/SCST-project/scst/commit/b5777ff9290b6fbc98b93dd19199cc569a66355a Author: Gleb Chesnokov Date: 2025-12-10T21:42:47+03:00 Log Message: ----------- scst: annotate workqueues for WQ_PERCPU / WQ_UNBOUND Upstream workqueue changes introduce a new WQ_PERCPU flag and plan to switch alloc_workqueue()'s default from per-CPU to unbound To kepp SCST behaviour unchanged across kernels, this patch makes all alloc_workqueue() users explicit about whether they want per-CPU or unbound queues. Modified Paths: -------------- iscsi-scst/kernel/isert-scst/iser_global.c | 7 +++++-- iscsi-scst/kernel/isert-scst/iser_rdma.c | 7 +++++-- qla2x00t-32gbit/qla_os.c | 6 +++++- qla2x00t/qla_os.c | 6 +++++- scst/src/scst_event.c | 4 +++- scst/src/scst_lib.c | 4 +++- srpt/src/ib_srpt.c | 6 +++++- 7 files changed, 31 insertions(+), 9 deletions(-) =================================================================== diff --git a/iscsi-scst/kernel/isert-scst/iser_global.c b/iscsi-scst/kernel/isert-scst/iser_global.c index 7f7ec72..a1e12fb 100644 --- a/iscsi-scst/kernel/isert-scst/iser_global.c +++ b/iscsi-scst/kernel/isert-scst/iser_global.c @@ -138,7 +138,11 @@ int isert_global_init(void) spin_lock_init(&isert_glob.portal_lock); init_waitqueue_head(&isert_glob.portal_wq); - isert_glob.conn_wq = alloc_workqueue("isert_conn_wq", 0, 1); + isert_glob.conn_wq = alloc_workqueue("isert_conn_wq", 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0) + | WQ_PERCPU +#endif + , 1); if (!isert_glob.conn_wq) { PRINT_ERROR("Failed to alloc iser conn work queue"); return -ENOMEM; @@ -164,7 +168,6 @@ free_cmnd_cache: free_wq: destroy_workqueue(isert_glob.conn_wq); - return -ENOMEM; } diff --git a/iscsi-scst/kernel/isert-scst/iser_rdma.c b/iscsi-scst/kernel/isert-scst/iser_rdma.c index 6ed53bc..dc8c45c 100644 --- a/iscsi-scst/kernel/isert-scst/iser_rdma.c +++ b/iscsi-scst/kernel/isert-scst/iser_rdma.c @@ -973,8 +973,11 @@ static struct isert_device *isert_device_create(struct ib_device *ib_dev) cq_desc->idx = i; INIT_WORK(&cq_desc->cq_comp_work, isert_cq_comp_work_cb); - cq_desc->cq_workqueue = alloc_workqueue("isert_cq_%p", - WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1, + cq_desc->cq_workqueue = alloc_workqueue("isert_cq_%p", 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0) + | WQ_PERCPU +#endif + | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1, cq_desc); if (unlikely(!cq_desc->cq_workqueue)) { PRINT_ERROR("Failed to alloc iser cq work queue for dev:%s", diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index 25bdb48..827412a 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -3508,7 +3508,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) "req->req_q_in=%p req->req_q_out=%p rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n", req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out); - ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 0); + ha->wq = alloc_workqueue("qla2xxx_wq", 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0) + | WQ_PERCPU +#endif + | WQ_MEM_RECLAIM, 0); if (unlikely(!ha->wq)) { ret = -ENOMEM; goto probe_failed; diff --git a/qla2x00t/qla_os.c b/qla2x00t/qla_os.c index 6279b63..f4ce570 100644 --- a/qla2x00t/qla_os.c +++ b/qla2x00t/qla_os.c @@ -468,7 +468,11 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) "Failed to create request queue.\n"); goto fail; } - ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1); + ha->wq = alloc_workqueue("qla2xxx_wq", 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0) + | WQ_PERCPU +#endif + | WQ_MEM_RECLAIM, 1); vha->req = ha->req_q_map[req]; options |= BIT_1; for (ques = 1; ques < ha->max_rsp_queues; ques++) { diff --git a/scst/src/scst_event.c b/scst/src/scst_event.c index 857155d..2c2ff49 100644 --- a/scst/src/scst_event.c +++ b/scst/src/scst_event.c @@ -1082,7 +1082,9 @@ int scst_event_init(void) TRACE_ENTRY(); - scst_event_wq = alloc_workqueue("scst_event_wq", 0, 0); + scst_event_wq = alloc_workqueue("scst_event_wq", 0 + | WQ_UNBOUND, + 0); if (unlikely(!scst_event_wq)) { PRINT_ERROR("Failed to allocate scst_event_wq"); res = -ENOMEM; diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index a78b7a9..eb7f70d 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -15747,7 +15747,9 @@ int __init scst_lib_init(void) scst_scsi_op_list_init(); - scst_release_acg_wq = alloc_workqueue("scst_release_acg", 0, 1); + scst_release_acg_wq = alloc_workqueue("scst_release_acg", 0 + | WQ_UNBOUND, + 0); if (unlikely(!scst_release_acg_wq)) { PRINT_ERROR("Failed to allocate scst_release_acg_wq"); res = -ENOMEM; diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index 056ac4e..b999ab6 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -4562,7 +4562,11 @@ static int __init srpt_init_module(void) goto out; } - srpt_wq = alloc_workqueue("srpt", WQ_SYSFS, 0); + srpt_wq = alloc_workqueue("srpt", 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 19, 0) + | WQ_PERCPU +#endif + | WQ_SYSFS, 0); if (!srpt_wq) { pr_err("Couldn't allocate the ib_srpt workqueue\n"); ret = -ENOMEM; |
|
From: Gleb C. <lna...@ya...> - 2025-12-10 18:43:12
|
Commit: b097d01 GitHub URL: https://github.com/SCST-project/scst/commit/b097d010fd776e59f29aa8e3a465ea6d9e52c7bb Author: Gleb Chesnokov Date: 2025-12-10T21:42:47+03:00 Log Message: ----------- qla2x00t-32gbit: Replace use of system_unbound_wq with system_dfl_wq Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistency cannot be addressed without refactoring the API. system_unbound_wq should be the default workqueue so as not to enforce locality constraints for random work whenever it's not required. Adding system_dfl_wq to encourage its use when unbound work should be used. The old system_unbound_wq will be kept for a few release cycles. Suggested-by: Tejun Heo <tj...@ke...> Signed-off-by: Marco Crivellari <mar...@su...> Link: https://patch.msgid.link/202...@su... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit 49783aca15fb upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_os.c | 4 ++++ 1 file changed, 4 insertions(+) =================================================================== diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index 58bb926..25bdb48 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -5402,7 +5402,11 @@ void qla24xx_sched_upd_fcport(fc_port_t *fcport) qla2x00_set_fcport_disc_state(fcport, DSC_UPD_FCPORT); spin_unlock_irqrestore(&fcport->vha->work_lock, flags); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 19, 0) queue_work(system_unbound_wq, &fcport->reg_work); +#else + queue_work(system_dfl_wq, &fcport->reg_work); +#endif } static |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:41:47
|
Commit: fe28091 GitHub URL: https://github.com/SCST-project/scst/commit/fe28091a05bb162000f342a14c4a17473d13801a Author: Gleb Chesnokov Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: Backport to older kernel versions Modified Paths: -------------- qla2x00t-32gbit/qla_target.c | 116 ++++++++------- scst/include/backport.h | 28 ++-- 2 files changed, 78 insertions(+), 66 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 1353f2a..57e2343 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -2002,7 +2002,7 @@ static void abort_cmds_for_lun(struct scsi_qla_host *vha, u64 lun, be_id_t s_id) if (cmd_key == key && cmd_lun == lun) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xe085, "qla_target(%d): tag %lld: aborted by TMR\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd)); cmd->aborted = 1; } } @@ -3270,7 +3270,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, cmd->reset_count != qpair->chip_reset)) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xe101, "qla_target(%d): tag %lld: skipping send response for aborted cmd\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd)); qlt_unmap_sg(vha, cmd); cmd->state = QLA_TGT_STATE_PROCESSED; vha->hw->tgt.tgt_ops->free_cmd(cmd); @@ -3433,7 +3433,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) cmd->reset_count != qpair->chip_reset)) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xe102, "qla_target(%d): tag %lld: skipping data-out for aborted cmd\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd)); qlt_unmap_sg(vha, cmd); cmd->aborted = 1; cmd->write_data_transferred = 0; @@ -3698,7 +3698,7 @@ void qlt_srr_abort(struct qla_tgt_cmd *cmd, bool reject) */ ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102e, "qla_target(%d): tag %lld: %s: SRR already scheduled\n", - vha->vp_idx, cmd->se_cmd.tag, __func__); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), __func__); } else { struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; unsigned long flags; @@ -3706,7 +3706,7 @@ void qlt_srr_abort(struct qla_tgt_cmd *cmd, bool reject) /* Shedule processing for the SRR immediate notify. */ ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102f, "qla_target(%d): tag %lld: %s: schedule SRR %s\n", - vha->vp_idx, cmd->se_cmd.tag, __func__, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), __func__, reject ? "reject" : "abort"); cmd->srr = NULL; srr->cmd = NULL; @@ -3718,7 +3718,7 @@ void qlt_srr_abort(struct qla_tgt_cmd *cmd, bool reject) } else { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11030, "qla_target(%d): tag %lld: %s: no IMM SRR; free SRR\n", - vha->vp_idx, cmd->se_cmd.tag, __func__); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), __func__); cmd->srr = NULL; kfree(srr); } @@ -3766,7 +3766,7 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair, if (cmd) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xe009, "qla_target(%d): tag %lld: Sending TERM EXCH CTIO state %d cmd_sent_to_fw %u\n", - vha->vp_idx, cmd->se_cmd.tag, cmd->state, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->state, cmd->cmd_sent_to_fw); } else { ql_dbg(ql_dbg_tgt_mgt, vha, 0xe009, @@ -3920,7 +3920,7 @@ int qlt_abort_cmd(struct qla_tgt_cmd *cmd) ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, "qla_target(%d): tag %lld: cmd being aborted (state %d) %s; %s\n", - vha->vp_idx, cmd->se_cmd.tag, cmd->state, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->state, cmd->cmd_sent_to_fw ? "sent to fw" : "not sent to fw", cmd->aborted ? "aborted" : "not aborted"); @@ -3972,7 +3972,7 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) TRC_SRR_CTIO | TRC_SRR_IMM)))) { ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xe086, "qla_target(%d): tag %lld: free cmd (trc_flags %x, aborted %u, sent_term_exchg %u, rsp_sent %u)\n", - cmd->vha->vp_idx, cmd->se_cmd.tag, + cmd->vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->trc_flags, cmd->aborted, cmd->sent_term_exchg, cmd->rsp_sent); } @@ -4017,7 +4017,7 @@ static int qlt_prepare_srr_ctio(struct qla_qpair *qpair, if (vha->hw->tgt.tgt_ops->get_cmd_ref(cmd)) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11037, "qla_target(%d): tag %lld: unable to get cmd ref for SRR processing\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd)); qlt_srr_abort(cmd, true); return -ESHUTDOWN; } @@ -4026,13 +4026,17 @@ static int qlt_prepare_srr_ctio(struct qla_qpair *qpair, ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100f, "qla_target(%d): tag %lld: Scheduling SRR work\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd)); /* Schedule the srr for processing in qlt_handle_srr(). */ /* IRQ is already OFF */ spin_lock(&tgt->srr_lock); list_add_tail(&srr->srr_list_entry, &tgt->srr_list); +#if HAVE_SE_CMD_CPUID queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq, &tgt->srr_work); +#else + queue_work(qla_tgt_wq, &tgt->srr_work); +#endif spin_unlock(&tgt->srr_lock); return 0; } @@ -4240,7 +4244,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, if (printk_ratelimit()) dev_info(&vha->hw->pdev->dev, "qla_target(%d): tag %lld, op %x: CTIO with INVALID_RX_ID status 0x%x received (state %d, port %8phC, LUN %lld, ATIO attr %x, CTIO Flags %x|%x)\n", - vha->vp_idx, cmd->se_cmd.tag, op, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), op, status, cmd->state, cmd->sess->port_name, cmd->unpacked_lun, cmd->atio.u.isp24.attr, ((cmd->ctio_flags >> 9) & 0xf), @@ -4273,7 +4277,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, } ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058, "qla_target(%d): tag %lld, op %x: CTIO with %s status 0x%x received (state %d, port %8phC, LUN %lld)\n", - vha->vp_idx, cmd->se_cmd.tag, op, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), op, status_str, status, cmd->state, cmd->sess->port_name, cmd->unpacked_lun); break; @@ -4287,7 +4291,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059, "qla_target(%d): tag %lld, op %x: CTIO with %s status 0x%x received (state %d, port %8phC, LUN %lld)\n", - vha->vp_idx, cmd->se_cmd.tag, op, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), op, logged_out ? "PORT LOGGED OUT" : "PORT UNAVAILABLE", status, cmd->state, cmd->sess->port_name, cmd->unpacked_lun); @@ -4311,7 +4315,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, case CTIO_SRR_RECEIVED: ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100e, "qla_target(%d): tag %lld, op %x: CTIO with SRR status 0x%x received (state %d, port %8phC, LUN %lld, bufflen %d)\n", - vha->vp_idx, cmd->se_cmd.tag, op, status, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), op, status, cmd->state, cmd->sess->port_name, cmd->unpacked_lun, cmd->bufflen); @@ -4324,7 +4328,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, (struct ctio_crc_from_fw *)ctio; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf073, "qla_target(%d): tag %lld, op %x: CTIO with DIF_ERROR status 0x%x received (state %d, port %8phC, LUN %lld, actual_dif[0x%llx] expect_dif[0x%llx])\n", - vha->vp_idx, cmd->se_cmd.tag, op, status, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), op, status, cmd->state, cmd->sess->port_name, cmd->unpacked_lun, *((u64 *)&crc->actual_dif[0]), @@ -4340,7 +4344,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, case CTIO_FAST_SPI_ERR: ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05b, "qla_target(%d): tag %lld, op %x: CTIO with EDIF error status 0x%x received (state %d, port %8phC, LUN %lld)\n", - vha->vp_idx, cmd->se_cmd.tag, op, status, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), op, status, cmd->state, cmd->sess->port_name, cmd->unpacked_lun); break; @@ -4348,7 +4352,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, default: ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05b, "qla_target(%d): tag %lld, op %x: CTIO with error status 0x%x received (state %d, port %8phC, LUN %lld)\n", - vha->vp_idx, cmd->se_cmd.tag, op, status, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), op, status, cmd->state, cmd->sess->port_name, cmd->unpacked_lun); break; @@ -4374,7 +4378,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, if (unlikely(cmd->srr != NULL)) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11031, "qla_target(%d): tag %lld, op %x: expected CTIO with SRR status; got status 0x%x: state %d, bufflen %d\n", - vha->vp_idx, cmd->se_cmd.tag, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->cdb ? cmd->cdb[0] : 0, status, cmd->state, cmd->bufflen); qlt_srr_abort(cmd, true); @@ -4399,12 +4403,12 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, cmd->trc_flags |= TRC_CTIO_ABORTED; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e, "qla_target(%d): tag %lld: Aborted command finished\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd)); } else { cmd->trc_flags |= TRC_CTIO_STRANGE; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c, "qla_target(%d): tag %lld: A command in state (%d) should not return a CTIO complete\n", - vha->vp_idx, cmd->se_cmd.tag, cmd->state); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->state); } if (unlikely(status != CTIO_SUCCESS) && @@ -5425,7 +5429,7 @@ static struct qla_tgt_cmd *qlt_srr_to_cmd(struct scsi_qla_host *vha, if (srr_ox_id != cmd_ox_id) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100c, "qla_target(%d): tag %lld: IMM SRR: srr_ox_id[%04x] != cmd_ox_id[%04x]; reject SRR\n", - vha->vp_idx, cmd->se_cmd.tag, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), srr_ox_id, cmd_ox_id); cmd = NULL; } @@ -5507,7 +5511,7 @@ static void qlt_handle_srr_imm(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt_mgt, vha, 0x11001, "qla_target(%d): tag %lld, op %x: received IMM SRR\n", - vha->vp_idx, cmd->se_cmd.tag, cmd->cdb ? cmd->cdb[0] : 0); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->cdb ? cmd->cdb[0] : 0); cmd->trc_flags |= TRC_SRR_IMM; @@ -5520,7 +5524,7 @@ static void qlt_handle_srr_imm(struct scsi_qla_host *vha, */ ql_dbg(ql_dbg_tgt_mgt, vha, 0x11006, "qla_target(%d): tag %lld: received multiple IMM SRR; reject SRR\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd)); spin_unlock_irq(qpair->qp_lock_ptr); ha->tgt.tgt_ops->put_cmd_ref(cmd); goto out_reject; @@ -5541,7 +5545,7 @@ static void qlt_handle_srr_imm(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt_mgt, vha, 0x11002, "qla_target(%d): tag %lld: schedule SRR work\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd)); /* Schedule the srr for processing in qlt_handle_srr(). */ spin_lock(&tgt->srr_lock); @@ -5561,7 +5565,7 @@ static void qlt_handle_srr_imm(struct scsi_qla_host *vha, if (cmd->sent_term_exchg) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11007, "qla_target(%d): tag %lld: IMM SRR: cmd already aborted\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd)); spin_unlock_irq(qpair->qp_lock_ptr); spin_lock_irq(&ha->hardware_lock); if (!qlt_srr_is_chip_reset(vha, ha->base_qpair, srr)) @@ -5576,7 +5580,7 @@ static void qlt_handle_srr_imm(struct scsi_qla_host *vha, if (!cmd->cmd_sent_to_fw) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11008, "qla_target(%d): tag %lld: IMM SRR but !cmd_sent_to_fw (state %d); reject SRR\n", - vha->vp_idx, cmd->se_cmd.tag, cmd->state); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->state); spin_unlock_irq(qpair->qp_lock_ptr); ha->tgt.tgt_ops->put_cmd_ref(cmd); goto out_reject; @@ -5585,7 +5589,7 @@ static void qlt_handle_srr_imm(struct scsi_qla_host *vha, /* Expect qlt_prepare_srr_ctio() to be called. */ ql_dbg(ql_dbg_tgt_mgt, vha, 0x11003, "qla_target(%d): tag %lld: wait for CTIO SRR (state %d)\n", - vha->vp_idx, cmd->se_cmd.tag, cmd->state); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->state); srr->cmd = cmd; cmd->srr = srr; @@ -5671,14 +5675,14 @@ static int qlt_restore_orig_sg(struct qla_tgt_cmd *cmd) /* The original scatterlist is not available. */ ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102c, "qla_target(%d): tag %lld: cannot restore original cmd buffer; keep modified buffer at offset %d\n", - vha->vp_idx, cmd->se_cmd.tag, cmd->offset); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->offset); return -ENOENT; } /* Restore the original scatterlist. */ ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102d, "qla_target(%d): tag %lld: restore original cmd buffer: offset %d -> 0\n", - vha->vp_idx, cmd->se_cmd.tag, cmd->offset); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->offset); if (cmd->free_sg) { cmd->free_sg = 0; qlt_free_sg(cmd); @@ -5711,21 +5715,21 @@ static int qlt_set_data_offset(struct qla_tgt_cmd *cmd, uint32_t offset) ql_dbg(ql_dbg_tgt, vha, 0x11020, "qla_target(%d): tag %lld: %s: sg %p sg_cnt %d dir %d cmd->offset %d cmd->bufflen %d add offset %u\n", - vha->vp_idx, cmd->se_cmd.tag, __func__, cmd->sg, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), __func__, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction, cmd->offset, cmd->bufflen, offset); if (cmd->se_cmd.prot_op != TARGET_PROT_NORMAL) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11021, "qla_target(%d): tag %lld: %s: SRR with protection information at nonzero offset not implemented\n", - vha->vp_idx, cmd->se_cmd.tag, __func__); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), __func__); return -EINVAL; } if (!cmd->sg || !cmd->sg_cnt) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11022, "qla_target(%d): tag %lld: %s: Missing cmd->sg or zero cmd->sg_cnt\n", - vha->vp_idx, cmd->se_cmd.tag, __func__); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), __func__); return -EINVAL; } @@ -5747,13 +5751,13 @@ static int qlt_set_data_offset(struct qla_tgt_cmd *cmd, uint32_t offset) if (!sg_srr_start) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11024, "qla_target(%d): tag %lld: Unable to locate sg_srr_start for offset: %u\n", - vha->vp_idx, cmd->se_cmd.tag, offset); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), offset); return -EINVAL; } ql_dbg(ql_dbg_tgt_mgt, vha, 0x11025, "qla_target(%d): tag %lld: prepare SRR sgl at sg index %d of %d byte offset %u of %u\n", - vha->vp_idx, cmd->se_cmd.tag, i, cmd->sg_cnt, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), i, cmd->sg_cnt, first_offset, sg_srr_start->length); sg_srr_cnt = cmd->sg_cnt - i; @@ -5778,7 +5782,7 @@ static int qlt_set_data_offset(struct qla_tgt_cmd *cmd, uint32_t offset) if (!sg_srr) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11027, "qla_target(%d): tag %lld: Unable to allocate SRR scatterlist\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd)); return -ENOMEM; } sg_init_table(sg_srr, n_alloc_sg); @@ -5831,7 +5835,7 @@ static int qlt_set_data_offset(struct qla_tgt_cmd *cmd, uint32_t offset) if (bufflen != cmd->bufflen) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102b, "qla_target(%d): tag %lld: %s: bad sgl length: expected %d got %d\n", - vha->vp_idx, cmd->se_cmd.tag, __func__, cmd->bufflen, bufflen); + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), __func__, cmd->bufflen, bufflen); return -EINVAL; } @@ -5858,7 +5862,7 @@ static inline int qlt_srr_adjust_data(struct qla_tgt_cmd *cmd, *xmit_type = 0; ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101e, "qla_target(%d): tag %lld: srr_rel_offs %u outside accepted range %u - %u\n", - vha->vp_idx, cmd->se_cmd.tag, srr_rel_offs, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), srr_rel_offs, cmd->offset, cmd->offset + cmd->bufflen); return -EINVAL; } @@ -5879,7 +5883,7 @@ static inline int qlt_srr_adjust_data(struct qla_tgt_cmd *cmd, ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101f, "qla_target(%d): tag %lld: current buffer [%u - %u); srr_rel_offs=%d, rel_offs=%d\n", - vha->vp_idx, cmd->se_cmd.tag, cmd->offset, + vha->vp_idx, se_cmd_tag(&cmd->se_cmd), cmd->offset, cmd->offset + cmd->bufflen, srr_rel_offs, rel_offs); *xmit_type = QLA_TGT_XMIT_ALL; @@ -5925,7 +5929,7 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) if (cmd->sent_term_exchg || cmd->sess->deleted || srr->aborted) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11010, "qla_target(%d): tag %lld: IMM SRR: cmd already aborted\n", - vha->vp_idx, cmd->se_cmd.tag); + vha->vp_idx, se_cmd_tag(se_cmd)); spin_unlock_irq(qpair->qp_lock_ptr); @@ -5958,7 +5962,7 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) if (cmd->state != QLA_TGT_STATE_PROCESSED) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11011, "qla_target(%d): tag %lld, op %x: reject SRR_IU_STATUS due to unexpected state %d\n", - vha->vp_idx, se_cmd->tag, op, + vha->vp_idx, se_cmd_tag(se_cmd), op, cmd->state); goto out_reject; } @@ -5966,13 +5970,13 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) if (did_timeout) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11033, "qla_target(%d): tag %lld, op %x: reject SRR_IU_STATUS due to timeout\n", - vha->vp_idx, se_cmd->tag, op); + vha->vp_idx, se_cmd_tag(se_cmd), op); goto out_reject; } ql_dbg(ql_dbg_tgt_mgt, vha, 0x11012, "qla_target(%d): tag %lld, op %x: accept SRR_IU_STATUS and retransmit scsi_status=%x\n", - vha->vp_idx, se_cmd->tag, op, + vha->vp_idx, se_cmd_tag(se_cmd), op, se_cmd->scsi_status); xmit_type = QLA_TGT_XMIT_STATUS; xmit_response = true; @@ -5982,14 +5986,14 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) case SRR_IU_DATA_IN: ql_dbg(ql_dbg_tgt_mgt, vha, 0x11013, "qla_target(%d): tag %lld, op %x: process SRR_IU_DATA_IN: bufflen=%d, sg_cnt=%d, offset=%d, srr_offset=%d, scsi_status=%x\n", - vha->vp_idx, se_cmd->tag, op, cmd->bufflen, + vha->vp_idx, se_cmd_tag(se_cmd), op, cmd->bufflen, cmd->sg_cnt, cmd->offset, srr_rel_offs, se_cmd->scsi_status); if (cmd->state != QLA_TGT_STATE_PROCESSED) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11014, "qla_target(%d): tag %lld: reject SRR_IU_DATA_IN due to unexpected state %d\n", - vha->vp_idx, se_cmd->tag, cmd->state); + vha->vp_idx, se_cmd_tag(se_cmd), cmd->state); goto out_reject; } @@ -5999,21 +6003,21 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) if (!qlt_has_data(cmd)) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11015, "qla_target(%d): tag %lld: reject SRR_IU_DATA_IN because cmd has no data to send\n", - vha->vp_idx, se_cmd->tag); + vha->vp_idx, se_cmd_tag(se_cmd)); goto out_reject; } if (!cmd->sg || !cmd->sg_cnt) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11016, "qla_target(%d): tag %lld: reject SRR_IU_DATA_IN because buffer is missing\n", - vha->vp_idx, se_cmd->tag); + vha->vp_idx, se_cmd_tag(se_cmd)); goto out_reject; } if (did_timeout) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11034, "qla_target(%d): tag %lld, op %x: reject SRR_IU_DATA_IN due to timeout\n", - vha->vp_idx, se_cmd->tag, op); + vha->vp_idx, se_cmd_tag(se_cmd), op); goto out_reject; } @@ -6022,7 +6026,7 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) ql_dbg(ql_dbg_tgt_mgt, vha, 0x11017, "qla_target(%d): tag %lld: accept SRR_IU_DATA_IN and retransmit data: bufflen=%d, offset=%d\n", - vha->vp_idx, se_cmd->tag, cmd->bufflen, + vha->vp_idx, se_cmd_tag(se_cmd), cmd->bufflen, cmd->offset); xmit_response = true; cmd->trc_flags |= TRC_SRR_RSP; @@ -6031,13 +6035,13 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) case SRR_IU_DATA_OUT: ql_dbg(ql_dbg_tgt_mgt, vha, 0x11018, "qla_target(%d): tag %lld, op %x: process SRR_IU_DATA_OUT: bufflen=%d, sg_cnt=%d, offset=%d, srr_offset=%d\n", - vha->vp_idx, se_cmd->tag, op, cmd->bufflen, + vha->vp_idx, se_cmd_tag(se_cmd), op, cmd->bufflen, cmd->sg_cnt, cmd->offset, srr_rel_offs); if (cmd->state != QLA_TGT_STATE_NEED_DATA) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11019, "qla_target(%d): tag %lld: reject SRR_IU_DATA_OUT due to unexpected state %d\n", - vha->vp_idx, se_cmd->tag, cmd->state); + vha->vp_idx, se_cmd_tag(se_cmd), cmd->state); goto out_reject; } @@ -6047,14 +6051,14 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) if (!qlt_has_data(cmd) || !cmd->sg || !cmd->sg_cnt) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101a, "qla_target(%d): tag %lld: reject SRR_IU_DATA_OUT because buffer is missing\n", - vha->vp_idx, se_cmd->tag); + vha->vp_idx, se_cmd_tag(se_cmd)); goto out_reject; } if (did_timeout) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x11035, "qla_target(%d): tag %lld, op %x: reject SRR_IU_DATA_OUT due to timeout\n", - vha->vp_idx, se_cmd->tag, op); + vha->vp_idx, se_cmd_tag(se_cmd), op); goto out_reject; } @@ -6064,13 +6068,13 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) if (!(xmit_type & QLA_TGT_XMIT_DATA)) { ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101b, "qla_target(%d): tag %lld: reject SRR_IU_DATA_OUT: bad offset\n", - vha->vp_idx, se_cmd->tag); + vha->vp_idx, se_cmd_tag(se_cmd)); goto out_reject; } ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101c, "qla_target(%d): tag %lld: accept SRR_IU_DATA_OUT and receive data again: bufflen=%d, offset=%d\n", - vha->vp_idx, se_cmd->tag, cmd->bufflen, + vha->vp_idx, se_cmd_tag(se_cmd), cmd->bufflen, cmd->offset); cmd->trc_flags |= TRC_SRR_XRDY; rdy_to_xfer = true; @@ -6079,7 +6083,7 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) default: ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101d, "qla_target(%d): tag %lld, op %x: reject unknown srr_ui value 0x%x: state=%d, bufflen=%d, offset=%d, srr_offset=%d\n", - vha->vp_idx, se_cmd->tag, op, srr_ui, cmd->state, + vha->vp_idx, se_cmd_tag(se_cmd), op, srr_ui, cmd->state, cmd->bufflen, cmd->offset, srr_rel_offs); goto out_reject; } diff --git a/scst/include/backport.h b/scst/include/backport.h index d07e7f1..77bf04b 100644 --- a/scst/include/backport.h +++ b/scst/include/backport.h @@ -34,8 +34,8 @@ #include <linux/debugfs.h> #include <linux/dmapool.h> #include <linux/eventpoll.h> -#include <linux/jiffies.h> #include <linux/iocontext.h> +#include <linux/jiffies.h> #include <linux/kobject_ns.h> #include <linux/preempt.h> #include <linux/scatterlist.h> /* struct scatterlist */ @@ -670,15 +670,6 @@ kernel_write_backport(struct file *file, const void *buf, size_t count, #define kernel_write kernel_write_backport #endif -/* <linux/jiffies.h> */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 13, 0) -/* - * See also commit b35108a51cf7 ("jiffies: Define secs_to_jiffies()") # v6.13. - */ -#define secs_to_jiffies(_secs) (unsigned long)((_secs) * HZ) -#endif - /* <linux/iocontext.h> */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 21, 0) || \ @@ -771,6 +762,23 @@ static inline long get_user_pages_backport(unsigned long start, #define get_user_pages get_user_pages_backport #endif +/* <linux/jiffies.h> */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) +/* + * See also commit 3740dcdf8a77 ("jiffies: add time comparison functions for 64 bit jiffies") + * # v4.9. + */ +#define time_is_before_jiffies64(a) time_after64(get_jiffies_64(), a) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 13, 0) +/* + * See also commit b35108a51cf7 ("jiffies: Define secs_to_jiffies()") # v6.13. + */ +#define secs_to_jiffies(_secs) (unsigned long)((_secs) * HZ) +#endif + /* <linux/kobject_ns.h> */ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0) && \ |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:41:40
|
Commit: 64918c6 GitHub URL: https://github.com/SCST-project/scst/commit/64918c69a29f8a199645a876596a325b4cc6b202 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Add on_abort_cmd callback This enables the initiator to abort commands that are stuck pending in the HW without waiting for a timeout. Signed-off-by: Tony Battersby <to...@cy...> Modified Paths: -------------- qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c | 42 +++++++++++++++ 1 file changed, 42 insertions(+) =================================================================== diff --git a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c index 1a7c472..3fca87f 100644 --- a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c +++ b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c @@ -83,6 +83,7 @@ static int sqa_xmit_response(struct scst_cmd *scst_cmd); static int sqa_rdy_to_xfer(struct scst_cmd *scst_cmd); static void sqa_on_free_cmd(struct scst_cmd *scst_cmd); static void sqa_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd); +static void sqa_on_abort_cmd(struct scst_cmd *scst_cmd); static int sqa_get_initiator_port_transport_id(struct scst_tgt *tgt, struct scst_session *scst_sess, uint8_t **transport_id); @@ -1273,6 +1274,7 @@ static struct scst_tgt_template sqa_scst_template = { .on_free_cmd = sqa_on_free_cmd, .task_mgmt_fn_done = sqa_task_mgmt_fn_done, + .on_abort_cmd = sqa_on_abort_cmd, .close_session = sqa_close_session, .get_initiator_port_transport_id = sqa_get_initiator_port_transport_id, @@ -2034,6 +2036,46 @@ out_unlock: TRACE_EXIT(); } +struct sqa_abort_work { + struct scst_cmd *scst_cmd; + struct work_struct abort_work; +}; + +static void sqa_on_abort_cmd_work(struct work_struct *work) +{ + struct sqa_abort_work *abort_work = + container_of(work, struct sqa_abort_work, abort_work); + struct scst_cmd *scst_cmd = abort_work->scst_cmd; + struct qla_tgt_cmd *cmd = scst_cmd_get_tgt_priv(scst_cmd); + + TRACE_ENTRY(); + + kfree(abort_work); + qlt_abort_cmd(cmd); + scst_cmd_put(scst_cmd); + + TRACE_EXIT(); +} + +static void sqa_on_abort_cmd(struct scst_cmd *scst_cmd) +{ + struct sqa_abort_work *abort_work; + + /* + * The caller holds sess->sess_list_lock, but qlt_abort_cmd() needs to + * acquire qpair->qp_lock_ptr (ha->hardware_lock); these locks are + * acquired in the reverse order elsewhere. Use a workqueue to avoid + * acquiring the locks in the wrong order here. + */ + abort_work = kmalloc(sizeof(*abort_work), GFP_ATOMIC); + if (!abort_work) + return; + scst_cmd_get(scst_cmd); + abort_work->scst_cmd = scst_cmd; + INIT_WORK(&abort_work->abort_work, sqa_on_abort_cmd_work); + schedule_work(&abort_work->abort_work); +} + /* * The following structure defines the callbacks which will be executed * from functions in the qla_target.c file back to this interface |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:41:31
|
Commit: f4b5277 GitHub URL: https://github.com/SCST-project/scst/commit/f4b52771b6c7a58f24e0318ce9136f9575726b76 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Improve safety of cmd lookup by handle The driver associates two different structs with numeric handles and passes the handles to the hardware. When the hardware passes the handle back to the driver, the driver consults a table of void * to convert the handle back to the struct without checking the type of struct. This can lead to type confusion if the HBA firmware misbehaves (and some firmware versions do). So verify the type of struct is what is expected before using it. But we can also do better than that. Also verify that the exchange address of the message sent from the hardware matches the exchange address of the command being returned. This adds an extra guard against buggy HBA firmware that returns duplicate messages multiple times (which has also been seen) in case the driver has reused the handle for a different command of the same type. These problems were seen on a QLE2694L with firmware 9.08.02 when testing SLER / SRR support. The SRR caused the HBA to flood the response queue with hundreds of bogus entries. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/7c7...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit 4f5eb50f7c82 upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_dbg.c | 2 +- qla2x00t-32gbit/qla_target.c | 109 ++++++++++++--- 2 files changed, 90 insertions(+), 21 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_dbg.c b/qla2x00t-32gbit/qla_dbg.c index ed0e06c..9b74345 100644 --- a/qla2x00t-32gbit/qla_dbg.c +++ b/qla2x00t-32gbit/qla_dbg.c @@ -54,7 +54,7 @@ * | Misc | 0xd303 | 0xd031-0xd0ff | * | | | 0xd101-0xd1fe | * | | | 0xd214-0xd2fe | - * | Target Mode | 0xe086 | | + * | Target Mode | 0xe089 | | * | Target Mode Management | 0xf09b | 0xf002 | * | | | 0xf046-0xf049 | * | Target Mode Task Management | 0x1000d | | diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 8210403..1353f2a 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -4051,7 +4051,8 @@ static int qlt_prepare_srr_ctio(struct qla_qpair *qpair, /* ha->hardware_lock supposed to be held on entry */ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, - struct rsp_que *rsp, uint32_t handle, void *ctio) + struct rsp_que *rsp, uint32_t handle, uint8_t cmd_type, + const void *ctio) { void *cmd = NULL; struct req_que *req; @@ -4074,29 +4075,97 @@ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, h &= QLA_CMD_HANDLE_MASK; - if (h != QLA_TGT_NULL_HANDLE) { - if (unlikely(h >= req->num_outstanding_cmds)) { - ql_dbg(ql_dbg_tgt, vha, 0xe052, - "qla_target(%d): Wrong handle %x received\n", - vha->vp_idx, handle); - return NULL; - } - - cmd = req->outstanding_cmds[h]; - if (unlikely(cmd == NULL)) { - ql_dbg(ql_dbg_async, vha, 0xe053, - "qla_target(%d): Suspicious: unable to find the command with handle %x req->id %d rsp->id %d\n", - vha->vp_idx, handle, req->id, rsp->id); - return NULL; - } - req->outstanding_cmds[h] = NULL; - } else if (ctio != NULL) { + if (h == QLA_TGT_NULL_HANDLE) { /* We can't get loop ID from CTIO7 */ ql_dbg(ql_dbg_tgt, vha, 0xe054, "qla_target(%d): Wrong CTIO received: QLA24xx doesn't " "support NULL handles\n", vha->vp_idx); return NULL; } + if (unlikely(h >= req->num_outstanding_cmds)) { + ql_dbg(ql_dbg_tgt, vha, 0xe052, + "qla_target(%d): Wrong handle %x received\n", + vha->vp_idx, handle); + return NULL; + } + + /* + * We passed a numeric handle for a cmd to the hardware, and the + * hardware passed the handle back to us. Look up the associated cmd, + * and validate that the cmd_type and exchange address match what the + * caller expects. This guards against buggy HBA firmware that returns + * the same CTIO multiple times. + */ + + cmd = req->outstanding_cmds[h]; + + if (unlikely(cmd == NULL)) { + if (cmd_type == TYPE_TGT_CMD) { + __le32 ctio_exchange_addr = + ((const struct ctio7_from_24xx *)ctio)-> + exchange_address; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe053, + "qla_target(%d): tag %u: handle %x: cmd detached; ignoring CTIO (handle %x req->id %d rsp->id %d)\n", + vha->vp_idx, le32_to_cpu(ctio_exchange_addr), h, + handle, req->id, rsp->id); + } else { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe053, + "qla_target(%d): cmd detached; ignoring CTIO (handle %x req->id %d rsp->id %d)\n", + vha->vp_idx, handle, req->id, rsp->id); + } + return NULL; + } + + if (unlikely(((srb_t *)cmd)->cmd_type != cmd_type)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe087, + "qla_target(%d): handle %x: cmd detached; ignoring CTIO (cmd_type mismatch)\n", + vha->vp_idx, h); + return NULL; + } + + switch (cmd_type) { + case TYPE_TGT_CMD: { + __le32 ctio_exchange_addr = + ((const struct ctio7_from_24xx *)ctio)-> + exchange_address; + __le32 cmd_exchange_addr = + ((struct qla_tgt_cmd *)cmd)-> + atio.u.isp24.exchange_addr; + + BUILD_BUG_ON(offsetof(struct ctio7_from_24xx, + exchange_address) != + offsetof(struct ctio_crc_from_fw, + exchange_address)); + + if (unlikely(ctio_exchange_addr != cmd_exchange_addr)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe088, + "qla_target(%d): tag %u: handle %x: cmd detached; ignoring CTIO (exchange address mismatch)\n", + vha->vp_idx, le32_to_cpu(ctio_exchange_addr), h); + return NULL; + } + break; + } + + case TYPE_TGT_TMCMD: { + __le32 ctio_exchange_addr = + ((const struct abts_resp_from_24xx_fw *)ctio)-> + exchange_address; + __le32 cmd_exchange_addr = + ((struct qla_tgt_mgmt_cmd *)cmd)-> + orig_iocb.abts.exchange_address; + + if (unlikely(ctio_exchange_addr != cmd_exchange_addr)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe089, + "qla_target(%d): ABTS: handle %x: cmd detached; ignoring CTIO (exchange address mismatch)\n", + vha->vp_idx, h); + return NULL; + } + break; + } + } + + req->outstanding_cmds[h] = NULL; return cmd; } @@ -4125,7 +4194,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, ctio_flags = le16_to_cpu(ctio->flags); - cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio); + cmd = qlt_ctio_to_cmd(vha, rsp, handle, TYPE_TGT_CMD, ctio); if (unlikely(cmd == NULL)) { if ((handle & ~QLA_TGT_HANDLE_MASK) == QLA_TGT_SKIP_HANDLE && (ctio_flags & 0xe1ff) == (CTIO7_FLAGS_STATUS_MODE_1 | @@ -6905,7 +6974,7 @@ static void qlt_handle_abts_completion(struct scsi_qla_host *vha, struct qla_tgt_mgmt_cmd *mcmd; struct qla_hw_data *ha = vha->hw; - mcmd = qlt_ctio_to_cmd(vha, rsp, pkt->handle, pkt); + mcmd = qlt_ctio_to_cmd(vha, rsp, pkt->handle, TYPE_TGT_TMCMD, pkt); if (mcmd == NULL && h != QLA_TGT_SKIP_HANDLE) { ql_dbg(ql_dbg_async, vha, 0xe064, "qla_target(%d): ABTS Comp without mcmd\n", |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:41:16
|
Commit: 6f2d203 GitHub URL: https://github.com/SCST-project/scst/commit/6f2d20360efd5479a24ba9dd40d09a67b451e65a Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Add back SRR support Signed-off-by: Tony Battersby <to...@cy...> Modified Paths: -------------- qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c | 157 ++++++++++++--- 1 file changed, 134 insertions(+), 23 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c index 437a8c5..1a7c472 100644 --- a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c +++ b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c @@ -72,6 +72,8 @@ #endif #endif +#define sense_initiator_detected_error HARDWARE_ERROR, 0x48, 0x00 + static LIST_HEAD(sqa_tgt_glist); /* Function definitions for callbacks from the SCST target core. */ @@ -394,6 +396,17 @@ static struct qla_tgt_cmd *sqa_qla2xxx_get_cmd(struct fc_port *sess) return cmd; } +static int sqa_qla2xxx_get_cmd_ref(struct qla_tgt_cmd *cmd) +{ + scst_cmd_get(cmd->scst_cmd); + return 0; +} + +static void sqa_qla2xxx_put_cmd_ref(struct qla_tgt_cmd *cmd) +{ + scst_cmd_put(cmd->scst_cmd); +} + static DEFINE_MUTEX(sqa_mutex); @@ -526,8 +539,12 @@ static void sqa_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) break; case DIF_ERR_NONE: default: - scst_set_cmd_error(scst_cmd, - SCST_LOAD_SENSE(scst_sense_aborted_command)); + if (cmd->srr_failed) + scst_set_cmd_error(scst_cmd, + SCST_LOAD_SENSE(sense_initiator_detected_error)); + else + scst_set_cmd_error(scst_cmd, + SCST_LOAD_SENSE(scst_sense_aborted_command)); break; } } @@ -1544,6 +1561,11 @@ static int sqa_xmit_response(struct scst_cmd *scst_cmd) } } + if (unlikely(cmd->free_sg)) { + cmd->free_sg = 0; + qlt_free_sg(cmd); + } + cmd->bufflen = scst_cmd_get_adjusted_resp_data_len(scst_cmd); cmd->sg = scst_cmd_get_sg(scst_cmd); cmd->sg_cnt = scst_cmd_get_sg_cnt(scst_cmd); @@ -1554,6 +1576,15 @@ static int sqa_xmit_response(struct scst_cmd *scst_cmd) cmd->lba = scst_cmd_get_lba(scst_cmd); cmd->trc_flags |= TRC_XMIT_STATUS; + /* + * se_cmd::data_length,t_data_sg,t_data_nents used by + * qlt_restore_orig_sg() + */ + cmd->se_cmd.data_length = cmd->bufflen; + cmd->se_cmd.t_data_sg = cmd->sg; + cmd->se_cmd.t_data_nents = cmd->sg_cnt; + cmd->se_cmd.scsi_status = cmd->scsi_status; + #if QLA_ENABLE_PI if (scst_get_tgt_dif_actions(scst_cmd->cmd_dif_actions)) { cmd->blk_sz = scst_cmd_get_block_size(scst_cmd); @@ -1598,7 +1629,7 @@ static int sqa_xmit_response(struct scst_cmd *scst_cmd) cmd->bufflen, cmd->sg_cnt, cmd->dma_data_direction, cmd->se_cmd.residual_count); - res = qlt_xmit_response(cmd, xmit_type, scst_cmd_get_status(scst_cmd)); + res = qlt_xmit_response(cmd, xmit_type, cmd->scsi_status); switch (res) { case 0: @@ -1628,16 +1659,30 @@ static int sqa_rdy_to_xfer(struct scst_cmd *scst_cmd) TRACE(TRACE_SCSI, "sqatgt(%ld/%d): tag=%lld", cmd->vha->host_no, cmd->vha->vp_idx, scst_cmd_get_tag(scst_cmd)); + if (unlikely(cmd->free_sg)) { + cmd->free_sg = 0; + qlt_free_sg(cmd); + } + cmd->bufflen = scst_cmd_get_write_fields(scst_cmd, &cmd->sg, &cmd->sg_cnt); + cmd->dma_data_direction = scst_to_tgt_dma_dir(scst_cmd_get_data_direction(scst_cmd)); + cmd->offset = 0; - cmd->sg = scst_cmd_get_sg(scst_cmd); - cmd->sg_cnt = scst_cmd_get_sg_cnt(scst_cmd); cmd->scsi_status = scst_cmd_get_status(scst_cmd); cmd->trc_flags |= TRC_XFR_RDY; + /* + * se_cmd::data_length,t_data_sg,t_data_nents used by + * qlt_restore_orig_sg() + */ + cmd->se_cmd.data_length = cmd->bufflen; + cmd->se_cmd.t_data_sg = cmd->sg; + cmd->se_cmd.t_data_nents = cmd->sg_cnt; + cmd->se_cmd.scsi_status = cmd->scsi_status; + #if QLA_ENABLE_PI if (scst_get_tgt_dif_actions(scst_cmd->cmd_dif_actions)) { cmd->blk_sz = scst_cmd_get_block_size(scst_cmd); @@ -1839,7 +1884,9 @@ static void sqa_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd) struct qla_tgt_cmd *cmd = scst_cmd_get_tgt_priv(scst_cmd); struct scsi_qla_host *vha = cmd->vha; struct qla_qpair *qpair = cmd->qpair; + struct qla_tgt_srr *srr; unsigned long flags; + bool advance_cmd = false; TRACE_ENTRY(); @@ -1870,13 +1917,46 @@ static void sqa_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd) break; } - /* Handle race with normal CTIO completion. */ - if (!cmd->cmd_sent_to_fw) { + srr = cmd->srr; + if (srr) { + /* Handle race with SRR processing. */ + if (srr->imm_ntfy_recvd && srr->ctio_recvd) { + TRACE_MGMT_DBG( + "sqatgt(%ld/%d): tag %lld: cmd should be scheduled for SRR processing", + vha->host_no, vha->vp_idx, + scst_cmd_get_tag(scst_cmd)); + goto out_unlock; + } + TRACE_MGMT_DBG( - "sqatgt(%ld/%d): tag %lld: cmd not sent to fw; assuming just completed", + "sqatgt(%ld/%d): tag %lld: timeout waiting for %s SRR", vha->host_no, vha->vp_idx, - scst_cmd_get_tag(scst_cmd)); - goto out_unlock; + scst_cmd_get_tag(scst_cmd), + (!srr->imm_ntfy_recvd) ? "IMM" : "CTIO"); + + if (srr->ctio_recvd) { + /* + * When the SRR CTIO was received, cmd processing was + * delayed to wait for the SRR immediate notify, which + * never arrived. Process the cmd now. + * + * Note that in this case cmd->cmd_sent_to_fw == 0 + * so we avoid checking that. + */ + advance_cmd = true; + } + + qlt_srr_abort(cmd, false); + srr = NULL; /* srr may have been freed */ + } else { + /* Handle race with normal CTIO completion. */ + if (!cmd->cmd_sent_to_fw) { + TRACE_MGMT_DBG( + "sqatgt(%ld/%d): tag %lld: cmd not sent to fw; assuming just completed", + vha->host_no, vha->vp_idx, + scst_cmd_get_tag(scst_cmd)); + goto out_unlock; + } } /* The command should be aborted elsewhere if the ISP was reset. */ @@ -1884,7 +1964,8 @@ static void sqa_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd) goto out_unlock; /* Reset the ISP if there was a timeout after sending a term exchange. */ - if (cmd->sent_term_exchg && + if (!advance_cmd && + cmd->sent_term_exchg && time_is_before_jiffies(cmd->jiffies_at_term_exchg + SQA_MAX_HW_PENDING_TIME * HZ / 2)) { if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) { @@ -1904,18 +1985,46 @@ static void sqa_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd) if (!cmd->sent_term_exchg) qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1); - /* - * Restart the timer so that this function is called again - * after another timeout. This is similar to - * scst_update_hw_pending_start() except that we also set - * cmd_hw_pending to 1. - * - * IRQs are already OFF. - */ - spin_lock(&scst_cmd->sess->sess_list_lock); - scst_cmd->cmd_hw_pending = 1; - scst_cmd->hw_pending_start = jiffies; - spin_unlock(&scst_cmd->sess->sess_list_lock); + if (advance_cmd) { + switch (cmd->state) { + case QLA_TGT_STATE_NEED_DATA: + TRACE_MGMT_DBG( + "sqatgt(%ld/%d): tag %lld: force rx_data", + vha->host_no, vha->vp_idx, + scst_cmd_get_tag(scst_cmd)); + cmd->state = QLA_TGT_STATE_DATA_IN; + scst_set_cmd_error(scst_cmd, + SCST_LOAD_SENSE(scst_sense_internal_failure)); + scst_rx_data(scst_cmd, SCST_RX_STATUS_ERROR_SENSE_SET, + SCST_CONTEXT_THREAD); + break; + + case QLA_TGT_STATE_PROCESSED: + TRACE_MGMT_DBG( + "sqatgt(%ld/%d): tag %lld: force finishing cmd", + vha->host_no, vha->vp_idx, + scst_cmd_get_tag(scst_cmd)); + scst_set_delivery_status(scst_cmd, SCST_CMD_DELIVERY_FAILED); + scst_tgt_cmd_done(scst_cmd, SCST_CONTEXT_THREAD); + break; + + default: + break; + } + } else { + /* + * Restart the timer so that this function is called again + * after another timeout. This is similar to + * scst_update_hw_pending_start() except that we also set + * cmd_hw_pending to 1. + * + * IRQs are already OFF. + */ + spin_lock(&scst_cmd->sess->sess_list_lock); + scst_cmd->cmd_hw_pending = 1; + scst_cmd->hw_pending_start = jiffies; + spin_unlock(&scst_cmd->sess->sess_list_lock); + } out_unlock: spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); @@ -1936,6 +2045,8 @@ static struct qla_tgt_func_tmpl sqa_qla2xxx_template = { .handle_tmr = sqa_qla2xxx_handle_tmr, .find_cmd_by_tag = sqa_qla2xxx_find_cmd_by_tag, .get_cmd = sqa_qla2xxx_get_cmd, + .get_cmd_ref = sqa_qla2xxx_get_cmd_ref, + .put_cmd_ref = sqa_qla2xxx_put_cmd_ref, .rel_cmd = sqa_qla2xxx_rel_cmd, .free_cmd = sqa_qla2xxx_free_cmd, .free_mcmd = sqa_qla2xxx_free_mcmd, |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:41:00
|
Commit: 46e11e4 GitHub URL: https://github.com/SCST-project/scst/commit/46e11e4b32e8b5e69eb2f2a17eeb576ac59a6e01 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Add back SRR support Background: loading qla2xxx with "ql2xtgt_tape_enable=1" enables Sequence Level Error Recovery (SLER), which is most commonly used for tape drives. With SLER enabled, if there is a recoverable I/O error during a SCSI command, a Sequence Retransmission Request (SRR) will be used to retry the I/O at a low-level completely within the driver without propagating the error to the upper levels of the SCSI stack. SRR support was removed in 2017 by commit 2c39b5ca2a8c ("qla2xxx: Remove SRR code"). Add it back, new and improved. The old removed SRR code used sequence numbers to correlate the SRR CTIOs with SRR immediate notify messages. I don't see how that would work reliably with MSI-X interrupts and multiple queues. So instead use the exchange address to find the command associated with the immediate notify (qlt_srr_to_cmd). The old removed SRR code had a function qlt_check_srr_debug() to simulate a SRR, but it didn't work for me. Instead I just used fiber optic attenuators attached to the FC cable to reduce the strength of the signal and induce errors. Unfortunately this only worked for inducing SRRs on Data-Out (write) commands, so that is all I was able to test. The code to build a new scatterlist for a SRR with nonzero offset has been improved to reduce memory requirements and has been well-tested. However it does not support protection information. When a single cmd gets multiple SRRs, the old removed SRR code would restore the data buffer from the values in cmd->se_cmd before processing the new SRR. That might be needed if the offset for the new SRR was lower than the offset for the previous SRR, but I am not sure if that can happen. In my testing, when a single cmd gets multiple SRRs, the SRR offset always increases or stays the same. But in case it can decrease, I added the function qlt_restore_orig_sg(). If this is not supposed to happen then qlt_restore_orig_sg() can be removed to simplify the code. I ran into some HBA firmware bugs with QLE269x, QLE27xx, and QLE28xx firmware 9.05.xx - 9.08.xx where a SRR would cause the HBA to misbehave badly. Since SRRs are rare and therefore difficult to test, I figured it would be worth checking for the buggy firmware and disabling SLER with a warning instead of letting others run into the same problem on the rare occasion that they get a SRR. This turned out to be difficult because the firmware version isn't known in the normal NVRAM config routine, so I added a second NVRAM config routine that is called after the firmware version is known. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/654...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit c7bd85a7b9c5 upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_dbg.c | 1 + qla2x00t-32gbit/qla_init.c | 1 + qla2x00t-32gbit/qla_target.c | 1045 ++++++++++++++- qla2x00t-32gbit/qla_target.h | 81 ++ 4 files changed, 1127 insertions(+), 1 deletion(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_dbg.c b/qla2x00t-32gbit/qla_dbg.c index fa2a34e..ed0e06c 100644 --- a/qla2x00t-32gbit/qla_dbg.c +++ b/qla2x00t-32gbit/qla_dbg.c @@ -58,6 +58,7 @@ * | Target Mode Management | 0xf09b | 0xf002 | * | | | 0xf046-0xf049 | * | Target Mode Task Management | 0x1000d | | + * | Target Mode SRR | 0x11038 | | * ---------------------------------------------------------------------- */ diff --git a/qla2x00t-32gbit/qla_init.c b/qla2x00t-32gbit/qla_init.c index def9537..9637e15 100644 --- a/qla2x00t-32gbit/qla_init.c +++ b/qla2x00t-32gbit/qla_init.c @@ -4372,6 +4372,7 @@ enable_82xx_npiv: ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; } + qlt_config_nvram_with_fw_version(vha); qla2x00_get_resource_cnts(vha); qla_init_iocb_limit(vha); diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 9198578..8210403 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -3258,6 +3258,10 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, * first. */ + /* Begin timer on the first call, not on SRR retry. */ + if (likely(cmd->jiffies_at_hw_st_entry == 0)) + cmd->jiffies_at_hw_st_entry = get_jiffies_64(); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); if (unlikely(cmd->sent_term_exchg || @@ -3405,6 +3409,10 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) int pci_map_res; struct qla_qpair *qpair = cmd->qpair; + /* Begin timer on the first call, not on SRR retry. */ + if (likely(cmd->jiffies_at_hw_st_entry == 0)) + cmd->jiffies_at_hw_st_entry = get_jiffies_64(); + memset(&prm, 0, sizeof(prm)); prm.cmd = cmd; prm.tgt = tgt; @@ -3430,6 +3438,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) cmd->aborted = 1; cmd->write_data_transferred = 0; cmd->state = QLA_TGT_STATE_DATA_IN; + cmd->jiffies_at_hw_st_entry = 0; vha->hw->tgt.tgt_ops->handle_data(cmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return 0; @@ -3481,6 +3490,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) return res; out_unlock_free_unmap: + cmd->jiffies_at_hw_st_entry = 0; qlt_unmap_sg(vha, cmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); @@ -3571,6 +3581,7 @@ out: case QLA_TGT_STATE_NEED_DATA: /* handle_data will load DIF error code */ cmd->state = QLA_TGT_STATE_DATA_IN; + cmd->jiffies_at_hw_st_entry = 0; vha->hw->tgt.tgt_ops->handle_data(cmd); break; default: @@ -3658,6 +3669,62 @@ static void qlt_send_term_imm_notif(struct scsi_qla_host *vha, pr_debug("rc = %d\n", rc); } +/* + * Handle a SRR that had been previously associated with a command when the + * command has been aborted or otherwise cannot process the SRR. + * + * If reject is true, then attempt to reject the SRR. Otherwise abort the + * immediate notify exchange. + */ +void qlt_srr_abort(struct qla_tgt_cmd *cmd, bool reject) +{ + struct scsi_qla_host *vha = cmd->vha; + struct qla_tgt_srr *srr = cmd->srr; + + if (srr->imm_ntfy_recvd) { + if (reject) + srr->reject = true; + else + srr->aborted = true; + + if (srr->ctio_recvd) { + /* + * The SRR should already be scheduled for processing, + * and the SRR processing code should see that the cmd + * has been aborted and take appropriate action. In + * addition, the cmd refcount should have been + * incremented, preventing the cmd from being freed + * until SRR processing is done. + */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102e, + "qla_target(%d): tag %lld: %s: SRR already scheduled\n", + vha->vp_idx, cmd->se_cmd.tag, __func__); + } else { + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + unsigned long flags; + + /* Shedule processing for the SRR immediate notify. */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102f, + "qla_target(%d): tag %lld: %s: schedule SRR %s\n", + vha->vp_idx, cmd->se_cmd.tag, __func__, + reject ? "reject" : "abort"); + cmd->srr = NULL; + srr->cmd = NULL; + spin_lock_irqsave(&tgt->srr_lock, flags); + list_add_tail(&srr->srr_list_entry, &tgt->srr_list); + queue_work(qla_tgt_wq, &tgt->srr_work); + spin_unlock_irqrestore(&tgt->srr_lock, flags); + } + } else { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11030, + "qla_target(%d): tag %lld: %s: no IMM SRR; free SRR\n", + vha->vp_idx, cmd->se_cmd.tag, __func__); + cmd->srr = NULL; + kfree(srr); + } +} +EXPORT_SYMBOL(qlt_srr_abort); + /* * If hardware_lock held on entry, might drop it, then reaquire * This function sends the appropriate CTIO to ISP 2xxx or 24xx @@ -3893,9 +3960,16 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) qlt_decr_num_pend_cmds(cmd->vha); BUG_ON(cmd->sg_mapped); + if (unlikely(cmd->free_sg)) { + cmd->free_sg = 0; + qlt_free_sg(cmd); + } + if (unlikely(cmd->srr)) + qlt_srr_abort(cmd, false); if (unlikely(cmd->aborted || - (cmd->trc_flags & (TRC_CTIO_STRANGE | TRC_CTIO_ERR)))) { + (cmd->trc_flags & (TRC_CTIO_STRANGE | TRC_CTIO_ERR | + TRC_SRR_CTIO | TRC_SRR_IMM)))) { ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xe086, "qla_target(%d): tag %lld: free cmd (trc_flags %x, aborted %u, sent_term_exchg %u, rsp_sent %u)\n", cmd->vha->vp_idx, cmd->se_cmd.tag, @@ -3919,6 +3993,62 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) } EXPORT_SYMBOL(qlt_free_cmd); +/* + * Process a CTIO response for a SCSI command that failed due to SRR. + * + * qpair->qp_lock_ptr supposed to be held on entry + */ +static int qlt_prepare_srr_ctio(struct qla_qpair *qpair, + struct qla_tgt_cmd *cmd) +{ + struct scsi_qla_host *vha = cmd->vha; + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + struct qla_tgt_srr *srr; + + cmd->trc_flags |= TRC_SRR_CTIO; + + srr = cmd->srr; + if (srr != NULL) { + /* qlt_prepare_srr_imm() was called first. */ + + WARN_ON(srr->ctio_recvd); + WARN_ON(!srr->imm_ntfy_recvd); + + if (vha->hw->tgt.tgt_ops->get_cmd_ref(cmd)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11037, + "qla_target(%d): tag %lld: unable to get cmd ref for SRR processing\n", + vha->vp_idx, cmd->se_cmd.tag); + qlt_srr_abort(cmd, true); + return -ESHUTDOWN; + } + + srr->ctio_recvd = true; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100f, + "qla_target(%d): tag %lld: Scheduling SRR work\n", + vha->vp_idx, cmd->se_cmd.tag); + + /* Schedule the srr for processing in qlt_handle_srr(). */ + /* IRQ is already OFF */ + spin_lock(&tgt->srr_lock); + list_add_tail(&srr->srr_list_entry, &tgt->srr_list); + queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq, &tgt->srr_work); + spin_unlock(&tgt->srr_lock); + return 0; + } + + srr = kzalloc(sizeof(*srr), GFP_ATOMIC); + if (!srr) + return -ENOMEM; + + /* Expect qlt_prepare_srr_imm() to be called. */ + srr->ctio_recvd = true; + srr->cmd = cmd; + srr->reset_count = cmd->reset_count; + cmd->srr = srr; + return 0; +} + /* ha->hardware_lock supposed to be held on entry */ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, struct rsp_que *rsp, uint32_t handle, void *ctio) @@ -4109,6 +4239,17 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, break; } + case CTIO_SRR_RECEIVED: + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100e, + "qla_target(%d): tag %lld, op %x: CTIO with SRR status 0x%x received (state %d, port %8phC, LUN %lld, bufflen %d)\n", + vha->vp_idx, cmd->se_cmd.tag, op, status, + cmd->state, cmd->sess->port_name, + cmd->unpacked_lun, cmd->bufflen); + + if (qlt_prepare_srr_ctio(qpair, cmd) == 0) + return; + break; + case CTIO_DIF_ERROR: { struct ctio_crc_from_fw *crc = (struct ctio_crc_from_fw *)ctio; @@ -4161,6 +4302,15 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1); } + if (unlikely(cmd->srr != NULL)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11031, + "qla_target(%d): tag %lld, op %x: expected CTIO with SRR status; got status 0x%x: state %d, bufflen %d\n", + vha->vp_idx, cmd->se_cmd.tag, + cmd->cdb ? cmd->cdb[0] : 0, status, cmd->state, + cmd->bufflen); + qlt_srr_abort(cmd, true); + } + if (cmd->state == QLA_TGT_STATE_PROCESSED) { cmd->trc_flags |= TRC_CTIO_DONE; @@ -4173,6 +4323,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, if (status == CTIO_SUCCESS) cmd->write_data_transferred = 1; + cmd->jiffies_at_hw_st_entry = 0; ha->tgt.tgt_ops->handle_data(cmd); return; } else if (cmd->aborted) { @@ -5091,6 +5242,863 @@ out: return res; } +/* + * Return true if the HBA firmware version is known to have bugs that + * prevent Sequence Level Error Recovery (SLER) / Sequence Retransmission + * Request (SRR) from working. + * + * Some bad versions are based on testing and some are based on "Marvell Fibre + * Channel Firmware Release Notes". + */ +static bool qlt_has_sler_fw_bug(struct qla_hw_data *ha) +{ + bool has_sler_fw_bug = false; + + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + /* + * In the fw release notes: + * ER147301 was added to v9.05.00 causing SLER regressions + * FCD-259 was fixed in v9.08.00 + * FCD-371 was fixed in v9.08.00 + * FCD-1183 was fixed in v9.09.00 + * + * QLE2694L (ISP2071) known bad firmware (tested): + * 9.06.02 + * 9.07.00 + * 9.08.02 + * SRRs trigger hundreds of bogus entries in the response + * queue and various other problems. + * + * QLE2694L known good firmware (tested): + * 8.08.05 + * 9.09.00 + * + * Suspected bad firmware (not confirmed by testing): + * v9.05.xx + * + * unknown firmware: + * 9.00.00 - 9.04.xx + */ + if (ha->fw_major_version == 9 && + ha->fw_minor_version >= 5 && + ha->fw_minor_version <= 8) + has_sler_fw_bug = true; + } + + return has_sler_fw_bug; +} + +/* + * Return true and print a message if the HA has been reset since the SRR + * immediate notify was received; else return false. + */ +static bool qlt_srr_is_chip_reset(struct scsi_qla_host *vha, + struct qla_qpair *qpair, struct qla_tgt_srr *srr) +{ + if (!vha->flags.online || + !qpair->fw_started || + srr->reset_count != qpair->chip_reset) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100d, + "qla_target(%d): chip reset; discarding IMM SRR\n", + vha->vp_idx); + return true; + } + return false; +} + +/* Find and return the command associated with a SRR immediate notify. */ +static struct qla_tgt_cmd *qlt_srr_to_cmd(struct scsi_qla_host *vha, + const struct imm_ntfy_from_isp *iocb) +{ + struct qla_hw_data *ha = vha->hw; + struct fc_port *sess; + struct qla_tgt_cmd *cmd; + uint32_t tag = le32_to_cpu(iocb->u.isp24.exchange_address); + uint16_t loop_id; + be_id_t s_id; + unsigned long flags; + + if (tag == ATIO_EXCHANGE_ADDRESS_UNKNOWN) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11009, + "qla_target(%d): IMM SRR with unknown exchange address; reject SRR\n", + vha->vp_idx); + return NULL; + } + + loop_id = le16_to_cpu(iocb->u.isp24.nport_handle); + + s_id.domain = iocb->u.isp24.port_id[2]; + s_id.area = iocb->u.isp24.port_id[1]; + s_id.al_pa = iocb->u.isp24.port_id[0]; + + spin_lock_irqsave(&ha->tgt.sess_lock, flags); + sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); + if (!sess) + sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id); + if (!sess || sess->deleted) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100a, + "qla_target(%d): could not find session for IMM SRR; reject SRR\n", + vha->vp_idx); + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + return NULL; + } + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + + cmd = ha->tgt.tgt_ops->find_cmd_by_tag(sess, tag); + if (!cmd) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100b, + "qla_target(%d): could not find cmd for IMM SRR; reject SRR\n", + vha->vp_idx); + } else { + u16 srr_ox_id = le16_to_cpu(iocb->u.isp24.srr_ox_id); + u16 cmd_ox_id = be16_to_cpu(cmd->atio.u.isp24.fcp_hdr.ox_id); + + if (srr_ox_id != cmd_ox_id) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1100c, + "qla_target(%d): tag %lld: IMM SRR: srr_ox_id[%04x] != cmd_ox_id[%04x]; reject SRR\n", + vha->vp_idx, cmd->se_cmd.tag, + srr_ox_id, cmd_ox_id); + cmd = NULL; + } + } + + return cmd; +} + +/* + * Handle an immediate notify SRR (Sequence Retransmission Request) message from + * the hardware. The hardware will also send a CTIO with CTIO_SRR_RECEIVED status + * for the affected command. + * + * This may be called a second time for the same immediate notify SRR if + * CTIO_SRR_RECEIVED is never received and qlt_srr_abort() is called. + * + * Process context, no locks + */ +static void qlt_handle_srr_imm(struct scsi_qla_host *vha, + struct qla_tgt_srr *srr) +{ + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qpair; + struct qla_tgt_cmd *cmd; + uint8_t srr_explain = NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL; + + /* handle qlt_srr_abort() */ + if (srr->aborted) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11004, + "qla_target(%d): IMM SRR: terminating SRR for aborted cmd\n", + vha->vp_idx); + spin_lock_irq(&ha->hardware_lock); + if (!qlt_srr_is_chip_reset(vha, ha->base_qpair, srr)) + qlt_send_term_imm_notif(vha, &srr->imm_ntfy, 1); + spin_unlock_irq(&ha->hardware_lock); + kfree(srr); + return; + } + if (srr->reject) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11005, + "qla_target(%d): IMM SRR: rejecting SRR for unknown cmd\n", + vha->vp_idx); + goto out_reject; + } + + /* Find the command associated with the SRR. */ + cmd = qlt_srr_to_cmd(vha, &srr->imm_ntfy); + if (cmd == NULL) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11005, + "qla_target(%d): IMM SRR: rejecting SRR for unknown cmd\n", + vha->vp_idx); + srr_explain = NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_INVALID_OX_ID_RX_ID; + goto out_reject; + } + + if (ha->tgt.tgt_ops->get_cmd_ref(cmd)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11038, + "qla_target(%d): IMM SRR: unable to get cmd ref; rejecting SRR\n", + vha->vp_idx); + cmd = NULL; + goto out_reject; + } + + qpair = cmd->qpair; + + spin_lock_irq(qpair->qp_lock_ptr); + + if (cmd->reset_count != srr->reset_count) { + /* force a miscompare */ + srr->reset_count = qpair->chip_reset ^ 1; + } + if (qlt_srr_is_chip_reset(vha, qpair, srr)) { + spin_unlock_irq(qpair->qp_lock_ptr); + ha->tgt.tgt_ops->put_cmd_ref(cmd); + kfree(srr); + return; + } + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11001, + "qla_target(%d): tag %lld, op %x: received IMM SRR\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->cdb ? cmd->cdb[0] : 0); + + cmd->trc_flags |= TRC_SRR_IMM; + + if (cmd->srr != NULL) { + if (cmd->srr->imm_ntfy_recvd) { + /* + * Received another immediate notify SRR message for + * this command before the previous one could be processed + * (not expected to happen). + */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11006, + "qla_target(%d): tag %lld: received multiple IMM SRR; reject SRR\n", + vha->vp_idx, cmd->se_cmd.tag); + spin_unlock_irq(qpair->qp_lock_ptr); + ha->tgt.tgt_ops->put_cmd_ref(cmd); + goto out_reject; + } + + /* qlt_prepare_srr_ctio() was called first. */ + WARN_ON(!cmd->srr->ctio_recvd); + + /* + * The immediate notify and CTIO handlers both allocated + * separate srr structs; combine them. + */ + memcpy(&cmd->srr->imm_ntfy, &srr->imm_ntfy, + sizeof(srr->imm_ntfy)); + kfree(srr); + srr = cmd->srr; + srr->imm_ntfy_recvd = true; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11002, + "qla_target(%d): tag %lld: schedule SRR work\n", + vha->vp_idx, cmd->se_cmd.tag); + + /* Schedule the srr for processing in qlt_handle_srr(). */ + spin_lock(&tgt->srr_lock); + list_add_tail(&srr->srr_list_entry, &tgt->srr_list); + /* + * Already running the work function; no need to schedule + * tgt->srr_work. + */ + spin_unlock(&tgt->srr_lock); + spin_unlock_irq(qpair->qp_lock_ptr); + /* return with cmd refcount incremented */ + return; + } + + /* The CTIO SRR for this command has not yet been received. */ + + if (cmd->sent_term_exchg) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11007, + "qla_target(%d): tag %lld: IMM SRR: cmd already aborted\n", + vha->vp_idx, cmd->se_cmd.tag); + spin_unlock_irq(qpair->qp_lock_ptr); + spin_lock_irq(&ha->hardware_lock); + if (!qlt_srr_is_chip_reset(vha, ha->base_qpair, srr)) + qlt_send_term_imm_notif(vha, &srr->imm_ntfy, 1); + spin_unlock_irq(&ha->hardware_lock); + kfree(srr); + ha->tgt.tgt_ops->put_cmd_ref(cmd); + return; + } + + /* If not expecting a CTIO, then reject IMM SRR. */ + if (!cmd->cmd_sent_to_fw) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11008, + "qla_target(%d): tag %lld: IMM SRR but !cmd_sent_to_fw (state %d); reject SRR\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->state); + spin_unlock_irq(qpair->qp_lock_ptr); + ha->tgt.tgt_ops->put_cmd_ref(cmd); + goto out_reject; + } + + /* Expect qlt_prepare_srr_ctio() to be called. */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11003, + "qla_target(%d): tag %lld: wait for CTIO SRR (state %d)\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->state); + srr->cmd = cmd; + cmd->srr = srr; + + spin_unlock_irq(qpair->qp_lock_ptr); + + ha->tgt.tgt_ops->put_cmd_ref(cmd); + return; + +out_reject: + qpair = vha->hw->base_qpair; + spin_lock_irq(qpair->qp_lock_ptr); + if (!qlt_srr_is_chip_reset(vha, qpair, srr)) + qlt_send_notify_ack(qpair, &srr->imm_ntfy, 0, 0, 0, + NOTIFY_ACK_SRR_FLAGS_REJECT, + NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM, + srr_explain); + spin_unlock_irq(qpair->qp_lock_ptr); + kfree(srr); +} + +/* + * Handle an immediate notify SRR (Sequence Retransmission Request) message from + * the hardware. The hardware will also send a CTIO with CTIO_SRR_RECEIVED status + * for the affected command. + * + * ha->hardware_lock supposed to be held on entry + */ +static void qlt_prepare_srr_imm(struct scsi_qla_host *vha, + struct imm_ntfy_from_isp *iocb) +{ + struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; + struct qla_tgt_srr *srr; + + ql_log(ql_log_warn, vha, 0x11000, "qla_target(%d): received IMM SRR\n", + vha->vp_idx); + + /* + * Need cmd->qpair->qp_lock_ptr, but have ha->hardware_lock. Defer + * processing to a workqueue so that the right lock can be acquired + * safely. + */ + + srr = kzalloc(sizeof(*srr), GFP_ATOMIC); + if (!srr) + goto out_reject; + + memcpy(&srr->imm_ntfy, iocb, sizeof(srr->imm_ntfy)); + srr->imm_ntfy_recvd = true; + srr->reset_count = vha->hw->base_qpair->chip_reset; + spin_lock(&tgt->srr_lock); + list_add_tail(&srr->srr_list_entry, &tgt->srr_list); + queue_work(qla_tgt_wq, &tgt->srr_work); + spin_unlock(&tgt->srr_lock); + /* resume processing in qlt_handle_srr_imm() */ + return; + +out_reject: + qlt_send_notify_ack(vha->hw->base_qpair, iocb, 0, 0, 0, + NOTIFY_ACK_SRR_FLAGS_REJECT, + NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM, + NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL); +} + +/* + * If possible, undo the effect of qlt_set_data_offset() and restore the cmd + * data buffer back to its full size. + */ +static int qlt_restore_orig_sg(struct qla_tgt_cmd *cmd) +{ + struct scsi_qla_host *vha = cmd->vha; + struct se_cmd *se_cmd = &cmd->se_cmd; + + WARN_ON(cmd->sg_mapped); + + if (cmd->offset == 0) { + /* qlt_set_data_offset() has not been called. */ + return 0; + } + + if (se_cmd->t_data_sg == NULL || + se_cmd->t_data_nents == 0 || + se_cmd->data_length == 0) { + /* The original scatterlist is not available. */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102c, + "qla_target(%d): tag %lld: cannot restore original cmd buffer; keep modified buffer at offset %d\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->offset); + return -ENOENT; + } + + /* Restore the original scatterlist. */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102d, + "qla_target(%d): tag %lld: restore original cmd buffer: offset %d -> 0\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->offset); + if (cmd->free_sg) { + cmd->free_sg = 0; + qlt_free_sg(cmd); + } + cmd->offset = 0; + cmd->sg = se_cmd->t_data_sg; + cmd->sg_cnt = se_cmd->t_data_nents; + cmd->bufflen = se_cmd->data_length; + return 0; +} + +/* + * Adjust the data buffer of the given command to skip over offset bytes from + * the beginning while also reducing the length by offset bytes. + * + * This may be called multiple times for a single command if there are multiple + * SRRs, which each call reducing the buffer size further relative to the + * previous call. Note that the buffer may be reset back to its original size + * by calling qlt_restore_orig_sg(). + */ +static int qlt_set_data_offset(struct qla_tgt_cmd *cmd, uint32_t offset) +{ + struct scsi_qla_host *vha = cmd->vha; + struct scatterlist *sg_srr_start = NULL, *sg; + uint32_t first_offset = offset; + int sg_srr_cnt, i; + int bufflen = 0; + + WARN_ON(cmd->sg_mapped); + + ql_dbg(ql_dbg_tgt, vha, 0x11020, + "qla_target(%d): tag %lld: %s: sg %p sg_cnt %d dir %d cmd->offset %d cmd->bufflen %d add offset %u\n", + vha->vp_idx, cmd->se_cmd.tag, __func__, cmd->sg, + cmd->sg_cnt, cmd->dma_data_direction, cmd->offset, cmd->bufflen, + offset); + + if (cmd->se_cmd.prot_op != TARGET_PROT_NORMAL) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11021, + "qla_target(%d): tag %lld: %s: SRR with protection information at nonzero offset not implemented\n", + vha->vp_idx, cmd->se_cmd.tag, __func__); + return -EINVAL; + } + + if (!cmd->sg || !cmd->sg_cnt) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11022, + "qla_target(%d): tag %lld: %s: Missing cmd->sg or zero cmd->sg_cnt\n", + vha->vp_idx, cmd->se_cmd.tag, __func__); + return -EINVAL; + } + + /* + * Walk the current cmd->sg list until we locate the new sg_srr_start + */ + for_each_sg(cmd->sg, sg, cmd->sg_cnt, i) { + ql_dbg(ql_dbg_tgt, vha, 0x11023, + "sg[%d]: %p page: %p, length: %d, offset: %d\n", + i, sg, sg_page(sg), sg->length, sg->offset); + + if (first_offset < sg->length) { + sg_srr_start = sg; + break; + } + first_offset -= sg->length; + } + + if (!sg_srr_start) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11024, + "qla_target(%d): tag %lld: Unable to locate sg_srr_start for offset: %u\n", + vha->vp_idx, cmd->se_cmd.tag, offset); + return -EINVAL; + } + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11025, + "qla_target(%d): tag %lld: prepare SRR sgl at sg index %d of %d byte offset %u of %u\n", + vha->vp_idx, cmd->se_cmd.tag, i, cmd->sg_cnt, + first_offset, sg_srr_start->length); + + sg_srr_cnt = cmd->sg_cnt - i; + + if (first_offset == 0 && !cmd->free_sg) { + /* + * The offset points to the beginning of a scatterlist element. + * In this case there is no need to modify the first scatterlist + * element, so we can just point directly inside the original + * unmodified scatterlist. + */ + ql_dbg(ql_dbg_tgt, vha, 0x11026, "point directly to old sgl\n"); + cmd->sg = sg_srr_start; + } else { + /* + * Allocate at most 2 new scatterlist elements to reduce memory + * requirements. + */ + int n_alloc_sg = min(sg_srr_cnt, 2); + struct scatterlist *sg_srr = + kmalloc_array(n_alloc_sg, sizeof(*sg_srr), GFP_ATOMIC); + if (!sg_srr) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11027, + "qla_target(%d): tag %lld: Unable to allocate SRR scatterlist\n", + vha->vp_idx, cmd->se_cmd.tag); + return -ENOMEM; + } + sg_init_table(sg_srr, n_alloc_sg); + + /* Init the first sg element to skip over the unneeded data. */ + sg_set_page(&sg_srr[0], sg_page(sg_srr_start), + sg_srr_start->length - first_offset, + sg_srr_start->offset + first_offset); + if (sg_srr_cnt == 1) { + ql_dbg(ql_dbg_tgt, vha, 0x11028, + "single-element array\n"); + } else if (sg_srr_cnt == 2) { + /* Only two elements; copy the last element. */ + ql_dbg(ql_dbg_tgt, vha, 0x11029, + "complete two-element array\n"); + sg = sg_next(sg_srr_start); + sg_set_page(&sg_srr[1], sg_page(sg), sg->length, + sg->offset); + } else { + /* + * Three or more elements; chain our newly-allocated + * 2-entry array to the rest of the original + * scatterlist at the splice point. + */ + ql_dbg(ql_dbg_tgt, vha, 0x1102a, + "chain to original scatterlist\n"); + sg = sg_next(sg_srr_start); + sg_chain(sg_srr, 2, sg); + } + + /* + * If the previous scatterlist was allocated here on a previous + * call, then it should be safe to free now. + */ + if (cmd->free_sg) + qlt_free_sg(cmd); + cmd->sg = sg_srr; + cmd->free_sg = 1; + } + + /* Note that sg_cnt doesn't include any extra chain elements. */ + cmd->sg_cnt = sg_srr_cnt; + cmd->offset += offset; + cmd->bufflen -= offset; + + /* Check the scatterlist length for consistency. */ + for_each_sg(cmd->sg, sg, cmd->sg_cnt, i) { + bufflen += sg->length; + } + if (bufflen != cmd->bufflen) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1102b, + "qla_target(%d): tag %lld: %s: bad sgl length: expected %d got %d\n", + vha->vp_idx, cmd->se_cmd.tag, __func__, cmd->bufflen, bufflen); + return -EINVAL; + } + + return 0; +} + +/* + * Given the "SRR relative offset" (offset of data to retry), determine what + * needs to be retransmitted (data and/or status) and return the mask in + * xmit_type. If retrying data, adjust the command buffer to point to only the + * data that need to be retried, skipping over the data that don't need to be + * retried. + * + * Returns 0 for success or a negative error number. + */ +static inline int qlt_srr_adjust_data(struct qla_tgt_cmd *cmd, + uint32_t srr_rel_offs, int *xmit_type) +{ + struct scsi_qla_host *vha = cmd->vha; + int res = 0, rel_offs; + + if (srr_rel_offs < cmd->offset || + srr_rel_offs > cmd->offset + cmd->bufflen) { + *xmit_type = 0; + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101e, + "qla_target(%d): tag %lld: srr_rel_offs %u outside accepted range %u - %u\n", + vha->vp_idx, cmd->se_cmd.tag, srr_rel_offs, + cmd->offset, cmd->offset + cmd->bufflen); + return -EINVAL; + } + + /* + * srr_rel_offs is the offset of the data we need from the beginning of + * the *original* buffer. + * + * cmd->offset is the offset of the current cmd scatterlist from the + * beginning of the *original* buffer, which might be nonzero if there + * was a previous SRR and the buffer could not be reset back to its + * original size. + * + * rel_offs is the offset of the data we need from the beginning of the + * current cmd scatterlist. + */ + rel_offs = srr_rel_offs - cmd->offset; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101f, + "qla_target(%d): tag %lld: current buffer [%u - %u); srr_rel_offs=%d, rel_offs=%d\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->offset, + cmd->offset + cmd->bufflen, srr_rel_offs, rel_offs); + + *xmit_type = QLA_TGT_XMIT_ALL; + + if (rel_offs == cmd->bufflen) + *xmit_type = QLA_TGT_XMIT_STATUS; + else if (rel_offs > 0) + res = qlt_set_data_offset(cmd, rel_offs); + + return res; +} + +/* + * Process a SRR (Sequence Retransmission Request) for a SCSI command once both + * the immediate notify SRR and CTIO SRR have been received from the hw. + * + * Process context, no locks + */ +static void qlt_handle_srr(struct scsi_qla_host *vha, struct qla_tgt_srr *srr) +{ + struct qla_tgt_cmd *cmd = srr->cmd; + struct se_cmd *se_cmd = &cmd->se_cmd; + struct qla_qpair *qpair = cmd->qpair; + struct qla_hw_data *ha = vha->hw; + uint8_t op = cmd->cdb ? cmd->cdb[0] : 0; + uint32_t srr_rel_offs = le32_to_cpu(srr->imm_ntfy.u.isp24.srr_rel_offs); + uint16_t srr_ui = le16_to_cpu(srr->imm_ntfy.u.isp24.srr_ui); + int xmit_type = 0; + bool xmit_response = false; + bool rdy_to_xfer = false; + bool did_timeout; + bool send_term_exch = false; + + spin_lock_irq(qpair->qp_lock_ptr); + + WARN_ON(cmd->cmd_sent_to_fw); + + cmd->srr = NULL; + + if (qlt_srr_is_chip_reset(vha, qpair, srr)) + goto out_advance_cmd; + + if (cmd->sent_term_exchg || cmd->sess->deleted || srr->aborted) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11010, + "qla_target(%d): tag %lld: IMM SRR: cmd already aborted\n", + vha->vp_idx, cmd->se_cmd.tag); + + spin_unlock_irq(qpair->qp_lock_ptr); + + spin_lock_irq(&ha->hardware_lock); + if (!qlt_srr_is_chip_reset(vha, ha->base_qpair, srr)) + qlt_send_term_imm_notif(vha, &srr->imm_ntfy, 1); + spin_unlock_irq(&ha->hardware_lock); + + send_term_exch = true; + + spin_lock_irq(qpair->qp_lock_ptr); + goto out_advance_cmd; + } + + if (srr->reject) + goto out_reject; + + /* + * If we receive multiple SRRs for the same command, place a time limit + * on how long we are willing to retry. This timeout should be less + * than SQA_MAX_HW_PENDING_TIME in scst_qla2xxx.c. + */ + did_timeout = time_is_before_jiffies64((cmd->jiffies_at_hw_st_entry ? : + cmd->jiffies_at_alloc) + 30 * HZ); + + qlt_restore_orig_sg(cmd); + + switch (srr_ui) { + case SRR_IU_STATUS: + if (cmd->state != QLA_TGT_STATE_PROCESSED) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11011, + "qla_target(%d): tag %lld, op %x: reject SRR_IU_STATUS due to unexpected state %d\n", + vha->vp_idx, se_cmd->tag, op, + cmd->state); + goto out_reject; + } + + if (did_timeout) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11033, + "qla_target(%d): tag %lld, op %x: reject SRR_IU_STATUS due to timeout\n", + vha->vp_idx, se_cmd->tag, op); + goto out_reject; + } + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11012, + "qla_target(%d): tag %lld, op %x: accept SRR_IU_STATUS and retransmit scsi_status=%x\n", + vha->vp_idx, se_cmd->tag, op, + se_cmd->scsi_status); + xmit_type = QLA_TGT_XMIT_STATUS; + xmit_response = true; + cmd->trc_flags |= TRC_SRR_RSP; + break; + + case SRR_IU_DATA_IN: + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11013, + "qla_target(%d): tag %lld, op %x: process SRR_IU_DATA_IN: bufflen=%d, sg_cnt=%d, offset=%d, srr_offset=%d, scsi_status=%x\n", + vha->vp_idx, se_cmd->tag, op, cmd->bufflen, + cmd->sg_cnt, cmd->offset, srr_rel_offs, + se_cmd->scsi_status); + + if (cmd->state != QLA_TGT_STATE_PROCESSED) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11014, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_IN due to unexpected state %d\n", + vha->vp_idx, se_cmd->tag, cmd->state); + goto out_reject; + } + + /* + * QLA_TGT_STATE_PROCESSED does not necessarily imply data-in + */ + if (!qlt_has_data(cmd)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11015, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_IN because cmd has no data to send\n", + vha->vp_idx, se_cmd->tag); + goto out_reject; + } + + if (!cmd->sg || !cmd->sg_cnt) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11016, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_IN because buffer is missing\n", + vha->vp_idx, se_cmd->tag); + goto out_reject; + } + + if (did_timeout) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11034, + "qla_target(%d): tag %lld, op %x: reject SRR_IU_DATA_IN due to timeout\n", + vha->vp_idx, se_cmd->tag, op); + goto out_reject; + } + + if (qlt_srr_adjust_data(cmd, srr_rel_offs, &xmit_type) != 0) + goto out_reject; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11017, + "qla_target(%d): tag %lld: accept SRR_IU_DATA_IN and retransmit data: bufflen=%d, offset=%d\n", + vha->vp_idx, se_cmd->tag, cmd->bufflen, + cmd->offset); + xmit_response = true; + cmd->trc_flags |= TRC_SRR_RSP; + break; + + case SRR_IU_DATA_OUT: + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11018, + "qla_target(%d): tag %lld, op %x: process SRR_IU_DATA_OUT: bufflen=%d, sg_cnt=%d, offset=%d, srr_offset=%d\n", + vha->vp_idx, se_cmd->tag, op, cmd->bufflen, + cmd->sg_cnt, cmd->offset, srr_rel_offs); + + if (cmd->state != QLA_TGT_STATE_NEED_DATA) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11019, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_OUT due to unexpected state %d\n", + vha->vp_idx, se_cmd->tag, cmd->state); + goto out_reject; + } + + /* + * QLA_TGT_STATE_NEED_DATA implies there should be data-out + */ + if (!qlt_has_data(cmd) || !cmd->sg || !cmd->sg_cnt) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101a, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_OUT because buffer is missing\n", + vha->vp_idx, se_cmd->tag); + goto out_reject; + } + + if (did_timeout) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11035, + "qla_target(%d): tag %lld, op %x: reject SRR_IU_DATA_OUT due to timeout\n", + vha->vp_idx, se_cmd->tag, op); + goto out_reject; + } + + if (qlt_srr_adjust_data(cmd, srr_rel_offs, &xmit_type) != 0) + goto out_reject; + + if (!(xmit_type & QLA_TGT_XMIT_DATA)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101b, + "qla_target(%d): tag %lld: reject SRR_IU_DATA_OUT: bad offset\n", + vha->vp_idx, se_cmd->tag); + goto out_reject; + } + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101c, + "qla_target(%d): tag %lld: accept SRR_IU_DATA_OUT and receive data again: bufflen=%d, offset=%d\n", + vha->vp_idx, se_cmd->tag, cmd->bufflen, + cmd->offset); + cmd->trc_flags |= TRC_SRR_XRDY; + rdy_to_xfer = true; + break; + + default: + ql_dbg(ql_dbg_tgt_mgt, vha, 0x1101d, + "qla_target(%d): tag %lld, op %x: reject unknown srr_ui value 0x%x: state=%d, bufflen=%d, offset=%d, srr_offset=%d\n", + vha->vp_idx, se_cmd->tag, op, srr_ui, cmd->state, + cmd->bufflen, cmd->offset, srr_rel_offs); + goto out_reject; + } + + qlt_send_notify_ack(qpair, &srr->imm_ntfy, 0, 0, 0, + NOTIFY_ACK_SRR_FLAGS_ACCEPT, 0, 0); + + spin_unlock_irq(qpair->qp_lock_ptr); + + if (xmit_response) { + /* For status and data-in, retransmit the response. */ + if (qlt_xmit_response(cmd, xmit_type, se_cmd->scsi_status)) { + send_term_exch = true; + spin_lock_irq(qpair->qp_lock_ptr); + goto out_advance_cmd; + } + } else if (rdy_to_xfer) { + /* For data-out, receive data again. */ + if (qlt_rdy_to_xfer(cmd)) { + send_term_exch = true; + spin_lock_irq(qpair->qp_lock_ptr); + goto out_advance_cmd; + } + } + + return; + +out_reject: + qlt_send_notify_ack(qpair, &srr->imm_ntfy, 0, 0, 0, + NOTIFY_ACK_SRR_FLAGS_REJECT, + NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM, + NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL); + +out_advance_cmd: + if (!cmd->sent_term_exchg && + (send_term_exch || cmd->state != QLA_TGT_STATE_NEED_DATA) && + !qlt_srr_is_chip_reset(vha, qpair, srr)) { + cmd->trc_flags |= TRC_SRR_TERM; + qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1); + } + if (cmd->state == QLA_TGT_STATE_NEED_DATA) { + /* + * The initiator should abort the command, but if not, try to + * return an error. + */ + cmd->srr_failed = 1; + cmd->write_data_transferred = 0; + cmd->state = QLA_TGT_STATE_DATA_IN; + cmd->jiffies_at_hw_st_entry = 0; + vha->hw->tgt.tgt_ops->handle_data(cmd); + } else { + vha->hw->tgt.tgt_ops->free_cmd(cmd); + } + spin_unlock_irq(qpair->qp_lock_ptr); +} + +/* Workqueue function for processing SRR work in process context. */ +static void qlt_handle_srr_work(struct work_struct *work) +{ + struct qla_tgt *tgt = container_of(work, struct qla_tgt, srr_work); + struct scsi_qla_host *vha = tgt->vha; + + ql_dbg(ql_dbg_tgt_mgt, vha, 0x11032, + "qla_target(%d): Entering SRR work\n", vha->vp_idx); + + for (;;) { + struct qla_tgt_srr *srr; + + spin_lock_irq(&tgt->srr_lock); + srr = list_first_entry_or_null(&tgt->srr_list, typeof(*srr), + srr_list_entry); + if (!srr) { + spin_unlock_irq(&tgt->srr_lock); + break; + } + list_del(&srr->srr_list_entry); + spin_unlock_irq(&tgt->srr_lock); + + if (!srr->cmd) { + qlt_handle_srr_imm(vha, srr); + } else { + qlt_handle_srr(vha, srr); + vha->hw->tgt.tgt_ops->put_cmd_ref(srr->cmd); + kfree(srr); + } + } +} + /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ @@ -5517,6 +6525,12 @@ static void qlt_handle_imm_notify(struct scsi_qla_host *vha, if (qlt_24xx_handle_els(vha, iocb) == 0) send_notify_ack = 0; break; + + case IMM_NTFY_SRR: + qlt_prepare_srr_imm(vha, iocb); + send_notify_ack = 0; + break; + default: ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06d, "qla_target(%d): Received unknown immediate " @@ -6497,6 +7511,9 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) spin_lock_init(&tgt->sess_work_lock); INIT_WORK(&tgt->sess_work, qlt_sess_work_fn); INIT_LIST_HEAD(&tgt->sess_works_list); + spin_lock_init(&tgt->srr_lock); + INIT_LIST_HEAD(&tgt->srr_list); + INIT_WORK(&tgt->srr_work, qlt_handle_srr_work); atomic_set(&tgt->tgt_global_resets_count, 0); base_vha->vha_tgt.qla_tgt = tgt; @@ -7145,6 +8162,32 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha, } } +/* Update any settings that depend on ha->fw_*_version. */ +void +qlt_config_nvram_with_fw_version(struct scsi_qla_host *vha) +{ + struct qla_hw_data *ha = vha->hw; + + if (!QLA_TGT_MODE_ENABLED()) + return; + + if (ql2xtgt_tape_enable && qlt_has_sler_fw_bug(ha)) { + ql_log(ql_log_warn, vha, 0x11036, + "WARNING: ignoring ql2xtgt_tape_enable due to buggy HBA firmware; please upgrade FW\n"); + + /* Disable FC Tape support */ + if (ha->isp_ops->nvram_config == qla81xx_nvram_config) { + struct init_cb_81xx *icb = + (struct init_cb_81xx *)ha->init_cb; + icb->firmware_options_2 &= cpu_to_le32(~BIT_12); + } else { + struct init_cb_24xx *icb = + (struct init_cb_24xx *)ha->init_cb; + icb->firmware_options_2 &= cpu_to_le32(~BIT_12); + } + } +} + void qlt_modify_vp_config(struct scsi_qla_host *vha, struct vp_config_entry_24xx *vpmod) diff --git a/qla2x00t-32gbit/qla_target.h b/qla2x00t-32gbit/qla_target.h index ec0835a..e24abc0 100644 --- a/qla2x00t-32gbit/qla_target.h +++ b/qla2x00t-32gbit/qla_target.h @@ -209,6 +209,7 @@ struct nack_to_isp { #define NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM 0x9 #define NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL 0 +#define NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_INVALID_OX_ID_RX_ID 0x17 #define NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_UNABLE_TO_SUPPLY_DATA 0x2a #define NOTIFY_ACK_SUCCESS 0x01 @@ -711,6 +712,8 @@ struct qla_tgt_func_tmpl { int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, u64, uint16_t, uint32_t); struct qla_tgt_cmd *(*get_cmd)(struct fc_port *); + int (*get_cmd_ref)(struct qla_tgt_cmd *cmd); + void (*put_cmd_ref)(struct qla_tgt_cmd *cmd); void (*rel_cmd)(struct qla_tgt_cmd *); void (*free_cmd)(struct qla_tgt_cmd *); void (*free_mcmd)(struct qla_tgt_mgmt_cmd *); @@ -852,7 +855,13 @@ struct qla_tgt { int notify_ack_expected; int abts_resp_expected; int modify_lun_expected; + + spinlock_t srr_lock; + struct list_head srr_list; + struct work_struct srr_work; + atomic_t tgt_global_resets_count; + struct list_head tgt_list_entry; }; @@ -890,6 +899,7 @@ enum trace_flags { TRC_DATA_IN = BIT_18, TRC_ABORT = BIT_19, TRC_DIF_ERR = BIT_20, + TRC_SRR_IMM = BIT_21, }; struct qla_tgt_cmd { @@ -921,6 +931,10 @@ struct qla_tgt_cmd { unsigned int conf_compl_supported:1; unsigned int sg_mapped:1; + + /* Call qlt_free_sg() if set. */ + unsigned int free_sg:1; + unsigned int write_data_transferred:1; /* Set if the SCSI status was sent successfully. */ @@ -932,6 +946,9 @@ struct qla_tgt_cmd { unsigned int cmd_in_wq:1; unsigned int edif:1; + /* Set if a SRR was rejected. */ + unsigned int srr_failed:1; + /* Set if the exchange has been terminated. */ unsigned int sent_term_exchg:1; @@ -941,6 +958,7 @@ struct qla_tgt_cmd { */ unsigned int aborted:1; + struct qla_tgt_srr *srr; struct scatterlist *sg; /* cmd data buffer SG vector */ int sg_cnt; /* SG segments count */ int bufflen; /* cmd buffer length */ @@ -980,6 +998,14 @@ struct qla_tgt_cmd { uint16_t prot_flags; unsigned long jiffies_at_term_exchg; + + /* + * jiffies64 when qlt_rdy_to_xfer() or qlt_xmit_response() first + * called, or 0 when not in those states. Used to limit the number of + * SRR retries. + */ + uint64_t jiffies_at_hw_st_entry; + uint64_t jiffies_at_alloc; uint64_t jiffies_at_free; @@ -1042,6 +1068,45 @@ struct qla_tgt_prm { uint16_t tot_dsds; }; +/* + * SRR (Sequence Retransmission Request) - resend or re-receive some or all + * data or status to recover from a transient I/O error. + */ +struct qla_tgt_srr { + /* + * Copy of immediate notify SRR message received from hw; valid only if + * imm_ntfy_recvd is true. + */ + struct imm_ntfy_from_isp imm_ntfy; + + struct list_head srr_list_entry; + + /* The command affected by this SRR, or NULL if not yet determined. */ + struct qla_tgt_cmd *cmd; + + /* Used to detect if the HBA has been reset since receiving the SRR. */ + uint32_t reset_count; + + /* + * The hardware sends two messages for each SRR - an immediate notify + * and a CTIO with CTIO_SRR_RECEIVED status. These keep track of which + * messages have been received. The SRR can be processed once both of + * these are true. + */ + bool imm_ntfy_recvd; + bool ctio_recvd; + + /* + * This is set to true if the affected command was aborted (cmd may be + * set to NULL), in which case the immediate notify exchange also needs + * to be aborted. + */ + bool aborted; + + /* This is set to true to force the SRR to be rejected. */ + bool reject; +}; + /* Check for Switch reserved address */ #define IS_SW_RESV_ADDR(_s_id) \ ((_s_id.b.domain == 0xff) && ((_s_id.b.area & 0xf0) == 0xf0)) @@ -1099,6 +1164,20 @@ static inline uint32_t sid_to_key(const be_id_t s_id) s_id.al_pa; } +/* + * Free the scatterlist allocated by qlt_set_data_offset(). Call this only if + * cmd->free_sg is set. + */ +static inline void qlt_free_sg(struct qla_tgt_cmd *cmd) +{ + /* + * The scatterlist may be chained to the original scatterlist, but we + * only need to free the first segment here since that is the only part + * allocated by qlt_set_data_offset(). + */ + kfree(cmd->sg); +} + /* * Exported symbols from qla_target.c LLD logic used by qla2xxx code.. */ @@ -1107,6 +1186,7 @@ extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, struct rsp_que *, extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *); extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t); extern int qlt_abort_cmd(struct qla_tgt_cmd *); +void qlt_srr_abort(struct qla_tgt_cmd *cmd, bool reject); void qlt_send_term_exchange(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked); extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *); @@ -1129,6 +1209,7 @@ extern void qlt_81xx_config_nvram_stage2(struct scsi_qla_host *, struct init_cb_81xx *); extern void qlt_81xx_config_nvram_stage1(struct scsi_qla_host *, struct nvram_81xx *); +void qlt_config_nvram_with_fw_version(struct scsi_qla_host *vha); extern void qlt_modify_vp_config(struct scsi_qla_host *, struct vp_config_entry_24xx *); extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *); |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:40:52
|
Commit: cdbe624 GitHub URL: https://github.com/SCST-project/scst/commit/cdbe624028d2f4650bea1cb331bf5128bde35502 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Improve cmd logging - Add the command tag to various messages so that different messages about the same command can be correlated. - For CTIO errors (i.e. when the HW reports an error about a cmd), print the cmd tag, opcode, state, initiator WWPN, and LUN. This info helps an administrator determine what is going wrong. - When a command experiences a transport error, log a message when it is freed. This makes debugging exceptions easier. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/c57...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit 04957d8c9852 upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_dbg.c | 2 +- qla2x00t-32gbit/qla_target.c | 89 ++++++++++----- 2 files changed, 64 insertions(+), 27 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_dbg.c b/qla2x00t-32gbit/qla_dbg.c index bca217a..fa2a34e 100644 --- a/qla2x00t-32gbit/qla_dbg.c +++ b/qla2x00t-32gbit/qla_dbg.c @@ -54,7 +54,7 @@ * | Misc | 0xd303 | 0xd031-0xd0ff | * | | | 0xd101-0xd1fe | * | | | 0xd214-0xd2fe | - * | Target Mode | 0xe084 | | + * | Target Mode | 0xe086 | | * | Target Mode Management | 0xf09b | 0xf002 | * | | | 0xf046-0xf049 | * | Target Mode Task Management | 0x1000d | | diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 14597c0..9198578 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -1999,8 +1999,12 @@ static void abort_cmds_for_lun(struct scsi_qla_host *vha, u64 lun, be_id_t s_id) cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id); cmd_lun = scsilun_to_int( (struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun); - if (cmd_key == key && cmd_lun == lun) + if (cmd_key == key && cmd_lun == lun) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe085, + "qla_target(%d): tag %lld: aborted by TMR\n", + vha->vp_idx, cmd->se_cmd.tag); cmd->aborted = 1; + } } spin_unlock_irqrestore(&vha->cmd_list_lock, flags); } @@ -3890,6 +3894,15 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) BUG_ON(cmd->sg_mapped); + if (unlikely(cmd->aborted || + (cmd->trc_flags & (TRC_CTIO_STRANGE | TRC_CTIO_ERR)))) { + ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xe086, + "qla_target(%d): tag %lld: free cmd (trc_flags %x, aborted %u, sent_term_exchg %u, rsp_sent %u)\n", + cmd->vha->vp_idx, cmd->se_cmd.tag, + cmd->trc_flags, cmd->aborted, cmd->sent_term_exchg, + cmd->rsp_sent); + } + if (unlikely(cmd->cdb != &cmd->atio.u.isp24.fcp_cmnd.cdb[0])) { kfree(cmd->cdb); cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0]; @@ -3902,7 +3915,6 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) WARN_ON(1); return; } - cmd->jiffies_at_free = get_jiffies_64(); cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); } EXPORT_SYMBOL(qlt_free_cmd); @@ -3967,7 +3979,6 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, struct ctio7_from_24xx *ctio) { struct qla_hw_data *ha = vha->hw; - struct se_cmd *se_cmd; struct qla_tgt_cmd *cmd; struct qla_qpair *qpair = rsp->qpair; uint16_t ctio_flags; @@ -4006,12 +4017,12 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, if ((ctio_flags & CTIO7_FLAGS_DATA_OUT) && cmd->sess) qlt_chk_edif_rx_sa_delete_pending(vha, cmd->sess, ctio); - se_cmd = &cmd->se_cmd; cmd->cmd_sent_to_fw = 0; qlt_unmap_sg(vha, cmd); if (unlikely(status != CTIO_SUCCESS)) { + u8 op = cmd->cdb ? cmd->cdb[0] : 0; bool term_exchg = false; /* @@ -4029,8 +4040,10 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, term_exchg = true; if (printk_ratelimit()) dev_info(&vha->hw->pdev->dev, - "qla_target(%d): CTIO with INVALID_RX_ID ATIO attr %x CTIO Flags %x|%x\n", - vha->vp_idx, cmd->atio.u.isp24.attr, + "qla_target(%d): tag %lld, op %x: CTIO with INVALID_RX_ID status 0x%x received (state %d, port %8phC, LUN %lld, ATIO attr %x, CTIO Flags %x|%x)\n", + vha->vp_idx, cmd->se_cmd.tag, op, + status, cmd->state, cmd->sess->port_name, + cmd->unpacked_lun, cmd->atio.u.isp24.attr, ((cmd->ctio_flags >> 9) & 0xf), cmd->ctio_flags); break; @@ -4041,13 +4054,31 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, term_exchg = true; fallthrough; case CTIO_TIMEOUT: + { + const char *status_str; + + switch (status & 0xFFFF) { + case CTIO_LIP_RESET: + status_str = "LIP_RESET"; + break; + case CTIO_TARGET_RESET: + status_str = "TARGET_RESET"; + break; + case CTIO_ABORTED: + status_str = "ABORTED"; + break; + case CTIO_TIMEOUT: + default: + status_str = "TIMEOUT"; + break; + } ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058, - "qla_target(%d): CTIO with " - "status %#x received, state %x, se_cmd %p, " - "(LIP_RESET=e, ABORTED=2, TARGET_RESET=17, " - "TIMEOUT=b, INVALID_RX_ID=8)\n", vha->vp_idx, - status, cmd->state, se_cmd); + "qla_target(%d): tag %lld, op %x: CTIO with %s status 0x%x received (state %d, port %8phC, LUN %lld)\n", + vha->vp_idx, cmd->se_cmd.tag, op, + status_str, status, cmd->state, + cmd->sess->port_name, cmd->unpacked_lun); break; + } case CTIO_PORT_LOGGED_OUT: case CTIO_PORT_UNAVAILABLE: @@ -4056,10 +4087,11 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, (status & 0xFFFF) == CTIO_PORT_LOGGED_OUT; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059, - "qla_target(%d): CTIO with %s status %x " - "received (state %x, se_cmd %p)\n", vha->vp_idx, + "qla_target(%d): tag %lld, op %x: CTIO with %s status 0x%x received (state %d, port %8phC, LUN %lld)\n", + vha->vp_idx, cmd->se_cmd.tag, op, logged_out ? "PORT LOGGED OUT" : "PORT UNAVAILABLE", - status, cmd->state, se_cmd); + status, cmd->state, cmd->sess->port_name, + cmd->unpacked_lun); term_exchg = true; if (logged_out && cmd->sess) { @@ -4076,14 +4108,15 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, } break; } + case CTIO_DIF_ERROR: { struct ctio_crc_from_fw *crc = (struct ctio_crc_from_fw *)ctio; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf073, - "qla_target(%d): CTIO with DIF_ERROR status %x " - "received (state %x, ulp_cmd %p) actual_dif[0x%llx] " - "expect_dif[0x%llx]\n", - vha->vp_idx, status, cmd->state, se_cmd, + "qla_target(%d): tag %lld, op %x: CTIO with DIF_ERROR status 0x%x received (state %d, port %8phC, LUN %lld, actual_dif[0x%llx] expect_dif[0x%llx])\n", + vha->vp_idx, cmd->se_cmd.tag, op, status, + cmd->state, cmd->sess->port_name, + cmd->unpacked_lun, *((u64 *)&crc->actual_dif[0]), *((u64 *)&crc->expected_dif[0])); @@ -4096,14 +4129,18 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, case CTIO_FAST_INVALID_REQ: case CTIO_FAST_SPI_ERR: ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05b, - "qla_target(%d): CTIO with EDIF error status 0x%x received (state %x, se_cmd %p\n", - vha->vp_idx, status, cmd->state, se_cmd); + "qla_target(%d): tag %lld, op %x: CTIO with EDIF error status 0x%x received (state %d, port %8phC, LUN %lld)\n", + vha->vp_idx, cmd->se_cmd.tag, op, status, + cmd->state, cmd->sess->port_name, + cmd->unpacked_lun); break; default: ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05b, - "qla_target(%d): CTIO with error status 0x%x received (state %x, se_cmd %p\n", - vha->vp_idx, status, cmd->state, se_cmd); + "qla_target(%d): tag %lld, op %x: CTIO with error status 0x%x received (state %d, port %8phC, LUN %lld)\n", + vha->vp_idx, cmd->se_cmd.tag, op, status, + cmd->state, cmd->sess->port_name, + cmd->unpacked_lun); break; } @@ -4141,13 +4178,13 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, } else if (cmd->aborted) { cmd->trc_flags |= TRC_CTIO_ABORTED; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e, - "Aborted command %p (tag %lld) finished\n", cmd, - se_cmd_tag(se_cmd)); + "qla_target(%d): tag %lld: Aborted command finished\n", + vha->vp_idx, cmd->se_cmd.tag); } else { cmd->trc_flags |= TRC_CTIO_STRANGE; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c, - "qla_target(%d): A command in state (%d) should " - "not return a CTIO complete\n", vha->vp_idx, cmd->state); + "qla_target(%d): tag %lld: A command in state (%d) should not return a CTIO complete\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->state); } if (unlikely(status != CTIO_SUCCESS) && |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:40:41
|
Commit: ead8a10 GitHub URL: https://github.com/SCST-project/scst/commit/ead8a100c95bb454049028c9e79cb93d52e8dd34 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Add cmd->rsp_sent Signed-off-by: Tony Battersby <to...@cy...> Modified Paths: -------------- qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c | 2 ++ 1 file changed, 2 insertions(+) =================================================================== diff --git a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c index f0f5332..437a8c5 100644 --- a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c +++ b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c @@ -684,6 +684,8 @@ static void sqa_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd) cmd->state = QLA_TGT_STATE_DONE; cmd->trc_flags |= TRC_CMD_DONE; + if (unlikely(!cmd->rsp_sent)) + scst_set_delivery_status(scst_cmd, SCST_CMD_DELIVERY_FAILED); scst_tgt_cmd_done(scst_cmd, scst_work_context); TRACE_EXIT(); |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:40:22
|
Commit: 658dce1 GitHub URL: https://github.com/SCST-project/scst/commit/658dce1cae025dbfd6194e127b488546b93bffc0 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Add cmd->rsp_sent Add cmd->rsp_sent to indicate that the SCSI status has been sent successfully, so that SCST can be informed of any transport errors. This will also be used for logging in later patches. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/d4b...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit f4199d581256 upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_target.c | 4 ++++ qla2x00t-32gbit/qla_target.h | 4 ++++ 2 files changed, 8 insertions(+) =================================================================== diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 00b5351..14597c0 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -4126,6 +4126,10 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, if (cmd->state == QLA_TGT_STATE_PROCESSED) { cmd->trc_flags |= TRC_CTIO_DONE; + + if (likely(status == CTIO_SUCCESS)) + cmd->rsp_sent = 1; + } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) { cmd->state = QLA_TGT_STATE_DATA_IN; diff --git a/qla2x00t-32gbit/qla_target.h b/qla2x00t-32gbit/qla_target.h index 1eb9445..ec0835a 100644 --- a/qla2x00t-32gbit/qla_target.h +++ b/qla2x00t-32gbit/qla_target.h @@ -922,6 +922,10 @@ struct qla_tgt_cmd { unsigned int conf_compl_supported:1; unsigned int sg_mapped:1; unsigned int write_data_transferred:1; + + /* Set if the SCSI status was sent successfully. */ + unsigned int rsp_sent:1; + unsigned int q_full:1; unsigned int term_exchg:1; unsigned int cmd_sent_to_fw:1; |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:40:11
|
Commit: 22a6aab GitHub URL: https://github.com/SCST-project/scst/commit/22a6aabf23855b7ada14a46628378fcf076ff584 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Fix invalid memory access with big CDBs Signed-off-by: Tony Battersby <to...@cy...> Modified Paths: -------------- qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c index 07aee6e..f0f5332 100644 --- a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c +++ b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c @@ -419,16 +419,15 @@ static int sqa_qla2xxx_handle_cmd(scsi_qla_host_t *vha, TRACE_DBG("sqatgt(%ld/%d): Handling command: length=%d, fcp_task_attr=%d, direction=%d, bidirectional=%d lun=%llx cdb=%x tag=%d cmd %p ulpcmd %p\n", vha->host_no, vha->vp_idx, data_length, task_codes, data_dir, bidi, cmd->unpacked_lun, - atio->u.isp24.fcp_cmnd.cdb[0], + cdb[0], atio->u.isp24.exchange_addr, cmd, cmd->scst_cmd); cmd->scst_cmd = scst_rx_cmd(scst_sess, (uint8_t *)&atio->u.isp24.fcp_cmnd.lun, sizeof(atio->u.isp24.fcp_cmnd.lun), - atio->u.isp24.fcp_cmnd.cdb, - sizeof(atio->u.isp24.fcp_cmnd.cdb) + - (atio->u.isp24.fcp_cmnd.add_cdb_len * 4), + cdb, + cmd->cdb_len, SCST_ATOMIC); if (cmd->scst_cmd == NULL) { @@ -1550,7 +1549,6 @@ static int sqa_xmit_response(struct scst_cmd *scst_cmd) scst_to_tgt_dma_dir(scst_cmd_get_data_direction(scst_cmd)); cmd->offset = scst_cmd_get_ppl_offset(scst_cmd); cmd->scsi_status = scst_cmd_get_status(scst_cmd); - cmd->cdb = (unsigned char *) scst_cmd_get_cdb(scst_cmd); cmd->lba = scst_cmd_get_lba(scst_cmd); cmd->trc_flags |= TRC_XMIT_STATUS; @@ -1633,7 +1631,6 @@ static int sqa_rdy_to_xfer(struct scst_cmd *scst_cmd) cmd->dma_data_direction = scst_to_tgt_dma_dir(scst_cmd_get_data_direction(scst_cmd)); - cmd->cdb = scst_cmd_get_cdb(scst_cmd); cmd->sg = scst_cmd_get_sg(scst_cmd); cmd->sg_cnt = scst_cmd_get_sg_cnt(scst_cmd); cmd->scsi_status = scst_cmd_get_status(scst_cmd); |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:40:11
|
Commit: c7e629c GitHub URL: https://github.com/SCST-project/scst/commit/c7e629c8fbaf02f7985ef07b4f4069f235a81b0c Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Fix invalid memory access with big CDBs struct atio7_fcp_cmnd is a variable-length data structure because of add_cdb_len, but it is embedded in struct atio_from_isp and copied around like a fixed-length data structure. For big CDBs > 16 bytes, get_datalen_for_atio() called on a fixed-length copy of the atio will access invalid memory. In some cases this can be fixed by moving the atio to the end of the data structure and using a variable-length allocation. In other cases such as allocating struct qla_tgt_cmd, the fixed-length data structures are preallocated for speed, so in the case that add_cdb_len != 0, allocate a separate buffer for the CDB. Also add memcpy_atio() as a safeguard against invalid memory accesses. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/306...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit 091719c21d5a upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_target.c | 83 +++++++++++++-- qla2x00t-32gbit/qla_target.h | 7 +- 2 files changed, 81 insertions(+), 9 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index a63b182..00b5351 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -225,6 +225,10 @@ static void qlt_queue_unknown_atio(scsi_qla_host_t *vha, struct qla_tgt_sess_op *u; struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; unsigned long flags; + unsigned int add_cdb_len = 0; + + /* atio must be the last member of qla_tgt_sess_op for add_cdb_len */ + BUILD_BUG_ON(offsetof(struct qla_tgt_sess_op, atio) + sizeof(u->atio) != sizeof(*u)); if (tgt->tgt_stop) { ql_dbg(ql_dbg_async, vha, 0x502c, @@ -233,12 +237,17 @@ static void qlt_queue_unknown_atio(scsi_qla_host_t *vha, goto out_term; } - u = kzalloc(sizeof(*u), GFP_ATOMIC); + if (atio->u.raw.entry_type == ATIO_TYPE7 && + atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0) + add_cdb_len = + ((unsigned int) atio->u.isp24.fcp_cmnd.add_cdb_len) * 4; + + u = kzalloc(sizeof(*u) + add_cdb_len, GFP_ATOMIC); if (u == NULL) goto out_term; u->vha = vha; - memcpy(&u->atio, atio, sizeof(*atio)); + memcpy(&u->atio, atio, sizeof(*atio) + add_cdb_len); INIT_LIST_HEAD(&u->cmd_list); spin_lock_irqsave(&vha->cmd_list_lock, flags); @@ -3880,6 +3889,13 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) qlt_decr_num_pend_cmds(cmd->vha); BUG_ON(cmd->sg_mapped); + + if (unlikely(cmd->cdb != &cmd->atio.u.isp24.fcp_cmnd.cdb[0])) { + kfree(cmd->cdb); + cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0]; + cmd->cdb_len = 16; + } + cmd->jiffies_at_free = get_jiffies_64(); if (!sess || !sess->se_sess) { @@ -4180,7 +4196,6 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) struct qla_hw_data *ha = vha->hw; struct fc_port *sess = cmd->sess; struct atio_from_isp *atio = &cmd->atio; - unsigned char *cdb; unsigned long flags; uint32_t data_length; int ret, fcp_task_attr, data_dir, bidi = 0; @@ -4196,7 +4211,6 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) goto out_term; } - cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; se_cmd_tag(&cmd->se_cmd) = le32_to_cpu(atio->u.isp24.exchange_addr); if (atio->u.isp24.fcp_cmnd.rddata && @@ -4214,7 +4228,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) atio->u.isp24.fcp_cmnd.task_attr); data_length = get_datalen_for_atio(atio); - ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length, + ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cmd->cdb, data_length, fcp_task_attr, data_dir, bidi); if (ret != 0) goto out_term; @@ -4235,6 +4249,11 @@ out_term: qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1); qlt_decr_num_pend_cmds(vha); + if (unlikely(cmd->cdb != &cmd->atio.u.isp24.fcp_cmnd.cdb[0])) { + kfree(cmd->cdb); + cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0]; + cmd->cdb_len = 16; + } cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); @@ -4360,18 +4379,43 @@ out: #endif } +/* + * Safely make a fixed-length copy of a variable-length atio by truncating the + * CDB if necessary. + */ +static void memcpy_atio(struct atio_from_isp *dst, + const struct atio_from_isp *src) +{ + int len; + + memcpy(dst, src, sizeof(*dst)); + + /* + * If the CDB was truncated, prevent get_datalen_for_atio() from + * accessing invalid memory. + */ + len = src->u.isp24.fcp_cmnd.add_cdb_len; + if (unlikely(len != 0)) { + dst->u.isp24.fcp_cmnd.add_cdb_len = 0; + memcpy(&dst->u.isp24.fcp_cmnd.add_cdb[0], + &src->u.isp24.fcp_cmnd.add_cdb[len * 4], + 4); + } +} + static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, struct fc_port *sess, struct atio_from_isp *atio) { struct qla_tgt_cmd *cmd; + int add_cdb_len; cmd = vha->hw->tgt.tgt_ops->get_cmd(sess); if (!cmd) return NULL; cmd->cmd_type = TYPE_TGT_CMD; - memcpy(&cmd->atio, atio, sizeof(*atio)); + memcpy_atio(&cmd->atio, atio); INIT_LIST_HEAD(&cmd->sess_cmd_list); cmd->state = QLA_TGT_STATE_NEW; cmd->tgt = vha->vha_tgt.qla_tgt; @@ -4391,6 +4435,29 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, cmd->vp_idx = vha->vp_idx; cmd->edif = sess->edif.enable; + cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0]; + cmd->cdb_len = 16; + + /* + * NOTE: memcpy_atio() set cmd->atio.u.isp24.fcp_cmnd.add_cdb_len to 0, + * so use the original value here. + */ + add_cdb_len = atio->u.isp24.fcp_cmnd.add_cdb_len; + if (unlikely(add_cdb_len != 0)) { + int cdb_len = 16 + add_cdb_len * 4; + u8 *cdb; + + cdb = kmalloc(cdb_len, GFP_ATOMIC); + if (unlikely(!cdb)) { + vha->hw->tgt.tgt_ops->free_cmd(cmd); + return NULL; + } + /* CAUTION: copy CDB from atio not cmd->atio */ + memcpy(cdb, atio->u.isp24.fcp_cmnd.cdb, cdb_len); + cmd->cdb = cdb; + cmd->cdb_len = cdb_len; + } + return cmd; } @@ -5553,13 +5620,15 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, qlt_incr_num_pend_cmds(vha); INIT_LIST_HEAD(&cmd->cmd_list); - memcpy(&cmd->atio, atio, sizeof(*atio)); + memcpy_atio(&cmd->atio, atio); cmd->tgt = vha->vha_tgt.qla_tgt; cmd->vha = vha; cmd->reset_count = ha->base_qpair->chip_reset; cmd->q_full = 1; cmd->qpair = ha->base_qpair; + cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0]; + cmd->cdb_len = 16; if (qfull) { cmd->q_full = 1; diff --git a/qla2x00t-32gbit/qla_target.h b/qla2x00t-32gbit/qla_target.h index fe9f77c..1eb9445 100644 --- a/qla2x00t-32gbit/qla_target.h +++ b/qla2x00t-32gbit/qla_target.h @@ -859,11 +859,13 @@ struct qla_tgt { struct qla_tgt_sess_op { struct scsi_qla_host *vha; uint32_t chip_reset; - struct atio_from_isp atio; struct work_struct work; struct list_head cmd_list; bool aborted; struct rsp_que *rsp; + + struct atio_from_isp atio; + /* DO NOT ADD ANYTHING ELSE HERE - atio must be last member */ }; enum trace_flags { @@ -965,8 +967,9 @@ struct qla_tgt_cmd { uint8_t scsi_status, sense_key, asc, ascq; struct crc_context *ctx; - const uint8_t *cdb; + uint8_t *cdb; uint64_t lba; + int cdb_len; uint16_t a_guard, e_guard, a_app_tag, e_app_tag; uint32_t a_ref_tag, e_ref_tag; #define DIF_BUNDL_DMA_VALID 1 |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:38:31
|
Commit: f9023c3 GitHub URL: https://github.com/SCST-project/scst/commit/f9023c31ef42262aedfb1ed223a6522e968eabbc Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: Fix TMR failure handling (target mode) If handle_tmr() fails: - The code for QLA_TGT_ABTS results in memory-use-after-free and double-free: qlt_do_tmr_work() qlt_build_abts_resp_iocb() qpair->req->outstanding_cmds[h] = (srb_t *)mcmd; mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); FIRST FREE qlt_handle_abts_completion() mcmd = qlt_ctio_to_cmd() cmd = req->outstanding_cmds[h]; return cmd; vha = mcmd->vha; USE-AFTER-FREE ha->tgt.tgt_ops->free_mcmd(mcmd); SECOND FREE - qlt_send_busy() makes no sense because it sends a SCSI command response instead of a TMR response. Instead just call qlt_xmit_tm_rsp() to send a TMR failed response, since that code is well-tested and handles a number of corner cases. But it would be incorrect to call ha->tgt.tgt_ops->free_mcmd() after handle_tmr() failed, so add a flag to mcmd indicating the proper way to free the mcmd so that qlt_xmit_tm_rsp() can be used for both cases. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/09a...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit 3d56983cc6f0 upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_os.c | 2 +- qla2x00t-32gbit/qla_target.c | 56 +++++++-------- qla2x00t-32gbit/qla_target.h | 2 + 3 files changed, 27 insertions(+), 33 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index bc0a5f5..58bb926 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -1943,7 +1943,7 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) * Currently, only ABTS response gets on the * outstanding_cmds[] */ - ha->tgt.tgt_ops->free_mcmd( + qlt_free_ul_mcmd(ha, (struct qla_tgt_mgmt_cmd *) sp); break; default: diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 499df17..a63b182 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -2020,7 +2020,6 @@ static void qlt_do_tmr_work(struct work_struct *work) struct qla_hw_data *ha = mcmd->vha->hw; int rc; uint32_t tag; - unsigned long flags; switch (mcmd->tmr_func) { case QLA_TGT_ABTS: @@ -2035,34 +2034,12 @@ static void qlt_do_tmr_work(struct work_struct *work) mcmd->tmr_func, tag); if (rc != 0) { - spin_lock_irqsave(mcmd->qpair->qp_lock_ptr, flags); - switch (mcmd->tmr_func) { - case QLA_TGT_ABTS: - mcmd->fc_tm_rsp = FCP_TMF_REJECTED; - qlt_build_abts_resp_iocb(mcmd); - break; - case QLA_TGT_LUN_RESET: - case QLA_TGT_CLEAR_TS: - case QLA_TGT_ABORT_TS: - case QLA_TGT_CLEAR_ACA: - case QLA_TGT_TARGET_RESET: - qlt_send_busy(mcmd->qpair, &mcmd->orig_iocb.atio, - qla_sam_status); - break; - - case QLA_TGT_ABORT_ALL: - case QLA_TGT_NEXUS_LOSS_SESS: - case QLA_TGT_NEXUS_LOSS: - qlt_send_notify_ack(mcmd->qpair, - &mcmd->orig_iocb.imm_ntfy, 0, 0, 0, 0, 0, 0); - break; - } - spin_unlock_irqrestore(mcmd->qpair->qp_lock_ptr, flags); - ql_dbg(ql_dbg_tgt_mgt, mcmd->vha, 0xf052, "qla_target(%d): tgt_ops->handle_tmr() failed: %d\n", mcmd->vha->vp_idx, rc); - mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); + mcmd->flags |= QLA24XX_MGMT_LLD_OWNED; + mcmd->fc_tm_rsp = FCP_TMF_FAILED; + qlt_xmit_tm_rsp(mcmd); } } @@ -2257,6 +2234,21 @@ void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd) } EXPORT_SYMBOL(qlt_free_mcmd); +/* + * If the upper layer knows about this mgmt cmd, then call its ->free_cmd() + * callback, which will eventually call qlt_free_mcmd(). Otherwise, call + * qlt_free_mcmd() directly. + */ +void qlt_free_ul_mcmd(struct qla_hw_data *ha, struct qla_tgt_mgmt_cmd *mcmd) +{ + if (!mcmd) + return; + if (mcmd->flags & QLA24XX_MGMT_LLD_OWNED) + qlt_free_mcmd(mcmd); + else + ha->tgt.tgt_ops->free_mcmd(mcmd); +} + /* * ha->hardware_lock supposed to be held on entry. Might drop it, then * reacquire @@ -2349,12 +2341,12 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) "RESET-TMR online/active/old-count/new-count = %d/%d/%d/%d.\n", vha->flags.online, qla2x00_reset_active(vha), mcmd->reset_count, qpair->chip_reset); - ha->tgt.tgt_ops->free_mcmd(mcmd); + qlt_free_ul_mcmd(ha, mcmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return; } - if (mcmd->flags == QLA24XX_MGMT_SEND_NACK) { + if (mcmd->flags & QLA24XX_MGMT_SEND_NACK) { switch (mcmd->orig_iocb.imm_ntfy.u.isp24.status_subcode) { case ELS_LOGO: case ELS_PRLO: @@ -2387,7 +2379,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) * qlt_xmit_tm_rsp() returns here.. */ if (free_mcmd) - ha->tgt.tgt_ops->free_mcmd(mcmd); + qlt_free_ul_mcmd(ha, mcmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); } @@ -5809,7 +5801,7 @@ static void qlt_handle_abts_completion(struct scsi_qla_host *vha, if (le32_to_cpu(entry->error_subcode1) == 0x1E && le32_to_cpu(entry->error_subcode2) == 0) { if (qlt_chk_unresolv_exchg(vha, rsp->qpair, entry)) { - ha->tgt.tgt_ops->free_mcmd(mcmd); + qlt_free_ul_mcmd(ha, mcmd); return; } qlt_24xx_retry_term_exchange(vha, rsp->qpair, @@ -5820,10 +5812,10 @@ static void qlt_handle_abts_completion(struct scsi_qla_host *vha, vha->vp_idx, entry->compl_status, entry->error_subcode1, entry->error_subcode2); - ha->tgt.tgt_ops->free_mcmd(mcmd); + qlt_free_ul_mcmd(ha, mcmd); } } else if (mcmd) { - ha->tgt.tgt_ops->free_mcmd(mcmd); + qlt_free_ul_mcmd(ha, mcmd); } } diff --git a/qla2x00t-32gbit/qla_target.h b/qla2x00t-32gbit/qla_target.h index c00488b..fe9f77c 100644 --- a/qla2x00t-32gbit/qla_target.h +++ b/qla2x00t-32gbit/qla_target.h @@ -1006,6 +1006,7 @@ struct qla_tgt_mgmt_cmd { unsigned int flags; #define QLA24XX_MGMT_SEND_NACK BIT_0 #define QLA24XX_MGMT_ABORT_IO_ATTR_VALID BIT_1 +#define QLA24XX_MGMT_LLD_OWNED BIT_2 uint32_t reset_count; struct work_struct work; uint64_t unpacked_lun; @@ -1102,6 +1103,7 @@ extern int qlt_abort_cmd(struct qla_tgt_cmd *); void qlt_send_term_exchange(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked); extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *); +void qlt_free_ul_mcmd(struct qla_hw_data *ha, struct qla_tgt_mgmt_cmd *mcmd); extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *); extern void qlt_free_cmd(struct qla_tgt_cmd *cmd); extern void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd); |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:36:33
|
Commit: 33bfeab GitHub URL: https://github.com/SCST-project/scst/commit/33bfeab7d0d9cd27979768d214df971ceed66cbc Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Improve checks in qlt_xmit_response / qlt_rdy_to_xfer Similar fixes to both functions: qlt_xmit_response: - If the cmd cannot be processed, remember to call ->free_cmd() to prevent the target-mode midlevel from seeing a cmd lockup. - Do not try to send the response if the exchange has been terminated. - Check for chip reset once after lock instead of both before and after lock. - Give errors from qlt_pre_xmit_response() a lower priority to compensate for removing the first check for chip reset. qlt_rdy_to_xfer: - Check for chip reset after lock instead of before lock to avoid races. - Do not try to receive data if the exchange has been terminated. - Give errors from qlt_pci_map_calc_cnt() a lower priority to compensate for moving the check for chip reset. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/cd6...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit 5c50d84798eb upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_target.c | 86 ++++++++------- 1 file changed, 48 insertions(+), 38 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index a4af749..499df17 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -3238,12 +3238,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, uint32_t full_req_cnt = 0; unsigned long flags = 0; int res; - - if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || - (cmd->sess && cmd->sess->deleted)) { - cmd->state = QLA_TGT_STATE_PROCESSED; - return 0; - } + int pre_xmit_res; ql_dbg_qp(ql_dbg_tgt, qpair, 0xe018, "is_send_status=%d, cmd->bufflen=%d, cmd->sg_cnt=%d, cmd->dma_data_direction=%d se_cmd[%p] qp %d\n", @@ -3251,33 +3246,39 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, 1 : 0, cmd->bufflen, cmd->sg_cnt, cmd->dma_data_direction, &cmd->se_cmd, qpair->id); - res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status, + pre_xmit_res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status, &full_req_cnt); - if (unlikely(res != 0)) { - return res; - } + /* + * Check pre_xmit_res later because we want to check other errors + * first. + */ spin_lock_irqsave(qpair->qp_lock_ptr, flags); + if (unlikely(cmd->sent_term_exchg || + cmd->sess->deleted || + !qpair->fw_started || + cmd->reset_count != qpair->chip_reset)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe101, + "qla_target(%d): tag %lld: skipping send response for aborted cmd\n", + vha->vp_idx, cmd->se_cmd.tag); + qlt_unmap_sg(vha, cmd); + cmd->state = QLA_TGT_STATE_PROCESSED; + vha->hw->tgt.tgt_ops->free_cmd(cmd); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + return 0; + } + + /* Check for errors from qlt_pre_xmit_response(). */ + res = pre_xmit_res; + if (unlikely(res)) + goto out_unmap_unlock; + if (xmit_type == QLA_TGT_XMIT_STATUS) qpair->tgt_counters.core_qla_snd_status++; else qpair->tgt_counters.core_qla_que_buf++; - if (!qpair->fw_started || cmd->reset_count != qpair->chip_reset) { - /* - * Either the port is not online or this request was from - * previous life, just abort the processing. - */ - cmd->state = QLA_TGT_STATE_PROCESSED; - ql_dbg_qp(ql_dbg_async, qpair, 0xe101, - "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n", - vha->flags.online, qla2x00_reset_active(vha), - cmd->reset_count, qpair->chip_reset); - res = 0; - goto out_unmap_unlock; - } - /* Does F/W have an IOCBs for this request */ res = qlt_check_reserve_free_req(qpair, full_req_cnt); if (unlikely(res)) @@ -3396,6 +3397,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) struct qla_tgt_prm prm; unsigned long flags = 0; int res = 0; + int pci_map_res; struct qla_qpair *qpair = cmd->qpair; memset(&prm, 0, sizeof(prm)); @@ -3404,28 +3406,36 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) prm.sg = NULL; prm.req_cnt = 1; - if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || - (cmd->sess && cmd->sess->deleted)) { - /* - * Either the port is not online or this request was from - * previous life, just abort the processing. - */ + /* Calculate number of entries and segments required */ + pci_map_res = qlt_pci_map_calc_cnt(&prm); + /* + * Check pci_map_res later because we want to check other errors first. + */ + + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + + if (unlikely(cmd->sent_term_exchg || + cmd->sess->deleted || + !qpair->fw_started || + cmd->reset_count != qpair->chip_reset)) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe102, + "qla_target(%d): tag %lld: skipping data-out for aborted cmd\n", + vha->vp_idx, cmd->se_cmd.tag); + qlt_unmap_sg(vha, cmd); cmd->aborted = 1; cmd->write_data_transferred = 0; cmd->state = QLA_TGT_STATE_DATA_IN; vha->hw->tgt.tgt_ops->handle_data(cmd); - ql_dbg_qp(ql_dbg_async, qpair, 0xe102, - "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n", - vha->flags.online, qla2x00_reset_active(vha), - cmd->reset_count, qpair->chip_reset); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return 0; } - /* Calculate number of entries and segments required */ - if (qlt_pci_map_calc_cnt(&prm) != 0) - return -EAGAIN; + /* Check for errors from qlt_pci_map_calc_cnt(). */ + if (unlikely(pci_map_res != 0)) { + res = -EAGAIN; + goto out_unlock_free_unmap; + } - spin_lock_irqsave(qpair->qp_lock_ptr, flags); /* Does F/W have an IOCBs for this request */ res = qlt_check_reserve_free_req(qpair, prm.req_cnt); if (res != 0) |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:36:11
|
Commit: dd23781 GitHub URL: https://github.com/SCST-project/scst/commit/dd237813508b2f4781ab66219890cf8f84e15b70 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Fix races with aborting commands sqa_on_hw_pending_cmd_timeout() currently unmaps DMA, sets outstanding_cmds[h] to NULL, and forces the command to complete. This could cause a kernel crash if the HW later accesses the DMA mapping. It can also cause other problems if outstanding_cmds[h] is reused for a different command. Fix by doing this instead: - In sqa_on_hw_pending_cmd_timeout(), call qlt_send_term_exchange() first and then restart the timeout. After another timeout, reset the ISP. Signed-off-by: Tony Battersby <to...@cy...> Modified Paths: -------------- qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c | 136 ++++++++------- 1 file changed, 76 insertions(+), 60 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c index e885b97..07aee6e 100644 --- a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c +++ b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c @@ -187,6 +187,7 @@ static struct cmd_state_name { {QLA_TGT_STATE_NEED_DATA, "NeedData"}, {QLA_TGT_STATE_DATA_IN, "DataIn"}, {QLA_TGT_STATE_PROCESSED, "Processed"}, + {QLA_TGT_STATE_DONE, "Done"}, }; static char *cmdstate_to_str(uint8_t state) @@ -497,23 +498,14 @@ static void sqa_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) { struct scst_cmd *scst_cmd = cmd->scst_cmd; int rx_status; - unsigned long flags; TRACE_ENTRY(); - spin_lock_irqsave(&cmd->cmd_lock, flags); - if (cmd->aborted) { - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - + if (unlikely(cmd->aborted)) { scst_set_cmd_error(scst_cmd, SCST_LOAD_SENSE(scst_sense_internal_failure)); - scst_rx_data(scst_cmd, SCST_RX_STATUS_ERROR_SENSE_SET, - SCST_CONTEXT_THREAD); - return; - } - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - - if (cmd->write_data_transferred) { + rx_status = SCST_RX_STATUS_ERROR_SENSE_SET; + } else if (likely(cmd->write_data_transferred)) { rx_status = SCST_RX_STATUS_SUCCESS; } else { rx_status = SCST_RX_STATUS_ERROR_SENSE_SET; @@ -691,6 +683,7 @@ static void sqa_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd) TRACE_ENTRY(); + cmd->state = QLA_TGT_STATE_DONE; cmd->trc_flags |= TRC_CMD_DONE; scst_tgt_cmd_done(scst_cmd, scst_work_context); @@ -1522,9 +1515,10 @@ static int sqa_xmit_response(struct scst_cmd *scst_cmd) cmd = scst_cmd_get_tgt_priv(scst_cmd); if (scst_cmd_aborted_on_xmit(scst_cmd)) { - TRACE_MGMT_DBG("sqatgt(%ld/%d): CMD_ABORTED cmd[%p]", - cmd->vha->host_no, cmd->vha->vp_idx, - cmd); + TRACE_MGMT_DBG( + "sqatgt(%ld/%d): tag %lld: skipping send response for aborted cmd", + cmd->vha->host_no, cmd->vha->vp_idx, + scst_cmd_get_tag(scst_cmd)); qlt_abort_cmd(cmd); scst_set_delivery_status(scst_cmd, SCST_CMD_DELIVERY_ABORTED); scst_tgt_cmd_done(scst_cmd, SCST_CONTEXT_DIRECT); @@ -1841,72 +1835,94 @@ static int sqa_qla2xxx_dif_tags(struct qla_tgt_cmd *cmd, return t32; } -static void sqa_cleanup_hw_pending_cmd(scsi_qla_host_t *vha, - struct qla_tgt_cmd *cmd) -{ - uint32_t h; - struct qla_qpair *qpair = cmd->qpair; - - for (h = 1; h < qpair->req->num_outstanding_cmds; h++) { - if (qpair->req->outstanding_cmds[h] == (srb_t *)cmd) { - printk(KERN_INFO "Clearing handle %d for cmd %p", h, - cmd); - //TRACE_DBG("Clearing handle %d for cmd %p", h, cmd); - qpair->req->outstanding_cmds[h] = NULL; - break; - } - } -} - static void sqa_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd) { struct qla_tgt_cmd *cmd = scst_cmd_get_tgt_priv(scst_cmd); struct scsi_qla_host *vha = cmd->vha; struct qla_qpair *qpair = cmd->qpair; - uint8_t aborted = cmd->aborted; unsigned long flags; TRACE_ENTRY(); - TRACE_MGMT_DBG("sqatgt(%ld/%d): Cmd %p HW pending for too long (state %s) %s; %s;", - vha->host_no, vha->vp_idx, cmd, - cmdstate_to_str((uint8_t)cmd->state), - cmd->cmd_sent_to_fw ? "sent to fw" : "not sent to fw", - aborted ? "aborted" : "not aborted"); - - qlt_abort_cmd(cmd); + scst_cmd_get(scst_cmd); spin_lock_irqsave(qpair->qp_lock_ptr, flags); + + TRACE_MGMT_DBG( + "sqatgt(%ld/%d): tag %lld: HW pending for too long (state %s) %s; %s", + vha->host_no, vha->vp_idx, scst_cmd_get_tag(scst_cmd), + cmdstate_to_str((uint8_t)cmd->state), + cmd->cmd_sent_to_fw ? "sent to fw" : "not sent to fw", + cmd->aborted ? "aborted" : "not aborted"); + switch (cmd->state) { case QLA_TGT_STATE_NEW: case QLA_TGT_STATE_DATA_IN: - PRINT_ERROR("sqa(%ld): A command in state (%s) should not be HW pending. %s", - vha->host_no, cmdstate_to_str((uint8_t)cmd->state), - aborted ? "aborted" : "not aborted"); - break; + case QLA_TGT_STATE_DONE: + PRINT_ERROR( + "sqatgt(%ld/%d): tag %lld: A command in state (%s) should not be HW pending. %s", + vha->host_no, vha->vp_idx, scst_cmd_get_tag(scst_cmd), + cmdstate_to_str((uint8_t)cmd->state), + cmd->aborted ? "aborted" : "not aborted"); + goto out_unlock; case QLA_TGT_STATE_NEED_DATA: - /* the abort will nudge it out of FW */ - TRACE_MGMT_DBG("Force rx_data cmd %p", cmd); - sqa_cleanup_hw_pending_cmd(vha, cmd); - scst_set_cmd_error(scst_cmd, - SCST_LOAD_SENSE(scst_sense_internal_failure)); - scst_rx_data(scst_cmd, SCST_RX_STATUS_ERROR_SENSE_SET, - SCST_CONTEXT_THREAD); - break; case QLA_TGT_STATE_PROCESSED: - if (!cmd->cmd_sent_to_fw) - PRINT_ERROR("sqa(%ld): command should not be in HW pending. It's already processed. ", - vha->host_no); - else - TRACE_MGMT_DBG("Force finishing cmd %p", cmd); - sqa_cleanup_hw_pending_cmd(vha, cmd); - scst_set_delivery_status(scst_cmd, SCST_CMD_DELIVERY_FAILED); - scst_tgt_cmd_done(scst_cmd, SCST_CONTEXT_THREAD); break; } + + /* Handle race with normal CTIO completion. */ + if (!cmd->cmd_sent_to_fw) { + TRACE_MGMT_DBG( + "sqatgt(%ld/%d): tag %lld: cmd not sent to fw; assuming just completed", + vha->host_no, vha->vp_idx, + scst_cmd_get_tag(scst_cmd)); + goto out_unlock; + } + + /* The command should be aborted elsewhere if the ISP was reset. */ + if (!qpair->fw_started || cmd->reset_count != qpair->chip_reset) + goto out_unlock; + + /* Reset the ISP if there was a timeout after sending a term exchange. */ + if (cmd->sent_term_exchg && + time_is_before_jiffies(cmd->jiffies_at_term_exchg + + SQA_MAX_HW_PENDING_TIME * HZ / 2)) { + if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) { + if (IS_P3P_TYPE(vha->hw)) + set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); + else + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } + goto out_unlock; + } + + /* + * We still expect a CTIO response from the hw. Terminating the + * exchange should force the CTIO response to happen sooner. + */ + if (!cmd->sent_term_exchg) + qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1); + + /* + * Restart the timer so that this function is called again + * after another timeout. This is similar to + * scst_update_hw_pending_start() except that we also set + * cmd_hw_pending to 1. + * + * IRQs are already OFF. + */ + spin_lock(&scst_cmd->sess->sess_list_lock); + scst_cmd->cmd_hw_pending = 1; + scst_cmd->hw_pending_start = jiffies; + spin_unlock(&scst_cmd->sess->sess_list_lock); + +out_unlock: spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + scst_cmd_put(scst_cmd); + TRACE_EXIT(); } |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:35:58
|
Commit: c704a87 GitHub URL: https://github.com/SCST-project/scst/commit/c704a8727105acf17c7f641fe1157485b15e1034 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Fix races with aborting commands cmd->cmd_lock only protects cmd->aborted, but when deciding how to process a cmd, it is necessary to consider other factors such as cmd->state and if the chip has been reset, which are protected by qpair->qp_lock_ptr. So replace cmd_lock with qp_lock_ptr, whick makes it possible to check additional values and make decisions about what to do without racing with the CTIO handler and other code. - Lock cmd->qpair->qp_lock_ptr when aborting a cmd. - Eliminate cmd->cmd_lock and change cmd->aborted to a bitfield since it is now protected by qp_lock_ptr just like all the other flags. - Add another command state QLA_TGT_STATE_DONE to avoid any possible races between qlt_abort_cmd() and tgt_ops->free_cmd(). - Add the cmd->sent_term_exchg flag to indicate if qlt_send_term_exchange() has already been called. - Export qlt_send_term_exchange() for SCST so that it can be called directly instead of trying to make qlt_abort_cmd() work for both TMR abort and HW timeout. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/2c8...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit 17488f139074 upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_os.c | 1 + qla2x00t-32gbit/qla_target.c | 199 +++++++-------- qla2x00t-32gbit/qla_target.h | 17 +- 3 files changed, 99 insertions(+), 118 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index 4462e16..bc0a5f5 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -7371,6 +7371,7 @@ qla2xxx_wake_dpc(struct scsi_qla_host *vha) if (!test_bit(UNLOADING, &vha->dpc_flags) && t) wake_up_process(t); } +EXPORT_SYMBOL(qla2xxx_wake_dpc); /* * qla2x00_rst_aen diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 19a9838..a4af749 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -117,8 +117,6 @@ static void qlt_response_pkt(struct scsi_qla_host *ha, struct rsp_que *rsp, response_t *pkt); static int qlt_issue_task_mgmt(struct fc_port *sess, u64 lun, int fn, void *iocb, int flags); -static void qlt_send_term_exchange(struct qla_qpair *, struct qla_tgt_cmd - *cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort); static void qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, struct atio_from_isp *atio, uint16_t status, int qfull); static void qlt_disable_vha(struct scsi_qla_host *vha); @@ -151,22 +149,6 @@ EXPORT_SYMBOL(qla_tgt_mutex); LIST_HEAD(qla_tgt_glist); EXPORT_SYMBOL(qla_tgt_glist); -#if QLA_ENABLE_PI -static const char *prot_op_str(u32 prot_op) -{ - switch (prot_op) { - case TARGET_PROT_NORMAL: return "NORMAL"; - case TARGET_PROT_DIN_INSERT: return "DIN_INSERT"; - case TARGET_PROT_DOUT_INSERT: return "DOUT_INSERT"; - case TARGET_PROT_DIN_STRIP: return "DIN_STRIP"; - case TARGET_PROT_DOUT_STRIP: return "DOUT_STRIP"; - case TARGET_PROT_DIN_PASS: return "DIN_PASS"; - case TARGET_PROT_DOUT_PASS: return "DOUT_PASS"; - default: return "UNKNOWN"; - } -} -#endif - /* This API intentionally takes dest as a parameter, rather than returning * int value to avoid caller forgetting to issue wmb() after the store */ void qlt_do_generation_tick(struct scsi_qla_host *vha, int *dest) @@ -269,7 +251,7 @@ out: return; out_term: - qlt_send_term_exchange(vha->hw->base_qpair, NULL, atio, ha_locked, 0); + qlt_send_term_exchange(vha->hw->base_qpair, NULL, atio, ha_locked); goto out; } @@ -288,7 +270,7 @@ static void qlt_try_to_dequeue_unknown_atios(struct scsi_qla_host *vha, "Freeing unknown %s %p, because of Abort\n", "ATIO_TYPE7", u); qlt_send_term_exchange(vha->hw->base_qpair, NULL, - &u->atio, ha_locked, 0); + &u->atio, ha_locked); goto abort; } @@ -302,7 +284,7 @@ static void qlt_try_to_dequeue_unknown_atios(struct scsi_qla_host *vha, "Freeing unknown %s %p, because tgt is being stopped\n", "ATIO_TYPE7", u); qlt_send_term_exchange(vha->hw->base_qpair, NULL, - &u->atio, ha_locked, 0); + &u->atio, ha_locked); } else { ql_dbg(ql_dbg_async + ql_dbg_verbose, vha, 0x503d, "Reschedule u %p, vha %p, host %p\n", u, vha, host); @@ -3504,7 +3486,6 @@ qlt_handle_dif_error(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, uint8_t *ep = &sts->expected_dif[0]; uint64_t lba = cmd->se_cmd.t_task_lba; uint8_t scsi_status, sense_key, asc, ascq; - unsigned long flags; struct scsi_qla_host *vha = cmd->vha; cmd->trc_flags |= TRC_DIF_ERR; @@ -3578,13 +3559,10 @@ out: vha->hw->tgt.tgt_ops->handle_data(cmd); break; default: - spin_lock_irqsave(&cmd->cmd_lock, flags); - if (cmd->aborted) { - spin_unlock_irqrestore(&cmd->cmd_lock, flags); + if (cmd->sent_term_exchg) { vha->hw->tgt.tgt_ops->free_cmd(cmd); break; } - spin_unlock_irqrestore(&cmd->cmd_lock, flags); qlt_send_resp_ctio(qpair, cmd, scsi_status, sense_key, asc, ascq); @@ -3747,9 +3725,22 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair, return 0; } -static void qlt_send_term_exchange(struct qla_qpair *qpair, - struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked, - int ul_abort) +/* + * Aborting a command that is active in the FW (i.e. cmd->cmd_sent_to_fw == 1) + * will usually trigger the FW to send a completion CTIO with error status, + * and the driver will then call the ->handle_data() or ->free_cmd() callbacks. + * This can be used to clear a command that is locked up in the FW unless there + * is something more seriously wrong. + * + * Aborting a command that is not active in the FW (i.e. + * cmd->cmd_sent_to_fw == 0) will not directly trigger any callbacks. Instead, + * when the target mode midlevel calls qlt_rdy_to_xfer() or + * qlt_xmit_response(), the driver will see that the cmd has been aborted and + * call the appropriate callback immediately without performing the requested + * operation. + */ +void qlt_send_term_exchange(struct qla_qpair *qpair, + struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked) { struct scsi_qla_host *vha; unsigned long flags = 0; @@ -3773,10 +3764,14 @@ static void qlt_send_term_exchange(struct qla_qpair *qpair, qlt_alloc_qfull_cmd(vha, atio, 0, 0); done: - if (cmd && !ul_abort && !cmd->aborted) { - if (cmd->sg_mapped) - qlt_unmap_sg(vha, cmd); - vha->hw->tgt.tgt_ops->free_cmd(cmd); + if (cmd) { + /* + * Set this even if -ENOMEM above, since term exchange will be + * sent eventually... + */ + cmd->sent_term_exchg = 1; + cmd->aborted = 1; + cmd->jiffies_at_term_exchg = jiffies; } if (!ha_locked) @@ -3784,6 +3779,7 @@ done: return; } +EXPORT_SYMBOL(qlt_send_term_exchange); static void qlt_init_term_exchange(struct scsi_qla_host *vha) { @@ -3834,33 +3830,35 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha) int qlt_abort_cmd(struct qla_tgt_cmd *cmd) { - struct qla_tgt *tgt = cmd->tgt; - struct scsi_qla_host *vha = tgt->vha; - struct se_cmd *se_cmd = &cmd->se_cmd; + struct scsi_qla_host *vha = cmd->vha; + struct qla_qpair *qpair = cmd->qpair; unsigned long flags; - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, - "qla_target(%d): terminating exchange for aborted cmd=%p " - "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd, - se_cmd_tag(se_cmd)); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); - spin_lock_irqsave(&cmd->cmd_lock, flags); - if (cmd->aborted) { - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - /* - * It's normal to see 2 calls in this path: - * 1) XFER Rdy completion + CMD_T_ABORT - * 2) TCM TMR - drain_state_list - */ - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf016, "multiple abort. %p\n", - cmd); - return -EIO; + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, + "qla_target(%d): tag %lld: cmd being aborted (state %d) %s; %s\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->state, + cmd->cmd_sent_to_fw ? "sent to fw" : "not sent to fw", + cmd->aborted ? "aborted" : "not aborted"); + + if (cmd->state != QLA_TGT_STATE_DONE && !cmd->sent_term_exchg) { + if (!qpair->fw_started || + cmd->reset_count != qpair->chip_reset) { + /* + * Chip was reset; just pretend that we sent the term + * exchange. + */ + cmd->sent_term_exchg = 1; + cmd->aborted = 1; + cmd->jiffies_at_term_exchg = jiffies; + } else { + qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1); + } } - cmd->aborted = 1; - cmd->trc_flags |= TRC_ABORT; - spin_unlock_irqrestore(&cmd->cmd_lock, flags); - qlt_send_term_exchange(cmd->qpair, cmd, &cmd->atio, 0, 1); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + return 0; } EXPORT_SYMBOL(qlt_abort_cmd); @@ -3891,42 +3889,6 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) } EXPORT_SYMBOL(qlt_free_cmd); -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static int qlt_term_ctio_exchange(struct qla_qpair *qpair, void *ctio, - struct qla_tgt_cmd *cmd, uint32_t status) -{ - int term = 0; -#if QLA_ENABLE_PI - struct scsi_qla_host *vha = qpair->vha; - - if (cmd->se_cmd.prot_op) - ql_dbg(ql_dbg_tgt_dif, vha, 0xe013, - "Term DIF cmd: lba[0x%llx|%lld] len[0x%x] " - "se_cmd=%p tag[%x] op %#x/%s", - cmd->lba, cmd->lba, - cmd->num_blks, &cmd->se_cmd, - cmd->atio.u.isp24.exchange_addr, - cmd->se_cmd.prot_op, - prot_op_str(cmd->se_cmd.prot_op)); -#endif - - if (ctio != NULL) { - struct ctio7_from_24xx *c = (struct ctio7_from_24xx *)ctio; - - term = !(c->flags & - cpu_to_le16(OF_TERM_EXCH)); - } else - term = 1; - - if (term) - qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1, 0); - - return term; -} - - /* ha->hardware_lock supposed to be held on entry */ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, struct rsp_que *rsp, uint32_t handle, void *ctio) @@ -4032,22 +3994,35 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, qlt_unmap_sg(vha, cmd); if (unlikely(status != CTIO_SUCCESS)) { + bool term_exchg = false; + + /* + * If the hardware terminated the exchange, then we don't need + * to send an explicit term exchange message. + */ + if (ctio_flags & OF_TERM_EXCH) { + cmd->sent_term_exchg = 1; + cmd->aborted = 1; + cmd->jiffies_at_term_exchg = jiffies; + } + switch (status & 0xFFFF) { case CTIO_INVALID_RX_ID: + term_exchg = true; if (printk_ratelimit()) dev_info(&vha->hw->pdev->dev, "qla_target(%d): CTIO with INVALID_RX_ID ATIO attr %x CTIO Flags %x|%x\n", vha->vp_idx, cmd->atio.u.isp24.attr, ((cmd->ctio_flags >> 9) & 0xf), cmd->ctio_flags); - break; + case CTIO_LIP_RESET: case CTIO_TARGET_RESET: case CTIO_ABORTED: - /* driver request abort via Terminate exchange */ + term_exchg = true; + fallthrough; case CTIO_TIMEOUT: - /* They are OK */ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058, "qla_target(%d): CTIO with " "status %#x received, state %x, se_cmd %p, " @@ -4068,6 +4043,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, logged_out ? "PORT LOGGED OUT" : "PORT UNAVAILABLE", status, cmd->state, se_cmd); + term_exchg = true; if (logged_out && cmd->sess) { /* * Session is already logged out, but we need @@ -4113,19 +4089,21 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, break; } + cmd->trc_flags |= TRC_CTIO_ERR; - /* "cmd->aborted" means - * cmd is already aborted/terminated, we don't - * need to terminate again. The exchange is already - * cleaned up/freed at FW level. Just cleanup at driver - * level. + /* + * In state QLA_TGT_STATE_NEED_DATA the failed CTIO was for + * Data-Out, so either abort the exchange or try sending check + * condition with sense data depending on the severity of + * the error. In state QLA_TGT_STATE_PROCESSED the failed CTIO + * was for status (and possibly Data-In), so don't try sending + * an error status again in that case (if the error was for + * Data-In with status, we could try sending status without + * Data-In, but we don't do that currently). */ - if ((cmd->state != QLA_TGT_STATE_NEED_DATA) && - (!cmd->aborted)) { - cmd->trc_flags |= TRC_CTIO_ERR; - if (qlt_term_ctio_exchange(qpair, ctio, cmd, status)) - return; - } + if (!cmd->sent_term_exchg && + (term_exchg || cmd->state != QLA_TGT_STATE_NEED_DATA)) + qlt_send_term_exchange(qpair, cmd, &cmd->atio, 1); } if (cmd->state == QLA_TGT_STATE_PROCESSED) { @@ -4216,7 +4194,6 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) goto out_term; } - spin_lock_init(&cmd->cmd_lock); cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; se_cmd_tag(&cmd->se_cmd) = le32_to_cpu(atio->u.isp24.exchange_addr); @@ -4253,7 +4230,7 @@ out_term: */ cmd->trc_flags |= TRC_DO_WORK_ERR; spin_lock_irqsave(qpair->qp_lock_ptr, flags); - qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1, 0); + qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1); qlt_decr_num_pend_cmds(vha); cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd); @@ -5464,7 +5441,7 @@ static int __qlt_send_busy(struct qla_qpair *qpair, sess = qla2x00_find_fcport_by_nportid(vha, &id, 1); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); if (!sess) { - qlt_send_term_exchange(qpair, NULL, atio, 1, 0); + qlt_send_term_exchange(qpair, NULL, atio, 1); return 0; } /* Sending marker isn't necessary, since we called from ISR */ @@ -5693,7 +5670,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt, vha, 0xe05f, "qla_target: Unable to send command to target, sending TERM EXCHANGE for rsp\n"); qlt_send_term_exchange(ha->base_qpair, NULL, - atio, 1, 0); + atio, 1); break; case -EBUSY: ql_dbg(ql_dbg_tgt, vha, 0xe060, @@ -5900,7 +5877,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt, vha, 0xe05f, "qla_target: Unable to send command to target, sending TERM EXCHANGE for rsp\n"); qlt_send_term_exchange(rsp->qpair, NULL, - atio, 1, 0); + atio, 1); break; case -EBUSY: ql_dbg(ql_dbg_tgt, vha, 0xe060, @@ -6790,7 +6767,7 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked) adjust_corrupted_atio(pkt); qlt_send_term_exchange(ha->base_qpair, NULL, pkt, - ha_locked, 0); + ha_locked); } else { qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt, ha_locked); diff --git a/qla2x00t-32gbit/qla_target.h b/qla2x00t-32gbit/qla_target.h index ed69cb7..c00488b 100644 --- a/qla2x00t-32gbit/qla_target.h +++ b/qla2x00t-32gbit/qla_target.h @@ -783,6 +783,7 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *); #define QLA_TGT_STATE_NEED_DATA 1 /* target needs data to continue */ #define QLA_TGT_STATE_DATA_IN 2 /* Data arrived + target processing */ #define QLA_TGT_STATE_PROCESSED 3 /* target done processing */ +#define QLA_TGT_STATE_DONE 4 /* cmd being freed */ /* ATIO task_codes field */ #define ATIO_SIMPLE_QUEUE 0 @@ -916,8 +917,6 @@ struct qla_tgt_cmd { /* Sense buffer that will be mapped into outgoing status */ unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; - spinlock_t cmd_lock; - /* to save extra sess dereferences */ unsigned int conf_compl_supported:1; unsigned int sg_mapped:1; unsigned int write_data_transferred:1; @@ -927,13 +926,14 @@ struct qla_tgt_cmd { unsigned int cmd_in_wq:1; unsigned int edif:1; + /* Set if the exchange has been terminated. */ + unsigned int sent_term_exchg:1; + /* - * This variable may be set from outside the LIO and I/O completion - * callback functions. Do not declare this member variable as a - * bitfield to avoid a read-modify-write operation when this variable - * is set. + * Set if sent_term_exchg is set, or if the cmd was aborted by a TMR, + * or if some other error prevents normal processing of the command. */ - unsigned int aborted; + unsigned int aborted:1; struct scatterlist *sg; /* cmd data buffer SG vector */ int sg_cnt; /* SG segments count */ @@ -972,6 +972,7 @@ struct qla_tgt_cmd { #define DIF_BUNDL_DMA_VALID 1 uint16_t prot_flags; + unsigned long jiffies_at_term_exchg; uint64_t jiffies_at_alloc; uint64_t jiffies_at_free; @@ -1098,6 +1099,8 @@ extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, struct rsp_que *, extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *); extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t); extern int qlt_abort_cmd(struct qla_tgt_cmd *); +void qlt_send_term_exchange(struct qla_qpair *qpair, + struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked); extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *); extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *); extern void qlt_free_cmd(struct qla_tgt_cmd *cmd); |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:35:51
|
Commit: 2c8529b GitHub URL: https://github.com/SCST-project/scst/commit/2c8529b5ba2ced8dc60069fd3a2f32c4ca780653 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: Clear cmds after chip reset Commit aefed3e5548f ("scsi: qla2xxx: target: Fix offline port handling and host reset handling") caused two problems: 1. Commands sent to FW, after chip reset got stuck and never freed as FW is not going to respond to them anymore. 2. BUG_ON(cmd->sg_mapped) in qlt_free_cmd(). Commit 26f9ce53817a ("scsi: qla2xxx: Fix missed DMA unmap for aborted commands") attempted to fix this, but introduced another bug under different circumstances when two different CPUs were racing to call qlt_unmap_sg() at the same time: BUG_ON(!valid_dma_direction(dir)) in dma_unmap_sg_attrs(). So revert "scsi: qla2xxx: Fix missed DMA unmap for aborted commands" and partially revert "scsi: qla2xxx: target: Fix offline port handling and host reset handling" at __qla2x00_abort_all_cmds. Fixes: aefed3e5548f ("scsi: qla2xxx: target: Fix offline port handling and host reset handling") Fixes: 26f9ce53817a ("scsi: qla2xxx: Fix missed DMA unmap for aborted commands") Co-developed-by: Dmitry Bogdanov <d.b...@ya...> Signed-off-by: Dmitry Bogdanov <d.b...@ya...> Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/0e7...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit d46c69a087aa upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_os.c | 20 +++++++++++++-- qla2x00t-32gbit/qla_target.c | 5 +--- qla2x00t-32gbit/qla_target.h | 1 + 3 files changed, 20 insertions(+), 6 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index c58259b..4462e16 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -1925,10 +1925,26 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) continue; } cmd = (struct qla_tgt_cmd *)sp; - cmd->aborted = 1; + + if (cmd->sg_mapped) + qlt_unmap_sg(vha, cmd); + + if (cmd->state == QLA_TGT_STATE_NEED_DATA) { + cmd->aborted = 1; + cmd->write_data_transferred = 0; + cmd->state = QLA_TGT_STATE_DATA_IN; + ha->tgt.tgt_ops->handle_data(cmd); + } else { + ha->tgt.tgt_ops->free_cmd(cmd); + } break; case TYPE_TGT_TMCMD: - /* Skip task management functions. */ + /* + * Currently, only ABTS response gets on the + * outstanding_cmds[] + */ + ha->tgt.tgt_ops->free_mcmd( + (struct qla_tgt_mgmt_cmd *) sp); break; default: break; diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 70abdbf..19a9838 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -2479,7 +2479,7 @@ out_err: return -1; } -static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) +void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) { struct qla_hw_data *ha; struct qla_qpair *qpair; @@ -3846,9 +3846,6 @@ int qlt_abort_cmd(struct qla_tgt_cmd *cmd) spin_lock_irqsave(&cmd->cmd_lock, flags); if (cmd->aborted) { - if (cmd->sg_mapped) - qlt_unmap_sg(vha, cmd); - spin_unlock_irqrestore(&cmd->cmd_lock, flags); /* * It's normal to see 2 calls in this path: diff --git a/qla2x00t-32gbit/qla_target.h b/qla2x00t-32gbit/qla_target.h index af0f4a4..ed69cb7 100644 --- a/qla2x00t-32gbit/qla_target.h +++ b/qla2x00t-32gbit/qla_target.h @@ -1101,6 +1101,7 @@ extern int qlt_abort_cmd(struct qla_tgt_cmd *); extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *); extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *); extern void qlt_free_cmd(struct qla_tgt_cmd *cmd); +extern void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd); extern void qlt_async_event(uint16_t, struct scsi_qla_host *, uint16_t *); extern void qlt_enable_vha(struct scsi_qla_host *); extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *); |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:35:43
|
Commit: 6151818 GitHub URL: https://github.com/SCST-project/scst/commit/61518181f524ac0f5ef52741acd9a371a0b7199b Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Fix term exchange when cmd_sent_to_fw == 1 Properly set the nport_handle field of the terminate exchange message. Previously when this field was not set properly, the term exchange would fail when cmd_sent_to_fw == 1 but work when cmd_sent_to_fw == 0 (i.e. it would fail when the HW was actively transferring data or status for the cmd but work when the HW was idle). With this change, term exchange works in any cmd state, which now makes it possible to abort a command that is locked up in the HW. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/1a2...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit ed382b95f5de upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_target.c | 52 +++++++++------ 1 file changed, 31 insertions(+), 21 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 2572338..70abdbf 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -3673,14 +3673,35 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, struct atio_from_isp *atio) { - struct scsi_qla_host *vha = qpair->vha; struct ctio7_to_24xx *ctio24; - request_t *pkt; - int ret = 0; + struct scsi_qla_host *vha; + uint16_t loop_id; uint16_t temp; - if (cmd) + if (cmd) { vha = cmd->vha; + loop_id = cmd->loop_id; + } else { + port_id_t id = be_to_port_id(atio->u.isp24.fcp_hdr.s_id); + struct qla_hw_data *ha; + struct fc_port *sess; + unsigned long flags; + + vha = qpair->vha; + ha = vha->hw; + + /* + * CTIO7_NHANDLE_UNRECOGNIZED works when aborting an idle + * command but not when aborting a command with an active CTIO + * exchange. + */ + loop_id = CTIO7_NHANDLE_UNRECOGNIZED; + spin_lock_irqsave(&ha->tgt.sess_lock, flags); + sess = qla2x00_find_fcport_by_nportid(vha, &id, 1); + if (sess) + loop_id = sess->loop_id; + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + } if (cmd) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xe009, @@ -3693,31 +3714,20 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair, vha->vp_idx, le32_to_cpu(atio->u.isp24.exchange_addr)); } - pkt = (request_t *)qla2x00_alloc_iocbs_ready(qpair, NULL); - if (pkt == NULL) { + ctio24 = qla2x00_alloc_iocbs_ready(qpair, NULL); + if (!ctio24) { ql_dbg(ql_dbg_tgt, vha, 0xe050, "qla_target(%d): %s failed: unable to allocate " "request packet\n", vha->vp_idx, __func__); return -ENOMEM; } - if (cmd != NULL) { - if (cmd->state < QLA_TGT_STATE_PROCESSED) { - ql_dbg(ql_dbg_tgt, vha, 0xe051, - "qla_target(%d): Terminating cmd %p with " - "incorrect state %d\n", vha->vp_idx, cmd, - cmd->state); - } else - ret = 1; - } - qpair->tgt_counters.num_term_xchg_sent++; - pkt->entry_count = 1; - pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; - ctio24 = (struct ctio7_to_24xx *)pkt; ctio24->entry_type = CTIO_TYPE7; - ctio24->nport_handle = cpu_to_le16(CTIO7_NHANDLE_UNRECOGNIZED); + ctio24->entry_count = 1; + ctio24->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; + ctio24->nport_handle = cpu_to_le16(loop_id); ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio24->vp_index = vha->vp_idx; ctio24->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); @@ -3734,7 +3744,7 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair, qpair->reqq_start_iocbs(qpair); else qla2x00_start_iocbs(vha, qpair->req); - return ret; + return 0; } static void qlt_send_term_exchange(struct qla_qpair *qpair, |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:35:22
|
Commit: c89a047 GitHub URL: https://github.com/SCST-project/scst/commit/c89a047a59a1753d6709adfae875ad66ade93bb5 Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Improve debug output for term exchange Print better debug info when terminating a command, and print the response status from the hardware. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/22f...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit c34e373f535e upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_dbg.c | 2 +- qla2x00t-32gbit/qla_target.c | 40 +++++++++++++-- 2 files changed, 36 insertions(+), 6 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_dbg.c b/qla2x00t-32gbit/qla_dbg.c index fb3a8ba..bca217a 100644 --- a/qla2x00t-32gbit/qla_dbg.c +++ b/qla2x00t-32gbit/qla_dbg.c @@ -54,7 +54,7 @@ * | Misc | 0xd303 | 0xd031-0xd0ff | * | | | 0xd101-0xd1fe | * | | | 0xd214-0xd2fe | - * | Target Mode | 0xe081 | | + * | Target Mode | 0xe084 | | * | Target Mode Management | 0xf09b | 0xf002 | * | | | 0xf046-0xf049 | * | Target Mode Task Management | 0x1000d | | diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index c9aa6c6..2572338 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -1926,6 +1926,10 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, * ABTS response. So, in it ID fields are reversed. */ + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe082, + "qla_target(%d): tag %u: Sending TERM EXCH CTIO for ABTS\n", + vha->vp_idx, le32_to_cpu(entry->exchange_addr_to_abort)); + ctio->entry_type = CTIO_TYPE7; ctio->entry_count = 1; ctio->nport_handle = entry->nport_handle; @@ -3671,16 +3675,24 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair, { struct scsi_qla_host *vha = qpair->vha; struct ctio7_to_24xx *ctio24; - struct qla_hw_data *ha = vha->hw; request_t *pkt; int ret = 0; uint16_t temp; - ql_dbg(ql_dbg_tgt, vha, 0xe009, "Sending TERM EXCH CTIO (ha=%p)\n", ha); - if (cmd) vha = cmd->vha; + if (cmd) { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe009, + "qla_target(%d): tag %lld: Sending TERM EXCH CTIO state %d cmd_sent_to_fw %u\n", + vha->vp_idx, cmd->se_cmd.tag, cmd->state, + cmd->cmd_sent_to_fw); + } else { + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe009, + "qla_target(%d): tag %u: Sending TERM EXCH CTIO (no cmd)\n", + vha->vp_idx, le32_to_cpu(atio->u.isp24.exchange_addr)); + } + pkt = (request_t *)qla2x00_alloc_iocbs_ready(qpair, NULL); if (pkt == NULL) { ql_dbg(ql_dbg_tgt, vha, 0xe050, @@ -3971,6 +3983,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, struct se_cmd *se_cmd; struct qla_tgt_cmd *cmd; struct qla_qpair *qpair = rsp->qpair; + uint16_t ctio_flags; if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) { /* That could happen only in case of an error/reset/abort */ @@ -3982,11 +3995,28 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, return; } + ctio_flags = le16_to_cpu(ctio->flags); + cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio); - if (cmd == NULL) + if (unlikely(cmd == NULL)) { + if ((handle & ~QLA_TGT_HANDLE_MASK) == QLA_TGT_SKIP_HANDLE && + (ctio_flags & 0xe1ff) == (CTIO7_FLAGS_STATUS_MODE_1 | + CTIO7_FLAGS_TERMINATE)) { + u32 tag = le32_to_cpu(ctio->exchange_address); + + if (status == CTIO_SUCCESS) + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe083, + "qla_target(%d): tag %u: term exchange successful\n", + vha->vp_idx, tag); + else + ql_dbg(ql_dbg_tgt_mgt, vha, 0xe084, + "qla_target(%d): tag %u: term exchange failed; status = 0x%x\n", + vha->vp_idx, tag, status); + } return; + } - if ((le16_to_cpu(ctio->flags) & CTIO7_FLAGS_DATA_OUT) && cmd->sess) + if ((ctio_flags & CTIO7_FLAGS_DATA_OUT) && cmd->sess) qlt_chk_edif_rx_sa_delete_pending(vha, cmd->sess, ctio); se_cmd = &cmd->se_cmd; |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:34:48
|
Commit: 635ea86 GitHub URL: https://github.com/SCST-project/scst/commit/635ea86df33082300524291747310e6dd0645f5b Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: target: Remove code for unsupported hardware As far as I can tell, CONTINUE_TGT_IO_TYPE and CTIO_A64_TYPE are message types from non-FWI2 boards (older than ISP24xx), which are not supported by qla_target.c. Removing them makes it possible to turn a void * into the real type and avoid some typecasts. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/cb0...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit 9da4e1dcea46 upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_target.c | 32 +++------------ 1 file changed, 5 insertions(+), 27 deletions(-) =================================================================== diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index f8d641d..c9aa6c6 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -3964,7 +3964,8 @@ static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, - struct rsp_que *rsp, uint32_t handle, uint32_t status, void *ctio) + struct rsp_que *rsp, uint32_t handle, uint32_t status, + struct ctio7_from_24xx *ctio) { struct qla_hw_data *ha = vha->hw; struct se_cmd *se_cmd; @@ -3985,11 +3986,8 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, if (cmd == NULL) return; - if ((le16_to_cpu(((struct ctio7_from_24xx *)ctio)->flags) & CTIO7_FLAGS_DATA_OUT) && - cmd->sess) { - qlt_chk_edif_rx_sa_delete_pending(vha, cmd->sess, - (struct ctio7_from_24xx *)ctio); - } + if ((le16_to_cpu(ctio->flags) & CTIO7_FLAGS_DATA_OUT) && cmd->sess) + qlt_chk_edif_rx_sa_delete_pending(vha, cmd->sess, ctio); se_cmd = &cmd->se_cmd; cmd->cmd_sent_to_fw = 0; @@ -4058,7 +4056,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, *((u64 *)&crc->actual_dif[0]), *((u64 *)&crc->expected_dif[0])); - qlt_handle_dif_error(qpair, cmd, ctio); + qlt_handle_dif_error(qpair, cmd, crc); return; } @@ -5886,26 +5884,6 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, } break; - case CONTINUE_TGT_IO_TYPE: - { - struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; - - qlt_do_ctio_completion(vha, rsp, entry->handle, - le16_to_cpu(entry->status)|(pkt->entry_status << 16), - entry); - break; - } - - case CTIO_A64_TYPE: - { - struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; - - qlt_do_ctio_completion(vha, rsp, entry->handle, - le16_to_cpu(entry->status)|(pkt->entry_status << 16), - entry); - break; - } - case IMMED_NOTIFY_TYPE: ql_dbg(ql_dbg_tgt, vha, 0xe035, "%s", "IMMED_NOTIFY\n"); qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)pkt); |
|
From: Gleb C. <lna...@ya...> - 2025-12-09 19:34:37
|
Commit: 6ea8d5e GitHub URL: https://github.com/SCST-project/scst/commit/6ea8d5e6ae1fe5d08d7e4f3d9c74447c956bd57e Author: Tony Battersby Date: 2025-12-09T22:33:47+03:00 Log Message: ----------- qla2x00t-32gbit: Use reinit_completion on mbx_intr_comp If a mailbox command completes immediately after wait_for_completion_timeout() times out, ha->mbx_intr_comp could be left in an inconsistent state, causing the next mailbox command not to wait for the hardware. Fix by reinitializing the completion before use. Signed-off-by: Tony Battersby <to...@cy...> Link: https://patch.msgid.link/11b...@cy... Signed-off-by: Martin K. Petersen <mar...@or...> [ commit 957aa5974989 upstream ] Modified Paths: -------------- qla2x00t-32gbit/qla_mbx.c | 2 ++ 1 file changed, 2 insertions(+) =================================================================== diff --git a/qla2x00t-32gbit/qla_mbx.c b/qla2x00t-32gbit/qla_mbx.c index 32eb0ce..1f01576 100644 --- a/qla2x00t-32gbit/qla_mbx.c +++ b/qla2x00t-32gbit/qla_mbx.c @@ -253,6 +253,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) /* Issue set host interrupt command to send cmd out. */ ha->flags.mbox_int = 0; clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + reinit_completion(&ha->mbx_intr_comp); /* Unlock mbx registers and wait for interrupt */ ql_dbg(ql_dbg_mbx, vha, 0x100f, @@ -279,6 +280,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) "cmd=%x Timeout.\n", command); spin_lock_irqsave(&ha->hardware_lock, flags); clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); + reinit_completion(&ha->mbx_intr_comp); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (chip_reset != ha->chip_reset) { |