diff options
| -rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 1 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 7 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 5 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 4 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 59 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 36 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 158 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 4 |
8 files changed, 242 insertions, 32 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8917bb2c5fc2..7b63fe530041 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
| @@ -525,6 +525,7 @@ struct lpfc_hba { | |||
| 525 | #define FCP_XRI_ABORT_EVENT 0x20 | 525 | #define FCP_XRI_ABORT_EVENT 0x20 |
| 526 | #define ELS_XRI_ABORT_EVENT 0x40 | 526 | #define ELS_XRI_ABORT_EVENT 0x40 |
| 527 | #define ASYNC_EVENT 0x80 | 527 | #define ASYNC_EVENT 0x80 |
| 528 | #define LINK_DISABLED 0x100 /* Link disabled by user */ | ||
| 528 | struct lpfc_dmabuf slim2p; | 529 | struct lpfc_dmabuf slim2p; |
| 529 | 530 | ||
| 530 | MAILBOX_t *mbox; | 531 | MAILBOX_t *mbox; |
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index fc07be5fbce9..7a629511338e 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
| @@ -394,7 +394,12 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr, | |||
| 394 | case LPFC_INIT_MBX_CMDS: | 394 | case LPFC_INIT_MBX_CMDS: |
| 395 | case LPFC_LINK_DOWN: | 395 | case LPFC_LINK_DOWN: |
| 396 | case LPFC_HBA_ERROR: | 396 | case LPFC_HBA_ERROR: |
| 397 | len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n"); | 397 | if (phba->hba_flag & LINK_DISABLED) |
| 398 | len += snprintf(buf + len, PAGE_SIZE-len, | ||
| 399 | "Link Down - User disabled\n"); | ||
| 400 | else | ||
| 401 | len += snprintf(buf + len, PAGE_SIZE-len, | ||
| 402 | "Link Down\n"); | ||
| 398 | break; | 403 | break; |
| 399 | case LPFC_LINK_UP: | 404 | case LPFC_LINK_UP: |
| 400 | case LPFC_CLEAR_LA: | 405 | case LPFC_CLEAR_LA: |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index d2a922997c0f..84e53bb1daa3 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
| @@ -21,7 +21,9 @@ | |||
| 21 | typedef int (*node_filter)(struct lpfc_nodelist *, void *); | 21 | typedef int (*node_filter)(struct lpfc_nodelist *, void *); |
| 22 | 22 | ||
| 23 | struct fc_rport; | 23 | struct fc_rport; |
| 24 | void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); | 24 | void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *); |
| 25 | void lpfc_sli_read_link_ste(struct lpfc_hba *); | ||
| 26 | void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t); | ||
| 25 | void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *); | 27 | void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *); |
| 26 | void lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); | 28 | void lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); |
| 27 | int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *); | 29 | int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *); |
| @@ -234,6 +236,7 @@ void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); | |||
| 234 | int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, | 236 | int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, |
| 235 | struct lpfc_iocbq *, uint32_t); | 237 | struct lpfc_iocbq *, uint32_t); |
| 236 | void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); | 238 | void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); |
| 239 | void lpfc_sli_bemem_bcopy(void *, void *, uint32_t); | ||
| 237 | void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); | 240 | void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); |
| 238 | void lpfc_sli_flush_fcp_rings(struct lpfc_hba *); | 241 | void lpfc_sli_flush_fcp_rings(struct lpfc_hba *); |
| 239 | int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, | 242 | int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, |
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 8a3a026667e4..ccb26724dc53 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h | |||
| @@ -2496,8 +2496,8 @@ typedef struct { | |||
| 2496 | #define DMP_VPORT_REGION_SIZE 0x200 | 2496 | #define DMP_VPORT_REGION_SIZE 0x200 |
| 2497 | #define DMP_MBOX_OFFSET_WORD 0x5 | 2497 | #define DMP_MBOX_OFFSET_WORD 0x5 |
| 2498 | 2498 | ||
| 2499 | #define DMP_REGION_FCOEPARAM 0x17 /* fcoe param region */ | 2499 | #define DMP_REGION_23 0x17 /* fcoe param and port state region */ |
| 2500 | #define DMP_FCOEPARAM_RGN_SIZE 0x400 | 2500 | #define DMP_RGN23_SIZE 0x400 |
| 2501 | 2501 | ||
| 2502 | #define WAKE_UP_PARMS_REGION_ID 4 | 2502 | #define WAKE_UP_PARMS_REGION_ID 4 |
| 2503 | #define WAKE_UP_PARMS_WORD_SIZE 15 | 2503 | #define WAKE_UP_PARMS_WORD_SIZE 15 |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f8271a587aab..900b5628ceb9 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
| @@ -211,7 +211,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) | |||
| 211 | goto out_free_mbox; | 211 | goto out_free_mbox; |
| 212 | 212 | ||
| 213 | do { | 213 | do { |
| 214 | lpfc_dump_mem(phba, pmb, offset); | 214 | lpfc_dump_mem(phba, pmb, offset, DMP_REGION_VPD); |
| 215 | rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); | 215 | rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); |
| 216 | 216 | ||
| 217 | if (rc != MBX_SUCCESS) { | 217 | if (rc != MBX_SUCCESS) { |
| @@ -425,6 +425,9 @@ lpfc_config_port_post(struct lpfc_hba *phba) | |||
| 425 | return -EIO; | 425 | return -EIO; |
| 426 | } | 426 | } |
| 427 | 427 | ||
| 428 | /* Check if the port is disabled */ | ||
| 429 | lpfc_sli_read_link_ste(phba); | ||
| 430 | |||
| 428 | /* Reset the DFT_HBA_Q_DEPTH to the max xri */ | 431 | /* Reset the DFT_HBA_Q_DEPTH to the max xri */ |
| 429 | if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1)) | 432 | if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1)) |
| 430 | phba->cfg_hba_queue_depth = | 433 | phba->cfg_hba_queue_depth = |
| @@ -524,27 +527,49 @@ lpfc_config_port_post(struct lpfc_hba *phba) | |||
| 524 | /* Set up error attention (ERATT) polling timer */ | 527 | /* Set up error attention (ERATT) polling timer */ |
| 525 | mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); | 528 | mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); |
| 526 | 529 | ||
| 527 | lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); | 530 | /* Check if the port is disabled */ |
| 528 | pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | 531 | lpfc_sli_read_serdes_param(phba); |
| 529 | lpfc_set_loopback_flag(phba); | 532 | |
| 530 | rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); | 533 | if (phba->hba_flag & LINK_DISABLED) { |
| 531 | if (rc != MBX_SUCCESS) { | 534 | lpfc_printf_log(phba, |
| 532 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | 535 | KERN_ERR, LOG_INIT, |
| 536 | "2598 Adapter Link is disabled.\n"); | ||
| 537 | lpfc_down_link(phba, pmb); | ||
| 538 | pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||
| 539 | rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); | ||
| 540 | if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { | ||
| 541 | lpfc_printf_log(phba, | ||
| 542 | KERN_ERR, LOG_INIT, | ||
| 543 | "2599 Adapter failed to issue DOWN_LINK" | ||
| 544 | " mbox command rc 0x%x\n", rc); | ||
| 545 | |||
| 546 | mempool_free(pmb, phba->mbox_mem_pool); | ||
| 547 | return -EIO; | ||
| 548 | } | ||
| 549 | } else { | ||
| 550 | lpfc_init_link(phba, pmb, phba->cfg_topology, | ||
| 551 | phba->cfg_link_speed); | ||
| 552 | pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||
| 553 | lpfc_set_loopback_flag(phba); | ||
| 554 | rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); | ||
| 555 | if (rc != MBX_SUCCESS) { | ||
| 556 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
| 533 | "0454 Adapter failed to init, mbxCmd x%x " | 557 | "0454 Adapter failed to init, mbxCmd x%x " |
| 534 | "INIT_LINK, mbxStatus x%x\n", | 558 | "INIT_LINK, mbxStatus x%x\n", |
| 535 | mb->mbxCommand, mb->mbxStatus); | 559 | mb->mbxCommand, mb->mbxStatus); |
| 536 | 560 | ||
| 537 | /* Clear all interrupt enable conditions */ | 561 | /* Clear all interrupt enable conditions */ |
| 538 | writel(0, phba->HCregaddr); | 562 | writel(0, phba->HCregaddr); |
| 539 | readl(phba->HCregaddr); /* flush */ | 563 | readl(phba->HCregaddr); /* flush */ |
| 540 | /* Clear all pending interrupts */ | 564 | /* Clear all pending interrupts */ |
| 541 | writel(0xffffffff, phba->HAregaddr); | 565 | writel(0xffffffff, phba->HAregaddr); |
| 542 | readl(phba->HAregaddr); /* flush */ | 566 | readl(phba->HAregaddr); /* flush */ |
| 543 | 567 | ||
| 544 | phba->link_state = LPFC_HBA_ERROR; | 568 | phba->link_state = LPFC_HBA_ERROR; |
| 545 | if (rc != MBX_BUSY) | 569 | if (rc != MBX_BUSY) |
| 546 | mempool_free(pmb, phba->mbox_mem_pool); | 570 | mempool_free(pmb, phba->mbox_mem_pool); |
| 547 | return -EIO; | 571 | return -EIO; |
| 572 | } | ||
| 548 | } | 573 | } |
| 549 | /* MBOX buffer will be freed in mbox compl */ | 574 | /* MBOX buffer will be freed in mbox compl */ |
| 550 | pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | 575 | pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); |
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 42b4f3841697..245945f2f3a0 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c | |||
| @@ -79,21 +79,37 @@ lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, | |||
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | /** | 81 | /** |
| 82 | * lpfc_dump_mem - Prepare a mailbox command for retrieving HBA's VPD memory | 82 | * lpfc_down_link - Bring down HBAs link. |
| 83 | * @phba: pointer to lpfc hba data structure. | 83 | * @phba: pointer to lpfc hba data structure. |
| 84 | * @pmb: pointer to the driver internal queue element for mailbox command. | 84 | * @pmb: pointer to the driver internal queue element for mailbox command. |
| 85 | * @offset: offset for dumping VPD memory mailbox command. | 85 | * |
| 86 | * This routine prepares a mailbox command to bring down HBA link. | ||
| 87 | **/ | ||
| 88 | void | ||
| 89 | lpfc_down_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | ||
| 90 | { | ||
| 91 | MAILBOX_t *mb; | ||
| 92 | memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); | ||
| 93 | mb = &pmb->u.mb; | ||
| 94 | mb->mbxCommand = MBX_DOWN_LINK; | ||
| 95 | mb->mbxOwner = OWN_HOST; | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * lpfc_dump_mem - Prepare a mailbox command for reading a region. | ||
| 100 | * @phba: pointer to lpfc hba data structure. | ||
| 101 | * @pmb: pointer to the driver internal queue element for mailbox command. | ||
| 102 | * @offset: offset into the region. | ||
| 103 | * @region_id: config region id. | ||
| 86 | * | 104 | * |
| 87 | * The dump mailbox command provides a method for the device driver to obtain | 105 | * The dump mailbox command provides a method for the device driver to obtain |
| 88 | * various types of information from the HBA device. | 106 | * various types of information from the HBA device. |
| 89 | * | 107 | * |
| 90 | * This routine prepares the mailbox command for dumping HBA Vital Product | 108 | * This routine prepares the mailbox command for dumping HBA's config region. |
| 91 | * Data (VPD) memory. This mailbox command is to be used for retrieving a | ||
| 92 | * portion (DMP_RSP_SIZE bytes) of a HBA's VPD from the HBA at an address | ||
| 93 | * offset specified by the offset parameter. | ||
| 94 | **/ | 109 | **/ |
| 95 | void | 110 | void |
| 96 | lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset) | 111 | lpfc_dump_mem(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, uint16_t offset, |
| 112 | uint16_t region_id) | ||
| 97 | { | 113 | { |
| 98 | MAILBOX_t *mb; | 114 | MAILBOX_t *mb; |
| 99 | void *ctx; | 115 | void *ctx; |
| @@ -107,7 +123,7 @@ lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset) | |||
| 107 | mb->un.varDmp.cv = 1; | 123 | mb->un.varDmp.cv = 1; |
| 108 | mb->un.varDmp.type = DMP_NV_PARAMS; | 124 | mb->un.varDmp.type = DMP_NV_PARAMS; |
| 109 | mb->un.varDmp.entry_index = offset; | 125 | mb->un.varDmp.entry_index = offset; |
| 110 | mb->un.varDmp.region_id = DMP_REGION_VPD; | 126 | mb->un.varDmp.region_id = region_id; |
| 111 | mb->un.varDmp.word_cnt = (DMP_RSP_SIZE / sizeof (uint32_t)); | 127 | mb->un.varDmp.word_cnt = (DMP_RSP_SIZE / sizeof (uint32_t)); |
| 112 | mb->un.varDmp.co = 0; | 128 | mb->un.varDmp.co = 0; |
| 113 | mb->un.varDmp.resp_offset = 0; | 129 | mb->un.varDmp.resp_offset = 0; |
| @@ -1864,8 +1880,8 @@ lpfc_dump_fcoe_param(struct lpfc_hba *phba, | |||
| 1864 | 1880 | ||
| 1865 | mb->mbxCommand = MBX_DUMP_MEMORY; | 1881 | mb->mbxCommand = MBX_DUMP_MEMORY; |
| 1866 | mb->un.varDmp.type = DMP_NV_PARAMS; | 1882 | mb->un.varDmp.type = DMP_NV_PARAMS; |
| 1867 | mb->un.varDmp.region_id = DMP_REGION_FCOEPARAM; | 1883 | mb->un.varDmp.region_id = DMP_REGION_23; |
| 1868 | mb->un.varDmp.sli4_length = DMP_FCOEPARAM_RGN_SIZE; | 1884 | mb->un.varDmp.sli4_length = DMP_RGN23_SIZE; |
| 1869 | mb->un.varWords[3] = putPaddrLow(mp->phys); | 1885 | mb->un.varWords[3] = putPaddrLow(mp->phys); |
| 1870 | mb->un.varWords[4] = putPaddrHigh(mp->phys); | 1886 | mb->un.varWords[4] = putPaddrHigh(mp->phys); |
| 1871 | return 0; | 1887 | return 0; |
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 | } | ||
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index b6f3e04f3848..b5f4ba1a5c27 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h | |||
| @@ -151,6 +151,10 @@ struct lpfc_fcf { | |||
| 151 | #define LPFC_REGION23_SIGNATURE "RG23" | 151 | #define LPFC_REGION23_SIGNATURE "RG23" |
| 152 | #define LPFC_REGION23_VERSION 1 | 152 | #define LPFC_REGION23_VERSION 1 |
| 153 | #define LPFC_REGION23_LAST_REC 0xff | 153 | #define LPFC_REGION23_LAST_REC 0xff |
| 154 | #define DRIVER_SPECIFIC_TYPE 0xA2 | ||
| 155 | #define LINUX_DRIVER_ID 0x20 | ||
| 156 | #define PORT_STE_TYPE 0x1 | ||
| 157 | |||
| 154 | struct lpfc_fip_param_hdr { | 158 | struct lpfc_fip_param_hdr { |
| 155 | uint8_t type; | 159 | uint8_t type; |
| 156 | #define FCOE_PARAM_TYPE 0xA0 | 160 | #define FCOE_PARAM_TYPE 0xA0 |
