diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-07-29 12:54:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-07-29 12:54:40 -0400 |
commit | 733db573a6451681b60e7372d2862de09d6eb04e (patch) | |
tree | e7b6b17e6b44070d8bc39896cf78c81650fc3273 | |
parent | 956325bd55bb020e574129c443a2c2c66a8316e7 (diff) | |
parent | c4cfdd81c8fde84e2c75bc90533c7e1276937d3a (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target fixes from Nicholas Bellinger:
"This series is larger than what I'd normally be conformable with
sending for a -rc5 PULL request..
However, the bulk of the series is localized to qla2xxx target
specific fixes that address a number of real-world correctness issues,
that have been outstanding on the list for ~6 weeks now. They where
submitted + verified + acked by the HW LLD vendor, contributed by a
major production customer of the code, and are marked for v3.18.y
stable code.
That said, I don't see a good reason to wait another month to get
these fixes into mainline.
Beyond the qla2xx specific fixes, this series also includes:
- bugfix for a long standing use-after-free in iscsi-target during
TPG shutdown + demo-mode sessions.
- bugfix for a >= v4.0 regression OOPs in iscsi-target during a
iscsi_start_kthreads() failure.
- bugfix for a >= v4.0 regression hang in iscsi-target for iser
explicit session/connection logout.
- bugfix for a iser-target bug where a early CMA REJECTED status
during login triggers a NULL pointer dereference OOPs.
- bugfixes for a handful of v4.2-rc1 specific regressions related to
the larger set of recent backend configfs attribute changes.
A big thanks to QLogic + Pure Storage for the qla2xxx target bugfixes"
* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (28 commits)
Documentation/target: Fix tcm_mod_builder.py build breakage
iser-target: Fix REJECT CM event use-after-free OOPs
iscsi-target: Fix iser explicit logout TX kthread leak
iscsi-target: Fix iscsit_start_kthreads failure OOPs
iscsi-target: Fix use-after-free during TPG session shutdown
qla2xxx: terminate exchange when command is aborted by LIO
qla2xxx: drop cmds/tmrs arrived while session is being deleted
qla2xxx: disable scsi_transport_fc registration in target mode
qla2xxx: added sess generations to detect RSCN update races
qla2xxx: Abort stale cmds on qla_tgt_wq when plogi arrives
qla2xxx: delay plogi/prli ack until existing sessions are deleted
qla2xxx: cleanup cmd in qla workqueue before processing TMR
qla2xxx: kill sessions/log out initiator on RSCN and port down events
qla2xxx: fix command initialization in target mode.
qla2xxx: Remove msleep in qlt_send_term_exchange
qla2xxx: adjust debug flags
qla2xxx: release request queue reservation.
qla2xxx: Add flush after updating ATIOQ consumer index.
qla2xxx: Enable target mode for ISP27XX
qla2xxx: Fix hardware lock/unlock issue causing kernel panic.
...
22 files changed, 1105 insertions, 220 deletions
diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 949de191fcdc..cda56df9b8a7 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py | |||
@@ -199,7 +199,8 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): | |||
199 | buf += "#include <linux/string.h>\n" | 199 | buf += "#include <linux/string.h>\n" |
200 | buf += "#include <linux/configfs.h>\n" | 200 | buf += "#include <linux/configfs.h>\n" |
201 | buf += "#include <linux/ctype.h>\n" | 201 | buf += "#include <linux/ctype.h>\n" |
202 | buf += "#include <asm/unaligned.h>\n\n" | 202 | buf += "#include <asm/unaligned.h>\n" |
203 | buf += "#include <scsi/scsi_proto.h>\n\n" | ||
203 | buf += "#include <target/target_core_base.h>\n" | 204 | buf += "#include <target/target_core_base.h>\n" |
204 | buf += "#include <target/target_core_fabric.h>\n" | 205 | buf += "#include <target/target_core_fabric.h>\n" |
205 | buf += "#include <target/target_core_fabric_configfs.h>\n" | 206 | buf += "#include <target/target_core_fabric_configfs.h>\n" |
@@ -230,8 +231,14 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): | |||
230 | buf += " }\n" | 231 | buf += " }\n" |
231 | buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n" | 232 | buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n" |
232 | buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n" | 233 | buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n" |
233 | buf += " ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n" | 234 | |
234 | buf += " &tpg->se_tpg, SCSI_PROTOCOL_SAS);\n" | 235 | if proto_ident == "FC": |
236 | buf += " ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP);\n" | ||
237 | elif proto_ident == "SAS": | ||
238 | buf += " ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_SAS);\n" | ||
239 | elif proto_ident == "iSCSI": | ||
240 | buf += " ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_ISCSI);\n" | ||
241 | |||
235 | buf += " if (ret < 0) {\n" | 242 | buf += " if (ret < 0) {\n" |
236 | buf += " kfree(tpg);\n" | 243 | buf += " kfree(tpg);\n" |
237 | buf += " return NULL;\n" | 244 | buf += " return NULL;\n" |
@@ -292,7 +299,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): | |||
292 | 299 | ||
293 | buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n" | 300 | buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n" |
294 | buf += " .module = THIS_MODULE,\n" | 301 | buf += " .module = THIS_MODULE,\n" |
295 | buf += " .name = " + fabric_mod_name + ",\n" | 302 | buf += " .name = \"" + fabric_mod_name + "\",\n" |
296 | buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n" | 303 | buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n" |
297 | buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" | 304 | buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" |
298 | buf += " .tpg_get_tag = " + fabric_mod_name + "_get_tag,\n" | 305 | buf += " .tpg_get_tag = " + fabric_mod_name + "_get_tag,\n" |
@@ -322,17 +329,17 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): | |||
322 | buf += " .fabric_make_tpg = " + fabric_mod_name + "_make_tpg,\n" | 329 | buf += " .fabric_make_tpg = " + fabric_mod_name + "_make_tpg,\n" |
323 | buf += " .fabric_drop_tpg = " + fabric_mod_name + "_drop_tpg,\n" | 330 | buf += " .fabric_drop_tpg = " + fabric_mod_name + "_drop_tpg,\n" |
324 | buf += "\n" | 331 | buf += "\n" |
325 | buf += " .tfc_wwn_attrs = " + fabric_mod_name + "_wwn_attrs;\n" | 332 | buf += " .tfc_wwn_attrs = " + fabric_mod_name + "_wwn_attrs,\n" |
326 | buf += "};\n\n" | 333 | buf += "};\n\n" |
327 | 334 | ||
328 | buf += "static int __init " + fabric_mod_name + "_init(void)\n" | 335 | buf += "static int __init " + fabric_mod_name + "_init(void)\n" |
329 | buf += "{\n" | 336 | buf += "{\n" |
330 | buf += " return target_register_template(" + fabric_mod_name + "_ops);\n" | 337 | buf += " return target_register_template(&" + fabric_mod_name + "_ops);\n" |
331 | buf += "};\n\n" | 338 | buf += "};\n\n" |
332 | 339 | ||
333 | buf += "static void __exit " + fabric_mod_name + "_exit(void)\n" | 340 | buf += "static void __exit " + fabric_mod_name + "_exit(void)\n" |
334 | buf += "{\n" | 341 | buf += "{\n" |
335 | buf += " target_unregister_template(" + fabric_mod_name + "_ops);\n" | 342 | buf += " target_unregister_template(&" + fabric_mod_name + "_ops);\n" |
336 | buf += "};\n\n" | 343 | buf += "};\n\n" |
337 | 344 | ||
338 | buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n" | 345 | buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n" |
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 771700963127..d851e1828d6f 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c | |||
@@ -775,6 +775,17 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) | |||
775 | ret = isert_rdma_post_recvl(isert_conn); | 775 | ret = isert_rdma_post_recvl(isert_conn); |
776 | if (ret) | 776 | if (ret) |
777 | goto out_conn_dev; | 777 | goto out_conn_dev; |
778 | /* | ||
779 | * Obtain the second reference now before isert_rdma_accept() to | ||
780 | * ensure that any initiator generated REJECT CM event that occurs | ||
781 | * asynchronously won't drop the last reference until the error path | ||
782 | * in iscsi_target_login_sess_out() does it's ->iscsit_free_conn() -> | ||
783 | * isert_free_conn() -> isert_put_conn() -> kref_put(). | ||
784 | */ | ||
785 | if (!kref_get_unless_zero(&isert_conn->kref)) { | ||
786 | isert_warn("conn %p connect_release is running\n", isert_conn); | ||
787 | goto out_conn_dev; | ||
788 | } | ||
778 | 789 | ||
779 | ret = isert_rdma_accept(isert_conn); | 790 | ret = isert_rdma_accept(isert_conn); |
780 | if (ret) | 791 | if (ret) |
@@ -836,11 +847,6 @@ isert_connected_handler(struct rdma_cm_id *cma_id) | |||
836 | 847 | ||
837 | isert_info("conn %p\n", isert_conn); | 848 | isert_info("conn %p\n", isert_conn); |
838 | 849 | ||
839 | if (!kref_get_unless_zero(&isert_conn->kref)) { | ||
840 | isert_warn("conn %p connect_release is running\n", isert_conn); | ||
841 | return; | ||
842 | } | ||
843 | |||
844 | mutex_lock(&isert_conn->mutex); | 850 | mutex_lock(&isert_conn->mutex); |
845 | if (isert_conn->state != ISER_CONN_FULL_FEATURE) | 851 | if (isert_conn->state != ISER_CONN_FULL_FEATURE) |
846 | isert_conn->state = ISER_CONN_UP; | 852 | isert_conn->state = ISER_CONN_UP; |
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 82b92c414a9c..437254e1c4de 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -738,7 +738,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, | |||
738 | ql_log(ql_log_info, vha, 0x706f, | 738 | ql_log(ql_log_info, vha, 0x706f, |
739 | "Issuing MPI reset.\n"); | 739 | "Issuing MPI reset.\n"); |
740 | 740 | ||
741 | if (IS_QLA83XX(ha)) { | 741 | if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { |
742 | uint32_t idc_control; | 742 | uint32_t idc_control; |
743 | 743 | ||
744 | qla83xx_idc_lock(vha, 0); | 744 | qla83xx_idc_lock(vha, 0); |
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 0e6ee3ca30e6..8b011aef12bd 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c | |||
@@ -67,10 +67,10 @@ | |||
67 | * | | | 0xd031-0xd0ff | | 67 | * | | | 0xd031-0xd0ff | |
68 | * | | | 0xd101-0xd1fe | | 68 | * | | | 0xd101-0xd1fe | |
69 | * | | | 0xd214-0xd2fe | | 69 | * | | | 0xd214-0xd2fe | |
70 | * | Target Mode | 0xe079 | | | 70 | * | Target Mode | 0xe080 | | |
71 | * | Target Mode Management | 0xf072 | 0xf002 | | 71 | * | Target Mode Management | 0xf096 | 0xf002 | |
72 | * | | | 0xf046-0xf049 | | 72 | * | | | 0xf046-0xf049 | |
73 | * | Target Mode Task Management | 0x1000b | | | 73 | * | Target Mode Task Management | 0x1000d | | |
74 | * ---------------------------------------------------------------------- | 74 | * ---------------------------------------------------------------------- |
75 | */ | 75 | */ |
76 | 76 | ||
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index e86201d3b8c6..9ad819edcd67 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -274,6 +274,7 @@ | |||
274 | #define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/ | 274 | #define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/ |
275 | 275 | ||
276 | struct req_que; | 276 | struct req_que; |
277 | struct qla_tgt_sess; | ||
277 | 278 | ||
278 | /* | 279 | /* |
279 | * (sd.h is not exported, hence local inclusion) | 280 | * (sd.h is not exported, hence local inclusion) |
@@ -2026,6 +2027,7 @@ typedef struct fc_port { | |||
2026 | uint16_t port_id; | 2027 | uint16_t port_id; |
2027 | 2028 | ||
2028 | unsigned long retry_delay_timestamp; | 2029 | unsigned long retry_delay_timestamp; |
2030 | struct qla_tgt_sess *tgt_session; | ||
2029 | } fc_port_t; | 2031 | } fc_port_t; |
2030 | 2032 | ||
2031 | #include "qla_mr.h" | 2033 | #include "qla_mr.h" |
@@ -3154,13 +3156,13 @@ struct qla_hw_data { | |||
3154 | /* Bit 21 of fw_attributes decides the MCTP capabilities */ | 3156 | /* Bit 21 of fw_attributes decides the MCTP capabilities */ |
3155 | #define IS_MCTP_CAPABLE(ha) (IS_QLA2031(ha) && \ | 3157 | #define IS_MCTP_CAPABLE(ha) (IS_QLA2031(ha) && \ |
3156 | ((ha)->fw_attributes_ext[0] & BIT_0)) | 3158 | ((ha)->fw_attributes_ext[0] & BIT_0)) |
3157 | #define IS_PI_UNINIT_CAPABLE(ha) (IS_QLA83XX(ha)) | 3159 | #define IS_PI_UNINIT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) |
3158 | #define IS_PI_IPGUARD_CAPABLE(ha) (IS_QLA83XX(ha)) | 3160 | #define IS_PI_IPGUARD_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) |
3159 | #define IS_PI_DIFB_DIX0_CAPABLE(ha) (0) | 3161 | #define IS_PI_DIFB_DIX0_CAPABLE(ha) (0) |
3160 | #define IS_PI_SPLIT_DET_CAPABLE_HBA(ha) (IS_QLA83XX(ha)) | 3162 | #define IS_PI_SPLIT_DET_CAPABLE_HBA(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) |
3161 | #define IS_PI_SPLIT_DET_CAPABLE(ha) (IS_PI_SPLIT_DET_CAPABLE_HBA(ha) && \ | 3163 | #define IS_PI_SPLIT_DET_CAPABLE(ha) (IS_PI_SPLIT_DET_CAPABLE_HBA(ha) && \ |
3162 | (((ha)->fw_attributes_h << 16 | (ha)->fw_attributes) & BIT_22)) | 3164 | (((ha)->fw_attributes_h << 16 | (ha)->fw_attributes) & BIT_22)) |
3163 | #define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha)) | 3165 | #define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) |
3164 | #define IS_TGT_MODE_CAPABLE(ha) (ha->tgt.atio_q_length) | 3166 | #define IS_TGT_MODE_CAPABLE(ha) (ha->tgt.atio_q_length) |
3165 | #define IS_SHADOW_REG_CAPABLE(ha) (IS_QLA27XX(ha)) | 3167 | #define IS_SHADOW_REG_CAPABLE(ha) (IS_QLA27XX(ha)) |
3166 | #define IS_DPORT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) | 3168 | #define IS_DPORT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) |
@@ -3579,6 +3581,16 @@ typedef struct scsi_qla_host { | |||
3579 | uint16_t fcoe_fcf_idx; | 3581 | uint16_t fcoe_fcf_idx; |
3580 | uint8_t fcoe_vn_port_mac[6]; | 3582 | uint8_t fcoe_vn_port_mac[6]; |
3581 | 3583 | ||
3584 | /* list of commands waiting on workqueue */ | ||
3585 | struct list_head qla_cmd_list; | ||
3586 | struct list_head qla_sess_op_cmd_list; | ||
3587 | spinlock_t cmd_list_lock; | ||
3588 | |||
3589 | /* Counter to detect races between ELS and RSCN events */ | ||
3590 | atomic_t generation_tick; | ||
3591 | /* Time when global fcport update has been scheduled */ | ||
3592 | int total_fcport_update_gen; | ||
3593 | |||
3582 | uint32_t vp_abort_cnt; | 3594 | uint32_t vp_abort_cnt; |
3583 | 3595 | ||
3584 | struct fc_vport *fc_vport; /* holds fc_vport * for each vport */ | 3596 | struct fc_vport *fc_vport; /* holds fc_vport * for each vport */ |
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 664013115c9d..11f2f3279eab 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
@@ -115,6 +115,8 @@ qla2x00_async_iocb_timeout(void *data) | |||
115 | QLA_LOGIO_LOGIN_RETRIED : 0; | 115 | QLA_LOGIO_LOGIN_RETRIED : 0; |
116 | qla2x00_post_async_login_done_work(fcport->vha, fcport, | 116 | qla2x00_post_async_login_done_work(fcport->vha, fcport, |
117 | lio->u.logio.data); | 117 | lio->u.logio.data); |
118 | } else if (sp->type == SRB_LOGOUT_CMD) { | ||
119 | qlt_logo_completion_handler(fcport, QLA_FUNCTION_TIMEOUT); | ||
118 | } | 120 | } |
119 | } | 121 | } |
120 | 122 | ||
@@ -497,7 +499,10 @@ void | |||
497 | qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, | 499 | qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, |
498 | uint16_t *data) | 500 | uint16_t *data) |
499 | { | 501 | { |
500 | qla2x00_mark_device_lost(vha, fcport, 1, 0); | 502 | /* Don't re-login in target mode */ |
503 | if (!fcport->tgt_session) | ||
504 | qla2x00_mark_device_lost(vha, fcport, 1, 0); | ||
505 | qlt_logo_completion_handler(fcport, data[0]); | ||
501 | return; | 506 | return; |
502 | } | 507 | } |
503 | 508 | ||
@@ -1538,7 +1543,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) | |||
1538 | mem_size = (ha->fw_memory_size - 0x11000 + 1) * | 1543 | mem_size = (ha->fw_memory_size - 0x11000 + 1) * |
1539 | sizeof(uint16_t); | 1544 | sizeof(uint16_t); |
1540 | } else if (IS_FWI2_CAPABLE(ha)) { | 1545 | } else if (IS_FWI2_CAPABLE(ha)) { |
1541 | if (IS_QLA83XX(ha)) | 1546 | if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) |
1542 | fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem); | 1547 | fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem); |
1543 | else if (IS_QLA81XX(ha)) | 1548 | else if (IS_QLA81XX(ha)) |
1544 | fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem); | 1549 | fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem); |
@@ -1550,7 +1555,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) | |||
1550 | mem_size = (ha->fw_memory_size - 0x100000 + 1) * | 1555 | mem_size = (ha->fw_memory_size - 0x100000 + 1) * |
1551 | sizeof(uint32_t); | 1556 | sizeof(uint32_t); |
1552 | if (ha->mqenable) { | 1557 | if (ha->mqenable) { |
1553 | if (!IS_QLA83XX(ha)) | 1558 | if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) |
1554 | mq_size = sizeof(struct qla2xxx_mq_chain); | 1559 | mq_size = sizeof(struct qla2xxx_mq_chain); |
1555 | /* | 1560 | /* |
1556 | * Allocate maximum buffer size for all queues. | 1561 | * Allocate maximum buffer size for all queues. |
@@ -2922,21 +2927,14 @@ qla2x00_rport_del(void *data) | |||
2922 | { | 2927 | { |
2923 | fc_port_t *fcport = data; | 2928 | fc_port_t *fcport = data; |
2924 | struct fc_rport *rport; | 2929 | struct fc_rport *rport; |
2925 | scsi_qla_host_t *vha = fcport->vha; | ||
2926 | unsigned long flags; | 2930 | unsigned long flags; |
2927 | 2931 | ||
2928 | spin_lock_irqsave(fcport->vha->host->host_lock, flags); | 2932 | spin_lock_irqsave(fcport->vha->host->host_lock, flags); |
2929 | rport = fcport->drport ? fcport->drport: fcport->rport; | 2933 | rport = fcport->drport ? fcport->drport: fcport->rport; |
2930 | fcport->drport = NULL; | 2934 | fcport->drport = NULL; |
2931 | spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); | 2935 | spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); |
2932 | if (rport) { | 2936 | if (rport) |
2933 | fc_remote_port_delete(rport); | 2937 | fc_remote_port_delete(rport); |
2934 | /* | ||
2935 | * Release the target mode FC NEXUS in qla_target.c code | ||
2936 | * if target mod is enabled. | ||
2937 | */ | ||
2938 | qlt_fc_port_deleted(vha, fcport); | ||
2939 | } | ||
2940 | } | 2938 | } |
2941 | 2939 | ||
2942 | /** | 2940 | /** |
@@ -3303,6 +3301,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) | |||
3303 | * Create target mode FC NEXUS in qla_target.c if target mode is | 3301 | * Create target mode FC NEXUS in qla_target.c if target mode is |
3304 | * enabled.. | 3302 | * enabled.. |
3305 | */ | 3303 | */ |
3304 | |||
3306 | qlt_fc_port_added(vha, fcport); | 3305 | qlt_fc_port_added(vha, fcport); |
3307 | 3306 | ||
3308 | spin_lock_irqsave(fcport->vha->host->host_lock, flags); | 3307 | spin_lock_irqsave(fcport->vha->host->host_lock, flags); |
@@ -3341,8 +3340,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) | |||
3341 | 3340 | ||
3342 | if (IS_QLAFX00(vha->hw)) { | 3341 | if (IS_QLAFX00(vha->hw)) { |
3343 | qla2x00_set_fcport_state(fcport, FCS_ONLINE); | 3342 | qla2x00_set_fcport_state(fcport, FCS_ONLINE); |
3344 | qla2x00_reg_remote_port(vha, fcport); | 3343 | goto reg_port; |
3345 | return; | ||
3346 | } | 3344 | } |
3347 | fcport->login_retry = 0; | 3345 | fcport->login_retry = 0; |
3348 | fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); | 3346 | fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); |
@@ -3350,7 +3348,16 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) | |||
3350 | qla2x00_set_fcport_state(fcport, FCS_ONLINE); | 3348 | qla2x00_set_fcport_state(fcport, FCS_ONLINE); |
3351 | qla2x00_iidma_fcport(vha, fcport); | 3349 | qla2x00_iidma_fcport(vha, fcport); |
3352 | qla24xx_update_fcport_fcp_prio(vha, fcport); | 3350 | qla24xx_update_fcport_fcp_prio(vha, fcport); |
3353 | qla2x00_reg_remote_port(vha, fcport); | 3351 | |
3352 | reg_port: | ||
3353 | if (qla_ini_mode_enabled(vha)) | ||
3354 | qla2x00_reg_remote_port(vha, fcport); | ||
3355 | else { | ||
3356 | /* | ||
3357 | * Create target mode FC NEXUS in qla_target.c | ||
3358 | */ | ||
3359 | qlt_fc_port_added(vha, fcport); | ||
3360 | } | ||
3354 | } | 3361 | } |
3355 | 3362 | ||
3356 | /* | 3363 | /* |
@@ -3375,6 +3382,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) | |||
3375 | LIST_HEAD(new_fcports); | 3382 | LIST_HEAD(new_fcports); |
3376 | struct qla_hw_data *ha = vha->hw; | 3383 | struct qla_hw_data *ha = vha->hw; |
3377 | struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); | 3384 | struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); |
3385 | int discovery_gen; | ||
3378 | 3386 | ||
3379 | /* If FL port exists, then SNS is present */ | 3387 | /* If FL port exists, then SNS is present */ |
3380 | if (IS_FWI2_CAPABLE(ha)) | 3388 | if (IS_FWI2_CAPABLE(ha)) |
@@ -3445,6 +3453,14 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) | |||
3445 | fcport->scan_state = QLA_FCPORT_SCAN; | 3453 | fcport->scan_state = QLA_FCPORT_SCAN; |
3446 | } | 3454 | } |
3447 | 3455 | ||
3456 | /* Mark the time right before querying FW for connected ports. | ||
3457 | * This process is long, asynchronous and by the time it's done, | ||
3458 | * collected information might not be accurate anymore. E.g. | ||
3459 | * disconnected port might have re-connected and a brand new | ||
3460 | * session has been created. In this case session's generation | ||
3461 | * will be newer than discovery_gen. */ | ||
3462 | qlt_do_generation_tick(vha, &discovery_gen); | ||
3463 | |||
3448 | rval = qla2x00_find_all_fabric_devs(vha, &new_fcports); | 3464 | rval = qla2x00_find_all_fabric_devs(vha, &new_fcports); |
3449 | if (rval != QLA_SUCCESS) | 3465 | if (rval != QLA_SUCCESS) |
3450 | break; | 3466 | break; |
@@ -3460,20 +3476,44 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) | |||
3460 | if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) | 3476 | if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) |
3461 | continue; | 3477 | continue; |
3462 | 3478 | ||
3463 | if (fcport->scan_state == QLA_FCPORT_SCAN && | 3479 | if (fcport->scan_state == QLA_FCPORT_SCAN) { |
3464 | atomic_read(&fcport->state) == FCS_ONLINE) { | 3480 | if (qla_ini_mode_enabled(base_vha) && |
3465 | qla2x00_mark_device_lost(vha, fcport, | 3481 | atomic_read(&fcport->state) == FCS_ONLINE) { |
3466 | ql2xplogiabsentdevice, 0); | 3482 | qla2x00_mark_device_lost(vha, fcport, |
3467 | if (fcport->loop_id != FC_NO_LOOP_ID && | 3483 | ql2xplogiabsentdevice, 0); |
3468 | (fcport->flags & FCF_FCP2_DEVICE) == 0 && | 3484 | if (fcport->loop_id != FC_NO_LOOP_ID && |
3469 | fcport->port_type != FCT_INITIATOR && | 3485 | (fcport->flags & FCF_FCP2_DEVICE) == 0 && |
3470 | fcport->port_type != FCT_BROADCAST) { | 3486 | fcport->port_type != FCT_INITIATOR && |
3471 | ha->isp_ops->fabric_logout(vha, | 3487 | fcport->port_type != FCT_BROADCAST) { |
3472 | fcport->loop_id, | 3488 | ha->isp_ops->fabric_logout(vha, |
3473 | fcport->d_id.b.domain, | 3489 | fcport->loop_id, |
3474 | fcport->d_id.b.area, | 3490 | fcport->d_id.b.domain, |
3475 | fcport->d_id.b.al_pa); | 3491 | fcport->d_id.b.area, |
3476 | qla2x00_clear_loop_id(fcport); | 3492 | fcport->d_id.b.al_pa); |
3493 | qla2x00_clear_loop_id(fcport); | ||
3494 | } | ||
3495 | } else if (!qla_ini_mode_enabled(base_vha)) { | ||
3496 | /* | ||
3497 | * In target mode, explicitly kill | ||
3498 | * sessions and log out of devices | ||
3499 | * that are gone, so that we don't | ||
3500 | * end up with an initiator using the | ||
3501 | * wrong ACL (if the fabric recycles | ||
3502 | * an FC address and we have a stale | ||
3503 | * session around) and so that we don't | ||
3504 | * report initiators that are no longer | ||
3505 | * on the fabric. | ||
3506 | */ | ||
3507 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf077, | ||
3508 | "port gone, logging out/killing session: " | ||
3509 | "%8phC state 0x%x flags 0x%x fc4_type 0x%x " | ||
3510 | "scan_state %d\n", | ||
3511 | fcport->port_name, | ||
3512 | atomic_read(&fcport->state), | ||
3513 | fcport->flags, fcport->fc4_type, | ||
3514 | fcport->scan_state); | ||
3515 | qlt_fc_port_deleted(vha, fcport, | ||
3516 | discovery_gen); | ||
3477 | } | 3517 | } |
3478 | } | 3518 | } |
3479 | } | 3519 | } |
@@ -3494,6 +3534,28 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) | |||
3494 | (fcport->flags & FCF_LOGIN_NEEDED) == 0) | 3534 | (fcport->flags & FCF_LOGIN_NEEDED) == 0) |
3495 | continue; | 3535 | continue; |
3496 | 3536 | ||
3537 | /* | ||
3538 | * If we're not an initiator, skip looking for devices | ||
3539 | * and logging in. There's no reason for us to do it, | ||
3540 | * and it seems to actively cause problems in target | ||
3541 | * mode if we race with the initiator logging into us | ||
3542 | * (we might get the "port ID used" status back from | ||
3543 | * our login command and log out the initiator, which | ||
3544 | * seems to cause havoc). | ||
3545 | */ | ||
3546 | if (!qla_ini_mode_enabled(base_vha)) { | ||
3547 | if (fcport->scan_state == QLA_FCPORT_FOUND) { | ||
3548 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf078, | ||
3549 | "port %8phC state 0x%x flags 0x%x fc4_type 0x%x " | ||
3550 | "scan_state %d (initiator mode disabled; skipping " | ||
3551 | "login)\n", fcport->port_name, | ||
3552 | atomic_read(&fcport->state), | ||
3553 | fcport->flags, fcport->fc4_type, | ||
3554 | fcport->scan_state); | ||
3555 | } | ||
3556 | continue; | ||
3557 | } | ||
3558 | |||
3497 | if (fcport->loop_id == FC_NO_LOOP_ID) { | 3559 | if (fcport->loop_id == FC_NO_LOOP_ID) { |
3498 | fcport->loop_id = next_loopid; | 3560 | fcport->loop_id = next_loopid; |
3499 | rval = qla2x00_find_new_loop_id( | 3561 | rval = qla2x00_find_new_loop_id( |
@@ -3520,16 +3582,38 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) | |||
3520 | test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) | 3582 | test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) |
3521 | break; | 3583 | break; |
3522 | 3584 | ||
3523 | /* Find a new loop ID to use. */ | 3585 | /* |
3524 | fcport->loop_id = next_loopid; | 3586 | * If we're not an initiator, skip looking for devices |
3525 | rval = qla2x00_find_new_loop_id(base_vha, fcport); | 3587 | * and logging in. There's no reason for us to do it, |
3526 | if (rval != QLA_SUCCESS) { | 3588 | * and it seems to actively cause problems in target |
3527 | /* Ran out of IDs to use */ | 3589 | * mode if we race with the initiator logging into us |
3528 | break; | 3590 | * (we might get the "port ID used" status back from |
3529 | } | 3591 | * our login command and log out the initiator, which |
3592 | * seems to cause havoc). | ||
3593 | */ | ||
3594 | if (qla_ini_mode_enabled(base_vha)) { | ||
3595 | /* Find a new loop ID to use. */ | ||
3596 | fcport->loop_id = next_loopid; | ||
3597 | rval = qla2x00_find_new_loop_id(base_vha, | ||
3598 | fcport); | ||
3599 | if (rval != QLA_SUCCESS) { | ||
3600 | /* Ran out of IDs to use */ | ||
3601 | break; | ||
3602 | } | ||
3530 | 3603 | ||
3531 | /* Login and update database */ | 3604 | /* Login and update database */ |
3532 | qla2x00_fabric_dev_login(vha, fcport, &next_loopid); | 3605 | qla2x00_fabric_dev_login(vha, fcport, |
3606 | &next_loopid); | ||
3607 | } else { | ||
3608 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf079, | ||
3609 | "new port %8phC state 0x%x flags 0x%x fc4_type " | ||
3610 | "0x%x scan_state %d (initiator mode disabled; " | ||
3611 | "skipping login)\n", | ||
3612 | fcport->port_name, | ||
3613 | atomic_read(&fcport->state), | ||
3614 | fcport->flags, fcport->fc4_type, | ||
3615 | fcport->scan_state); | ||
3616 | } | ||
3533 | 3617 | ||
3534 | list_move_tail(&fcport->list, &vha->vp_fcports); | 3618 | list_move_tail(&fcport->list, &vha->vp_fcports); |
3535 | } | 3619 | } |
@@ -3725,11 +3809,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, | |||
3725 | fcport->fp_speed = new_fcport->fp_speed; | 3809 | fcport->fp_speed = new_fcport->fp_speed; |
3726 | 3810 | ||
3727 | /* | 3811 | /* |
3728 | * If address the same and state FCS_ONLINE, nothing | 3812 | * If address the same and state FCS_ONLINE |
3729 | * changed. | 3813 | * (or in target mode), nothing changed. |
3730 | */ | 3814 | */ |
3731 | if (fcport->d_id.b24 == new_fcport->d_id.b24 && | 3815 | if (fcport->d_id.b24 == new_fcport->d_id.b24 && |
3732 | atomic_read(&fcport->state) == FCS_ONLINE) { | 3816 | (atomic_read(&fcport->state) == FCS_ONLINE || |
3817 | !qla_ini_mode_enabled(base_vha))) { | ||
3733 | break; | 3818 | break; |
3734 | } | 3819 | } |
3735 | 3820 | ||
@@ -3749,6 +3834,22 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, | |||
3749 | * Log it out if still logged in and mark it for | 3834 | * Log it out if still logged in and mark it for |
3750 | * relogin later. | 3835 | * relogin later. |
3751 | */ | 3836 | */ |
3837 | if (!qla_ini_mode_enabled(base_vha)) { | ||
3838 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf080, | ||
3839 | "port changed FC ID, %8phC" | ||
3840 | " old %x:%x:%x (loop_id 0x%04x)-> new %x:%x:%x\n", | ||
3841 | fcport->port_name, | ||
3842 | fcport->d_id.b.domain, | ||
3843 | fcport->d_id.b.area, | ||
3844 | fcport->d_id.b.al_pa, | ||
3845 | fcport->loop_id, | ||
3846 | new_fcport->d_id.b.domain, | ||
3847 | new_fcport->d_id.b.area, | ||
3848 | new_fcport->d_id.b.al_pa); | ||
3849 | fcport->d_id.b24 = new_fcport->d_id.b24; | ||
3850 | break; | ||
3851 | } | ||
3852 | |||
3752 | fcport->d_id.b24 = new_fcport->d_id.b24; | 3853 | fcport->d_id.b24 = new_fcport->d_id.b24; |
3753 | fcport->flags |= FCF_LOGIN_NEEDED; | 3854 | fcport->flags |= FCF_LOGIN_NEEDED; |
3754 | if (fcport->loop_id != FC_NO_LOOP_ID && | 3855 | if (fcport->loop_id != FC_NO_LOOP_ID && |
@@ -3768,6 +3869,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, | |||
3768 | if (found) | 3869 | if (found) |
3769 | continue; | 3870 | continue; |
3770 | /* If device was not in our fcports list, then add it. */ | 3871 | /* If device was not in our fcports list, then add it. */ |
3872 | new_fcport->scan_state = QLA_FCPORT_FOUND; | ||
3771 | list_add_tail(&new_fcport->list, new_fcports); | 3873 | list_add_tail(&new_fcport->list, new_fcports); |
3772 | 3874 | ||
3773 | /* Allocate a new replacement fcport. */ | 3875 | /* Allocate a new replacement fcport. */ |
@@ -4188,6 +4290,14 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha) | |||
4188 | atomic_read(&fcport->state) != FCS_UNCONFIGURED) { | 4290 | atomic_read(&fcport->state) != FCS_UNCONFIGURED) { |
4189 | spin_unlock_irqrestore(&ha->vport_slock, flags); | 4291 | spin_unlock_irqrestore(&ha->vport_slock, flags); |
4190 | qla2x00_rport_del(fcport); | 4292 | qla2x00_rport_del(fcport); |
4293 | |||
4294 | /* | ||
4295 | * Release the target mode FC NEXUS in | ||
4296 | * qla_target.c, if target mod is enabled. | ||
4297 | */ | ||
4298 | qlt_fc_port_deleted(vha, fcport, | ||
4299 | base_vha->total_fcport_update_gen); | ||
4300 | |||
4191 | spin_lock_irqsave(&ha->vport_slock, flags); | 4301 | spin_lock_irqsave(&ha->vport_slock, flags); |
4192 | } | 4302 | } |
4193 | } | 4303 | } |
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 36fbd4c7af8f..6f02b26a35cf 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c | |||
@@ -1943,6 +1943,9 @@ qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio) | |||
1943 | logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; | 1943 | logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; |
1944 | logio->control_flags = | 1944 | logio->control_flags = |
1945 | cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); | 1945 | cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); |
1946 | if (!sp->fcport->tgt_session || | ||
1947 | !sp->fcport->tgt_session->keep_nport_handle) | ||
1948 | logio->control_flags |= cpu_to_le16(LCF_FREE_NPORT); | ||
1946 | logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); | 1949 | logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); |
1947 | logio->port_id[0] = sp->fcport->d_id.b.al_pa; | 1950 | logio->port_id[0] = sp->fcport->d_id.b.al_pa; |
1948 | logio->port_id[1] = sp->fcport->d_id.b.area; | 1951 | logio->port_id[1] = sp->fcport->d_id.b.area; |
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 02b1c1c5355b..b2f713ad9034 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |||
@@ -2415,7 +2415,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt, | |||
2415 | *orig_iocb_cnt = mcp->mb[10]; | 2415 | *orig_iocb_cnt = mcp->mb[10]; |
2416 | if (vha->hw->flags.npiv_supported && max_npiv_vports) | 2416 | if (vha->hw->flags.npiv_supported && max_npiv_vports) |
2417 | *max_npiv_vports = mcp->mb[11]; | 2417 | *max_npiv_vports = mcp->mb[11]; |
2418 | if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw)) && max_fcfs) | 2418 | if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) || |
2419 | IS_QLA27XX(vha->hw)) && max_fcfs) | ||
2419 | *max_fcfs = mcp->mb[12]; | 2420 | *max_fcfs = mcp->mb[12]; |
2420 | } | 2421 | } |
2421 | 2422 | ||
@@ -3898,7 +3899,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) | |||
3898 | spin_lock_irqsave(&ha->hardware_lock, flags); | 3899 | spin_lock_irqsave(&ha->hardware_lock, flags); |
3899 | if (!(rsp->options & BIT_0)) { | 3900 | if (!(rsp->options & BIT_0)) { |
3900 | WRT_REG_DWORD(rsp->rsp_q_out, 0); | 3901 | WRT_REG_DWORD(rsp->rsp_q_out, 0); |
3901 | if (!IS_QLA83XX(ha)) | 3902 | if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) |
3902 | WRT_REG_DWORD(rsp->rsp_q_in, 0); | 3903 | WRT_REG_DWORD(rsp->rsp_q_in, 0); |
3903 | } | 3904 | } |
3904 | 3905 | ||
@@ -5345,7 +5346,7 @@ qla83xx_restart_nic_firmware(scsi_qla_host_t *vha) | |||
5345 | mbx_cmd_t *mcp = &mc; | 5346 | mbx_cmd_t *mcp = &mc; |
5346 | struct qla_hw_data *ha = vha->hw; | 5347 | struct qla_hw_data *ha = vha->hw; |
5347 | 5348 | ||
5348 | if (!IS_QLA83XX(ha)) | 5349 | if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) |
5349 | return QLA_FUNCTION_FAILED; | 5350 | return QLA_FUNCTION_FAILED; |
5350 | 5351 | ||
5351 | ql_dbg(ql_dbg_mbx, vha, 0x1143, "Entered %s.\n", __func__); | 5352 | ql_dbg(ql_dbg_mbx, vha, 0x1143, "Entered %s.\n", __func__); |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index a28815b8276f..8a5cac8448c7 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -2504,6 +2504,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
2504 | ha->mbx_count = MAILBOX_REGISTER_COUNT; | 2504 | ha->mbx_count = MAILBOX_REGISTER_COUNT; |
2505 | req_length = REQUEST_ENTRY_CNT_24XX; | 2505 | req_length = REQUEST_ENTRY_CNT_24XX; |
2506 | rsp_length = RESPONSE_ENTRY_CNT_2300; | 2506 | rsp_length = RESPONSE_ENTRY_CNT_2300; |
2507 | ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; | ||
2507 | ha->max_loop_id = SNS_LAST_LOOP_ID_2300; | 2508 | ha->max_loop_id = SNS_LAST_LOOP_ID_2300; |
2508 | ha->init_cb_size = sizeof(struct mid_init_cb_81xx); | 2509 | ha->init_cb_size = sizeof(struct mid_init_cb_81xx); |
2509 | ha->gid_list_info_size = 8; | 2510 | ha->gid_list_info_size = 8; |
@@ -3229,11 +3230,15 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, | |||
3229 | spin_lock_irqsave(vha->host->host_lock, flags); | 3230 | spin_lock_irqsave(vha->host->host_lock, flags); |
3230 | fcport->drport = rport; | 3231 | fcport->drport = rport; |
3231 | spin_unlock_irqrestore(vha->host->host_lock, flags); | 3232 | spin_unlock_irqrestore(vha->host->host_lock, flags); |
3233 | qlt_do_generation_tick(vha, &base_vha->total_fcport_update_gen); | ||
3232 | set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); | 3234 | set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); |
3233 | qla2xxx_wake_dpc(base_vha); | 3235 | qla2xxx_wake_dpc(base_vha); |
3234 | } else { | 3236 | } else { |
3235 | fc_remote_port_delete(rport); | 3237 | int now; |
3236 | qlt_fc_port_deleted(vha, fcport); | 3238 | if (rport) |
3239 | fc_remote_port_delete(rport); | ||
3240 | qlt_do_generation_tick(vha, &now); | ||
3241 | qlt_fc_port_deleted(vha, fcport, now); | ||
3237 | } | 3242 | } |
3238 | } | 3243 | } |
3239 | 3244 | ||
@@ -3763,8 +3768,11 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, | |||
3763 | INIT_LIST_HEAD(&vha->vp_fcports); | 3768 | INIT_LIST_HEAD(&vha->vp_fcports); |
3764 | INIT_LIST_HEAD(&vha->work_list); | 3769 | INIT_LIST_HEAD(&vha->work_list); |
3765 | INIT_LIST_HEAD(&vha->list); | 3770 | INIT_LIST_HEAD(&vha->list); |
3771 | INIT_LIST_HEAD(&vha->qla_cmd_list); | ||
3772 | INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list); | ||
3766 | 3773 | ||
3767 | spin_lock_init(&vha->work_lock); | 3774 | spin_lock_init(&vha->work_lock); |
3775 | spin_lock_init(&vha->cmd_list_lock); | ||
3768 | 3776 | ||
3769 | sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no); | 3777 | sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no); |
3770 | ql_dbg(ql_dbg_init, vha, 0x0041, | 3778 | ql_dbg(ql_dbg_init, vha, 0x0041, |
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 028e8c8a7de9..2feb5f38edcd 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c | |||
@@ -1697,7 +1697,7 @@ qla83xx_select_led_port(struct qla_hw_data *ha) | |||
1697 | { | 1697 | { |
1698 | uint32_t led_select_value = 0; | 1698 | uint32_t led_select_value = 0; |
1699 | 1699 | ||
1700 | if (!IS_QLA83XX(ha)) | 1700 | if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha)) |
1701 | goto out; | 1701 | goto out; |
1702 | 1702 | ||
1703 | if (ha->port_no == 0) | 1703 | if (ha->port_no == 0) |
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index b749026aa592..58651ecbd88c 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c | |||
@@ -113,6 +113,11 @@ static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, | |||
113 | static void qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, | 113 | static void qlt_alloc_qfull_cmd(struct scsi_qla_host *vha, |
114 | struct atio_from_isp *atio, uint16_t status, int qfull); | 114 | struct atio_from_isp *atio, uint16_t status, int qfull); |
115 | static void qlt_disable_vha(struct scsi_qla_host *vha); | 115 | static void qlt_disable_vha(struct scsi_qla_host *vha); |
116 | static void qlt_clear_tgt_db(struct qla_tgt *tgt); | ||
117 | static void qlt_send_notify_ack(struct scsi_qla_host *vha, | ||
118 | struct imm_ntfy_from_isp *ntfy, | ||
119 | uint32_t add_flags, uint16_t resp_code, int resp_code_valid, | ||
120 | uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan); | ||
116 | /* | 121 | /* |
117 | * Global Variables | 122 | * Global Variables |
118 | */ | 123 | */ |
@@ -122,6 +127,16 @@ static struct workqueue_struct *qla_tgt_wq; | |||
122 | static DEFINE_MUTEX(qla_tgt_mutex); | 127 | static DEFINE_MUTEX(qla_tgt_mutex); |
123 | static LIST_HEAD(qla_tgt_glist); | 128 | static LIST_HEAD(qla_tgt_glist); |
124 | 129 | ||
130 | /* This API intentionally takes dest as a parameter, rather than returning | ||
131 | * int value to avoid caller forgetting to issue wmb() after the store */ | ||
132 | void qlt_do_generation_tick(struct scsi_qla_host *vha, int *dest) | ||
133 | { | ||
134 | scsi_qla_host_t *base_vha = pci_get_drvdata(vha->hw->pdev); | ||
135 | *dest = atomic_inc_return(&base_vha->generation_tick); | ||
136 | /* memory barrier */ | ||
137 | wmb(); | ||
138 | } | ||
139 | |||
125 | /* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list) */ | 140 | /* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list) */ |
126 | static struct qla_tgt_sess *qlt_find_sess_by_port_name( | 141 | static struct qla_tgt_sess *qlt_find_sess_by_port_name( |
127 | struct qla_tgt *tgt, | 142 | struct qla_tgt *tgt, |
@@ -381,14 +396,73 @@ static void qlt_free_session_done(struct work_struct *work) | |||
381 | struct qla_tgt *tgt = sess->tgt; | 396 | struct qla_tgt *tgt = sess->tgt; |
382 | struct scsi_qla_host *vha = sess->vha; | 397 | struct scsi_qla_host *vha = sess->vha; |
383 | struct qla_hw_data *ha = vha->hw; | 398 | struct qla_hw_data *ha = vha->hw; |
399 | unsigned long flags; | ||
400 | bool logout_started = false; | ||
401 | fc_port_t fcport; | ||
402 | |||
403 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084, | ||
404 | "%s: se_sess %p / sess %p from port %8phC loop_id %#04x" | ||
405 | " s_id %02x:%02x:%02x logout %d keep %d plogi %d\n", | ||
406 | __func__, sess->se_sess, sess, sess->port_name, sess->loop_id, | ||
407 | sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa, | ||
408 | sess->logout_on_delete, sess->keep_nport_handle, | ||
409 | sess->plogi_ack_needed); | ||
384 | 410 | ||
385 | BUG_ON(!tgt); | 411 | BUG_ON(!tgt); |
412 | |||
413 | if (sess->logout_on_delete) { | ||
414 | int rc; | ||
415 | |||
416 | memset(&fcport, 0, sizeof(fcport)); | ||
417 | fcport.loop_id = sess->loop_id; | ||
418 | fcport.d_id = sess->s_id; | ||
419 | memcpy(fcport.port_name, sess->port_name, WWN_SIZE); | ||
420 | fcport.vha = vha; | ||
421 | fcport.tgt_session = sess; | ||
422 | |||
423 | rc = qla2x00_post_async_logout_work(vha, &fcport, NULL); | ||
424 | if (rc != QLA_SUCCESS) | ||
425 | ql_log(ql_log_warn, vha, 0xf085, | ||
426 | "Schedule logo failed sess %p rc %d\n", | ||
427 | sess, rc); | ||
428 | else | ||
429 | logout_started = true; | ||
430 | } | ||
431 | |||
386 | /* | 432 | /* |
387 | * Release the target session for FC Nexus from fabric module code. | 433 | * Release the target session for FC Nexus from fabric module code. |
388 | */ | 434 | */ |
389 | if (sess->se_sess != NULL) | 435 | if (sess->se_sess != NULL) |
390 | ha->tgt.tgt_ops->free_session(sess); | 436 | ha->tgt.tgt_ops->free_session(sess); |
391 | 437 | ||
438 | if (logout_started) { | ||
439 | bool traced = false; | ||
440 | |||
441 | while (!ACCESS_ONCE(sess->logout_completed)) { | ||
442 | if (!traced) { | ||
443 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf086, | ||
444 | "%s: waiting for sess %p logout\n", | ||
445 | __func__, sess); | ||
446 | traced = true; | ||
447 | } | ||
448 | msleep(100); | ||
449 | } | ||
450 | |||
451 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf087, | ||
452 | "%s: sess %p logout completed\n", | ||
453 | __func__, sess); | ||
454 | } | ||
455 | |||
456 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
457 | |||
458 | if (sess->plogi_ack_needed) | ||
459 | qlt_send_notify_ack(vha, &sess->tm_iocb, | ||
460 | 0, 0, 0, 0, 0, 0); | ||
461 | |||
462 | list_del(&sess->sess_list_entry); | ||
463 | |||
464 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
465 | |||
392 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf001, | 466 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf001, |
393 | "Unregistration of sess %p finished\n", sess); | 467 | "Unregistration of sess %p finished\n", sess); |
394 | 468 | ||
@@ -409,9 +483,9 @@ void qlt_unreg_sess(struct qla_tgt_sess *sess) | |||
409 | 483 | ||
410 | vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess); | 484 | vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess); |
411 | 485 | ||
412 | list_del(&sess->sess_list_entry); | 486 | if (!list_empty(&sess->del_list_entry)) |
413 | if (sess->deleted) | 487 | list_del_init(&sess->del_list_entry); |
414 | list_del(&sess->del_list_entry); | 488 | sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; |
415 | 489 | ||
416 | INIT_WORK(&sess->free_work, qlt_free_session_done); | 490 | INIT_WORK(&sess->free_work, qlt_free_session_done); |
417 | schedule_work(&sess->free_work); | 491 | schedule_work(&sess->free_work); |
@@ -431,10 +505,10 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd) | |||
431 | 505 | ||
432 | loop_id = le16_to_cpu(n->u.isp24.nport_handle); | 506 | loop_id = le16_to_cpu(n->u.isp24.nport_handle); |
433 | if (loop_id == 0xFFFF) { | 507 | if (loop_id == 0xFFFF) { |
434 | #if 0 /* FIXME: Re-enable Global event handling.. */ | ||
435 | /* Global event */ | 508 | /* Global event */ |
436 | atomic_inc(&ha->tgt.qla_tgt->tgt_global_resets_count); | 509 | atomic_inc(&vha->vha_tgt.qla_tgt->tgt_global_resets_count); |
437 | qlt_clear_tgt_db(ha->tgt.qla_tgt); | 510 | qlt_clear_tgt_db(vha->vha_tgt.qla_tgt); |
511 | #if 0 /* FIXME: do we need to choose a session here? */ | ||
438 | if (!list_empty(&ha->tgt.qla_tgt->sess_list)) { | 512 | if (!list_empty(&ha->tgt.qla_tgt->sess_list)) { |
439 | sess = list_entry(ha->tgt.qla_tgt->sess_list.next, | 513 | sess = list_entry(ha->tgt.qla_tgt->sess_list.next, |
440 | typeof(*sess), sess_list_entry); | 514 | typeof(*sess), sess_list_entry); |
@@ -489,27 +563,38 @@ static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess, | |||
489 | struct qla_tgt *tgt = sess->tgt; | 563 | struct qla_tgt *tgt = sess->tgt; |
490 | uint32_t dev_loss_tmo = tgt->ha->port_down_retry_count + 5; | 564 | uint32_t dev_loss_tmo = tgt->ha->port_down_retry_count + 5; |
491 | 565 | ||
492 | if (sess->deleted) | 566 | if (sess->deleted) { |
493 | return; | 567 | /* Upgrade to unconditional deletion in case it was temporary */ |
568 | if (immediate && sess->deleted == QLA_SESS_DELETION_PENDING) | ||
569 | list_del(&sess->del_list_entry); | ||
570 | else | ||
571 | return; | ||
572 | } | ||
494 | 573 | ||
495 | ql_dbg(ql_dbg_tgt, sess->vha, 0xe001, | 574 | ql_dbg(ql_dbg_tgt, sess->vha, 0xe001, |
496 | "Scheduling sess %p for deletion\n", sess); | 575 | "Scheduling sess %p for deletion\n", sess); |
497 | list_add_tail(&sess->del_list_entry, &tgt->del_sess_list); | ||
498 | sess->deleted = 1; | ||
499 | 576 | ||
500 | if (immediate) | 577 | if (immediate) { |
501 | dev_loss_tmo = 0; | 578 | dev_loss_tmo = 0; |
579 | sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; | ||
580 | list_add(&sess->del_list_entry, &tgt->del_sess_list); | ||
581 | } else { | ||
582 | sess->deleted = QLA_SESS_DELETION_PENDING; | ||
583 | list_add_tail(&sess->del_list_entry, &tgt->del_sess_list); | ||
584 | } | ||
502 | 585 | ||
503 | sess->expires = jiffies + dev_loss_tmo * HZ; | 586 | sess->expires = jiffies + dev_loss_tmo * HZ; |
504 | 587 | ||
505 | ql_dbg(ql_dbg_tgt, sess->vha, 0xe048, | 588 | ql_dbg(ql_dbg_tgt, sess->vha, 0xe048, |
506 | "qla_target(%d): session for port %8phC (loop ID %d) scheduled for " | 589 | "qla_target(%d): session for port %8phC (loop ID %d s_id %02x:%02x:%02x)" |
507 | "deletion in %u secs (expires: %lu) immed: %d\n", | 590 | " scheduled for deletion in %u secs (expires: %lu) immed: %d, logout: %d, gen: %#x\n", |
508 | sess->vha->vp_idx, sess->port_name, sess->loop_id, dev_loss_tmo, | 591 | sess->vha->vp_idx, sess->port_name, sess->loop_id, |
509 | sess->expires, immediate); | 592 | sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa, |
593 | dev_loss_tmo, sess->expires, immediate, sess->logout_on_delete, | ||
594 | sess->generation); | ||
510 | 595 | ||
511 | if (immediate) | 596 | if (immediate) |
512 | schedule_delayed_work(&tgt->sess_del_work, 0); | 597 | mod_delayed_work(system_wq, &tgt->sess_del_work, 0); |
513 | else | 598 | else |
514 | schedule_delayed_work(&tgt->sess_del_work, | 599 | schedule_delayed_work(&tgt->sess_del_work, |
515 | sess->expires - jiffies); | 600 | sess->expires - jiffies); |
@@ -578,9 +663,9 @@ out_free_id_list: | |||
578 | /* ha->hardware_lock supposed to be held on entry */ | 663 | /* ha->hardware_lock supposed to be held on entry */ |
579 | static void qlt_undelete_sess(struct qla_tgt_sess *sess) | 664 | static void qlt_undelete_sess(struct qla_tgt_sess *sess) |
580 | { | 665 | { |
581 | BUG_ON(!sess->deleted); | 666 | BUG_ON(sess->deleted != QLA_SESS_DELETION_PENDING); |
582 | 667 | ||
583 | list_del(&sess->del_list_entry); | 668 | list_del_init(&sess->del_list_entry); |
584 | sess->deleted = 0; | 669 | sess->deleted = 0; |
585 | } | 670 | } |
586 | 671 | ||
@@ -599,7 +684,9 @@ static void qlt_del_sess_work_fn(struct delayed_work *work) | |||
599 | del_list_entry); | 684 | del_list_entry); |
600 | elapsed = jiffies; | 685 | elapsed = jiffies; |
601 | if (time_after_eq(elapsed, sess->expires)) { | 686 | if (time_after_eq(elapsed, sess->expires)) { |
602 | qlt_undelete_sess(sess); | 687 | /* No turning back */ |
688 | list_del_init(&sess->del_list_entry); | ||
689 | sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; | ||
603 | 690 | ||
604 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004, | 691 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004, |
605 | "Timeout: sess %p about to be deleted\n", | 692 | "Timeout: sess %p about to be deleted\n", |
@@ -643,6 +730,13 @@ static struct qla_tgt_sess *qlt_create_sess( | |||
643 | fcport->d_id.b.al_pa, fcport->d_id.b.area, | 730 | fcport->d_id.b.al_pa, fcport->d_id.b.area, |
644 | fcport->loop_id); | 731 | fcport->loop_id); |
645 | 732 | ||
733 | /* Cannot undelete at this point */ | ||
734 | if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { | ||
735 | spin_unlock_irqrestore(&ha->hardware_lock, | ||
736 | flags); | ||
737 | return NULL; | ||
738 | } | ||
739 | |||
646 | if (sess->deleted) | 740 | if (sess->deleted) |
647 | qlt_undelete_sess(sess); | 741 | qlt_undelete_sess(sess); |
648 | 742 | ||
@@ -652,6 +746,9 @@ static struct qla_tgt_sess *qlt_create_sess( | |||
652 | 746 | ||
653 | if (sess->local && !local) | 747 | if (sess->local && !local) |
654 | sess->local = 0; | 748 | sess->local = 0; |
749 | |||
750 | qlt_do_generation_tick(vha, &sess->generation); | ||
751 | |||
655 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 752 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
656 | 753 | ||
657 | return sess; | 754 | return sess; |
@@ -673,6 +770,14 @@ static struct qla_tgt_sess *qlt_create_sess( | |||
673 | sess->s_id = fcport->d_id; | 770 | sess->s_id = fcport->d_id; |
674 | sess->loop_id = fcport->loop_id; | 771 | sess->loop_id = fcport->loop_id; |
675 | sess->local = local; | 772 | sess->local = local; |
773 | INIT_LIST_HEAD(&sess->del_list_entry); | ||
774 | |||
775 | /* Under normal circumstances we want to logout from firmware when | ||
776 | * session eventually ends and release corresponding nport handle. | ||
777 | * In the exception cases (e.g. when new PLOGI is waiting) corresponding | ||
778 | * code will adjust these flags as necessary. */ | ||
779 | sess->logout_on_delete = 1; | ||
780 | sess->keep_nport_handle = 0; | ||
676 | 781 | ||
677 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf006, | 782 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf006, |
678 | "Adding sess %p to tgt %p via ->check_initiator_node_acl()\n", | 783 | "Adding sess %p to tgt %p via ->check_initiator_node_acl()\n", |
@@ -705,6 +810,7 @@ static struct qla_tgt_sess *qlt_create_sess( | |||
705 | spin_lock_irqsave(&ha->hardware_lock, flags); | 810 | spin_lock_irqsave(&ha->hardware_lock, flags); |
706 | list_add_tail(&sess->sess_list_entry, &vha->vha_tgt.qla_tgt->sess_list); | 811 | list_add_tail(&sess->sess_list_entry, &vha->vha_tgt.qla_tgt->sess_list); |
707 | vha->vha_tgt.qla_tgt->sess_count++; | 812 | vha->vha_tgt.qla_tgt->sess_count++; |
813 | qlt_do_generation_tick(vha, &sess->generation); | ||
708 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 814 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
709 | 815 | ||
710 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b, | 816 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b, |
@@ -718,7 +824,7 @@ static struct qla_tgt_sess *qlt_create_sess( | |||
718 | } | 824 | } |
719 | 825 | ||
720 | /* | 826 | /* |
721 | * Called from drivers/scsi/qla2xxx/qla_init.c:qla2x00_reg_remote_port() | 827 | * Called from qla2x00_reg_remote_port() |
722 | */ | 828 | */ |
723 | void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) | 829 | void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) |
724 | { | 830 | { |
@@ -750,6 +856,10 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) | |||
750 | mutex_unlock(&vha->vha_tgt.tgt_mutex); | 856 | mutex_unlock(&vha->vha_tgt.tgt_mutex); |
751 | 857 | ||
752 | spin_lock_irqsave(&ha->hardware_lock, flags); | 858 | spin_lock_irqsave(&ha->hardware_lock, flags); |
859 | } else if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { | ||
860 | /* Point of no return */ | ||
861 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
862 | return; | ||
753 | } else { | 863 | } else { |
754 | kref_get(&sess->se_sess->sess_kref); | 864 | kref_get(&sess->se_sess->sess_kref); |
755 | 865 | ||
@@ -780,27 +890,36 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) | |||
780 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 890 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
781 | } | 891 | } |
782 | 892 | ||
783 | void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport) | 893 | /* |
894 | * max_gen - specifies maximum session generation | ||
895 | * at which this deletion requestion is still valid | ||
896 | */ | ||
897 | void | ||
898 | qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen) | ||
784 | { | 899 | { |
785 | struct qla_hw_data *ha = vha->hw; | ||
786 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; | 900 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; |
787 | struct qla_tgt_sess *sess; | 901 | struct qla_tgt_sess *sess; |
788 | unsigned long flags; | ||
789 | 902 | ||
790 | if (!vha->hw->tgt.tgt_ops) | 903 | if (!vha->hw->tgt.tgt_ops) |
791 | return; | 904 | return; |
792 | 905 | ||
793 | if (!tgt || (fcport->port_type != FCT_INITIATOR)) | 906 | if (!tgt) |
794 | return; | 907 | return; |
795 | 908 | ||
796 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
797 | if (tgt->tgt_stop) { | 909 | if (tgt->tgt_stop) { |
798 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
799 | return; | 910 | return; |
800 | } | 911 | } |
801 | sess = qlt_find_sess_by_port_name(tgt, fcport->port_name); | 912 | sess = qlt_find_sess_by_port_name(tgt, fcport->port_name); |
802 | if (!sess) { | 913 | if (!sess) { |
803 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 914 | return; |
915 | } | ||
916 | |||
917 | if (max_gen - sess->generation < 0) { | ||
918 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092, | ||
919 | "Ignoring stale deletion request for se_sess %p / sess %p" | ||
920 | " for port %8phC, req_gen %d, sess_gen %d\n", | ||
921 | sess->se_sess, sess, sess->port_name, max_gen, | ||
922 | sess->generation); | ||
804 | return; | 923 | return; |
805 | } | 924 | } |
806 | 925 | ||
@@ -808,7 +927,6 @@ void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport) | |||
808 | 927 | ||
809 | sess->local = 1; | 928 | sess->local = 1; |
810 | qlt_schedule_sess_for_deletion(sess, false); | 929 | qlt_schedule_sess_for_deletion(sess, false); |
811 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
812 | } | 930 | } |
813 | 931 | ||
814 | static inline int test_tgt_sess_count(struct qla_tgt *tgt) | 932 | static inline int test_tgt_sess_count(struct qla_tgt *tgt) |
@@ -1175,6 +1293,70 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, | |||
1175 | FCP_TMF_CMPL, true); | 1293 | FCP_TMF_CMPL, true); |
1176 | } | 1294 | } |
1177 | 1295 | ||
1296 | static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag) | ||
1297 | { | ||
1298 | struct qla_tgt_sess_op *op; | ||
1299 | struct qla_tgt_cmd *cmd; | ||
1300 | |||
1301 | spin_lock(&vha->cmd_list_lock); | ||
1302 | |||
1303 | list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) { | ||
1304 | if (tag == op->atio.u.isp24.exchange_addr) { | ||
1305 | op->aborted = true; | ||
1306 | spin_unlock(&vha->cmd_list_lock); | ||
1307 | return 1; | ||
1308 | } | ||
1309 | } | ||
1310 | |||
1311 | list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) { | ||
1312 | if (tag == cmd->atio.u.isp24.exchange_addr) { | ||
1313 | cmd->state = QLA_TGT_STATE_ABORTED; | ||
1314 | spin_unlock(&vha->cmd_list_lock); | ||
1315 | return 1; | ||
1316 | } | ||
1317 | } | ||
1318 | |||
1319 | spin_unlock(&vha->cmd_list_lock); | ||
1320 | return 0; | ||
1321 | } | ||
1322 | |||
1323 | /* drop cmds for the given lun | ||
1324 | * XXX only looks for cmds on the port through which lun reset was recieved | ||
1325 | * XXX does not go through the list of other port (which may have cmds | ||
1326 | * for the same lun) | ||
1327 | */ | ||
1328 | static void abort_cmds_for_lun(struct scsi_qla_host *vha, | ||
1329 | uint32_t lun, uint8_t *s_id) | ||
1330 | { | ||
1331 | struct qla_tgt_sess_op *op; | ||
1332 | struct qla_tgt_cmd *cmd; | ||
1333 | uint32_t key; | ||
1334 | |||
1335 | key = sid_to_key(s_id); | ||
1336 | spin_lock(&vha->cmd_list_lock); | ||
1337 | list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) { | ||
1338 | uint32_t op_key; | ||
1339 | uint32_t op_lun; | ||
1340 | |||
1341 | op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id); | ||
1342 | op_lun = scsilun_to_int( | ||
1343 | (struct scsi_lun *)&op->atio.u.isp24.fcp_cmnd.lun); | ||
1344 | if (op_key == key && op_lun == lun) | ||
1345 | op->aborted = true; | ||
1346 | } | ||
1347 | list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) { | ||
1348 | uint32_t cmd_key; | ||
1349 | uint32_t cmd_lun; | ||
1350 | |||
1351 | cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id); | ||
1352 | cmd_lun = scsilun_to_int( | ||
1353 | (struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun); | ||
1354 | if (cmd_key == key && cmd_lun == lun) | ||
1355 | cmd->state = QLA_TGT_STATE_ABORTED; | ||
1356 | } | ||
1357 | spin_unlock(&vha->cmd_list_lock); | ||
1358 | } | ||
1359 | |||
1178 | /* ha->hardware_lock supposed to be held on entry */ | 1360 | /* ha->hardware_lock supposed to be held on entry */ |
1179 | static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, | 1361 | static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, |
1180 | struct abts_recv_from_24xx *abts, struct qla_tgt_sess *sess) | 1362 | struct abts_recv_from_24xx *abts, struct qla_tgt_sess *sess) |
@@ -1199,8 +1381,19 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, | |||
1199 | } | 1381 | } |
1200 | spin_unlock(&se_sess->sess_cmd_lock); | 1382 | spin_unlock(&se_sess->sess_cmd_lock); |
1201 | 1383 | ||
1202 | if (!found_lun) | 1384 | /* cmd not in LIO lists, look in qla list */ |
1203 | return -ENOENT; | 1385 | if (!found_lun) { |
1386 | if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) { | ||
1387 | /* send TASK_ABORT response immediately */ | ||
1388 | qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_CMPL, false); | ||
1389 | return 0; | ||
1390 | } else { | ||
1391 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf081, | ||
1392 | "unable to find cmd in driver or LIO for tag 0x%x\n", | ||
1393 | abts->exchange_addr_to_abort); | ||
1394 | return -ENOENT; | ||
1395 | } | ||
1396 | } | ||
1204 | 1397 | ||
1205 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f, | 1398 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f, |
1206 | "qla_target(%d): task abort (tag=%d)\n", | 1399 | "qla_target(%d): task abort (tag=%d)\n", |
@@ -1284,6 +1477,11 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, | |||
1284 | return; | 1477 | return; |
1285 | } | 1478 | } |
1286 | 1479 | ||
1480 | if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { | ||
1481 | qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false); | ||
1482 | return; | ||
1483 | } | ||
1484 | |||
1287 | rc = __qlt_24xx_handle_abts(vha, abts, sess); | 1485 | rc = __qlt_24xx_handle_abts(vha, abts, sess); |
1288 | if (rc != 0) { | 1486 | if (rc != 0) { |
1289 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf054, | 1487 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf054, |
@@ -1726,20 +1924,6 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, | |||
1726 | struct qla_hw_data *ha = vha->hw; | 1924 | struct qla_hw_data *ha = vha->hw; |
1727 | struct se_cmd *se_cmd = &cmd->se_cmd; | 1925 | struct se_cmd *se_cmd = &cmd->se_cmd; |
1728 | 1926 | ||
1729 | if (unlikely(cmd->aborted)) { | ||
1730 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, | ||
1731 | "qla_target(%d): terminating exchange for aborted cmd=%p (se_cmd=%p, tag=%lld)", | ||
1732 | vha->vp_idx, cmd, se_cmd, se_cmd->tag); | ||
1733 | |||
1734 | cmd->state = QLA_TGT_STATE_ABORTED; | ||
1735 | cmd->cmd_flags |= BIT_6; | ||
1736 | |||
1737 | qlt_send_term_exchange(vha, cmd, &cmd->atio, 0); | ||
1738 | |||
1739 | /* !! At this point cmd could be already freed !! */ | ||
1740 | return QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED; | ||
1741 | } | ||
1742 | |||
1743 | prm->cmd = cmd; | 1927 | prm->cmd = cmd; |
1744 | prm->tgt = tgt; | 1928 | prm->tgt = tgt; |
1745 | prm->rq_result = scsi_status; | 1929 | prm->rq_result = scsi_status; |
@@ -2301,6 +2485,19 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, | |||
2301 | unsigned long flags = 0; | 2485 | unsigned long flags = 0; |
2302 | int res; | 2486 | int res; |
2303 | 2487 | ||
2488 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
2489 | if (cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { | ||
2490 | cmd->state = QLA_TGT_STATE_PROCESSED; | ||
2491 | if (cmd->sess->logout_completed) | ||
2492 | /* no need to terminate. FW already freed exchange. */ | ||
2493 | qlt_abort_cmd_on_host_reset(cmd->vha, cmd); | ||
2494 | else | ||
2495 | qlt_send_term_exchange(vha, cmd, &cmd->atio, 1); | ||
2496 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
2497 | return 0; | ||
2498 | } | ||
2499 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
2500 | |||
2304 | memset(&prm, 0, sizeof(prm)); | 2501 | memset(&prm, 0, sizeof(prm)); |
2305 | qlt_check_srr_debug(cmd, &xmit_type); | 2502 | qlt_check_srr_debug(cmd, &xmit_type); |
2306 | 2503 | ||
@@ -2313,9 +2510,6 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, | |||
2313 | res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status, | 2510 | res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status, |
2314 | &full_req_cnt); | 2511 | &full_req_cnt); |
2315 | if (unlikely(res != 0)) { | 2512 | if (unlikely(res != 0)) { |
2316 | if (res == QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED) | ||
2317 | return 0; | ||
2318 | |||
2319 | return res; | 2513 | return res; |
2320 | } | 2514 | } |
2321 | 2515 | ||
@@ -2345,9 +2539,10 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, | |||
2345 | res = qlt_build_ctio_crc2_pkt(&prm, vha); | 2539 | res = qlt_build_ctio_crc2_pkt(&prm, vha); |
2346 | else | 2540 | else |
2347 | res = qlt_24xx_build_ctio_pkt(&prm, vha); | 2541 | res = qlt_24xx_build_ctio_pkt(&prm, vha); |
2348 | if (unlikely(res != 0)) | 2542 | if (unlikely(res != 0)) { |
2543 | vha->req->cnt += full_req_cnt; | ||
2349 | goto out_unmap_unlock; | 2544 | goto out_unmap_unlock; |
2350 | 2545 | } | |
2351 | 2546 | ||
2352 | pkt = (struct ctio7_to_24xx *)prm.pkt; | 2547 | pkt = (struct ctio7_to_24xx *)prm.pkt; |
2353 | 2548 | ||
@@ -2461,7 +2656,8 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) | |||
2461 | 2656 | ||
2462 | spin_lock_irqsave(&ha->hardware_lock, flags); | 2657 | spin_lock_irqsave(&ha->hardware_lock, flags); |
2463 | 2658 | ||
2464 | if (qla2x00_reset_active(vha) || cmd->reset_count != ha->chip_reset) { | 2659 | if (qla2x00_reset_active(vha) || (cmd->reset_count != ha->chip_reset) || |
2660 | (cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)) { | ||
2465 | /* | 2661 | /* |
2466 | * Either a chip reset is active or this request was from | 2662 | * Either a chip reset is active or this request was from |
2467 | * previous life, just abort the processing. | 2663 | * previous life, just abort the processing. |
@@ -2485,8 +2681,11 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) | |||
2485 | else | 2681 | else |
2486 | res = qlt_24xx_build_ctio_pkt(&prm, vha); | 2682 | res = qlt_24xx_build_ctio_pkt(&prm, vha); |
2487 | 2683 | ||
2488 | if (unlikely(res != 0)) | 2684 | if (unlikely(res != 0)) { |
2685 | vha->req->cnt += prm.req_cnt; | ||
2489 | goto out_unlock_free_unmap; | 2686 | goto out_unlock_free_unmap; |
2687 | } | ||
2688 | |||
2490 | pkt = (struct ctio7_to_24xx *)prm.pkt; | 2689 | pkt = (struct ctio7_to_24xx *)prm.pkt; |
2491 | pkt->u.status0.flags |= __constant_cpu_to_le16(CTIO7_FLAGS_DATA_OUT | | 2690 | pkt->u.status0.flags |= __constant_cpu_to_le16(CTIO7_FLAGS_DATA_OUT | |
2492 | CTIO7_FLAGS_STATUS_MODE_0); | 2691 | CTIO7_FLAGS_STATUS_MODE_0); |
@@ -2651,6 +2850,89 @@ out: | |||
2651 | 2850 | ||
2652 | /* If hardware_lock held on entry, might drop it, then reaquire */ | 2851 | /* If hardware_lock held on entry, might drop it, then reaquire */ |
2653 | /* This function sends the appropriate CTIO to ISP 2xxx or 24xx */ | 2852 | /* This function sends the appropriate CTIO to ISP 2xxx or 24xx */ |
2853 | static int __qlt_send_term_imm_notif(struct scsi_qla_host *vha, | ||
2854 | struct imm_ntfy_from_isp *ntfy) | ||
2855 | { | ||
2856 | struct nack_to_isp *nack; | ||
2857 | struct qla_hw_data *ha = vha->hw; | ||
2858 | request_t *pkt; | ||
2859 | int ret = 0; | ||
2860 | |||
2861 | ql_dbg(ql_dbg_tgt_tmr, vha, 0xe01c, | ||
2862 | "Sending TERM ELS CTIO (ha=%p)\n", ha); | ||
2863 | |||
2864 | pkt = (request_t *)qla2x00_alloc_iocbs_ready(vha, NULL); | ||
2865 | if (pkt == NULL) { | ||
2866 | ql_dbg(ql_dbg_tgt, vha, 0xe080, | ||
2867 | "qla_target(%d): %s failed: unable to allocate " | ||
2868 | "request packet\n", vha->vp_idx, __func__); | ||
2869 | return -ENOMEM; | ||
2870 | } | ||
2871 | |||
2872 | pkt->entry_type = NOTIFY_ACK_TYPE; | ||
2873 | pkt->entry_count = 1; | ||
2874 | pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; | ||
2875 | |||
2876 | nack = (struct nack_to_isp *)pkt; | ||
2877 | nack->ox_id = ntfy->ox_id; | ||
2878 | |||
2879 | nack->u.isp24.nport_handle = ntfy->u.isp24.nport_handle; | ||
2880 | if (le16_to_cpu(ntfy->u.isp24.status) == IMM_NTFY_ELS) { | ||
2881 | nack->u.isp24.flags = ntfy->u.isp24.flags & | ||
2882 | __constant_cpu_to_le32(NOTIFY24XX_FLAGS_PUREX_IOCB); | ||
2883 | } | ||
2884 | |||
2885 | /* terminate */ | ||
2886 | nack->u.isp24.flags |= | ||
2887 | __constant_cpu_to_le16(NOTIFY_ACK_FLAGS_TERMINATE); | ||
2888 | |||
2889 | nack->u.isp24.srr_rx_id = ntfy->u.isp24.srr_rx_id; | ||
2890 | nack->u.isp24.status = ntfy->u.isp24.status; | ||
2891 | nack->u.isp24.status_subcode = ntfy->u.isp24.status_subcode; | ||
2892 | nack->u.isp24.fw_handle = ntfy->u.isp24.fw_handle; | ||
2893 | nack->u.isp24.exchange_address = ntfy->u.isp24.exchange_address; | ||
2894 | nack->u.isp24.srr_rel_offs = ntfy->u.isp24.srr_rel_offs; | ||
2895 | nack->u.isp24.srr_ui = ntfy->u.isp24.srr_ui; | ||
2896 | nack->u.isp24.vp_index = ntfy->u.isp24.vp_index; | ||
2897 | |||
2898 | qla2x00_start_iocbs(vha, vha->req); | ||
2899 | return ret; | ||
2900 | } | ||
2901 | |||
2902 | static void qlt_send_term_imm_notif(struct scsi_qla_host *vha, | ||
2903 | struct imm_ntfy_from_isp *imm, int ha_locked) | ||
2904 | { | ||
2905 | unsigned long flags = 0; | ||
2906 | int rc; | ||
2907 | |||
2908 | if (qlt_issue_marker(vha, ha_locked) < 0) | ||
2909 | return; | ||
2910 | |||
2911 | if (ha_locked) { | ||
2912 | rc = __qlt_send_term_imm_notif(vha, imm); | ||
2913 | |||
2914 | #if 0 /* Todo */ | ||
2915 | if (rc == -ENOMEM) | ||
2916 | qlt_alloc_qfull_cmd(vha, imm, 0, 0); | ||
2917 | #endif | ||
2918 | goto done; | ||
2919 | } | ||
2920 | |||
2921 | spin_lock_irqsave(&vha->hw->hardware_lock, flags); | ||
2922 | rc = __qlt_send_term_imm_notif(vha, imm); | ||
2923 | |||
2924 | #if 0 /* Todo */ | ||
2925 | if (rc == -ENOMEM) | ||
2926 | qlt_alloc_qfull_cmd(vha, imm, 0, 0); | ||
2927 | #endif | ||
2928 | |||
2929 | done: | ||
2930 | if (!ha_locked) | ||
2931 | spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); | ||
2932 | } | ||
2933 | |||
2934 | /* If hardware_lock held on entry, might drop it, then reaquire */ | ||
2935 | /* This function sends the appropriate CTIO to ISP 2xxx or 24xx */ | ||
2654 | static int __qlt_send_term_exchange(struct scsi_qla_host *vha, | 2936 | static int __qlt_send_term_exchange(struct scsi_qla_host *vha, |
2655 | struct qla_tgt_cmd *cmd, | 2937 | struct qla_tgt_cmd *cmd, |
2656 | struct atio_from_isp *atio) | 2938 | struct atio_from_isp *atio) |
@@ -2715,7 +2997,7 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha, | |||
2715 | static void qlt_send_term_exchange(struct scsi_qla_host *vha, | 2997 | static void qlt_send_term_exchange(struct scsi_qla_host *vha, |
2716 | struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked) | 2998 | struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked) |
2717 | { | 2999 | { |
2718 | unsigned long flags; | 3000 | unsigned long flags = 0; |
2719 | int rc; | 3001 | int rc; |
2720 | 3002 | ||
2721 | if (qlt_issue_marker(vha, ha_locked) < 0) | 3003 | if (qlt_issue_marker(vha, ha_locked) < 0) |
@@ -2731,17 +3013,18 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha, | |||
2731 | rc = __qlt_send_term_exchange(vha, cmd, atio); | 3013 | rc = __qlt_send_term_exchange(vha, cmd, atio); |
2732 | if (rc == -ENOMEM) | 3014 | if (rc == -ENOMEM) |
2733 | qlt_alloc_qfull_cmd(vha, atio, 0, 0); | 3015 | qlt_alloc_qfull_cmd(vha, atio, 0, 0); |
2734 | spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); | ||
2735 | 3016 | ||
2736 | done: | 3017 | done: |
2737 | if (cmd && ((cmd->state != QLA_TGT_STATE_ABORTED) || | 3018 | if (cmd && ((cmd->state != QLA_TGT_STATE_ABORTED) || |
2738 | !cmd->cmd_sent_to_fw)) { | 3019 | !cmd->cmd_sent_to_fw)) { |
2739 | if (!ha_locked && !in_interrupt()) | 3020 | if (cmd->sg_mapped) |
2740 | msleep(250); /* just in case */ | 3021 | qlt_unmap_sg(vha, cmd); |
2741 | |||
2742 | qlt_unmap_sg(vha, cmd); | ||
2743 | vha->hw->tgt.tgt_ops->free_cmd(cmd); | 3022 | vha->hw->tgt.tgt_ops->free_cmd(cmd); |
2744 | } | 3023 | } |
3024 | |||
3025 | if (!ha_locked) | ||
3026 | spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); | ||
3027 | |||
2745 | return; | 3028 | return; |
2746 | } | 3029 | } |
2747 | 3030 | ||
@@ -2792,6 +3075,24 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha) | |||
2792 | 3075 | ||
2793 | } | 3076 | } |
2794 | 3077 | ||
3078 | void qlt_abort_cmd(struct qla_tgt_cmd *cmd) | ||
3079 | { | ||
3080 | struct qla_tgt *tgt = cmd->tgt; | ||
3081 | struct scsi_qla_host *vha = tgt->vha; | ||
3082 | struct se_cmd *se_cmd = &cmd->se_cmd; | ||
3083 | |||
3084 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, | ||
3085 | "qla_target(%d): terminating exchange for aborted cmd=%p " | ||
3086 | "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd, | ||
3087 | se_cmd->tag); | ||
3088 | |||
3089 | cmd->state = QLA_TGT_STATE_ABORTED; | ||
3090 | cmd->cmd_flags |= BIT_6; | ||
3091 | |||
3092 | qlt_send_term_exchange(vha, cmd, &cmd->atio, 0); | ||
3093 | } | ||
3094 | EXPORT_SYMBOL(qlt_abort_cmd); | ||
3095 | |||
2795 | void qlt_free_cmd(struct qla_tgt_cmd *cmd) | 3096 | void qlt_free_cmd(struct qla_tgt_cmd *cmd) |
2796 | { | 3097 | { |
2797 | struct qla_tgt_sess *sess = cmd->sess; | 3098 | struct qla_tgt_sess *sess = cmd->sess; |
@@ -3015,7 +3316,7 @@ qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) | |||
3015 | dump_stack(); | 3316 | dump_stack(); |
3016 | } | 3317 | } |
3017 | 3318 | ||
3018 | cmd->cmd_flags |= BIT_12; | 3319 | cmd->cmd_flags |= BIT_17; |
3019 | ha->tgt.tgt_ops->free_cmd(cmd); | 3320 | ha->tgt.tgt_ops->free_cmd(cmd); |
3020 | } | 3321 | } |
3021 | 3322 | ||
@@ -3177,7 +3478,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, | |||
3177 | skip_term: | 3478 | skip_term: |
3178 | 3479 | ||
3179 | if (cmd->state == QLA_TGT_STATE_PROCESSED) { | 3480 | if (cmd->state == QLA_TGT_STATE_PROCESSED) { |
3180 | ; | 3481 | cmd->cmd_flags |= BIT_12; |
3181 | } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) { | 3482 | } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) { |
3182 | int rx_status = 0; | 3483 | int rx_status = 0; |
3183 | 3484 | ||
@@ -3191,9 +3492,11 @@ skip_term: | |||
3191 | ha->tgt.tgt_ops->handle_data(cmd); | 3492 | ha->tgt.tgt_ops->handle_data(cmd); |
3192 | return; | 3493 | return; |
3193 | } else if (cmd->state == QLA_TGT_STATE_ABORTED) { | 3494 | } else if (cmd->state == QLA_TGT_STATE_ABORTED) { |
3495 | cmd->cmd_flags |= BIT_18; | ||
3194 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e, | 3496 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e, |
3195 | "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag); | 3497 | "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag); |
3196 | } else { | 3498 | } else { |
3499 | cmd->cmd_flags |= BIT_19; | ||
3197 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c, | 3500 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c, |
3198 | "qla_target(%d): A command in state (%d) should " | 3501 | "qla_target(%d): A command in state (%d) should " |
3199 | "not return a CTIO complete\n", vha->vp_idx, cmd->state); | 3502 | "not return a CTIO complete\n", vha->vp_idx, cmd->state); |
@@ -3205,7 +3508,6 @@ skip_term: | |||
3205 | dump_stack(); | 3508 | dump_stack(); |
3206 | } | 3509 | } |
3207 | 3510 | ||
3208 | |||
3209 | ha->tgt.tgt_ops->free_cmd(cmd); | 3511 | ha->tgt.tgt_ops->free_cmd(cmd); |
3210 | } | 3512 | } |
3211 | 3513 | ||
@@ -3263,6 +3565,13 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) | |||
3263 | if (tgt->tgt_stop) | 3565 | if (tgt->tgt_stop) |
3264 | goto out_term; | 3566 | goto out_term; |
3265 | 3567 | ||
3568 | if (cmd->state == QLA_TGT_STATE_ABORTED) { | ||
3569 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082, | ||
3570 | "cmd with tag %u is aborted\n", | ||
3571 | cmd->atio.u.isp24.exchange_addr); | ||
3572 | goto out_term; | ||
3573 | } | ||
3574 | |||
3266 | cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; | 3575 | cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; |
3267 | cmd->se_cmd.tag = atio->u.isp24.exchange_addr; | 3576 | cmd->se_cmd.tag = atio->u.isp24.exchange_addr; |
3268 | cmd->unpacked_lun = scsilun_to_int( | 3577 | cmd->unpacked_lun = scsilun_to_int( |
@@ -3316,6 +3625,12 @@ out_term: | |||
3316 | static void qlt_do_work(struct work_struct *work) | 3625 | static void qlt_do_work(struct work_struct *work) |
3317 | { | 3626 | { |
3318 | struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); | 3627 | struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); |
3628 | scsi_qla_host_t *vha = cmd->vha; | ||
3629 | unsigned long flags; | ||
3630 | |||
3631 | spin_lock_irqsave(&vha->cmd_list_lock, flags); | ||
3632 | list_del(&cmd->cmd_list); | ||
3633 | spin_unlock_irqrestore(&vha->cmd_list_lock, flags); | ||
3319 | 3634 | ||
3320 | __qlt_do_work(cmd); | 3635 | __qlt_do_work(cmd); |
3321 | } | 3636 | } |
@@ -3345,6 +3660,11 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, | |||
3345 | cmd->loop_id = sess->loop_id; | 3660 | cmd->loop_id = sess->loop_id; |
3346 | cmd->conf_compl_supported = sess->conf_compl_supported; | 3661 | cmd->conf_compl_supported = sess->conf_compl_supported; |
3347 | 3662 | ||
3663 | cmd->cmd_flags = 0; | ||
3664 | cmd->jiffies_at_alloc = get_jiffies_64(); | ||
3665 | |||
3666 | cmd->reset_count = vha->hw->chip_reset; | ||
3667 | |||
3348 | return cmd; | 3668 | return cmd; |
3349 | } | 3669 | } |
3350 | 3670 | ||
@@ -3362,14 +3682,25 @@ static void qlt_create_sess_from_atio(struct work_struct *work) | |||
3362 | unsigned long flags; | 3682 | unsigned long flags; |
3363 | uint8_t *s_id = op->atio.u.isp24.fcp_hdr.s_id; | 3683 | uint8_t *s_id = op->atio.u.isp24.fcp_hdr.s_id; |
3364 | 3684 | ||
3685 | spin_lock_irqsave(&vha->cmd_list_lock, flags); | ||
3686 | list_del(&op->cmd_list); | ||
3687 | spin_unlock_irqrestore(&vha->cmd_list_lock, flags); | ||
3688 | |||
3689 | if (op->aborted) { | ||
3690 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf083, | ||
3691 | "sess_op with tag %u is aborted\n", | ||
3692 | op->atio.u.isp24.exchange_addr); | ||
3693 | goto out_term; | ||
3694 | } | ||
3695 | |||
3365 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022, | 3696 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022, |
3366 | "qla_target(%d): Unable to find wwn login" | 3697 | "qla_target(%d): Unable to find wwn login" |
3367 | " (s_id %x:%x:%x), trying to create it manually\n", | 3698 | " (s_id %x:%x:%x), trying to create it manually\n", |
3368 | vha->vp_idx, s_id[0], s_id[1], s_id[2]); | 3699 | vha->vp_idx, s_id[0], s_id[1], s_id[2]); |
3369 | 3700 | ||
3370 | if (op->atio.u.raw.entry_count > 1) { | 3701 | if (op->atio.u.raw.entry_count > 1) { |
3371 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023, | 3702 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023, |
3372 | "Dropping multy entry atio %p\n", &op->atio); | 3703 | "Dropping multy entry atio %p\n", &op->atio); |
3373 | goto out_term; | 3704 | goto out_term; |
3374 | } | 3705 | } |
3375 | 3706 | ||
@@ -3434,10 +3765,25 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, | |||
3434 | 3765 | ||
3435 | memcpy(&op->atio, atio, sizeof(*atio)); | 3766 | memcpy(&op->atio, atio, sizeof(*atio)); |
3436 | op->vha = vha; | 3767 | op->vha = vha; |
3768 | |||
3769 | spin_lock(&vha->cmd_list_lock); | ||
3770 | list_add_tail(&op->cmd_list, &vha->qla_sess_op_cmd_list); | ||
3771 | spin_unlock(&vha->cmd_list_lock); | ||
3772 | |||
3437 | INIT_WORK(&op->work, qlt_create_sess_from_atio); | 3773 | INIT_WORK(&op->work, qlt_create_sess_from_atio); |
3438 | queue_work(qla_tgt_wq, &op->work); | 3774 | queue_work(qla_tgt_wq, &op->work); |
3439 | return 0; | 3775 | return 0; |
3440 | } | 3776 | } |
3777 | |||
3778 | /* Another WWN used to have our s_id. Our PLOGI scheduled its | ||
3779 | * session deletion, but it's still in sess_del_work wq */ | ||
3780 | if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { | ||
3781 | ql_dbg(ql_dbg_io, vha, 0x3061, | ||
3782 | "New command while old session %p is being deleted\n", | ||
3783 | sess); | ||
3784 | return -EFAULT; | ||
3785 | } | ||
3786 | |||
3441 | /* | 3787 | /* |
3442 | * Do kref_get() before returning + dropping qla_hw_data->hardware_lock. | 3788 | * Do kref_get() before returning + dropping qla_hw_data->hardware_lock. |
3443 | */ | 3789 | */ |
@@ -3451,13 +3797,13 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, | |||
3451 | return -ENOMEM; | 3797 | return -ENOMEM; |
3452 | } | 3798 | } |
3453 | 3799 | ||
3454 | cmd->cmd_flags = 0; | ||
3455 | cmd->jiffies_at_alloc = get_jiffies_64(); | ||
3456 | |||
3457 | cmd->reset_count = vha->hw->chip_reset; | ||
3458 | |||
3459 | cmd->cmd_in_wq = 1; | 3800 | cmd->cmd_in_wq = 1; |
3460 | cmd->cmd_flags |= BIT_0; | 3801 | cmd->cmd_flags |= BIT_0; |
3802 | |||
3803 | spin_lock(&vha->cmd_list_lock); | ||
3804 | list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list); | ||
3805 | spin_unlock(&vha->cmd_list_lock); | ||
3806 | |||
3461 | INIT_WORK(&cmd->work, qlt_do_work); | 3807 | INIT_WORK(&cmd->work, qlt_do_work); |
3462 | queue_work(qla_tgt_wq, &cmd->work); | 3808 | queue_work(qla_tgt_wq, &cmd->work); |
3463 | return 0; | 3809 | return 0; |
@@ -3471,6 +3817,7 @@ static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun, | |||
3471 | struct scsi_qla_host *vha = sess->vha; | 3817 | struct scsi_qla_host *vha = sess->vha; |
3472 | struct qla_hw_data *ha = vha->hw; | 3818 | struct qla_hw_data *ha = vha->hw; |
3473 | struct qla_tgt_mgmt_cmd *mcmd; | 3819 | struct qla_tgt_mgmt_cmd *mcmd; |
3820 | struct atio_from_isp *a = (struct atio_from_isp *)iocb; | ||
3474 | int res; | 3821 | int res; |
3475 | uint8_t tmr_func; | 3822 | uint8_t tmr_func; |
3476 | 3823 | ||
@@ -3511,6 +3858,7 @@ static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun, | |||
3511 | ql_dbg(ql_dbg_tgt_tmr, vha, 0x10002, | 3858 | ql_dbg(ql_dbg_tgt_tmr, vha, 0x10002, |
3512 | "qla_target(%d): LUN_RESET received\n", sess->vha->vp_idx); | 3859 | "qla_target(%d): LUN_RESET received\n", sess->vha->vp_idx); |
3513 | tmr_func = TMR_LUN_RESET; | 3860 | tmr_func = TMR_LUN_RESET; |
3861 | abort_cmds_for_lun(vha, lun, a->u.isp24.fcp_hdr.s_id); | ||
3514 | break; | 3862 | break; |
3515 | 3863 | ||
3516 | case QLA_TGT_CLEAR_TS: | 3864 | case QLA_TGT_CLEAR_TS: |
@@ -3599,6 +3947,9 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb) | |||
3599 | sizeof(struct atio_from_isp)); | 3947 | sizeof(struct atio_from_isp)); |
3600 | } | 3948 | } |
3601 | 3949 | ||
3950 | if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) | ||
3951 | return -EFAULT; | ||
3952 | |||
3602 | return qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); | 3953 | return qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); |
3603 | } | 3954 | } |
3604 | 3955 | ||
@@ -3664,22 +4015,280 @@ static int qlt_abort_task(struct scsi_qla_host *vha, | |||
3664 | return __qlt_abort_task(vha, iocb, sess); | 4015 | return __qlt_abort_task(vha, iocb, sess); |
3665 | } | 4016 | } |
3666 | 4017 | ||
4018 | void qlt_logo_completion_handler(fc_port_t *fcport, int rc) | ||
4019 | { | ||
4020 | if (fcport->tgt_session) { | ||
4021 | if (rc != MBS_COMMAND_COMPLETE) { | ||
4022 | ql_dbg(ql_dbg_tgt_mgt, fcport->vha, 0xf093, | ||
4023 | "%s: se_sess %p / sess %p from" | ||
4024 | " port %8phC loop_id %#04x s_id %02x:%02x:%02x" | ||
4025 | " LOGO failed: %#x\n", | ||
4026 | __func__, | ||
4027 | fcport->tgt_session->se_sess, | ||
4028 | fcport->tgt_session, | ||
4029 | fcport->port_name, fcport->loop_id, | ||
4030 | fcport->d_id.b.domain, fcport->d_id.b.area, | ||
4031 | fcport->d_id.b.al_pa, rc); | ||
4032 | } | ||
4033 | |||
4034 | fcport->tgt_session->logout_completed = 1; | ||
4035 | } | ||
4036 | } | ||
4037 | |||
4038 | static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a, | ||
4039 | struct imm_ntfy_from_isp *b) | ||
4040 | { | ||
4041 | struct imm_ntfy_from_isp tmp; | ||
4042 | memcpy(&tmp, a, sizeof(struct imm_ntfy_from_isp)); | ||
4043 | memcpy(a, b, sizeof(struct imm_ntfy_from_isp)); | ||
4044 | memcpy(b, &tmp, sizeof(struct imm_ntfy_from_isp)); | ||
4045 | } | ||
4046 | |||
4047 | /* | ||
4048 | * ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list) | ||
4049 | * | ||
4050 | * Schedules sessions with matching port_id/loop_id but different wwn for | ||
4051 | * deletion. Returns existing session with matching wwn if present. | ||
4052 | * Null otherwise. | ||
4053 | */ | ||
4054 | static struct qla_tgt_sess * | ||
4055 | qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn, | ||
4056 | port_id_t port_id, uint16_t loop_id) | ||
4057 | { | ||
4058 | struct qla_tgt_sess *sess = NULL, *other_sess; | ||
4059 | uint64_t other_wwn; | ||
4060 | |||
4061 | list_for_each_entry(other_sess, &tgt->sess_list, sess_list_entry) { | ||
4062 | |||
4063 | other_wwn = wwn_to_u64(other_sess->port_name); | ||
4064 | |||
4065 | if (wwn == other_wwn) { | ||
4066 | WARN_ON(sess); | ||
4067 | sess = other_sess; | ||
4068 | continue; | ||
4069 | } | ||
4070 | |||
4071 | /* find other sess with nport_id collision */ | ||
4072 | if (port_id.b24 == other_sess->s_id.b24) { | ||
4073 | if (loop_id != other_sess->loop_id) { | ||
4074 | ql_dbg(ql_dbg_tgt_tmr, tgt->vha, 0x1000c, | ||
4075 | "Invalidating sess %p loop_id %d wwn %llx.\n", | ||
4076 | other_sess, other_sess->loop_id, other_wwn); | ||
4077 | |||
4078 | /* | ||
4079 | * logout_on_delete is set by default, but another | ||
4080 | * session that has the same s_id/loop_id combo | ||
4081 | * might have cleared it when requested this session | ||
4082 | * deletion, so don't touch it | ||
4083 | */ | ||
4084 | qlt_schedule_sess_for_deletion(other_sess, true); | ||
4085 | } else { | ||
4086 | /* | ||
4087 | * Another wwn used to have our s_id/loop_id | ||
4088 | * combo - kill the session, but don't log out | ||
4089 | */ | ||
4090 | sess->logout_on_delete = 0; | ||
4091 | qlt_schedule_sess_for_deletion(other_sess, | ||
4092 | true); | ||
4093 | } | ||
4094 | continue; | ||
4095 | } | ||
4096 | |||
4097 | /* find other sess with nport handle collision */ | ||
4098 | if (loop_id == other_sess->loop_id) { | ||
4099 | ql_dbg(ql_dbg_tgt_tmr, tgt->vha, 0x1000d, | ||
4100 | "Invalidating sess %p loop_id %d wwn %llx.\n", | ||
4101 | other_sess, other_sess->loop_id, other_wwn); | ||
4102 | |||
4103 | /* Same loop_id but different s_id | ||
4104 | * Ok to kill and logout */ | ||
4105 | qlt_schedule_sess_for_deletion(other_sess, true); | ||
4106 | } | ||
4107 | } | ||
4108 | |||
4109 | return sess; | ||
4110 | } | ||
4111 | |||
4112 | /* Abort any commands for this s_id waiting on qla_tgt_wq workqueue */ | ||
4113 | static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id) | ||
4114 | { | ||
4115 | struct qla_tgt_sess_op *op; | ||
4116 | struct qla_tgt_cmd *cmd; | ||
4117 | uint32_t key; | ||
4118 | int count = 0; | ||
4119 | |||
4120 | key = (((u32)s_id->b.domain << 16) | | ||
4121 | ((u32)s_id->b.area << 8) | | ||
4122 | ((u32)s_id->b.al_pa)); | ||
4123 | |||
4124 | spin_lock(&vha->cmd_list_lock); | ||
4125 | list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) { | ||
4126 | uint32_t op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id); | ||
4127 | if (op_key == key) { | ||
4128 | op->aborted = true; | ||
4129 | count++; | ||
4130 | } | ||
4131 | } | ||
4132 | list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) { | ||
4133 | uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id); | ||
4134 | if (cmd_key == key) { | ||
4135 | cmd->state = QLA_TGT_STATE_ABORTED; | ||
4136 | count++; | ||
4137 | } | ||
4138 | } | ||
4139 | spin_unlock(&vha->cmd_list_lock); | ||
4140 | |||
4141 | return count; | ||
4142 | } | ||
4143 | |||
3667 | /* | 4144 | /* |
3668 | * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire | 4145 | * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire |
3669 | */ | 4146 | */ |
3670 | static int qlt_24xx_handle_els(struct scsi_qla_host *vha, | 4147 | static int qlt_24xx_handle_els(struct scsi_qla_host *vha, |
3671 | struct imm_ntfy_from_isp *iocb) | 4148 | struct imm_ntfy_from_isp *iocb) |
3672 | { | 4149 | { |
4150 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; | ||
4151 | struct qla_hw_data *ha = vha->hw; | ||
4152 | struct qla_tgt_sess *sess = NULL; | ||
4153 | uint64_t wwn; | ||
4154 | port_id_t port_id; | ||
4155 | uint16_t loop_id; | ||
4156 | uint16_t wd3_lo; | ||
3673 | int res = 0; | 4157 | int res = 0; |
3674 | 4158 | ||
4159 | wwn = wwn_to_u64(iocb->u.isp24.port_name); | ||
4160 | |||
4161 | port_id.b.domain = iocb->u.isp24.port_id[2]; | ||
4162 | port_id.b.area = iocb->u.isp24.port_id[1]; | ||
4163 | port_id.b.al_pa = iocb->u.isp24.port_id[0]; | ||
4164 | port_id.b.rsvd_1 = 0; | ||
4165 | |||
4166 | loop_id = le16_to_cpu(iocb->u.isp24.nport_handle); | ||
4167 | |||
3675 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf026, | 4168 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf026, |
3676 | "qla_target(%d): Port ID: 0x%3phC ELS opcode: 0x%02x\n", | 4169 | "qla_target(%d): Port ID: 0x%3phC ELS opcode: 0x%02x\n", |
3677 | vha->vp_idx, iocb->u.isp24.port_id, iocb->u.isp24.status_subcode); | 4170 | vha->vp_idx, iocb->u.isp24.port_id, iocb->u.isp24.status_subcode); |
3678 | 4171 | ||
4172 | /* res = 1 means ack at the end of thread | ||
4173 | * res = 0 means ack async/later. | ||
4174 | */ | ||
3679 | switch (iocb->u.isp24.status_subcode) { | 4175 | switch (iocb->u.isp24.status_subcode) { |
3680 | case ELS_PLOGI: | 4176 | case ELS_PLOGI: |
3681 | case ELS_FLOGI: | 4177 | |
4178 | /* Mark all stale commands in qla_tgt_wq for deletion */ | ||
4179 | abort_cmds_for_s_id(vha, &port_id); | ||
4180 | |||
4181 | if (wwn) | ||
4182 | sess = qlt_find_sess_invalidate_other(tgt, wwn, | ||
4183 | port_id, loop_id); | ||
4184 | |||
4185 | if (!sess || IS_SW_RESV_ADDR(sess->s_id)) { | ||
4186 | res = 1; | ||
4187 | break; | ||
4188 | } | ||
4189 | |||
4190 | if (sess->plogi_ack_needed) { | ||
4191 | /* | ||
4192 | * Initiator sent another PLOGI before last PLOGI could | ||
4193 | * finish. Swap plogi iocbs and terminate old one | ||
4194 | * without acking, new one will get acked when session | ||
4195 | * deletion completes. | ||
4196 | */ | ||
4197 | ql_log(ql_log_warn, sess->vha, 0xf094, | ||
4198 | "sess %p received double plogi.\n", sess); | ||
4199 | |||
4200 | qlt_swap_imm_ntfy_iocb(iocb, &sess->tm_iocb); | ||
4201 | |||
4202 | qlt_send_term_imm_notif(vha, iocb, 1); | ||
4203 | |||
4204 | res = 0; | ||
4205 | break; | ||
4206 | } | ||
4207 | |||
4208 | res = 0; | ||
4209 | |||
4210 | /* | ||
4211 | * Save immediate Notif IOCB for Ack when sess is done | ||
4212 | * and being deleted. | ||
4213 | */ | ||
4214 | memcpy(&sess->tm_iocb, iocb, sizeof(sess->tm_iocb)); | ||
4215 | sess->plogi_ack_needed = 1; | ||
4216 | |||
4217 | /* | ||
4218 | * Under normal circumstances we want to release nport handle | ||
4219 | * during LOGO process to avoid nport handle leaks inside FW. | ||
4220 | * The exception is when LOGO is done while another PLOGI with | ||
4221 | * the same nport handle is waiting as might be the case here. | ||
4222 | * Note: there is always a possibily of a race where session | ||
4223 | * deletion has already started for other reasons (e.g. ACL | ||
4224 | * removal) and now PLOGI arrives: | ||
4225 | * 1. if PLOGI arrived in FW after nport handle has been freed, | ||
4226 | * FW must have assigned this PLOGI a new/same handle and we | ||
4227 | * can proceed ACK'ing it as usual when session deletion | ||
4228 | * completes. | ||
4229 | * 2. if PLOGI arrived in FW before LOGO with LCF_FREE_NPORT | ||
4230 | * bit reached it, the handle has now been released. We'll | ||
4231 | * get an error when we ACK this PLOGI. Nothing will be sent | ||
4232 | * back to initiator. Initiator should eventually retry | ||
4233 | * PLOGI and situation will correct itself. | ||
4234 | */ | ||
4235 | sess->keep_nport_handle = ((sess->loop_id == loop_id) && | ||
4236 | (sess->s_id.b24 == port_id.b24)); | ||
4237 | qlt_schedule_sess_for_deletion(sess, true); | ||
4238 | break; | ||
4239 | |||
3682 | case ELS_PRLI: | 4240 | case ELS_PRLI: |
4241 | wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo); | ||
4242 | |||
4243 | if (wwn) | ||
4244 | sess = qlt_find_sess_invalidate_other(tgt, wwn, port_id, | ||
4245 | loop_id); | ||
4246 | |||
4247 | if (sess != NULL) { | ||
4248 | if (sess->deleted) { | ||
4249 | /* | ||
4250 | * Impatient initiator sent PRLI before last | ||
4251 | * PLOGI could finish. Will force him to re-try, | ||
4252 | * while last one finishes. | ||
4253 | */ | ||
4254 | ql_log(ql_log_warn, sess->vha, 0xf095, | ||
4255 | "sess %p PRLI received, before plogi ack.\n", | ||
4256 | sess); | ||
4257 | qlt_send_term_imm_notif(vha, iocb, 1); | ||
4258 | res = 0; | ||
4259 | break; | ||
4260 | } | ||
4261 | |||
4262 | /* | ||
4263 | * This shouldn't happen under normal circumstances, | ||
4264 | * since we have deleted the old session during PLOGI | ||
4265 | */ | ||
4266 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf096, | ||
4267 | "PRLI (loop_id %#04x) for existing sess %p (loop_id %#04x)\n", | ||
4268 | sess->loop_id, sess, iocb->u.isp24.nport_handle); | ||
4269 | |||
4270 | sess->local = 0; | ||
4271 | sess->loop_id = loop_id; | ||
4272 | sess->s_id = port_id; | ||
4273 | |||
4274 | if (wd3_lo & BIT_7) | ||
4275 | sess->conf_compl_supported = 1; | ||
4276 | |||
4277 | } | ||
4278 | res = 1; /* send notify ack */ | ||
4279 | |||
4280 | /* Make session global (not used in fabric mode) */ | ||
4281 | if (ha->current_topology != ISP_CFG_F) { | ||
4282 | set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); | ||
4283 | set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); | ||
4284 | qla2xxx_wake_dpc(vha); | ||
4285 | } else { | ||
4286 | /* todo: else - create sess here. */ | ||
4287 | res = 1; /* send notify ack */ | ||
4288 | } | ||
4289 | |||
4290 | break; | ||
4291 | |||
3683 | case ELS_LOGO: | 4292 | case ELS_LOGO: |
3684 | case ELS_PRLO: | 4293 | case ELS_PRLO: |
3685 | res = qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS); | 4294 | res = qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS); |
@@ -3697,6 +4306,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, | |||
3697 | break; | 4306 | break; |
3698 | } | 4307 | } |
3699 | 4308 | ||
4309 | case ELS_FLOGI: /* should never happen */ | ||
3700 | default: | 4310 | default: |
3701 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf061, | 4311 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf061, |
3702 | "qla_target(%d): Unsupported ELS command %x " | 4312 | "qla_target(%d): Unsupported ELS command %x " |
@@ -5012,6 +5622,11 @@ static void qlt_abort_work(struct qla_tgt *tgt, | |||
5012 | if (!sess) | 5622 | if (!sess) |
5013 | goto out_term; | 5623 | goto out_term; |
5014 | } else { | 5624 | } else { |
5625 | if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { | ||
5626 | sess = NULL; | ||
5627 | goto out_term; | ||
5628 | } | ||
5629 | |||
5015 | kref_get(&sess->se_sess->sess_kref); | 5630 | kref_get(&sess->se_sess->sess_kref); |
5016 | } | 5631 | } |
5017 | 5632 | ||
@@ -5066,6 +5681,11 @@ static void qlt_tmr_work(struct qla_tgt *tgt, | |||
5066 | if (!sess) | 5681 | if (!sess) |
5067 | goto out_term; | 5682 | goto out_term; |
5068 | } else { | 5683 | } else { |
5684 | if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { | ||
5685 | sess = NULL; | ||
5686 | goto out_term; | ||
5687 | } | ||
5688 | |||
5069 | kref_get(&sess->se_sess->sess_kref); | 5689 | kref_get(&sess->se_sess->sess_kref); |
5070 | } | 5690 | } |
5071 | 5691 | ||
@@ -5552,6 +6172,7 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha) | |||
5552 | 6172 | ||
5553 | /* Adjust ring index */ | 6173 | /* Adjust ring index */ |
5554 | WRT_REG_DWORD(ISP_ATIO_Q_OUT(vha), ha->tgt.atio_ring_index); | 6174 | WRT_REG_DWORD(ISP_ATIO_Q_OUT(vha), ha->tgt.atio_ring_index); |
6175 | RD_REG_DWORD_RELAXED(ISP_ATIO_Q_OUT(vha)); | ||
5555 | } | 6176 | } |
5556 | 6177 | ||
5557 | void | 6178 | void |
@@ -5793,7 +6414,7 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha) | |||
5793 | if (!QLA_TGT_MODE_ENABLED()) | 6414 | if (!QLA_TGT_MODE_ENABLED()) |
5794 | return; | 6415 | return; |
5795 | 6416 | ||
5796 | if (ha->mqenable || IS_QLA83XX(ha)) { | 6417 | if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) { |
5797 | ISP_ATIO_Q_IN(base_vha) = &ha->mqiobase->isp25mq.atio_q_in; | 6418 | ISP_ATIO_Q_IN(base_vha) = &ha->mqiobase->isp25mq.atio_q_in; |
5798 | ISP_ATIO_Q_OUT(base_vha) = &ha->mqiobase->isp25mq.atio_q_out; | 6419 | ISP_ATIO_Q_OUT(base_vha) = &ha->mqiobase->isp25mq.atio_q_out; |
5799 | } else { | 6420 | } else { |
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 985d76dd706b..bca584ae45b7 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h | |||
@@ -167,7 +167,24 @@ struct imm_ntfy_from_isp { | |||
167 | uint32_t srr_rel_offs; | 167 | uint32_t srr_rel_offs; |
168 | uint16_t srr_ui; | 168 | uint16_t srr_ui; |
169 | uint16_t srr_ox_id; | 169 | uint16_t srr_ox_id; |
170 | uint8_t reserved_4[19]; | 170 | union { |
171 | struct { | ||
172 | uint8_t node_name[8]; | ||
173 | } plogi; /* PLOGI/ADISC/PDISC */ | ||
174 | struct { | ||
175 | /* PRLI word 3 bit 0-15 */ | ||
176 | uint16_t wd3_lo; | ||
177 | uint8_t resv0[6]; | ||
178 | } prli; | ||
179 | struct { | ||
180 | uint8_t port_id[3]; | ||
181 | uint8_t resv1; | ||
182 | uint16_t nport_handle; | ||
183 | uint16_t resv2; | ||
184 | } req_els; | ||
185 | } u; | ||
186 | uint8_t port_name[8]; | ||
187 | uint8_t resv3[3]; | ||
171 | uint8_t vp_index; | 188 | uint8_t vp_index; |
172 | uint32_t reserved_5; | 189 | uint32_t reserved_5; |
173 | uint8_t port_id[3]; | 190 | uint8_t port_id[3]; |
@@ -234,6 +251,7 @@ struct nack_to_isp { | |||
234 | uint8_t reserved[2]; | 251 | uint8_t reserved[2]; |
235 | uint16_t ox_id; | 252 | uint16_t ox_id; |
236 | } __packed; | 253 | } __packed; |
254 | #define NOTIFY_ACK_FLAGS_TERMINATE BIT_3 | ||
237 | #define NOTIFY_ACK_SRR_FLAGS_ACCEPT 0 | 255 | #define NOTIFY_ACK_SRR_FLAGS_ACCEPT 0 |
238 | #define NOTIFY_ACK_SRR_FLAGS_REJECT 1 | 256 | #define NOTIFY_ACK_SRR_FLAGS_REJECT 1 |
239 | 257 | ||
@@ -790,13 +808,6 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *); | |||
790 | #define FC_TM_REJECT 4 | 808 | #define FC_TM_REJECT 4 |
791 | #define FC_TM_FAILED 5 | 809 | #define FC_TM_FAILED 5 |
792 | 810 | ||
793 | /* | ||
794 | * Error code of qlt_pre_xmit_response() meaning that cmd's exchange was | ||
795 | * terminated, so no more actions is needed and success should be returned | ||
796 | * to target. | ||
797 | */ | ||
798 | #define QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED 0x1717 | ||
799 | |||
800 | #if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G) | 811 | #if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G) |
801 | #define pci_dma_lo32(a) (a & 0xffffffff) | 812 | #define pci_dma_lo32(a) (a & 0xffffffff) |
802 | #define pci_dma_hi32(a) ((((a) >> 16)>>16) & 0xffffffff) | 813 | #define pci_dma_hi32(a) ((((a) >> 16)>>16) & 0xffffffff) |
@@ -874,6 +885,15 @@ struct qla_tgt_sess_op { | |||
874 | struct scsi_qla_host *vha; | 885 | struct scsi_qla_host *vha; |
875 | struct atio_from_isp atio; | 886 | struct atio_from_isp atio; |
876 | struct work_struct work; | 887 | struct work_struct work; |
888 | struct list_head cmd_list; | ||
889 | bool aborted; | ||
890 | }; | ||
891 | |||
892 | enum qla_sess_deletion { | ||
893 | QLA_SESS_DELETION_NONE = 0, | ||
894 | QLA_SESS_DELETION_PENDING = 1, /* hopefully we can get rid of | ||
895 | * this one */ | ||
896 | QLA_SESS_DELETION_IN_PROGRESS = 2, | ||
877 | }; | 897 | }; |
878 | 898 | ||
879 | /* | 899 | /* |
@@ -884,8 +904,15 @@ struct qla_tgt_sess { | |||
884 | port_id_t s_id; | 904 | port_id_t s_id; |
885 | 905 | ||
886 | unsigned int conf_compl_supported:1; | 906 | unsigned int conf_compl_supported:1; |
887 | unsigned int deleted:1; | 907 | unsigned int deleted:2; |
888 | unsigned int local:1; | 908 | unsigned int local:1; |
909 | unsigned int logout_on_delete:1; | ||
910 | unsigned int plogi_ack_needed:1; | ||
911 | unsigned int keep_nport_handle:1; | ||
912 | |||
913 | unsigned char logout_completed; | ||
914 | |||
915 | int generation; | ||
889 | 916 | ||
890 | struct se_session *se_sess; | 917 | struct se_session *se_sess; |
891 | struct scsi_qla_host *vha; | 918 | struct scsi_qla_host *vha; |
@@ -897,6 +924,10 @@ struct qla_tgt_sess { | |||
897 | 924 | ||
898 | uint8_t port_name[WWN_SIZE]; | 925 | uint8_t port_name[WWN_SIZE]; |
899 | struct work_struct free_work; | 926 | struct work_struct free_work; |
927 | |||
928 | union { | ||
929 | struct imm_ntfy_from_isp tm_iocb; | ||
930 | }; | ||
900 | }; | 931 | }; |
901 | 932 | ||
902 | struct qla_tgt_cmd { | 933 | struct qla_tgt_cmd { |
@@ -912,7 +943,6 @@ struct qla_tgt_cmd { | |||
912 | unsigned int conf_compl_supported:1; | 943 | unsigned int conf_compl_supported:1; |
913 | unsigned int sg_mapped:1; | 944 | unsigned int sg_mapped:1; |
914 | unsigned int free_sg:1; | 945 | unsigned int free_sg:1; |
915 | unsigned int aborted:1; /* Needed in case of SRR */ | ||
916 | unsigned int write_data_transferred:1; | 946 | unsigned int write_data_transferred:1; |
917 | unsigned int ctx_dsd_alloced:1; | 947 | unsigned int ctx_dsd_alloced:1; |
918 | unsigned int q_full:1; | 948 | unsigned int q_full:1; |
@@ -961,6 +991,9 @@ struct qla_tgt_cmd { | |||
961 | * BIT_14 - Back end data received/sent. | 991 | * BIT_14 - Back end data received/sent. |
962 | * BIT_15 - SRR prepare ctio | 992 | * BIT_15 - SRR prepare ctio |
963 | * BIT_16 - complete free | 993 | * BIT_16 - complete free |
994 | * BIT_17 - flush - qlt_abort_cmd_on_host_reset | ||
995 | * BIT_18 - completion w/abort status | ||
996 | * BIT_19 - completion w/unknown status | ||
964 | */ | 997 | */ |
965 | uint32_t cmd_flags; | 998 | uint32_t cmd_flags; |
966 | }; | 999 | }; |
@@ -1026,6 +1059,10 @@ struct qla_tgt_srr_ctio { | |||
1026 | struct qla_tgt_cmd *cmd; | 1059 | struct qla_tgt_cmd *cmd; |
1027 | }; | 1060 | }; |
1028 | 1061 | ||
1062 | /* Check for Switch reserved address */ | ||
1063 | #define IS_SW_RESV_ADDR(_s_id) \ | ||
1064 | ((_s_id.b.domain == 0xff) && (_s_id.b.area == 0xfc)) | ||
1065 | |||
1029 | #define QLA_TGT_XMIT_DATA 1 | 1066 | #define QLA_TGT_XMIT_DATA 1 |
1030 | #define QLA_TGT_XMIT_STATUS 2 | 1067 | #define QLA_TGT_XMIT_STATUS 2 |
1031 | #define QLA_TGT_XMIT_ALL (QLA_TGT_XMIT_STATUS|QLA_TGT_XMIT_DATA) | 1068 | #define QLA_TGT_XMIT_ALL (QLA_TGT_XMIT_STATUS|QLA_TGT_XMIT_DATA) |
@@ -1043,7 +1080,7 @@ extern int qlt_lport_register(void *, u64, u64, u64, | |||
1043 | extern void qlt_lport_deregister(struct scsi_qla_host *); | 1080 | extern void qlt_lport_deregister(struct scsi_qla_host *); |
1044 | extern void qlt_unreg_sess(struct qla_tgt_sess *); | 1081 | extern void qlt_unreg_sess(struct qla_tgt_sess *); |
1045 | extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *); | 1082 | extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *); |
1046 | extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *); | 1083 | extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *, int); |
1047 | extern int __init qlt_init(void); | 1084 | extern int __init qlt_init(void); |
1048 | extern void qlt_exit(void); | 1085 | extern void qlt_exit(void); |
1049 | extern void qlt_update_vp_map(struct scsi_qla_host *, int); | 1086 | extern void qlt_update_vp_map(struct scsi_qla_host *, int); |
@@ -1073,12 +1110,23 @@ static inline void qla_reverse_ini_mode(struct scsi_qla_host *ha) | |||
1073 | ha->host->active_mode |= MODE_INITIATOR; | 1110 | ha->host->active_mode |= MODE_INITIATOR; |
1074 | } | 1111 | } |
1075 | 1112 | ||
1113 | static inline uint32_t sid_to_key(const uint8_t *s_id) | ||
1114 | { | ||
1115 | uint32_t key; | ||
1116 | |||
1117 | key = (((unsigned long)s_id[0] << 16) | | ||
1118 | ((unsigned long)s_id[1] << 8) | | ||
1119 | (unsigned long)s_id[2]); | ||
1120 | return key; | ||
1121 | } | ||
1122 | |||
1076 | /* | 1123 | /* |
1077 | * Exported symbols from qla_target.c LLD logic used by qla2xxx code.. | 1124 | * Exported symbols from qla_target.c LLD logic used by qla2xxx code.. |
1078 | */ | 1125 | */ |
1079 | extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *); | 1126 | extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *); |
1080 | extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *); | 1127 | extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *); |
1081 | extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t); | 1128 | extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t); |
1129 | extern void qlt_abort_cmd(struct qla_tgt_cmd *); | ||
1082 | extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *); | 1130 | extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *); |
1083 | extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *); | 1131 | extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *); |
1084 | extern void qlt_free_cmd(struct qla_tgt_cmd *cmd); | 1132 | extern void qlt_free_cmd(struct qla_tgt_cmd *cmd); |
@@ -1109,5 +1157,7 @@ extern void qlt_stop_phase2(struct qla_tgt *); | |||
1109 | extern irqreturn_t qla83xx_msix_atio_q(int, void *); | 1157 | extern irqreturn_t qla83xx_msix_atio_q(int, void *); |
1110 | extern void qlt_83xx_iospace_config(struct qla_hw_data *); | 1158 | extern void qlt_83xx_iospace_config(struct qla_hw_data *); |
1111 | extern int qlt_free_qfull_cmds(struct scsi_qla_host *); | 1159 | extern int qlt_free_qfull_cmds(struct scsi_qla_host *); |
1160 | extern void qlt_logo_completion_handler(fc_port_t *, int); | ||
1161 | extern void qlt_do_generation_tick(struct scsi_qla_host *, int *); | ||
1112 | 1162 | ||
1113 | #endif /* __QLA_TARGET_H */ | 1163 | #endif /* __QLA_TARGET_H */ |
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index d9a8c6084346..9224a06646e6 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c | |||
@@ -374,7 +374,7 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd) | |||
374 | { | 374 | { |
375 | struct qla_tgt_cmd *cmd = container_of(se_cmd, | 375 | struct qla_tgt_cmd *cmd = container_of(se_cmd, |
376 | struct qla_tgt_cmd, se_cmd); | 376 | struct qla_tgt_cmd, se_cmd); |
377 | 377 | cmd->cmd_flags |= BIT_3; | |
378 | cmd->bufflen = se_cmd->data_length; | 378 | cmd->bufflen = se_cmd->data_length; |
379 | cmd->dma_data_direction = target_reverse_dma_direction(se_cmd); | 379 | cmd->dma_data_direction = target_reverse_dma_direction(se_cmd); |
380 | 380 | ||
@@ -405,7 +405,7 @@ static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd) | |||
405 | se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) { | 405 | se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) { |
406 | spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); | 406 | spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); |
407 | wait_for_completion_timeout(&se_cmd->t_transport_stop_comp, | 407 | wait_for_completion_timeout(&se_cmd->t_transport_stop_comp, |
408 | 3000); | 408 | 3 * HZ); |
409 | return 0; | 409 | return 0; |
410 | } | 410 | } |
411 | spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); | 411 | spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); |
@@ -541,12 +541,10 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd) | |||
541 | cmd->cmd_flags |= BIT_4; | 541 | cmd->cmd_flags |= BIT_4; |
542 | cmd->bufflen = se_cmd->data_length; | 542 | cmd->bufflen = se_cmd->data_length; |
543 | cmd->dma_data_direction = target_reverse_dma_direction(se_cmd); | 543 | cmd->dma_data_direction = target_reverse_dma_direction(se_cmd); |
544 | cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED); | ||
545 | 544 | ||
546 | cmd->sg_cnt = se_cmd->t_data_nents; | 545 | cmd->sg_cnt = se_cmd->t_data_nents; |
547 | cmd->sg = se_cmd->t_data_sg; | 546 | cmd->sg = se_cmd->t_data_sg; |
548 | cmd->offset = 0; | 547 | cmd->offset = 0; |
549 | cmd->cmd_flags |= BIT_3; | ||
550 | 548 | ||
551 | cmd->prot_sg_cnt = se_cmd->t_prot_nents; | 549 | cmd->prot_sg_cnt = se_cmd->t_prot_nents; |
552 | cmd->prot_sg = se_cmd->t_prot_sg; | 550 | cmd->prot_sg = se_cmd->t_prot_sg; |
@@ -571,7 +569,6 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd) | |||
571 | cmd->sg_cnt = 0; | 569 | cmd->sg_cnt = 0; |
572 | cmd->offset = 0; | 570 | cmd->offset = 0; |
573 | cmd->dma_data_direction = target_reverse_dma_direction(se_cmd); | 571 | cmd->dma_data_direction = target_reverse_dma_direction(se_cmd); |
574 | cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED); | ||
575 | if (cmd->cmd_flags & BIT_5) { | 572 | if (cmd->cmd_flags & BIT_5) { |
576 | pr_crit("Bit_5 already set for cmd = %p.\n", cmd); | 573 | pr_crit("Bit_5 already set for cmd = %p.\n", cmd); |
577 | dump_stack(); | 574 | dump_stack(); |
@@ -636,14 +633,7 @@ static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd) | |||
636 | { | 633 | { |
637 | struct qla_tgt_cmd *cmd = container_of(se_cmd, | 634 | struct qla_tgt_cmd *cmd = container_of(se_cmd, |
638 | struct qla_tgt_cmd, se_cmd); | 635 | struct qla_tgt_cmd, se_cmd); |
639 | struct scsi_qla_host *vha = cmd->vha; | 636 | qlt_abort_cmd(cmd); |
640 | struct qla_hw_data *ha = vha->hw; | ||
641 | |||
642 | if (!cmd->sg_mapped) | ||
643 | return; | ||
644 | |||
645 | pci_unmap_sg(ha->pdev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction); | ||
646 | cmd->sg_mapped = 0; | ||
647 | } | 637 | } |
648 | 638 | ||
649 | static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *, | 639 | static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *, |
@@ -1149,9 +1139,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id( | |||
1149 | return NULL; | 1139 | return NULL; |
1150 | } | 1140 | } |
1151 | 1141 | ||
1152 | key = (((unsigned long)s_id[0] << 16) | | 1142 | key = sid_to_key(s_id); |
1153 | ((unsigned long)s_id[1] << 8) | | ||
1154 | (unsigned long)s_id[2]); | ||
1155 | pr_debug("find_sess_by_s_id: 0x%06x\n", key); | 1143 | pr_debug("find_sess_by_s_id: 0x%06x\n", key); |
1156 | 1144 | ||
1157 | se_nacl = btree_lookup32(&lport->lport_fcport_map, key); | 1145 | se_nacl = btree_lookup32(&lport->lport_fcport_map, key); |
@@ -1186,9 +1174,7 @@ static void tcm_qla2xxx_set_sess_by_s_id( | |||
1186 | void *slot; | 1174 | void *slot; |
1187 | int rc; | 1175 | int rc; |
1188 | 1176 | ||
1189 | key = (((unsigned long)s_id[0] << 16) | | 1177 | key = sid_to_key(s_id); |
1190 | ((unsigned long)s_id[1] << 8) | | ||
1191 | (unsigned long)s_id[2]); | ||
1192 | pr_debug("set_sess_by_s_id: %06x\n", key); | 1178 | pr_debug("set_sess_by_s_id: %06x\n", key); |
1193 | 1179 | ||
1194 | slot = btree_lookup32(&lport->lport_fcport_map, key); | 1180 | slot = btree_lookup32(&lport->lport_fcport_map, key); |
@@ -1544,6 +1530,10 @@ static void tcm_qla2xxx_update_sess(struct qla_tgt_sess *sess, port_id_t s_id, | |||
1544 | } | 1530 | } |
1545 | 1531 | ||
1546 | sess->conf_compl_supported = conf_compl_supported; | 1532 | sess->conf_compl_supported = conf_compl_supported; |
1533 | |||
1534 | /* Reset logout parameters to default */ | ||
1535 | sess->logout_on_delete = 1; | ||
1536 | sess->keep_nport_handle = 0; | ||
1547 | } | 1537 | } |
1548 | 1538 | ||
1549 | /* | 1539 | /* |
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 4e68b62193ed..cd77a064c772 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -3998,7 +3998,13 @@ get_immediate: | |||
3998 | } | 3998 | } |
3999 | 3999 | ||
4000 | transport_err: | 4000 | transport_err: |
4001 | iscsit_take_action_for_connection_exit(conn); | 4001 | /* |
4002 | * Avoid the normal connection failure code-path if this connection | ||
4003 | * is still within LOGIN mode, and iscsi_np process context is | ||
4004 | * responsible for cleaning up the early connection failure. | ||
4005 | */ | ||
4006 | if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN) | ||
4007 | iscsit_take_action_for_connection_exit(conn); | ||
4002 | out: | 4008 | out: |
4003 | return 0; | 4009 | return 0; |
4004 | } | 4010 | } |
@@ -4082,7 +4088,7 @@ reject: | |||
4082 | 4088 | ||
4083 | int iscsi_target_rx_thread(void *arg) | 4089 | int iscsi_target_rx_thread(void *arg) |
4084 | { | 4090 | { |
4085 | int ret; | 4091 | int ret, rc; |
4086 | u8 buffer[ISCSI_HDR_LEN], opcode; | 4092 | u8 buffer[ISCSI_HDR_LEN], opcode; |
4087 | u32 checksum = 0, digest = 0; | 4093 | u32 checksum = 0, digest = 0; |
4088 | struct iscsi_conn *conn = arg; | 4094 | struct iscsi_conn *conn = arg; |
@@ -4092,10 +4098,16 @@ int iscsi_target_rx_thread(void *arg) | |||
4092 | * connection recovery / failure event can be triggered externally. | 4098 | * connection recovery / failure event can be triggered externally. |
4093 | */ | 4099 | */ |
4094 | allow_signal(SIGINT); | 4100 | allow_signal(SIGINT); |
4101 | /* | ||
4102 | * Wait for iscsi_post_login_handler() to complete before allowing | ||
4103 | * incoming iscsi/tcp socket I/O, and/or failing the connection. | ||
4104 | */ | ||
4105 | rc = wait_for_completion_interruptible(&conn->rx_login_comp); | ||
4106 | if (rc < 0) | ||
4107 | return 0; | ||
4095 | 4108 | ||
4096 | if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { | 4109 | if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { |
4097 | struct completion comp; | 4110 | struct completion comp; |
4098 | int rc; | ||
4099 | 4111 | ||
4100 | init_completion(&comp); | 4112 | init_completion(&comp); |
4101 | rc = wait_for_completion_interruptible(&comp); | 4113 | rc = wait_for_completion_interruptible(&comp); |
@@ -4532,7 +4544,18 @@ static void iscsit_logout_post_handler_closesession( | |||
4532 | struct iscsi_conn *conn) | 4544 | struct iscsi_conn *conn) |
4533 | { | 4545 | { |
4534 | struct iscsi_session *sess = conn->sess; | 4546 | struct iscsi_session *sess = conn->sess; |
4535 | int sleep = cmpxchg(&conn->tx_thread_active, true, false); | 4547 | int sleep = 1; |
4548 | /* | ||
4549 | * Traditional iscsi/tcp will invoke this logic from TX thread | ||
4550 | * context during session logout, so clear tx_thread_active and | ||
4551 | * sleep if iscsit_close_connection() has not already occured. | ||
4552 | * | ||
4553 | * Since iser-target invokes this logic from it's own workqueue, | ||
4554 | * always sleep waiting for RX/TX thread shutdown to complete | ||
4555 | * within iscsit_close_connection(). | ||
4556 | */ | ||
4557 | if (conn->conn_transport->transport_type == ISCSI_TCP) | ||
4558 | sleep = cmpxchg(&conn->tx_thread_active, true, false); | ||
4536 | 4559 | ||
4537 | atomic_set(&conn->conn_logout_remove, 0); | 4560 | atomic_set(&conn->conn_logout_remove, 0); |
4538 | complete(&conn->conn_logout_comp); | 4561 | complete(&conn->conn_logout_comp); |
@@ -4546,7 +4569,10 @@ static void iscsit_logout_post_handler_closesession( | |||
4546 | static void iscsit_logout_post_handler_samecid( | 4569 | static void iscsit_logout_post_handler_samecid( |
4547 | struct iscsi_conn *conn) | 4570 | struct iscsi_conn *conn) |
4548 | { | 4571 | { |
4549 | int sleep = cmpxchg(&conn->tx_thread_active, true, false); | 4572 | int sleep = 1; |
4573 | |||
4574 | if (conn->conn_transport->transport_type == ISCSI_TCP) | ||
4575 | sleep = cmpxchg(&conn->tx_thread_active, true, false); | ||
4550 | 4576 | ||
4551 | atomic_set(&conn->conn_logout_remove, 0); | 4577 | atomic_set(&conn->conn_logout_remove, 0); |
4552 | complete(&conn->conn_logout_comp); | 4578 | complete(&conn->conn_logout_comp); |
@@ -4765,6 +4791,7 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force) | |||
4765 | struct iscsi_session *sess; | 4791 | struct iscsi_session *sess; |
4766 | struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; | 4792 | struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; |
4767 | struct se_session *se_sess, *se_sess_tmp; | 4793 | struct se_session *se_sess, *se_sess_tmp; |
4794 | LIST_HEAD(free_list); | ||
4768 | int session_count = 0; | 4795 | int session_count = 0; |
4769 | 4796 | ||
4770 | spin_lock_bh(&se_tpg->session_lock); | 4797 | spin_lock_bh(&se_tpg->session_lock); |
@@ -4786,14 +4813,17 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force) | |||
4786 | } | 4813 | } |
4787 | atomic_set(&sess->session_reinstatement, 1); | 4814 | atomic_set(&sess->session_reinstatement, 1); |
4788 | spin_unlock(&sess->conn_lock); | 4815 | spin_unlock(&sess->conn_lock); |
4789 | spin_unlock_bh(&se_tpg->session_lock); | ||
4790 | 4816 | ||
4791 | iscsit_free_session(sess); | 4817 | list_move_tail(&se_sess->sess_list, &free_list); |
4792 | spin_lock_bh(&se_tpg->session_lock); | 4818 | } |
4819 | spin_unlock_bh(&se_tpg->session_lock); | ||
4820 | |||
4821 | list_for_each_entry_safe(se_sess, se_sess_tmp, &free_list, sess_list) { | ||
4822 | sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; | ||
4793 | 4823 | ||
4824 | iscsit_free_session(sess); | ||
4794 | session_count++; | 4825 | session_count++; |
4795 | } | 4826 | } |
4796 | spin_unlock_bh(&se_tpg->session_lock); | ||
4797 | 4827 | ||
4798 | pr_debug("Released %d iSCSI Session(s) from Target Portal" | 4828 | pr_debug("Released %d iSCSI Session(s) from Target Portal" |
4799 | " Group: %hu\n", session_count, tpg->tpgt); | 4829 | " Group: %hu\n", session_count, tpg->tpgt); |
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 3d0fe4ff5590..7e8f65e5448f 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
@@ -82,6 +82,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn) | |||
82 | init_completion(&conn->conn_logout_comp); | 82 | init_completion(&conn->conn_logout_comp); |
83 | init_completion(&conn->rx_half_close_comp); | 83 | init_completion(&conn->rx_half_close_comp); |
84 | init_completion(&conn->tx_half_close_comp); | 84 | init_completion(&conn->tx_half_close_comp); |
85 | init_completion(&conn->rx_login_comp); | ||
85 | spin_lock_init(&conn->cmd_lock); | 86 | spin_lock_init(&conn->cmd_lock); |
86 | spin_lock_init(&conn->conn_usage_lock); | 87 | spin_lock_init(&conn->conn_usage_lock); |
87 | spin_lock_init(&conn->immed_queue_lock); | 88 | spin_lock_init(&conn->immed_queue_lock); |
@@ -644,7 +645,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn) | |||
644 | iscsit_start_nopin_timer(conn); | 645 | iscsit_start_nopin_timer(conn); |
645 | } | 646 | } |
646 | 647 | ||
647 | static int iscsit_start_kthreads(struct iscsi_conn *conn) | 648 | int iscsit_start_kthreads(struct iscsi_conn *conn) |
648 | { | 649 | { |
649 | int ret = 0; | 650 | int ret = 0; |
650 | 651 | ||
@@ -679,6 +680,7 @@ static int iscsit_start_kthreads(struct iscsi_conn *conn) | |||
679 | 680 | ||
680 | return 0; | 681 | return 0; |
681 | out_tx: | 682 | out_tx: |
683 | send_sig(SIGINT, conn->tx_thread, 1); | ||
682 | kthread_stop(conn->tx_thread); | 684 | kthread_stop(conn->tx_thread); |
683 | conn->tx_thread_active = false; | 685 | conn->tx_thread_active = false; |
684 | out_bitmap: | 686 | out_bitmap: |
@@ -689,7 +691,7 @@ out_bitmap: | |||
689 | return ret; | 691 | return ret; |
690 | } | 692 | } |
691 | 693 | ||
692 | int iscsi_post_login_handler( | 694 | void iscsi_post_login_handler( |
693 | struct iscsi_np *np, | 695 | struct iscsi_np *np, |
694 | struct iscsi_conn *conn, | 696 | struct iscsi_conn *conn, |
695 | u8 zero_tsih) | 697 | u8 zero_tsih) |
@@ -699,7 +701,6 @@ int iscsi_post_login_handler( | |||
699 | struct se_session *se_sess = sess->se_sess; | 701 | struct se_session *se_sess = sess->se_sess; |
700 | struct iscsi_portal_group *tpg = sess->tpg; | 702 | struct iscsi_portal_group *tpg = sess->tpg; |
701 | struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; | 703 | struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; |
702 | int rc; | ||
703 | 704 | ||
704 | iscsit_inc_conn_usage_count(conn); | 705 | iscsit_inc_conn_usage_count(conn); |
705 | 706 | ||
@@ -739,10 +740,6 @@ int iscsi_post_login_handler( | |||
739 | sess->sess_ops->InitiatorName); | 740 | sess->sess_ops->InitiatorName); |
740 | spin_unlock_bh(&sess->conn_lock); | 741 | spin_unlock_bh(&sess->conn_lock); |
741 | 742 | ||
742 | rc = iscsit_start_kthreads(conn); | ||
743 | if (rc) | ||
744 | return rc; | ||
745 | |||
746 | iscsi_post_login_start_timers(conn); | 743 | iscsi_post_login_start_timers(conn); |
747 | /* | 744 | /* |
748 | * Determine CPU mask to ensure connection's RX and TX kthreads | 745 | * Determine CPU mask to ensure connection's RX and TX kthreads |
@@ -751,15 +748,20 @@ int iscsi_post_login_handler( | |||
751 | iscsit_thread_get_cpumask(conn); | 748 | iscsit_thread_get_cpumask(conn); |
752 | conn->conn_rx_reset_cpumask = 1; | 749 | conn->conn_rx_reset_cpumask = 1; |
753 | conn->conn_tx_reset_cpumask = 1; | 750 | conn->conn_tx_reset_cpumask = 1; |
754 | 751 | /* | |
752 | * Wakeup the sleeping iscsi_target_rx_thread() now that | ||
753 | * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state. | ||
754 | */ | ||
755 | complete(&conn->rx_login_comp); | ||
755 | iscsit_dec_conn_usage_count(conn); | 756 | iscsit_dec_conn_usage_count(conn); |
757 | |||
756 | if (stop_timer) { | 758 | if (stop_timer) { |
757 | spin_lock_bh(&se_tpg->session_lock); | 759 | spin_lock_bh(&se_tpg->session_lock); |
758 | iscsit_stop_time2retain_timer(sess); | 760 | iscsit_stop_time2retain_timer(sess); |
759 | spin_unlock_bh(&se_tpg->session_lock); | 761 | spin_unlock_bh(&se_tpg->session_lock); |
760 | } | 762 | } |
761 | iscsit_dec_session_usage_count(sess); | 763 | iscsit_dec_session_usage_count(sess); |
762 | return 0; | 764 | return; |
763 | } | 765 | } |
764 | 766 | ||
765 | iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1); | 767 | iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1); |
@@ -800,10 +802,6 @@ int iscsi_post_login_handler( | |||
800 | " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt); | 802 | " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt); |
801 | spin_unlock_bh(&se_tpg->session_lock); | 803 | spin_unlock_bh(&se_tpg->session_lock); |
802 | 804 | ||
803 | rc = iscsit_start_kthreads(conn); | ||
804 | if (rc) | ||
805 | return rc; | ||
806 | |||
807 | iscsi_post_login_start_timers(conn); | 805 | iscsi_post_login_start_timers(conn); |
808 | /* | 806 | /* |
809 | * Determine CPU mask to ensure connection's RX and TX kthreads | 807 | * Determine CPU mask to ensure connection's RX and TX kthreads |
@@ -812,10 +810,12 @@ int iscsi_post_login_handler( | |||
812 | iscsit_thread_get_cpumask(conn); | 810 | iscsit_thread_get_cpumask(conn); |
813 | conn->conn_rx_reset_cpumask = 1; | 811 | conn->conn_rx_reset_cpumask = 1; |
814 | conn->conn_tx_reset_cpumask = 1; | 812 | conn->conn_tx_reset_cpumask = 1; |
815 | 813 | /* | |
814 | * Wakeup the sleeping iscsi_target_rx_thread() now that | ||
815 | * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state. | ||
816 | */ | ||
817 | complete(&conn->rx_login_comp); | ||
816 | iscsit_dec_conn_usage_count(conn); | 818 | iscsit_dec_conn_usage_count(conn); |
817 | |||
818 | return 0; | ||
819 | } | 819 | } |
820 | 820 | ||
821 | static void iscsi_handle_login_thread_timeout(unsigned long data) | 821 | static void iscsi_handle_login_thread_timeout(unsigned long data) |
@@ -1380,23 +1380,12 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1380 | if (ret < 0) | 1380 | if (ret < 0) |
1381 | goto new_sess_out; | 1381 | goto new_sess_out; |
1382 | 1382 | ||
1383 | if (!conn->sess) { | ||
1384 | pr_err("struct iscsi_conn session pointer is NULL!\n"); | ||
1385 | goto new_sess_out; | ||
1386 | } | ||
1387 | |||
1388 | iscsi_stop_login_thread_timer(np); | 1383 | iscsi_stop_login_thread_timer(np); |
1389 | 1384 | ||
1390 | if (signal_pending(current)) | ||
1391 | goto new_sess_out; | ||
1392 | |||
1393 | if (ret == 1) { | 1385 | if (ret == 1) { |
1394 | tpg_np = conn->tpg_np; | 1386 | tpg_np = conn->tpg_np; |
1395 | 1387 | ||
1396 | ret = iscsi_post_login_handler(np, conn, zero_tsih); | 1388 | iscsi_post_login_handler(np, conn, zero_tsih); |
1397 | if (ret < 0) | ||
1398 | goto new_sess_out; | ||
1399 | |||
1400 | iscsit_deaccess_np(np, tpg, tpg_np); | 1389 | iscsit_deaccess_np(np, tpg, tpg_np); |
1401 | } | 1390 | } |
1402 | 1391 | ||
diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index 1c7358081533..57aa0d0fd820 100644 --- a/drivers/target/iscsi/iscsi_target_login.h +++ b/drivers/target/iscsi/iscsi_target_login.h | |||
@@ -12,7 +12,8 @@ extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *); | |||
12 | extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); | 12 | extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); |
13 | extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); | 13 | extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); |
14 | extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); | 14 | extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); |
15 | extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8); | 15 | extern int iscsit_start_kthreads(struct iscsi_conn *); |
16 | extern void iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8); | ||
16 | extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *, | 17 | extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *, |
17 | bool, bool); | 18 | bool, bool); |
18 | extern int iscsi_target_login_thread(void *); | 19 | extern int iscsi_target_login_thread(void *); |
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 8c02fa34716f..f9cde9141836 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c | |||
@@ -17,6 +17,7 @@ | |||
17 | ******************************************************************************/ | 17 | ******************************************************************************/ |
18 | 18 | ||
19 | #include <linux/ctype.h> | 19 | #include <linux/ctype.h> |
20 | #include <linux/kthread.h> | ||
20 | #include <scsi/iscsi_proto.h> | 21 | #include <scsi/iscsi_proto.h> |
21 | #include <target/target_core_base.h> | 22 | #include <target/target_core_base.h> |
22 | #include <target/target_core_fabric.h> | 23 | #include <target/target_core_fabric.h> |
@@ -361,10 +362,24 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log | |||
361 | ntohl(login_rsp->statsn), login->rsp_length); | 362 | ntohl(login_rsp->statsn), login->rsp_length); |
362 | 363 | ||
363 | padding = ((-login->rsp_length) & 3); | 364 | padding = ((-login->rsp_length) & 3); |
365 | /* | ||
366 | * Before sending the last login response containing the transition | ||
367 | * bit for full-feature-phase, go ahead and start up TX/RX threads | ||
368 | * now to avoid potential resource allocation failures after the | ||
369 | * final login response has been sent. | ||
370 | */ | ||
371 | if (login->login_complete) { | ||
372 | int rc = iscsit_start_kthreads(conn); | ||
373 | if (rc) { | ||
374 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
375 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
376 | return -1; | ||
377 | } | ||
378 | } | ||
364 | 379 | ||
365 | if (conn->conn_transport->iscsit_put_login_tx(conn, login, | 380 | if (conn->conn_transport->iscsit_put_login_tx(conn, login, |
366 | login->rsp_length + padding) < 0) | 381 | login->rsp_length + padding) < 0) |
367 | return -1; | 382 | goto err; |
368 | 383 | ||
369 | login->rsp_length = 0; | 384 | login->rsp_length = 0; |
370 | mutex_lock(&sess->cmdsn_mutex); | 385 | mutex_lock(&sess->cmdsn_mutex); |
@@ -373,6 +388,23 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log | |||
373 | mutex_unlock(&sess->cmdsn_mutex); | 388 | mutex_unlock(&sess->cmdsn_mutex); |
374 | 389 | ||
375 | return 0; | 390 | return 0; |
391 | |||
392 | err: | ||
393 | if (login->login_complete) { | ||
394 | if (conn->rx_thread && conn->rx_thread_active) { | ||
395 | send_sig(SIGINT, conn->rx_thread, 1); | ||
396 | kthread_stop(conn->rx_thread); | ||
397 | } | ||
398 | if (conn->tx_thread && conn->tx_thread_active) { | ||
399 | send_sig(SIGINT, conn->tx_thread, 1); | ||
400 | kthread_stop(conn->tx_thread); | ||
401 | } | ||
402 | spin_lock(&iscsit_global->ts_bitmap_lock); | ||
403 | bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id, | ||
404 | get_order(1)); | ||
405 | spin_unlock(&iscsit_global->ts_bitmap_lock); | ||
406 | } | ||
407 | return -1; | ||
376 | } | 408 | } |
377 | 409 | ||
378 | static void iscsi_target_sk_data_ready(struct sock *sk) | 410 | static void iscsi_target_sk_data_ready(struct sock *sk) |
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 0b0de3647478..c2e9fea90b4a 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c | |||
@@ -747,7 +747,7 @@ static ssize_t store_pi_prot_type(struct se_dev_attrib *da, | |||
747 | if (!dev->transport->init_prot || !dev->transport->free_prot) { | 747 | if (!dev->transport->init_prot || !dev->transport->free_prot) { |
748 | /* 0 is only allowed value for non-supporting backends */ | 748 | /* 0 is only allowed value for non-supporting backends */ |
749 | if (flag == 0) | 749 | if (flag == 0) |
750 | return 0; | 750 | return count; |
751 | 751 | ||
752 | pr_err("DIF protection not supported by backend: %s\n", | 752 | pr_err("DIF protection not supported by backend: %s\n", |
753 | dev->transport->name); | 753 | dev->transport->name); |
@@ -1590,9 +1590,9 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1590 | u8 type = 0; | 1590 | u8 type = 0; |
1591 | 1591 | ||
1592 | if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) | 1592 | if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) |
1593 | return 0; | 1593 | return count; |
1594 | if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) | 1594 | if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) |
1595 | return 0; | 1595 | return count; |
1596 | 1596 | ||
1597 | if (dev->export_count) { | 1597 | if (dev->export_count) { |
1598 | pr_debug("Unable to process APTPL metadata while" | 1598 | pr_debug("Unable to process APTPL metadata while" |
@@ -1658,22 +1658,32 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1658 | * PR APTPL Metadata for Reservation | 1658 | * PR APTPL Metadata for Reservation |
1659 | */ | 1659 | */ |
1660 | case Opt_res_holder: | 1660 | case Opt_res_holder: |
1661 | match_int(args, &arg); | 1661 | ret = match_int(args, &arg); |
1662 | if (ret) | ||
1663 | goto out; | ||
1662 | res_holder = arg; | 1664 | res_holder = arg; |
1663 | break; | 1665 | break; |
1664 | case Opt_res_type: | 1666 | case Opt_res_type: |
1665 | match_int(args, &arg); | 1667 | ret = match_int(args, &arg); |
1668 | if (ret) | ||
1669 | goto out; | ||
1666 | type = (u8)arg; | 1670 | type = (u8)arg; |
1667 | break; | 1671 | break; |
1668 | case Opt_res_scope: | 1672 | case Opt_res_scope: |
1669 | match_int(args, &arg); | 1673 | ret = match_int(args, &arg); |
1674 | if (ret) | ||
1675 | goto out; | ||
1670 | break; | 1676 | break; |
1671 | case Opt_res_all_tg_pt: | 1677 | case Opt_res_all_tg_pt: |
1672 | match_int(args, &arg); | 1678 | ret = match_int(args, &arg); |
1679 | if (ret) | ||
1680 | goto out; | ||
1673 | all_tg_pt = (int)arg; | 1681 | all_tg_pt = (int)arg; |
1674 | break; | 1682 | break; |
1675 | case Opt_mapped_lun: | 1683 | case Opt_mapped_lun: |
1676 | match_int(args, &arg); | 1684 | ret = match_int(args, &arg); |
1685 | if (ret) | ||
1686 | goto out; | ||
1677 | mapped_lun = (u64)arg; | 1687 | mapped_lun = (u64)arg; |
1678 | break; | 1688 | break; |
1679 | /* | 1689 | /* |
@@ -1701,14 +1711,20 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1701 | } | 1711 | } |
1702 | break; | 1712 | break; |
1703 | case Opt_tpgt: | 1713 | case Opt_tpgt: |
1704 | match_int(args, &arg); | 1714 | ret = match_int(args, &arg); |
1715 | if (ret) | ||
1716 | goto out; | ||
1705 | tpgt = (u16)arg; | 1717 | tpgt = (u16)arg; |
1706 | break; | 1718 | break; |
1707 | case Opt_port_rtpi: | 1719 | case Opt_port_rtpi: |
1708 | match_int(args, &arg); | 1720 | ret = match_int(args, &arg); |
1721 | if (ret) | ||
1722 | goto out; | ||
1709 | break; | 1723 | break; |
1710 | case Opt_target_lun: | 1724 | case Opt_target_lun: |
1711 | match_int(args, &arg); | 1725 | ret = match_int(args, &arg); |
1726 | if (ret) | ||
1727 | goto out; | ||
1712 | target_lun = (u64)arg; | 1728 | target_lun = (u64)arg; |
1713 | break; | 1729 | break; |
1714 | default: | 1730 | default: |
@@ -1985,7 +2001,7 @@ static ssize_t target_core_store_alua_lu_gp( | |||
1985 | 2001 | ||
1986 | lu_gp_mem = dev->dev_alua_lu_gp_mem; | 2002 | lu_gp_mem = dev->dev_alua_lu_gp_mem; |
1987 | if (!lu_gp_mem) | 2003 | if (!lu_gp_mem) |
1988 | return 0; | 2004 | return count; |
1989 | 2005 | ||
1990 | if (count > LU_GROUP_NAME_BUF) { | 2006 | if (count > LU_GROUP_NAME_BUF) { |
1991 | pr_err("ALUA LU Group Alias too large!\n"); | 2007 | pr_err("ALUA LU Group Alias too large!\n"); |
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 0fdbe43b7dad..5ab7100de17e 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
@@ -1474,7 +1474,7 @@ core_scsi3_decode_spec_i_port( | |||
1474 | LIST_HEAD(tid_dest_list); | 1474 | LIST_HEAD(tid_dest_list); |
1475 | struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; | 1475 | struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; |
1476 | unsigned char *buf, *ptr, proto_ident; | 1476 | unsigned char *buf, *ptr, proto_ident; |
1477 | const unsigned char *i_str; | 1477 | const unsigned char *i_str = NULL; |
1478 | char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; | 1478 | char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; |
1479 | sense_reason_t ret; | 1479 | sense_reason_t ret; |
1480 | u32 tpdl, tid_len = 0; | 1480 | u32 tpdl, tid_len = 0; |
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 4703f403f31c..384cf8894411 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c | |||
@@ -333,6 +333,7 @@ static int rd_configure_device(struct se_device *dev) | |||
333 | dev->dev_attrib.hw_block_size = RD_BLOCKSIZE; | 333 | dev->dev_attrib.hw_block_size = RD_BLOCKSIZE; |
334 | dev->dev_attrib.hw_max_sectors = UINT_MAX; | 334 | dev->dev_attrib.hw_max_sectors = UINT_MAX; |
335 | dev->dev_attrib.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH; | 335 | dev->dev_attrib.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH; |
336 | dev->dev_attrib.is_nonrot = 1; | ||
336 | 337 | ||
337 | rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++; | 338 | rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++; |
338 | 339 | ||
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index b0744433315a..b5ba1ec3c354 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c | |||
@@ -454,10 +454,17 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) | |||
454 | cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE1_PROT) | 454 | cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE1_PROT) |
455 | buf[4] = 0x5; | 455 | buf[4] = 0x5; |
456 | else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT || | 456 | else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT || |
457 | cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT) | 457 | cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT) |
458 | buf[4] = 0x4; | 458 | buf[4] = 0x4; |
459 | } | 459 | } |
460 | 460 | ||
461 | /* logical unit supports type 1 and type 3 protection */ | ||
462 | if ((dev->transport->get_device_type(dev) == TYPE_DISK) && | ||
463 | (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) && | ||
464 | (dev->dev_attrib.pi_prot_type || cmd->se_sess->sess_prot_type)) { | ||
465 | buf[4] |= (0x3 << 3); | ||
466 | } | ||
467 | |||
461 | /* Set HEADSUP, ORDSUP, SIMPSUP */ | 468 | /* Set HEADSUP, ORDSUP, SIMPSUP */ |
462 | buf[5] = 0x07; | 469 | buf[5] = 0x07; |
463 | 470 | ||
diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 34117b8b72e4..0aedbb2c10e0 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h | |||
@@ -595,6 +595,7 @@ struct iscsi_conn { | |||
595 | int bitmap_id; | 595 | int bitmap_id; |
596 | int rx_thread_active; | 596 | int rx_thread_active; |
597 | struct task_struct *rx_thread; | 597 | struct task_struct *rx_thread; |
598 | struct completion rx_login_comp; | ||
598 | int tx_thread_active; | 599 | int tx_thread_active; |
599 | struct task_struct *tx_thread; | 600 | struct task_struct *tx_thread; |
600 | /* list_head for session connection list */ | 601 | /* list_head for session connection list */ |