return 0;
 }
 
+static ssize_t
+lpfc_xcvr_data_show(struct device *dev, struct device_attribute *attr,
+                   char *buf)
+{
+       struct Scsi_Host  *shost = class_to_shost(dev);
+       struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+       struct lpfc_hba   *phba = vport->phba;
+       int rc;
+       int len = 0;
+       struct lpfc_rdp_context *rdp_context;
+       u16 temperature;
+       u16 rx_power;
+       u16 tx_bias;
+       u16 tx_power;
+       u16 vcc;
+       char chbuf[128];
+       u16 wavelength = 0;
+       struct sff_trasnceiver_codes_byte7 *trasn_code_byte7;
+
+       /* Get transceiver information */
+       rdp_context = kmalloc(sizeof(*rdp_context), GFP_KERNEL);
+
+       rc = lpfc_get_sfp_info_wait(phba, rdp_context);
+       if (rc) {
+               len = scnprintf(buf, PAGE_SIZE - len, "SFP info NA:\n");
+               goto out_free_rdp;
+       }
+
+       strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_NAME], 16);
+       chbuf[16] = 0;
+
+       len = scnprintf(buf, PAGE_SIZE - len, "VendorName:\t%s\n", chbuf);
+       len += scnprintf(buf + len, PAGE_SIZE - len,
+                        "VendorOUI:\t%02x-%02x-%02x\n",
+                        (uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI],
+                        (uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI + 1],
+                        (uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI + 2]);
+       strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_PN], 16);
+       chbuf[16] = 0;
+       len += scnprintf(buf + len, PAGE_SIZE - len, "VendorPN:\t%s\n", chbuf);
+       strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_SN], 16);
+       chbuf[16] = 0;
+       len += scnprintf(buf + len, PAGE_SIZE - len, "VendorSN:\t%s\n", chbuf);
+       strncpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_REV], 4);
+       chbuf[4] = 0;
+       len += scnprintf(buf + len, PAGE_SIZE - len, "VendorRev:\t%s\n", chbuf);
+       strncpy(chbuf, &rdp_context->page_a0[SSF_DATE_CODE], 8);
+       chbuf[8] = 0;
+       len += scnprintf(buf + len, PAGE_SIZE - len, "DateCode:\t%s\n", chbuf);
+       len += scnprintf(buf + len, PAGE_SIZE - len, "Identifier:\t%xh\n",
+                        (uint8_t)rdp_context->page_a0[SSF_IDENTIFIER]);
+       len += scnprintf(buf + len, PAGE_SIZE - len, "ExtIdentifier:\t%xh\n",
+                        (uint8_t)rdp_context->page_a0[SSF_EXT_IDENTIFIER]);
+       len += scnprintf(buf + len, PAGE_SIZE - len, "Connector:\t%xh\n",
+                        (uint8_t)rdp_context->page_a0[SSF_CONNECTOR]);
+       wavelength = (rdp_context->page_a0[SSF_WAVELENGTH_B1] << 8) |
+                     rdp_context->page_a0[SSF_WAVELENGTH_B0];
+
+       len += scnprintf(buf + len, PAGE_SIZE - len, "Wavelength:\t%d nm\n",
+                        wavelength);
+       trasn_code_byte7 = (struct sff_trasnceiver_codes_byte7 *)
+                       &rdp_context->page_a0[SSF_TRANSCEIVER_CODE_B7];
+
+       len += scnprintf(buf + len, PAGE_SIZE - len, "Speeds: \t");
+               if (*(uint8_t *)trasn_code_byte7 == 0) {
+                       len += scnprintf(buf + len, PAGE_SIZE - len,
+                                        "Unknown\n");
+               } else {
+                       if (trasn_code_byte7->fc_sp_100MB)
+                               len += scnprintf(buf + len, PAGE_SIZE - len,
+                                                "1 ");
+                       if (trasn_code_byte7->fc_sp_200mb)
+                               len += scnprintf(buf + len, PAGE_SIZE - len,
+                                                "2 ");
+                       if (trasn_code_byte7->fc_sp_400MB)
+                               len += scnprintf(buf + len, PAGE_SIZE - len,
+                                                "4 ");
+                       if (trasn_code_byte7->fc_sp_800MB)
+                               len += scnprintf(buf + len, PAGE_SIZE - len,
+                                                "8 ");
+                       if (trasn_code_byte7->fc_sp_1600MB)
+                               len += scnprintf(buf + len, PAGE_SIZE - len,
+                                                "16 ");
+                       if (trasn_code_byte7->fc_sp_3200MB)
+                               len += scnprintf(buf + len, PAGE_SIZE - len,
+                                                "32 ");
+                       if (trasn_code_byte7->speed_chk_ecc)
+                               len += scnprintf(buf + len, PAGE_SIZE - len,
+                                                "64 ");
+                       len += scnprintf(buf + len, PAGE_SIZE - len, "GB\n");
+               }
+       temperature = (rdp_context->page_a2[SFF_TEMPERATURE_B1] << 8 |
+                      rdp_context->page_a2[SFF_TEMPERATURE_B0]);
+       vcc = (rdp_context->page_a2[SFF_VCC_B1] << 8 |
+              rdp_context->page_a2[SFF_VCC_B0]);
+       tx_power = (rdp_context->page_a2[SFF_TXPOWER_B1] << 8 |
+                   rdp_context->page_a2[SFF_TXPOWER_B0]);
+       tx_bias = (rdp_context->page_a2[SFF_TX_BIAS_CURRENT_B1] << 8 |
+                  rdp_context->page_a2[SFF_TX_BIAS_CURRENT_B0]);
+       rx_power = (rdp_context->page_a2[SFF_RXPOWER_B1] << 8 |
+                   rdp_context->page_a2[SFF_RXPOWER_B0]);
+
+       len += scnprintf(buf + len, PAGE_SIZE - len,
+                        "Temperature:\tx%04x C\n", temperature);
+       len += scnprintf(buf + len, PAGE_SIZE - len, "Vcc:\t\tx%04x V\n", vcc);
+       len += scnprintf(buf + len, PAGE_SIZE - len,
+                        "TxBiasCurrent:\tx%04x mA\n", tx_bias);
+       len += scnprintf(buf + len, PAGE_SIZE - len, "TxPower:\tx%04x mW\n",
+                        tx_power);
+       len += scnprintf(buf + len, PAGE_SIZE - len, "RxPower:\tx%04x mW\n",
+                        rx_power);
+out_free_rdp:
+       kfree(rdp_context);
+       return len;
+}
+
 /**
  * lpfc_board_mode_show - Return the state of the board
  * @dev: class device that is converted into a Scsi_host.
 static DEVICE_ATTR_RO(lpfc_enable_fip);
 static DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
                   lpfc_board_mode_show, lpfc_board_mode_store);
+static DEVICE_ATTR_RO(lpfc_xcvr_data);
 static DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
 static DEVICE_ATTR(max_vpi, S_IRUGO, lpfc_max_vpi_show, NULL);
 static DEVICE_ATTR(used_vpi, S_IRUGO, lpfc_used_vpi_show, NULL);
        &dev_attr_lpfc_fcp_wait_abts_rsp.attr,
        &dev_attr_nport_evt_cnt.attr,
        &dev_attr_board_mode.attr,
+       &dev_attr_lpfc_xcvr_data.attr,
        &dev_attr_max_vpi.attr,
        &dev_attr_used_vpi.attr,
        &dev_attr_max_rpi.attr,
 
        return 1;
 }
 
+int lpfc_get_sfp_info_wait(struct lpfc_hba *phba,
+                          struct lpfc_rdp_context *rdp_context)
+{
+       LPFC_MBOXQ_t *mbox = NULL;
+       int rc;
+       struct lpfc_dmabuf *mp;
+       struct lpfc_dmabuf *mpsave;
+       void *virt;
+       MAILBOX_t *mb;
+
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox) {
+               lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_ELS,
+                               "7205 failed to allocate mailbox memory");
+               return 1;
+       }
+
+       if (lpfc_sli4_dump_page_a0(phba, mbox))
+               goto sfp_fail;
+       mp = mbox->ctx_buf;
+       mpsave = mp;
+       virt = mp->virt;
+       if (phba->sli_rev < LPFC_SLI_REV4) {
+               mb = &mbox->u.mb;
+               mb->un.varDmp.cv = 1;
+               mb->un.varDmp.co = 1;
+               mb->un.varWords[2] = 0;
+               mb->un.varWords[3] = DMP_SFF_PAGE_A0_SIZE / 4;
+               mb->un.varWords[4] = 0;
+               mb->un.varWords[5] = 0;
+               mb->un.varWords[6] = 0;
+               mb->un.varWords[7] = 0;
+               mb->un.varWords[8] = 0;
+               mb->un.varWords[9] = 0;
+               mb->un.varWords[10] = 0;
+               mbox->in_ext_byte_len = DMP_SFF_PAGE_A0_SIZE;
+               mbox->out_ext_byte_len = DMP_SFF_PAGE_A0_SIZE;
+               mbox->mbox_offset_word = 5;
+               mbox->ctx_buf = virt;
+       } else {
+               bf_set(lpfc_mbx_memory_dump_type3_length,
+                      &mbox->u.mqe.un.mem_dump_type3, DMP_SFF_PAGE_A0_SIZE);
+               mbox->u.mqe.un.mem_dump_type3.addr_lo = putPaddrLow(mp->phys);
+               mbox->u.mqe.un.mem_dump_type3.addr_hi = putPaddrHigh(mp->phys);
+       }
+       mbox->vport = phba->pport;
+       mbox->ctx_ndlp = (struct lpfc_rdp_context *)rdp_context;
+
+       rc = lpfc_sli_issue_mbox_wait(phba, mbox, 30);
+       if (rc == MBX_NOT_FINISHED) {
+               rc = 1;
+               goto error;
+       }
+
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               mp = (struct lpfc_dmabuf *)(mbox->ctx_buf);
+       else
+               mp = mpsave;
+
+       if (bf_get(lpfc_mqe_status, &mbox->u.mqe)) {
+               rc = 1;
+               goto error;
+       }
+
+       lpfc_sli_bemem_bcopy(mp->virt, &rdp_context->page_a0,
+                            DMP_SFF_PAGE_A0_SIZE);
+
+       memset(mbox, 0, sizeof(*mbox));
+       memset(mp->virt, 0, DMP_SFF_PAGE_A2_SIZE);
+       INIT_LIST_HEAD(&mp->list);
+
+       /* save address for completion */
+       mbox->ctx_buf = mp;
+       mbox->vport = phba->pport;
+
+       bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_DUMP_MEMORY);
+       bf_set(lpfc_mbx_memory_dump_type3_type,
+              &mbox->u.mqe.un.mem_dump_type3, DMP_LMSD);
+       bf_set(lpfc_mbx_memory_dump_type3_link,
+              &mbox->u.mqe.un.mem_dump_type3, phba->sli4_hba.physical_port);
+       bf_set(lpfc_mbx_memory_dump_type3_page_no,
+              &mbox->u.mqe.un.mem_dump_type3, DMP_PAGE_A2);
+       if (phba->sli_rev < LPFC_SLI_REV4) {
+               mb = &mbox->u.mb;
+               mb->un.varDmp.cv = 1;
+               mb->un.varDmp.co = 1;
+               mb->un.varWords[2] = 0;
+               mb->un.varWords[3] = DMP_SFF_PAGE_A2_SIZE / 4;
+               mb->un.varWords[4] = 0;
+               mb->un.varWords[5] = 0;
+               mb->un.varWords[6] = 0;
+               mb->un.varWords[7] = 0;
+               mb->un.varWords[8] = 0;
+               mb->un.varWords[9] = 0;
+               mb->un.varWords[10] = 0;
+               mbox->in_ext_byte_len = DMP_SFF_PAGE_A2_SIZE;
+               mbox->out_ext_byte_len = DMP_SFF_PAGE_A2_SIZE;
+               mbox->mbox_offset_word = 5;
+               mbox->ctx_buf = virt;
+       } else {
+               bf_set(lpfc_mbx_memory_dump_type3_length,
+                      &mbox->u.mqe.un.mem_dump_type3, DMP_SFF_PAGE_A2_SIZE);
+               mbox->u.mqe.un.mem_dump_type3.addr_lo = putPaddrLow(mp->phys);
+               mbox->u.mqe.un.mem_dump_type3.addr_hi = putPaddrHigh(mp->phys);
+       }
+
+       mbox->ctx_ndlp = (struct lpfc_rdp_context *)rdp_context;
+       rc = lpfc_sli_issue_mbox_wait(phba, mbox, 30);
+       if (bf_get(lpfc_mqe_status, &mbox->u.mqe)) {
+               rc = 1;
+               goto error;
+       }
+       rc = 0;
+
+       lpfc_sli_bemem_bcopy(mp->virt, &rdp_context->page_a2,
+                            DMP_SFF_PAGE_A2_SIZE);
+
+error:
+       mbox->ctx_buf = mpsave;
+       lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
+
+       return rc;
+
+sfp_fail:
+       mempool_free(mbox, phba->mbox_mem_pool);
+       return 1;
+}
+
 /*
  * lpfc_els_rcv_rdp - Process an unsolicited RDP ELS.
  * @vport: pointer to a host virtual N_Port data structure.