diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_sli.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 158 |
1 files changed, 157 insertions, 1 deletions
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 04f527ca8f5f..a3f85454368d 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -4139,7 +4139,7 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, | |||
4139 | return -EIO; | 4139 | return -EIO; |
4140 | } | 4140 | } |
4141 | data_length = mqe->un.mb_words[5]; | 4141 | data_length = mqe->un.mb_words[5]; |
4142 | if (data_length > DMP_FCOEPARAM_RGN_SIZE) { | 4142 | if (data_length > DMP_RGN23_SIZE) { |
4143 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 4143 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
4144 | kfree(mp); | 4144 | kfree(mp); |
4145 | return -EIO; | 4145 | return -EIO; |
@@ -6789,6 +6789,33 @@ lpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt) | |||
6789 | 6789 | ||
6790 | 6790 | ||
6791 | /** | 6791 | /** |
6792 | * lpfc_sli_bemem_bcopy - SLI memory copy function | ||
6793 | * @srcp: Source memory pointer. | ||
6794 | * @destp: Destination memory pointer. | ||
6795 | * @cnt: Number of words required to be copied. | ||
6796 | * | ||
6797 | * This function is used for copying data between a data structure | ||
6798 | * with big endian representation to local endianness. | ||
6799 | * This function can be called with or without lock. | ||
6800 | **/ | ||
6801 | void | ||
6802 | lpfc_sli_bemem_bcopy(void *srcp, void *destp, uint32_t cnt) | ||
6803 | { | ||
6804 | uint32_t *src = srcp; | ||
6805 | uint32_t *dest = destp; | ||
6806 | uint32_t ldata; | ||
6807 | int i; | ||
6808 | |||
6809 | for (i = 0; i < (int)cnt; i += sizeof(uint32_t)) { | ||
6810 | ldata = *src; | ||
6811 | ldata = be32_to_cpu(ldata); | ||
6812 | *dest = ldata; | ||
6813 | src++; | ||
6814 | dest++; | ||
6815 | } | ||
6816 | } | ||
6817 | |||
6818 | /** | ||
6792 | * lpfc_sli_ringpostbuf_put - Function to add a buffer to postbufq | 6819 | * lpfc_sli_ringpostbuf_put - Function to add a buffer to postbufq |
6793 | * @phba: Pointer to HBA context object. | 6820 | * @phba: Pointer to HBA context object. |
6794 | * @pring: Pointer to driver SLI ring object. | 6821 | * @pring: Pointer to driver SLI ring object. |
@@ -11564,3 +11591,132 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) | |||
11564 | error = 0; | 11591 | error = 0; |
11565 | return error; | 11592 | return error; |
11566 | } | 11593 | } |
11594 | |||
11595 | /** | ||
11596 | * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled. | ||
11597 | * @phba: pointer to lpfc hba data structure. | ||
11598 | * | ||
11599 | * This function read region 23 and parse TLV for port status to | ||
11600 | * decide if the user disaled the port. If the TLV indicates the | ||
11601 | * port is disabled, the hba_flag is set accordingly. | ||
11602 | **/ | ||
11603 | void | ||
11604 | lpfc_sli_read_link_ste(struct lpfc_hba *phba) | ||
11605 | { | ||
11606 | LPFC_MBOXQ_t *pmb = NULL; | ||
11607 | MAILBOX_t *mb; | ||
11608 | uint8_t *rgn23_data = NULL; | ||
11609 | uint32_t offset = 0, data_size, sub_tlv_len, tlv_offset; | ||
11610 | int rc; | ||
11611 | |||
11612 | pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
11613 | if (!pmb) { | ||
11614 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
11615 | "2600 lpfc_sli_read_serdes_param failed to" | ||
11616 | " allocate mailbox memory\n"); | ||
11617 | goto out; | ||
11618 | } | ||
11619 | mb = &pmb->u.mb; | ||
11620 | |||
11621 | /* Get adapter Region 23 data */ | ||
11622 | rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL); | ||
11623 | if (!rgn23_data) | ||
11624 | goto out; | ||
11625 | |||
11626 | do { | ||
11627 | lpfc_dump_mem(phba, pmb, offset, DMP_REGION_23); | ||
11628 | rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); | ||
11629 | |||
11630 | if (rc != MBX_SUCCESS) { | ||
11631 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
11632 | "2601 lpfc_sli_read_link_ste failed to" | ||
11633 | " read config region 23 rc 0x%x Status 0x%x\n", | ||
11634 | rc, mb->mbxStatus); | ||
11635 | mb->un.varDmp.word_cnt = 0; | ||
11636 | } | ||
11637 | /* | ||
11638 | * dump mem may return a zero when finished or we got a | ||
11639 | * mailbox error, either way we are done. | ||
11640 | */ | ||
11641 | if (mb->un.varDmp.word_cnt == 0) | ||
11642 | break; | ||
11643 | if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset) | ||
11644 | mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset; | ||
11645 | |||
11646 | lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, | ||
11647 | rgn23_data + offset, | ||
11648 | mb->un.varDmp.word_cnt); | ||
11649 | offset += mb->un.varDmp.word_cnt; | ||
11650 | } while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE); | ||
11651 | |||
11652 | data_size = offset; | ||
11653 | offset = 0; | ||
11654 | |||
11655 | if (!data_size) | ||
11656 | goto out; | ||
11657 | |||
11658 | /* Check the region signature first */ | ||
11659 | if (memcmp(&rgn23_data[offset], LPFC_REGION23_SIGNATURE, 4)) { | ||
11660 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
11661 | "2619 Config region 23 has bad signature\n"); | ||
11662 | goto out; | ||
11663 | } | ||
11664 | offset += 4; | ||
11665 | |||
11666 | /* Check the data structure version */ | ||
11667 | if (rgn23_data[offset] != LPFC_REGION23_VERSION) { | ||
11668 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
11669 | "2620 Config region 23 has bad version\n"); | ||
11670 | goto out; | ||
11671 | } | ||
11672 | offset += 4; | ||
11673 | |||
11674 | /* Parse TLV entries in the region */ | ||
11675 | while (offset < data_size) { | ||
11676 | if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) | ||
11677 | break; | ||
11678 | /* | ||
11679 | * If the TLV is not driver specific TLV or driver id is | ||
11680 | * not linux driver id, skip the record. | ||
11681 | */ | ||
11682 | if ((rgn23_data[offset] != DRIVER_SPECIFIC_TYPE) || | ||
11683 | (rgn23_data[offset + 2] != LINUX_DRIVER_ID) || | ||
11684 | (rgn23_data[offset + 3] != 0)) { | ||
11685 | offset += rgn23_data[offset + 1] * 4 + 4; | ||
11686 | continue; | ||
11687 | } | ||
11688 | |||
11689 | /* Driver found a driver specific TLV in the config region */ | ||
11690 | sub_tlv_len = rgn23_data[offset + 1] * 4; | ||
11691 | offset += 4; | ||
11692 | tlv_offset = 0; | ||
11693 | |||
11694 | /* | ||
11695 | * Search for configured port state sub-TLV. | ||
11696 | */ | ||
11697 | while ((offset < data_size) && | ||
11698 | (tlv_offset < sub_tlv_len)) { | ||
11699 | if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) { | ||
11700 | offset += 4; | ||
11701 | tlv_offset += 4; | ||
11702 | break; | ||
11703 | } | ||
11704 | if (rgn23_data[offset] != PORT_STE_TYPE) { | ||
11705 | offset += rgn23_data[offset + 1] * 4 + 4; | ||
11706 | tlv_offset += rgn23_data[offset + 1] * 4 + 4; | ||
11707 | continue; | ||
11708 | } | ||
11709 | |||
11710 | /* This HBA contains PORT_STE configured */ | ||
11711 | if (!rgn23_data[offset + 2]) | ||
11712 | phba->hba_flag |= LINK_DISABLED; | ||
11713 | |||
11714 | goto out; | ||
11715 | } | ||
11716 | } | ||
11717 | out: | ||
11718 | if (pmb) | ||
11719 | mempool_free(pmb, phba->mbox_mem_pool); | ||
11720 | kfree(rgn23_data); | ||
11721 | return; | ||
11722 | } | ||