diff options
author | James Smart <James.Smart@Emulex.Com> | 2008-01-11 01:52:36 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-23 12:29:21 -0500 |
commit | 0ff10d46cf0a373c9c855a23cc9383ba4030d8d2 (patch) | |
tree | 111eb8303ad63cecad266d507af4c2c0bfec4d5b | |
parent | b18268fc631034882f5f3dd93daa248a3bfdd085 (diff) |
[SCSI] lpfc 8.2.4 : Miscellaneous Discovery/ELS Fixes
Miscellaneous Discovery/ELS Fixes:
- Delay free's of ELS requests if adapter reject conditions
- Fix concurrent PLOGI vs ADISC state handling
- Add retry mechanism for GFF_ID
- Correct some illegal state transitions around RSCN timeouts
- Fix missing return in FAN handling
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 5 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 83 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 56 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 23 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 43 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 26 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 1 |
9 files changed, 224 insertions, 15 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 1ddfd688fea3..b06635ac3356 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -583,6 +583,11 @@ struct lpfc_hba { | |||
583 | atomic_t slow_ring_trc_cnt; | 583 | atomic_t slow_ring_trc_cnt; |
584 | #endif | 584 | #endif |
585 | 585 | ||
586 | /* Used for deferred freeing of ELS data buffers */ | ||
587 | struct list_head elsbuf; | ||
588 | int elsbuf_cnt; | ||
589 | int elsbuf_prev_cnt; | ||
590 | |||
586 | uint8_t temp_sensor_support; | 591 | uint8_t temp_sensor_support; |
587 | /* Fields used for heart beat. */ | 592 | /* Fields used for heart beat. */ |
588 | unsigned long last_completion_time; | 593 | unsigned long last_completion_time; |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index d09eb533a27d..50fcb7c930bc 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -89,6 +89,7 @@ int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, | |||
89 | struct serv_parm *, uint32_t); | 89 | struct serv_parm *, uint32_t); |
90 | int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); | 90 | int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); |
91 | void lpfc_more_plogi(struct lpfc_vport *); | 91 | void lpfc_more_plogi(struct lpfc_vport *); |
92 | void lpfc_more_adisc(struct lpfc_vport *); | ||
92 | void lpfc_end_rscn(struct lpfc_vport *); | 93 | void lpfc_end_rscn(struct lpfc_vport *); |
93 | int lpfc_els_chk_latt(struct lpfc_vport *); | 94 | int lpfc_els_chk_latt(struct lpfc_vport *); |
94 | int lpfc_els_abort_flogi(struct lpfc_hba *); | 95 | int lpfc_els_abort_flogi(struct lpfc_hba *); |
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index e8bd7c122f1e..c735ed4ad070 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c | |||
@@ -426,6 +426,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) | |||
426 | 426 | ||
427 | lpfc_set_disctmo(vport); | 427 | lpfc_set_disctmo(vport); |
428 | vport->num_disc_nodes = 0; | 428 | vport->num_disc_nodes = 0; |
429 | vport->fc_ns_retry = 0; | ||
429 | 430 | ||
430 | 431 | ||
431 | list_add_tail(&head, &mp->list); | 432 | list_add_tail(&head, &mp->list); |
@@ -506,7 +507,17 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) | |||
506 | Did, vport->fc_flag, | 507 | Did, vport->fc_flag, |
507 | vport->fc_rscn_id_cnt); | 508 | vport->fc_rscn_id_cnt); |
508 | 509 | ||
509 | if (lpfc_ns_cmd(vport, | 510 | /* This NPortID was previously |
511 | * a FCP target, * Don't even | ||
512 | * bother to send GFF_ID. | ||
513 | */ | ||
514 | ndlp = lpfc_findnode_did(vport, | ||
515 | Did); | ||
516 | if (ndlp && (ndlp->nlp_type & | ||
517 | NLP_FCP_TARGET)) | ||
518 | lpfc_setup_disc_node | ||
519 | (vport, Did); | ||
520 | else if (lpfc_ns_cmd(vport, | ||
510 | SLI_CTNS_GFF_ID, | 521 | SLI_CTNS_GFF_ID, |
511 | 0, Did) == 0) | 522 | 0, Did) == 0) |
512 | vport->num_disc_nodes++; | 523 | vport->num_disc_nodes++; |
@@ -554,7 +565,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
554 | struct lpfc_dmabuf *outp; | 565 | struct lpfc_dmabuf *outp; |
555 | struct lpfc_sli_ct_request *CTrsp; | 566 | struct lpfc_sli_ct_request *CTrsp; |
556 | struct lpfc_nodelist *ndlp; | 567 | struct lpfc_nodelist *ndlp; |
557 | int rc; | 568 | int rc, retry; |
558 | 569 | ||
559 | /* First save ndlp, before we overwrite it */ | 570 | /* First save ndlp, before we overwrite it */ |
560 | ndlp = cmdiocb->context_un.ndlp; | 571 | ndlp = cmdiocb->context_un.ndlp; |
@@ -585,14 +596,35 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
585 | if (irsp->ulpStatus) { | 596 | if (irsp->ulpStatus) { |
586 | /* Check for retry */ | 597 | /* Check for retry */ |
587 | if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { | 598 | if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { |
588 | if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || | 599 | retry = 1; |
589 | (irsp->un.ulpWord[4] != IOERR_NO_RESOURCES)) | 600 | if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { |
601 | switch (irsp->un.ulpWord[4]) { | ||
602 | case IOERR_NO_RESOURCES: | ||
603 | /* We don't increment the retry | ||
604 | * count for this case. | ||
605 | */ | ||
606 | break; | ||
607 | case IOERR_LINK_DOWN: | ||
608 | case IOERR_SLI_ABORTED: | ||
609 | case IOERR_SLI_DOWN: | ||
610 | retry = 0; | ||
611 | break; | ||
612 | default: | ||
613 | vport->fc_ns_retry++; | ||
614 | } | ||
615 | } | ||
616 | else | ||
590 | vport->fc_ns_retry++; | 617 | vport->fc_ns_retry++; |
591 | /* CT command is being retried */ | 618 | |
592 | rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, | 619 | if (retry) { |
620 | /* CT command is being retried */ | ||
621 | rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, | ||
593 | vport->fc_ns_retry, 0); | 622 | vport->fc_ns_retry, 0); |
594 | if (rc == 0) | 623 | if (rc == 0) { |
595 | goto out; | 624 | /* success */ |
625 | goto out; | ||
626 | } | ||
627 | } | ||
596 | } | 628 | } |
597 | lpfc_vport_set_state(vport, FC_VPORT_FAILED); | 629 | lpfc_vport_set_state(vport, FC_VPORT_FAILED); |
598 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | 630 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, |
@@ -698,7 +730,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
698 | struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1; | 730 | struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1; |
699 | struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2; | 731 | struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2; |
700 | struct lpfc_sli_ct_request *CTrsp; | 732 | struct lpfc_sli_ct_request *CTrsp; |
701 | int did; | 733 | int did, rc, retry; |
702 | uint8_t fbits; | 734 | uint8_t fbits; |
703 | struct lpfc_nodelist *ndlp; | 735 | struct lpfc_nodelist *ndlp; |
704 | 736 | ||
@@ -729,6 +761,39 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
729 | } | 761 | } |
730 | } | 762 | } |
731 | else { | 763 | else { |
764 | /* Check for retry */ | ||
765 | if (cmdiocb->retry < LPFC_MAX_NS_RETRY) { | ||
766 | retry = 1; | ||
767 | if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { | ||
768 | switch (irsp->un.ulpWord[4]) { | ||
769 | case IOERR_NO_RESOURCES: | ||
770 | /* We don't increment the retry | ||
771 | * count for this case. | ||
772 | */ | ||
773 | break; | ||
774 | case IOERR_LINK_DOWN: | ||
775 | case IOERR_SLI_ABORTED: | ||
776 | case IOERR_SLI_DOWN: | ||
777 | retry = 0; | ||
778 | break; | ||
779 | default: | ||
780 | cmdiocb->retry++; | ||
781 | } | ||
782 | } | ||
783 | else | ||
784 | cmdiocb->retry++; | ||
785 | |||
786 | if (retry) { | ||
787 | /* CT command is being retried */ | ||
788 | rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID, | ||
789 | cmdiocb->retry, did); | ||
790 | if (rc == 0) { | ||
791 | /* success */ | ||
792 | lpfc_ct_free_iocb(phba, cmdiocb); | ||
793 | return; | ||
794 | } | ||
795 | } | ||
796 | } | ||
732 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | 797 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, |
733 | "0267 NameServer GFF Rsp " | 798 | "0267 NameServer GFF Rsp " |
734 | "x%x Error (%d %d) Data: x%x x%x\n", | 799 | "x%x Error (%d %d) Data: x%x x%x\n", |
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index bf332cba2fc0..f5e002435972 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -783,6 +783,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
783 | { | 783 | { |
784 | struct lpfc_vport *vport = ndlp->vport; | 784 | struct lpfc_vport *vport = ndlp->vport; |
785 | struct lpfc_nodelist *new_ndlp; | 785 | struct lpfc_nodelist *new_ndlp; |
786 | struct lpfc_rport_data *rdata; | ||
787 | struct fc_rport *rport; | ||
786 | struct serv_parm *sp; | 788 | struct serv_parm *sp; |
787 | uint8_t name[sizeof(struct lpfc_name)]; | 789 | uint8_t name[sizeof(struct lpfc_name)]; |
788 | uint32_t rc; | 790 | uint32_t rc; |
@@ -819,6 +821,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
819 | lpfc_unreg_rpi(vport, new_ndlp); | 821 | lpfc_unreg_rpi(vport, new_ndlp); |
820 | new_ndlp->nlp_DID = ndlp->nlp_DID; | 822 | new_ndlp->nlp_DID = ndlp->nlp_DID; |
821 | new_ndlp->nlp_prev_state = ndlp->nlp_prev_state; | 823 | new_ndlp->nlp_prev_state = ndlp->nlp_prev_state; |
824 | |||
825 | if (ndlp->nlp_flag & NLP_NPR_2B_DISC) | ||
826 | new_ndlp->nlp_flag |= NLP_NPR_2B_DISC; | ||
827 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
828 | |||
822 | lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); | 829 | lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); |
823 | 830 | ||
824 | /* Move this back to NPR state */ | 831 | /* Move this back to NPR state */ |
@@ -826,6 +833,20 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
826 | /* The new_ndlp is replacing ndlp totally, so we need | 833 | /* The new_ndlp is replacing ndlp totally, so we need |
827 | * to put ndlp on UNUSED list and try to free it. | 834 | * to put ndlp on UNUSED list and try to free it. |
828 | */ | 835 | */ |
836 | |||
837 | /* Fix up the rport accordingly */ | ||
838 | rport = ndlp->rport; | ||
839 | if (rport) { | ||
840 | rdata = rport->dd_data; | ||
841 | if (rdata->pnode == ndlp) { | ||
842 | lpfc_nlp_put(ndlp); | ||
843 | ndlp->rport = NULL; | ||
844 | rdata->pnode = lpfc_nlp_get(new_ndlp); | ||
845 | new_ndlp->rport = rport; | ||
846 | } | ||
847 | new_ndlp->nlp_type = ndlp->nlp_type; | ||
848 | } | ||
849 | |||
829 | lpfc_drop_node(vport, ndlp); | 850 | lpfc_drop_node(vport, ndlp); |
830 | } | 851 | } |
831 | else { | 852 | else { |
@@ -1149,7 +1170,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1149 | return 0; | 1170 | return 0; |
1150 | } | 1171 | } |
1151 | 1172 | ||
1152 | static void | 1173 | void |
1153 | lpfc_more_adisc(struct lpfc_vport *vport) | 1174 | lpfc_more_adisc(struct lpfc_vport *vport) |
1154 | { | 1175 | { |
1155 | int sentadisc; | 1176 | int sentadisc; |
@@ -2100,8 +2121,35 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) | |||
2100 | } | 2121 | } |
2101 | /* context2 = cmd, context2->next = rsp, context3 = bpl */ | 2122 | /* context2 = cmd, context2->next = rsp, context3 = bpl */ |
2102 | if (elsiocb->context2) { | 2123 | if (elsiocb->context2) { |
2103 | buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; | 2124 | if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) { |
2104 | lpfc_els_free_data(phba, buf_ptr1); | 2125 | /* Firmware could still be in progress of DMAing |
2126 | * payload, so don't free data buffer till after | ||
2127 | * a hbeat. | ||
2128 | */ | ||
2129 | elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE; | ||
2130 | buf_ptr = elsiocb->context2; | ||
2131 | elsiocb->context2 = NULL; | ||
2132 | if (buf_ptr) { | ||
2133 | buf_ptr1 = NULL; | ||
2134 | spin_lock_irq(&phba->hbalock); | ||
2135 | if (!list_empty(&buf_ptr->list)) { | ||
2136 | list_remove_head(&buf_ptr->list, | ||
2137 | buf_ptr1, struct lpfc_dmabuf, | ||
2138 | list); | ||
2139 | INIT_LIST_HEAD(&buf_ptr1->list); | ||
2140 | list_add_tail(&buf_ptr1->list, | ||
2141 | &phba->elsbuf); | ||
2142 | phba->elsbuf_cnt++; | ||
2143 | } | ||
2144 | INIT_LIST_HEAD(&buf_ptr->list); | ||
2145 | list_add_tail(&buf_ptr->list, &phba->elsbuf); | ||
2146 | phba->elsbuf_cnt++; | ||
2147 | spin_unlock_irq(&phba->hbalock); | ||
2148 | } | ||
2149 | } else { | ||
2150 | buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; | ||
2151 | lpfc_els_free_data(phba, buf_ptr1); | ||
2152 | } | ||
2105 | } | 2153 | } |
2106 | 2154 | ||
2107 | if (elsiocb->context3) { | 2155 | if (elsiocb->context3) { |
@@ -3027,6 +3075,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) | |||
3027 | 3075 | ||
3028 | /* To process RSCN, first compare RSCN data with NameServer */ | 3076 | /* To process RSCN, first compare RSCN data with NameServer */ |
3029 | vport->fc_ns_retry = 0; | 3077 | vport->fc_ns_retry = 0; |
3078 | vport->num_disc_nodes = 0; | ||
3079 | |||
3030 | ndlp = lpfc_findnode_did(vport, NameServer_DID); | 3080 | ndlp = lpfc_findnode_did(vport, NameServer_DID); |
3031 | if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | 3081 | if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { |
3032 | /* Good ndlp, issue CT Request to NameServer */ | 3082 | /* Good ndlp, issue CT Request to NameServer */ |
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 74c3b7039c9e..f2b8bc49fe52 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -2564,6 +2564,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
2564 | } | 2564 | } |
2565 | if (vport->port_state != LPFC_FLOGI) { | 2565 | if (vport->port_state != LPFC_FLOGI) { |
2566 | lpfc_initial_flogi(vport); | 2566 | lpfc_initial_flogi(vport); |
2567 | return; | ||
2567 | } | 2568 | } |
2568 | break; | 2569 | break; |
2569 | 2570 | ||
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 0143baf4ba3b..f32cd9acd3f6 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -547,8 +547,10 @@ void | |||
547 | lpfc_hb_timeout_handler(struct lpfc_hba *phba) | 547 | lpfc_hb_timeout_handler(struct lpfc_hba *phba) |
548 | { | 548 | { |
549 | LPFC_MBOXQ_t *pmboxq; | 549 | LPFC_MBOXQ_t *pmboxq; |
550 | struct lpfc_dmabuf *buf_ptr; | ||
550 | int retval; | 551 | int retval; |
551 | struct lpfc_sli *psli = &phba->sli; | 552 | struct lpfc_sli *psli = &phba->sli; |
553 | LIST_HEAD(completions); | ||
552 | 554 | ||
553 | if ((phba->link_state == LPFC_HBA_ERROR) || | 555 | if ((phba->link_state == LPFC_HBA_ERROR) || |
554 | (phba->pport->load_flag & FC_UNLOADING) || | 556 | (phba->pport->load_flag & FC_UNLOADING) || |
@@ -575,6 +577,24 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) | |||
575 | } | 577 | } |
576 | spin_unlock_irq(&phba->pport->work_port_lock); | 578 | spin_unlock_irq(&phba->pport->work_port_lock); |
577 | 579 | ||
580 | if (phba->elsbuf_cnt && | ||
581 | (phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) { | ||
582 | spin_lock_irq(&phba->hbalock); | ||
583 | list_splice_init(&phba->elsbuf, &completions); | ||
584 | phba->elsbuf_cnt = 0; | ||
585 | phba->elsbuf_prev_cnt = 0; | ||
586 | spin_unlock_irq(&phba->hbalock); | ||
587 | |||
588 | while (!list_empty(&completions)) { | ||
589 | list_remove_head(&completions, buf_ptr, | ||
590 | struct lpfc_dmabuf, list); | ||
591 | lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); | ||
592 | kfree(buf_ptr); | ||
593 | } | ||
594 | } | ||
595 | phba->elsbuf_prev_cnt = phba->elsbuf_cnt; | ||
596 | |||
597 | |||
578 | /* If there is no heart beat outstanding, issue a heartbeat command */ | 598 | /* If there is no heart beat outstanding, issue a heartbeat command */ |
579 | if (!phba->hb_outstanding) { | 599 | if (!phba->hb_outstanding) { |
580 | pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); | 600 | pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); |
@@ -1999,6 +2019,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
1999 | /* Initialize list of fabric iocbs */ | 2019 | /* Initialize list of fabric iocbs */ |
2000 | INIT_LIST_HEAD(&phba->fabric_iocb_list); | 2020 | INIT_LIST_HEAD(&phba->fabric_iocb_list); |
2001 | 2021 | ||
2022 | /* Initialize list to save ELS buffers */ | ||
2023 | INIT_LIST_HEAD(&phba->elsbuf); | ||
2024 | |||
2002 | vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev); | 2025 | vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev); |
2003 | if (!vport) | 2026 | if (!vport) |
2004 | goto out_kthread_stop; | 2027 | goto out_kthread_stop; |
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index c654c787c3e6..783659aa2102 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -442,7 +442,27 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
442 | spin_lock_irq(shost->host_lock); | 442 | spin_lock_irq(shost->host_lock); |
443 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | 443 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; |
444 | spin_unlock_irq(shost->host_lock); | 444 | spin_unlock_irq(shost->host_lock); |
445 | if (vport->num_disc_nodes) { | 445 | |
446 | if ((ndlp->nlp_flag & NLP_ADISC_SND) && | ||
447 | (vport->num_disc_nodes)) { | ||
448 | /* Check to see if there are more | ||
449 | * ADISCs to be sent | ||
450 | */ | ||
451 | lpfc_more_adisc(vport); | ||
452 | |||
453 | if ((vport->num_disc_nodes == 0) && | ||
454 | (vport->fc_npr_cnt)) | ||
455 | lpfc_els_disc_plogi(vport); | ||
456 | |||
457 | if (vport->num_disc_nodes == 0) { | ||
458 | spin_lock_irq(shost->host_lock); | ||
459 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
460 | spin_unlock_irq(shost->host_lock); | ||
461 | lpfc_can_disctmo(vport); | ||
462 | lpfc_end_rscn(vport); | ||
463 | } | ||
464 | } | ||
465 | else if (vport->num_disc_nodes) { | ||
446 | /* Check to see if there are more | 466 | /* Check to see if there are more |
447 | * PLOGIs to be sent | 467 | * PLOGIs to be sent |
448 | */ | 468 | */ |
@@ -813,6 +833,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, | |||
813 | uint32_t evt) | 833 | uint32_t evt) |
814 | { | 834 | { |
815 | struct lpfc_hba *phba = vport->phba; | 835 | struct lpfc_hba *phba = vport->phba; |
836 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
816 | struct lpfc_iocbq *cmdiocb, *rspiocb; | 837 | struct lpfc_iocbq *cmdiocb, *rspiocb; |
817 | struct lpfc_dmabuf *pcmd, *prsp, *mp; | 838 | struct lpfc_dmabuf *pcmd, *prsp, *mp; |
818 | uint32_t *lp; | 839 | uint32_t *lp; |
@@ -930,11 +951,27 @@ out: | |||
930 | "0261 Cannot Register NameServer login\n"); | 951 | "0261 Cannot Register NameServer login\n"); |
931 | } | 952 | } |
932 | 953 | ||
954 | spin_lock_irq(shost->host_lock); | ||
933 | ndlp->nlp_flag |= NLP_DEFER_RM; | 955 | ndlp->nlp_flag |= NLP_DEFER_RM; |
956 | spin_unlock_irq(shost->host_lock); | ||
934 | return NLP_STE_FREED_NODE; | 957 | return NLP_STE_FREED_NODE; |
935 | } | 958 | } |
936 | 959 | ||
937 | static uint32_t | 960 | static uint32_t |
961 | lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||
962 | void *arg, uint32_t evt) | ||
963 | { | ||
964 | return ndlp->nlp_state; | ||
965 | } | ||
966 | |||
967 | static uint32_t | ||
968 | lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport, | ||
969 | struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) | ||
970 | { | ||
971 | return ndlp->nlp_state; | ||
972 | } | ||
973 | |||
974 | static uint32_t | ||
938 | lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | 975 | lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, |
939 | void *arg, uint32_t evt) | 976 | void *arg, uint32_t evt) |
940 | { | 977 | { |
@@ -2006,9 +2043,9 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) | |||
2006 | lpfc_rcv_els_plogi_issue, /* RCV_PRLO */ | 2043 | lpfc_rcv_els_plogi_issue, /* RCV_PRLO */ |
2007 | lpfc_cmpl_plogi_plogi_issue, /* CMPL_PLOGI */ | 2044 | lpfc_cmpl_plogi_plogi_issue, /* CMPL_PLOGI */ |
2008 | lpfc_disc_illegal, /* CMPL_PRLI */ | 2045 | lpfc_disc_illegal, /* CMPL_PRLI */ |
2009 | lpfc_disc_illegal, /* CMPL_LOGO */ | 2046 | lpfc_cmpl_logo_plogi_issue, /* CMPL_LOGO */ |
2010 | lpfc_disc_illegal, /* CMPL_ADISC */ | 2047 | lpfc_disc_illegal, /* CMPL_ADISC */ |
2011 | lpfc_disc_illegal, /* CMPL_REG_LOGIN */ | 2048 | lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN */ |
2012 | lpfc_device_rm_plogi_issue, /* DEVICE_RM */ | 2049 | lpfc_device_rm_plogi_issue, /* DEVICE_RM */ |
2013 | lpfc_device_recov_plogi_issue, /* DEVICE_RECOVERY */ | 2050 | lpfc_device_recov_plogi_issue, /* DEVICE_RECOVERY */ |
2014 | 2051 | ||
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dcc48988040c..be6519793f8a 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -1147,6 +1147,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
1147 | IOSTAT_LOCAL_REJECT; | 1147 | IOSTAT_LOCAL_REJECT; |
1148 | saveq->iocb.un.ulpWord[4] = | 1148 | saveq->iocb.un.ulpWord[4] = |
1149 | IOERR_SLI_ABORTED; | 1149 | IOERR_SLI_ABORTED; |
1150 | |||
1151 | /* Firmware could still be in progress | ||
1152 | * of DMAing payload, so don't free data | ||
1153 | * buffer till after a hbeat. | ||
1154 | */ | ||
1155 | saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; | ||
1150 | } | 1156 | } |
1151 | } | 1157 | } |
1152 | (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); | 1158 | (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); |
@@ -3281,6 +3287,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) | |||
3281 | LIST_HEAD(completions); | 3287 | LIST_HEAD(completions); |
3282 | struct lpfc_sli *psli = &phba->sli; | 3288 | struct lpfc_sli *psli = &phba->sli; |
3283 | struct lpfc_sli_ring *pring; | 3289 | struct lpfc_sli_ring *pring; |
3290 | struct lpfc_dmabuf *buf_ptr; | ||
3284 | LPFC_MBOXQ_t *pmb; | 3291 | LPFC_MBOXQ_t *pmb; |
3285 | struct lpfc_iocbq *iocb; | 3292 | struct lpfc_iocbq *iocb; |
3286 | IOCB_t *cmd = NULL; | 3293 | IOCB_t *cmd = NULL; |
@@ -3320,6 +3327,19 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) | |||
3320 | } | 3327 | } |
3321 | } | 3328 | } |
3322 | 3329 | ||
3330 | spin_lock_irqsave(&phba->hbalock, flags); | ||
3331 | list_splice_init(&phba->elsbuf, &completions); | ||
3332 | phba->elsbuf_cnt = 0; | ||
3333 | phba->elsbuf_prev_cnt = 0; | ||
3334 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
3335 | |||
3336 | while (!list_empty(&completions)) { | ||
3337 | list_remove_head(&completions, buf_ptr, | ||
3338 | struct lpfc_dmabuf, list); | ||
3339 | lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); | ||
3340 | kfree(buf_ptr); | ||
3341 | } | ||
3342 | |||
3323 | /* Return any active mbox cmds */ | 3343 | /* Return any active mbox cmds */ |
3324 | del_timer_sync(&psli->mbox_tmo); | 3344 | del_timer_sync(&psli->mbox_tmo); |
3325 | spin_lock_irqsave(&phba->hbalock, flags); | 3345 | spin_lock_irqsave(&phba->hbalock, flags); |
@@ -3490,6 +3510,12 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
3490 | pring->txcmplq_cnt--; | 3510 | pring->txcmplq_cnt--; |
3491 | spin_unlock_irq(&phba->hbalock); | 3511 | spin_unlock_irq(&phba->hbalock); |
3492 | 3512 | ||
3513 | /* Firmware could still be in progress of DMAing | ||
3514 | * payload, so don't free data buffer till after | ||
3515 | * a hbeat. | ||
3516 | */ | ||
3517 | abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE; | ||
3518 | |||
3493 | abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; | 3519 | abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; |
3494 | abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; | 3520 | abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; |
3495 | abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; | 3521 | abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; |
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 5fcfe88e2a3f..1796473ad65e 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h | |||
@@ -44,6 +44,7 @@ struct lpfc_iocbq { | |||
44 | #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ | 44 | #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ |
45 | #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ | 45 | #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ |
46 | #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ | 46 | #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ |
47 | #define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ | ||
47 | 48 | ||
48 | uint8_t abort_count; | 49 | uint8_t abort_count; |
49 | uint8_t rsvd2; | 50 | uint8_t rsvd2; |