diff options
author | James Smart <James.Smart@Emulex.Com> | 2008-02-08 18:50:25 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-02-11 18:52:58 -0500 |
commit | 3163f725a5d071eea1830bbbfab78cfe3fc9baaf (patch) | |
tree | c9c7904bcfade4e1ea45c3a6e47fbd83e77d348e /drivers/scsi/lpfc/lpfc_sli.c | |
parent | 7f5f3d0d02aa2f124e764aee5c775589ce72fd42 (diff) |
[SCSI] lpfc 8.2.5 : Fix buffer leaks
Fix buffer leaks:
- HBQ dma buffer leak at dma_pool_destroy when unloading driver
- Fix missing buffer free in slow ring buffer handling
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_sli.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 97 |
1 files changed, 95 insertions, 2 deletions
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index c8c5b48baa66..f53206411cd8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -203,8 +203,25 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) | |||
203 | case CMD_IOCB_RCV_SEQ64_CX: | 203 | case CMD_IOCB_RCV_SEQ64_CX: |
204 | case CMD_IOCB_RCV_ELS64_CX: | 204 | case CMD_IOCB_RCV_ELS64_CX: |
205 | case CMD_IOCB_RCV_CONT64_CX: | 205 | case CMD_IOCB_RCV_CONT64_CX: |
206 | case CMD_IOCB_RET_XRI64_CX: | ||
206 | type = LPFC_UNSOL_IOCB; | 207 | type = LPFC_UNSOL_IOCB; |
207 | break; | 208 | break; |
209 | case CMD_IOCB_XMIT_MSEQ64_CR: | ||
210 | case CMD_IOCB_XMIT_MSEQ64_CX: | ||
211 | case CMD_IOCB_RCV_SEQ_LIST64_CX: | ||
212 | case CMD_IOCB_RCV_ELS_LIST64_CX: | ||
213 | case CMD_IOCB_CLOSE_EXTENDED_CN: | ||
214 | case CMD_IOCB_ABORT_EXTENDED_CN: | ||
215 | case CMD_IOCB_RET_HBQE64_CN: | ||
216 | case CMD_IOCB_FCP_IBIDIR64_CR: | ||
217 | case CMD_IOCB_FCP_IBIDIR64_CX: | ||
218 | case CMD_IOCB_FCP_ITASKMGT64_CX: | ||
219 | case CMD_IOCB_LOGENTRY_CN: | ||
220 | case CMD_IOCB_LOGENTRY_ASYNC_CN: | ||
221 | printk("%s - Unhandled SLI-3 Command x%x\n", | ||
222 | __FUNCTION__, iocb_cmnd); | ||
223 | type = LPFC_UNKNOWN_IOCB; | ||
224 | break; | ||
208 | default: | 225 | default: |
209 | type = LPFC_UNKNOWN_IOCB; | 226 | type = LPFC_UNKNOWN_IOCB; |
210 | break; | 227 | break; |
@@ -529,10 +546,13 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) | |||
529 | { | 546 | { |
530 | struct lpfc_dmabuf *dmabuf, *next_dmabuf; | 547 | struct lpfc_dmabuf *dmabuf, *next_dmabuf; |
531 | struct hbq_dmabuf *hbq_buf; | 548 | struct hbq_dmabuf *hbq_buf; |
549 | unsigned long flags; | ||
532 | int i, hbq_count; | 550 | int i, hbq_count; |
551 | uint32_t hbqno; | ||
533 | 552 | ||
534 | hbq_count = lpfc_sli_hbq_count(); | 553 | hbq_count = lpfc_sli_hbq_count(); |
535 | /* Return all memory used by all HBQs */ | 554 | /* Return all memory used by all HBQs */ |
555 | spin_lock_irqsave(&phba->hbalock, flags); | ||
536 | for (i = 0; i < hbq_count; ++i) { | 556 | for (i = 0; i < hbq_count; ++i) { |
537 | list_for_each_entry_safe(dmabuf, next_dmabuf, | 557 | list_for_each_entry_safe(dmabuf, next_dmabuf, |
538 | &phba->hbqs[i].hbq_buffer_list, list) { | 558 | &phba->hbqs[i].hbq_buffer_list, list) { |
@@ -542,6 +562,28 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) | |||
542 | } | 562 | } |
543 | phba->hbqs[i].buffer_count = 0; | 563 | phba->hbqs[i].buffer_count = 0; |
544 | } | 564 | } |
565 | /* Return all HBQ buffer that are in-fly */ | ||
566 | list_for_each_entry_safe(dmabuf, next_dmabuf, | ||
567 | &phba->hbqbuf_in_list, list) { | ||
568 | hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf); | ||
569 | list_del(&hbq_buf->dbuf.list); | ||
570 | if (hbq_buf->tag == -1) { | ||
571 | (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) | ||
572 | (phba, hbq_buf); | ||
573 | } else { | ||
574 | hbqno = hbq_buf->tag >> 16; | ||
575 | if (hbqno >= LPFC_MAX_HBQS) | ||
576 | (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) | ||
577 | (phba, hbq_buf); | ||
578 | else | ||
579 | (phba->hbqs[hbqno].hbq_free_buffer)(phba, | ||
580 | hbq_buf); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | /* Mark the HBQs not in use */ | ||
585 | phba->hbq_in_use = 0; | ||
586 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
545 | } | 587 | } |
546 | 588 | ||
547 | static struct lpfc_hbq_entry * | 589 | static struct lpfc_hbq_entry * |
@@ -603,6 +645,7 @@ static int | |||
603 | lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) | 645 | lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) |
604 | { | 646 | { |
605 | uint32_t i, start, end; | 647 | uint32_t i, start, end; |
648 | unsigned long flags; | ||
606 | struct hbq_dmabuf *hbq_buffer; | 649 | struct hbq_dmabuf *hbq_buffer; |
607 | 650 | ||
608 | if (!phba->hbqs[hbqno].hbq_alloc_buffer) { | 651 | if (!phba->hbqs[hbqno].hbq_alloc_buffer) { |
@@ -615,6 +658,13 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) | |||
615 | end = lpfc_hbq_defs[hbqno]->entry_count; | 658 | end = lpfc_hbq_defs[hbqno]->entry_count; |
616 | } | 659 | } |
617 | 660 | ||
661 | /* Check whether HBQ is still in use */ | ||
662 | spin_lock_irqsave(&phba->hbalock, flags); | ||
663 | if (!phba->hbq_in_use) { | ||
664 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
665 | return 0; | ||
666 | } | ||
667 | |||
618 | /* Populate HBQ entries */ | 668 | /* Populate HBQ entries */ |
619 | for (i = start; i < end; i++) { | 669 | for (i = start; i < end; i++) { |
620 | hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); | 670 | hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); |
@@ -626,6 +676,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) | |||
626 | else | 676 | else |
627 | (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); | 677 | (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); |
628 | } | 678 | } |
679 | |||
680 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
629 | return 0; | 681 | return 0; |
630 | } | 682 | } |
631 | 683 | ||
@@ -910,16 +962,29 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) | |||
910 | uint32_t hbqno; | 962 | uint32_t hbqno; |
911 | void *virt; /* virtual address ptr */ | 963 | void *virt; /* virtual address ptr */ |
912 | dma_addr_t phys; /* mapped address */ | 964 | dma_addr_t phys; /* mapped address */ |
965 | unsigned long flags; | ||
966 | |||
967 | /* Check whether HBQ is still in use */ | ||
968 | spin_lock_irqsave(&phba->hbalock, flags); | ||
969 | if (!phba->hbq_in_use) { | ||
970 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
971 | return NULL; | ||
972 | } | ||
913 | 973 | ||
914 | hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); | 974 | hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); |
915 | if (hbq_entry == NULL) | 975 | if (hbq_entry == NULL) { |
976 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
916 | return NULL; | 977 | return NULL; |
978 | } | ||
917 | list_del(&hbq_entry->dbuf.list); | 979 | list_del(&hbq_entry->dbuf.list); |
918 | 980 | ||
919 | hbqno = tag >> 16; | 981 | hbqno = tag >> 16; |
920 | new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); | 982 | new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); |
921 | if (new_hbq_entry == NULL) | 983 | if (new_hbq_entry == NULL) { |
984 | list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list); | ||
985 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
922 | return &hbq_entry->dbuf; | 986 | return &hbq_entry->dbuf; |
987 | } | ||
923 | new_hbq_entry->tag = -1; | 988 | new_hbq_entry->tag = -1; |
924 | phys = new_hbq_entry->dbuf.phys; | 989 | phys = new_hbq_entry->dbuf.phys; |
925 | virt = new_hbq_entry->dbuf.virt; | 990 | virt = new_hbq_entry->dbuf.virt; |
@@ -928,6 +993,9 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) | |||
928 | hbq_entry->dbuf.phys = phys; | 993 | hbq_entry->dbuf.phys = phys; |
929 | hbq_entry->dbuf.virt = virt; | 994 | hbq_entry->dbuf.virt = virt; |
930 | lpfc_sli_free_hbq(phba, hbq_entry); | 995 | lpfc_sli_free_hbq(phba, hbq_entry); |
996 | list_add_tail(&new_hbq_entry->dbuf.list, &phba->hbqbuf_in_list); | ||
997 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
998 | |||
931 | return &new_hbq_entry->dbuf; | 999 | return &new_hbq_entry->dbuf; |
932 | } | 1000 | } |
933 | 1001 | ||
@@ -951,6 +1019,7 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
951 | uint32_t Rctl, Type; | 1019 | uint32_t Rctl, Type; |
952 | uint32_t match, i; | 1020 | uint32_t match, i; |
953 | struct lpfc_iocbq *iocbq; | 1021 | struct lpfc_iocbq *iocbq; |
1022 | struct lpfc_dmabuf *dmzbuf; | ||
954 | 1023 | ||
955 | match = 0; | 1024 | match = 0; |
956 | irsp = &(saveq->iocb); | 1025 | irsp = &(saveq->iocb); |
@@ -972,6 +1041,29 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
972 | return 1; | 1041 | return 1; |
973 | } | 1042 | } |
974 | 1043 | ||
1044 | if ((irsp->ulpCommand == CMD_IOCB_RET_XRI64_CX) && | ||
1045 | (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) { | ||
1046 | if (irsp->ulpBdeCount > 0) { | ||
1047 | dmzbuf = lpfc_sli_get_buff(phba, pring, | ||
1048 | irsp->un.ulpWord[3]); | ||
1049 | lpfc_in_buf_free(phba, dmzbuf); | ||
1050 | } | ||
1051 | |||
1052 | if (irsp->ulpBdeCount > 1) { | ||
1053 | dmzbuf = lpfc_sli_get_buff(phba, pring, | ||
1054 | irsp->unsli3.sli3Words[3]); | ||
1055 | lpfc_in_buf_free(phba, dmzbuf); | ||
1056 | } | ||
1057 | |||
1058 | if (irsp->ulpBdeCount > 2) { | ||
1059 | dmzbuf = lpfc_sli_get_buff(phba, pring, | ||
1060 | irsp->unsli3.sli3Words[7]); | ||
1061 | lpfc_in_buf_free(phba, dmzbuf); | ||
1062 | } | ||
1063 | |||
1064 | return 1; | ||
1065 | } | ||
1066 | |||
975 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { | 1067 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { |
976 | if (irsp->ulpBdeCount != 0) { | 1068 | if (irsp->ulpBdeCount != 0) { |
977 | saveq->context2 = lpfc_sli_get_buff(phba, pring, | 1069 | saveq->context2 = lpfc_sli_get_buff(phba, pring, |
@@ -2293,6 +2385,7 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba) | |||
2293 | 2385 | ||
2294 | /* Initialize the struct lpfc_sli_hbq structure for each hbq */ | 2386 | /* Initialize the struct lpfc_sli_hbq structure for each hbq */ |
2295 | phba->link_state = LPFC_INIT_MBX_CMDS; | 2387 | phba->link_state = LPFC_INIT_MBX_CMDS; |
2388 | phba->hbq_in_use = 1; | ||
2296 | 2389 | ||
2297 | hbq_entry_index = 0; | 2390 | hbq_entry_index = 0; |
2298 | for (hbqno = 0; hbqno < hbq_count; ++hbqno) { | 2391 | for (hbqno = 0; hbqno < hbq_count; ++hbqno) { |