aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Potashnik <alexei@purestorage.com>2015-12-17 14:57:01 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2016-01-07 16:57:44 -0500
commit71cdc07964651db51ddeea05245ac899357f0e71 (patch)
tree7a2f2d868bf2e36995b0970d9f8516a5992c8e80
parent6eb54715b54bb8324f3293e49635277652730e55 (diff)
qla2xxx: Delete session if initiator is gone from FW
1. Initiator A is logged in with fc_id(1)/loop_id(1) 2. Initiator A re-logs in with fc_id(2)/loop_id(2) 3. Part of old session deletion async logoout for 1/1 is queued 4. Initiator B logs in with fc_id(1)/loop_id(1), starts passing data and creates session. 5. Async logo from 3 is processed by DPC and sent to FW Now initiator B has the session but is logged out from FW. This condition is detected first with CTIO error 29 at which point we should delete current session. During session deletion we will send LOGO to initiator to force re-login. Under rare circumstances initiator might be logged out of FW, not have driver session, but still think it's logged in. E.g. the above sequence plus session deletion due to re-config. Incoming commands will fail to create local session because initiator is not found in FW. In this case we also issue LOGO to initiator to force him re-login. Finally this patch fixes exchange leak when commands where received in logged out state. In this case loop_id must be set to FFFF when corresponding exchange is terminated. The patch modifies exchange termination to always use FFFF, since in certain scenarios it's impossible to tell whether command was received in logged in or logged out state. Signed-off-by: Alexei Potashnik <alexei@purestorage.com> Acked-by: Quinn Tran <quinn.tran@qlogic.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Reviewed-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c1
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c108
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h9
4 files changed, 104 insertions, 16 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 83d2251eefe4..495a0aa26757 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3652,6 +3652,8 @@ typedef struct scsi_qla_host {
3652 atomic_t generation_tick; 3652 atomic_t generation_tick;
3653 /* Time when global fcport update has been scheduled */ 3653 /* Time when global fcport update has been scheduled */
3654 int total_fcport_update_gen; 3654 int total_fcport_update_gen;
3655 /* List of pending LOGOs, protected by tgt_mutex */
3656 struct list_head logo_list;
3655 3657
3656 uint32_t vp_abort_cnt; 3658 uint32_t vp_abort_cnt;
3657 3659
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 266dd746841a..cb0784a8705e 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3920,6 +3920,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
3920 INIT_LIST_HEAD(&vha->list); 3920 INIT_LIST_HEAD(&vha->list);
3921 INIT_LIST_HEAD(&vha->qla_cmd_list); 3921 INIT_LIST_HEAD(&vha->qla_cmd_list);
3922 INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list); 3922 INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list);
3923 INIT_LIST_HEAD(&vha->logo_list);
3923 3924
3924 spin_lock_init(&vha->work_lock); 3925 spin_lock_init(&vha->work_lock);
3925 spin_lock_init(&vha->cmd_list_lock); 3926 spin_lock_init(&vha->cmd_list_lock);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 661124afae90..5ef9d4c21e38 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -389,6 +389,52 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
389 389
390} 390}
391 391
392typedef struct {
393 /* These fields must be initialized by the caller */
394 port_id_t id;
395 /*
396 * number of cmds dropped while we were waiting for
397 * initiator to ack LOGO initialize to 1 if LOGO is
398 * triggered by a command, otherwise, to 0
399 */
400 int cmd_count;
401
402 /* These fields are used by callee */
403 struct list_head list;
404} qlt_port_logo_t;
405
406static void
407qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo)
408{
409 qlt_port_logo_t *tmp;
410 int res;
411
412 mutex_lock(&vha->vha_tgt.tgt_mutex);
413
414 list_for_each_entry(tmp, &vha->logo_list, list) {
415 if (tmp->id.b24 == logo->id.b24) {
416 tmp->cmd_count += logo->cmd_count;
417 mutex_unlock(&vha->vha_tgt.tgt_mutex);
418 return;
419 }
420 }
421
422 list_add_tail(&logo->list, &vha->logo_list);
423
424 mutex_unlock(&vha->vha_tgt.tgt_mutex);
425
426 res = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, logo->id);
427
428 mutex_lock(&vha->vha_tgt.tgt_mutex);
429 list_del(&logo->list);
430 mutex_unlock(&vha->vha_tgt.tgt_mutex);
431
432 dev_info(&vha->hw->pdev->dev,
433 "Finished LOGO to %02x:%02x:%02x, dropped %d cmds, res = %#x\n",
434 logo->id.b.domain, logo->id.b.area, logo->id.b.al_pa,
435 logo->cmd_count, res);
436}
437
392static void qlt_free_session_done(struct work_struct *work) 438static void qlt_free_session_done(struct work_struct *work)
393{ 439{
394 struct qla_tgt_sess *sess = container_of(work, struct qla_tgt_sess, 440 struct qla_tgt_sess *sess = container_of(work, struct qla_tgt_sess,
@@ -402,14 +448,21 @@ static void qlt_free_session_done(struct work_struct *work)
402 448
403 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084, 449 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
404 "%s: se_sess %p / sess %p from port %8phC loop_id %#04x" 450 "%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", 451 " s_id %02x:%02x:%02x logout %d keep %d plogi %d els_logo %d\n",
406 __func__, sess->se_sess, sess, sess->port_name, sess->loop_id, 452 __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, 453 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, 454 sess->logout_on_delete, sess->keep_nport_handle,
409 sess->plogi_ack_needed); 455 sess->plogi_ack_needed, sess->send_els_logo);
410 456
411 BUG_ON(!tgt); 457 BUG_ON(!tgt);
412 458
459 if (sess->send_els_logo) {
460 qlt_port_logo_t logo;
461 logo.id = sess->s_id;
462 logo.cmd_count = 0;
463 qlt_send_first_logo(vha, &logo);
464 }
465
413 if (sess->logout_on_delete) { 466 if (sess->logout_on_delete) {
414 int rc; 467 int rc;
415 468
@@ -636,12 +689,12 @@ static int qla24xx_get_loop_id(struct scsi_qla_host *vha, const uint8_t *s_id,
636 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf045, 689 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf045,
637 "qla_target(%d): get_id_list() failed: %x\n", 690 "qla_target(%d): get_id_list() failed: %x\n",
638 vha->vp_idx, rc); 691 vha->vp_idx, rc);
639 res = -1; 692 res = -EBUSY;
640 goto out_free_id_list; 693 goto out_free_id_list;
641 } 694 }
642 695
643 id_iter = (char *)gid_list; 696 id_iter = (char *)gid_list;
644 res = -1; 697 res = -ENOENT;
645 for (i = 0; i < entries; i++) { 698 for (i = 0; i < entries; i++) {
646 struct gid_list_info *gid = (struct gid_list_info *)id_iter; 699 struct gid_list_info *gid = (struct gid_list_info *)id_iter;
647 if ((gid->al_pa == s_id[2]) && 700 if ((gid->al_pa == s_id[2]) &&
@@ -2968,7 +3021,7 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
2968 3021
2969 ctio24 = (struct ctio7_to_24xx *)pkt; 3022 ctio24 = (struct ctio7_to_24xx *)pkt;
2970 ctio24->entry_type = CTIO_TYPE7; 3023 ctio24->entry_type = CTIO_TYPE7;
2971 ctio24->nport_handle = cmd ? cmd->loop_id : CTIO7_NHANDLE_UNRECOGNIZED; 3024 ctio24->nport_handle = CTIO7_NHANDLE_UNRECOGNIZED;
2972 ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); 3025 ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
2973 ctio24->vp_index = vha->vp_idx; 3026 ctio24->vp_index = vha->vp_idx;
2974 ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; 3027 ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2];
@@ -3404,13 +3457,26 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
3404 3457
3405 case CTIO_PORT_LOGGED_OUT: 3458 case CTIO_PORT_LOGGED_OUT:
3406 case CTIO_PORT_UNAVAILABLE: 3459 case CTIO_PORT_UNAVAILABLE:
3460 {
3461 bool logged_out = (status & 0xFFFF);
3407 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059, 3462 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059,
3408 "qla_target(%d): CTIO with PORT LOGGED " 3463 "qla_target(%d): CTIO with %s status %x "
3409 "OUT (29) or PORT UNAVAILABLE (28) status %x "
3410 "received (state %x, se_cmd %p)\n", vha->vp_idx, 3464 "received (state %x, se_cmd %p)\n", vha->vp_idx,
3465 (logged_out == CTIO_PORT_LOGGED_OUT) ?
3466 "PORT LOGGED OUT" : "PORT UNAVAILABLE",
3411 status, cmd->state, se_cmd); 3467 status, cmd->state, se_cmd);
3412 break;
3413 3468
3469 if (logged_out && cmd->sess) {
3470 /*
3471 * Session is already logged out, but we need
3472 * to notify initiator, who's not aware of this
3473 */
3474 cmd->sess->logout_on_delete = 0;
3475 cmd->sess->send_els_logo = 1;
3476 qlt_schedule_sess_for_deletion(cmd->sess, true);
3477 }
3478 break;
3479 }
3414 case CTIO_SRR_RECEIVED: 3480 case CTIO_SRR_RECEIVED:
3415 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05a, 3481 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05a,
3416 "qla_target(%d): CTIO with SRR_RECEIVED" 3482 "qla_target(%d): CTIO with SRR_RECEIVED"
@@ -3698,10 +3764,8 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
3698 goto out_term; 3764 goto out_term;
3699 } 3765 }
3700 3766
3701 mutex_lock(&vha->vha_tgt.tgt_mutex);
3702 sess = qlt_make_local_sess(vha, s_id); 3767 sess = qlt_make_local_sess(vha, s_id);
3703 /* sess has an extra creation ref. */ 3768 /* sess has an extra creation ref. */
3704 mutex_unlock(&vha->vha_tgt.tgt_mutex);
3705 3769
3706 if (!sess) 3770 if (!sess)
3707 goto out_term; 3771 goto out_term;
@@ -5541,12 +5605,16 @@ static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *vha,
5541 int rc, global_resets; 5605 int rc, global_resets;
5542 uint16_t loop_id = 0; 5606 uint16_t loop_id = 0;
5543 5607
5608 mutex_lock(&vha->vha_tgt.tgt_mutex);
5609
5544retry: 5610retry:
5545 global_resets = 5611 global_resets =
5546 atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count); 5612 atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
5547 5613
5548 rc = qla24xx_get_loop_id(vha, s_id, &loop_id); 5614 rc = qla24xx_get_loop_id(vha, s_id, &loop_id);
5549 if (rc != 0) { 5615 if (rc != 0) {
5616 mutex_unlock(&vha->vha_tgt.tgt_mutex);
5617
5550 if ((s_id[0] == 0xFF) && 5618 if ((s_id[0] == 0xFF) &&
5551 (s_id[1] == 0xFC)) { 5619 (s_id[1] == 0xFC)) {
5552 /* 5620 /*
@@ -5557,17 +5625,27 @@ retry:
5557 "Unable to find initiator with S_ID %x:%x:%x", 5625 "Unable to find initiator with S_ID %x:%x:%x",
5558 s_id[0], s_id[1], s_id[2]); 5626 s_id[0], s_id[1], s_id[2]);
5559 } else 5627 } else
5560 ql_dbg(ql_dbg_tgt_mgt, vha, 0xf071, 5628 ql_log(ql_log_info, vha, 0xf071,
5561 "qla_target(%d): Unable to find " 5629 "qla_target(%d): Unable to find "
5562 "initiator with S_ID %x:%x:%x", 5630 "initiator with S_ID %x:%x:%x",
5563 vha->vp_idx, s_id[0], s_id[1], 5631 vha->vp_idx, s_id[0], s_id[1],
5564 s_id[2]); 5632 s_id[2]);
5633
5634 if (rc == -ENOENT) {
5635 qlt_port_logo_t logo;
5636 sid_to_portid(s_id, &logo.id);
5637 logo.cmd_count = 1;
5638 qlt_send_first_logo(vha, &logo);
5639 }
5640
5565 return NULL; 5641 return NULL;
5566 } 5642 }
5567 5643
5568 fcport = qlt_get_port_database(vha, loop_id); 5644 fcport = qlt_get_port_database(vha, loop_id);
5569 if (!fcport) 5645 if (!fcport) {
5646 mutex_unlock(&vha->vha_tgt.tgt_mutex);
5570 return NULL; 5647 return NULL;
5648 }
5571 5649
5572 if (global_resets != 5650 if (global_resets !=
5573 atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count)) { 5651 atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count)) {
@@ -5582,6 +5660,8 @@ retry:
5582 5660
5583 sess = qlt_create_sess(vha, fcport, true); 5661 sess = qlt_create_sess(vha, fcport, true);
5584 5662
5663 mutex_unlock(&vha->vha_tgt.tgt_mutex);
5664
5585 kfree(fcport); 5665 kfree(fcport);
5586 return sess; 5666 return sess;
5587} 5667}
@@ -5611,10 +5691,8 @@ static void qlt_abort_work(struct qla_tgt *tgt,
5611 if (!sess) { 5691 if (!sess) {
5612 spin_unlock_irqrestore(&ha->hardware_lock, flags); 5692 spin_unlock_irqrestore(&ha->hardware_lock, flags);
5613 5693
5614 mutex_lock(&vha->vha_tgt.tgt_mutex);
5615 sess = qlt_make_local_sess(vha, s_id); 5694 sess = qlt_make_local_sess(vha, s_id);
5616 /* sess has got an extra creation ref */ 5695 /* sess has got an extra creation ref */
5617 mutex_unlock(&vha->vha_tgt.tgt_mutex);
5618 5696
5619 spin_lock_irqsave(&ha->hardware_lock, flags); 5697 spin_lock_irqsave(&ha->hardware_lock, flags);
5620 if (!sess) 5698 if (!sess)
@@ -5670,10 +5748,8 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
5670 if (!sess) { 5748 if (!sess) {
5671 spin_unlock_irqrestore(&ha->hardware_lock, flags); 5749 spin_unlock_irqrestore(&ha->hardware_lock, flags);
5672 5750
5673 mutex_lock(&vha->vha_tgt.tgt_mutex);
5674 sess = qlt_make_local_sess(vha, s_id); 5751 sess = qlt_make_local_sess(vha, s_id);
5675 /* sess has got an extra creation ref */ 5752 /* sess has got an extra creation ref */
5676 mutex_unlock(&vha->vha_tgt.tgt_mutex);
5677 5753
5678 spin_lock_irqsave(&ha->hardware_lock, flags); 5754 spin_lock_irqsave(&ha->hardware_lock, flags);
5679 if (!sess) 5755 if (!sess)
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index bca584ae45b7..e316d42b46fa 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -909,6 +909,7 @@ struct qla_tgt_sess {
909 unsigned int logout_on_delete:1; 909 unsigned int logout_on_delete:1;
910 unsigned int plogi_ack_needed:1; 910 unsigned int plogi_ack_needed:1;
911 unsigned int keep_nport_handle:1; 911 unsigned int keep_nport_handle:1;
912 unsigned int send_els_logo:1;
912 913
913 unsigned char logout_completed; 914 unsigned char logout_completed;
914 915
@@ -1120,6 +1121,14 @@ static inline uint32_t sid_to_key(const uint8_t *s_id)
1120 return key; 1121 return key;
1121} 1122}
1122 1123
1124static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p)
1125{
1126 memset(p, 0, sizeof(*p));
1127 p->b.domain = s_id[0];
1128 p->b.area = s_id[1];
1129 p->b.al_pa = s_id[2];
1130}
1131
1123/* 1132/*
1124 * Exported symbols from qla_target.c LLD logic used by qla2xxx code.. 1133 * Exported symbols from qla_target.c LLD logic used by qla2xxx code..
1125 */ 1134 */