diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_nportdisc.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 99 |
1 files changed, 94 insertions, 5 deletions
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index e331204a4d5..b90820a699f 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -493,6 +493,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
493 | struct lpfc_iocbq *cmdiocb, uint32_t els_cmd) | 493 | struct lpfc_iocbq *cmdiocb, uint32_t els_cmd) |
494 | { | 494 | { |
495 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 495 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
496 | struct lpfc_hba *phba = vport->phba; | ||
497 | struct lpfc_vport **vports; | ||
498 | int i, active_vlink_present = 0 ; | ||
496 | 499 | ||
497 | /* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */ | 500 | /* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */ |
498 | /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary | 501 | /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary |
@@ -505,15 +508,44 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
505 | lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); | 508 | lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); |
506 | else | 509 | else |
507 | lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); | 510 | lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); |
508 | if ((ndlp->nlp_DID == Fabric_DID) && | 511 | if (ndlp->nlp_DID == Fabric_DID) { |
509 | vport->port_type == LPFC_NPIV_PORT) { | 512 | if (vport->port_state <= LPFC_FDISC) |
513 | goto out; | ||
510 | lpfc_linkdown_port(vport); | 514 | lpfc_linkdown_port(vport); |
511 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); | ||
512 | spin_lock_irq(shost->host_lock); | 515 | spin_lock_irq(shost->host_lock); |
513 | ndlp->nlp_flag |= NLP_DELAY_TMO; | 516 | vport->fc_flag |= FC_VPORT_LOGO_RCVD; |
514 | spin_unlock_irq(shost->host_lock); | 517 | spin_unlock_irq(shost->host_lock); |
518 | vports = lpfc_create_vport_work_array(phba); | ||
519 | if (vports) { | ||
520 | for (i = 0; i <= phba->max_vports && vports[i] != NULL; | ||
521 | i++) { | ||
522 | if ((!(vports[i]->fc_flag & | ||
523 | FC_VPORT_LOGO_RCVD)) && | ||
524 | (vports[i]->port_state > LPFC_FDISC)) { | ||
525 | active_vlink_present = 1; | ||
526 | break; | ||
527 | } | ||
528 | } | ||
529 | lpfc_destroy_vport_work_array(phba, vports); | ||
530 | } | ||
515 | 531 | ||
516 | ndlp->nlp_last_elscmd = ELS_CMD_FDISC; | 532 | if (active_vlink_present) { |
533 | /* | ||
534 | * If there are other active VLinks present, | ||
535 | * re-instantiate the Vlink using FDISC. | ||
536 | */ | ||
537 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); | ||
538 | spin_lock_irq(shost->host_lock); | ||
539 | ndlp->nlp_flag |= NLP_DELAY_TMO; | ||
540 | spin_unlock_irq(shost->host_lock); | ||
541 | ndlp->nlp_last_elscmd = ELS_CMD_FDISC; | ||
542 | vport->port_state = LPFC_FDISC; | ||
543 | } else { | ||
544 | spin_lock_irq(shost->host_lock); | ||
545 | phba->pport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG; | ||
546 | spin_unlock_irq(shost->host_lock); | ||
547 | lpfc_retry_pport_discovery(phba); | ||
548 | } | ||
517 | } else if ((!(ndlp->nlp_type & NLP_FABRIC) && | 549 | } else if ((!(ndlp->nlp_type & NLP_FABRIC) && |
518 | ((ndlp->nlp_type & NLP_FCP_TARGET) || | 550 | ((ndlp->nlp_type & NLP_FCP_TARGET) || |
519 | !(ndlp->nlp_type & NLP_FCP_INITIATOR))) || | 551 | !(ndlp->nlp_type & NLP_FCP_INITIATOR))) || |
@@ -526,6 +558,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
526 | 558 | ||
527 | ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; | 559 | ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; |
528 | } | 560 | } |
561 | out: | ||
529 | ndlp->nlp_prev_state = ndlp->nlp_state; | 562 | ndlp->nlp_prev_state = ndlp->nlp_state; |
530 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | 563 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); |
531 | 564 | ||
@@ -604,11 +637,55 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
604 | lpfc_unreg_rpi(vport, ndlp); | 637 | lpfc_unreg_rpi(vport, ndlp); |
605 | return 0; | 638 | return 0; |
606 | } | 639 | } |
640 | /** | ||
641 | * lpfc_release_rpi - Release a RPI by issueing unreg_login mailbox cmd. | ||
642 | * @phba : Pointer to lpfc_hba structure. | ||
643 | * @vport: Pointer to lpfc_vport structure. | ||
644 | * @rpi : rpi to be release. | ||
645 | * | ||
646 | * This function will send a unreg_login mailbox command to the firmware | ||
647 | * to release a rpi. | ||
648 | **/ | ||
649 | void | ||
650 | lpfc_release_rpi(struct lpfc_hba *phba, | ||
651 | struct lpfc_vport *vport, | ||
652 | uint16_t rpi) | ||
653 | { | ||
654 | LPFC_MBOXQ_t *pmb; | ||
655 | int rc; | ||
656 | |||
657 | pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, | ||
658 | GFP_KERNEL); | ||
659 | if (!pmb) | ||
660 | lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, | ||
661 | "2796 mailbox memory allocation failed \n"); | ||
662 | else { | ||
663 | lpfc_unreg_login(phba, vport->vpi, rpi, pmb); | ||
664 | pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||
665 | rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); | ||
666 | if (rc == MBX_NOT_FINISHED) | ||
667 | mempool_free(pmb, phba->mbox_mem_pool); | ||
668 | } | ||
669 | } | ||
607 | 670 | ||
608 | static uint32_t | 671 | static uint32_t |
609 | lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | 672 | lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, |
610 | void *arg, uint32_t evt) | 673 | void *arg, uint32_t evt) |
611 | { | 674 | { |
675 | struct lpfc_hba *phba; | ||
676 | LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; | ||
677 | MAILBOX_t *mb; | ||
678 | uint16_t rpi; | ||
679 | |||
680 | phba = vport->phba; | ||
681 | /* Release the RPI if reglogin completing */ | ||
682 | if (!(phba->pport->load_flag & FC_UNLOADING) && | ||
683 | (evt == NLP_EVT_CMPL_REG_LOGIN) && | ||
684 | (!pmb->u.mb.mbxStatus)) { | ||
685 | mb = &pmb->u.mb; | ||
686 | rpi = pmb->u.mb.un.varWords[0]; | ||
687 | lpfc_release_rpi(phba, vport, rpi); | ||
688 | } | ||
612 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | 689 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, |
613 | "0271 Illegal State Transition: node x%x " | 690 | "0271 Illegal State Transition: node x%x " |
614 | "event x%x, state x%x Data: x%x x%x\n", | 691 | "event x%x, state x%x Data: x%x x%x\n", |
@@ -944,6 +1021,18 @@ static uint32_t | |||
944 | lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport, | 1021 | lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport, |
945 | struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) | 1022 | struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) |
946 | { | 1023 | { |
1024 | struct lpfc_hba *phba; | ||
1025 | LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; | ||
1026 | MAILBOX_t *mb = &pmb->u.mb; | ||
1027 | uint16_t rpi; | ||
1028 | |||
1029 | phba = vport->phba; | ||
1030 | /* Release the RPI */ | ||
1031 | if (!(phba->pport->load_flag & FC_UNLOADING) && | ||
1032 | !mb->mbxStatus) { | ||
1033 | rpi = pmb->u.mb.un.varWords[0]; | ||
1034 | lpfc_release_rpi(phba, vport, rpi); | ||
1035 | } | ||
947 | return ndlp->nlp_state; | 1036 | return ndlp->nlp_state; |
948 | } | 1037 | } |
949 | 1038 | ||