diff options
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 */ |
