in qla2xxx/qla_os.c [5946:6348]
void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
struct purex_item *item)
{
struct qla_hw_data *ha = vha->hw;
struct purex_entry_24xx *purex =
(struct purex_entry_24xx *)&item->iocb;
dma_addr_t rsp_els_dma;
dma_addr_t rsp_payload_dma;
dma_addr_t stat_dma;
dma_addr_t sfp_dma;
struct els_entry_24xx *rsp_els = NULL;
struct rdp_rsp_payload *rsp_payload = NULL;
struct link_statistics *stat = NULL;
uint8_t *sfp = NULL;
uint16_t sfp_flags = 0;
uint rsp_payload_length = sizeof(*rsp_payload);
int rval;
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0180,
"%s: Enter\n", __func__);
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0181,
"-------- ELS REQ -------\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0182,
purex, sizeof(*purex));
if (qla25xx_rdp_rsp_reduce_size(vha, purex)) {
rsp_payload_length =
offsetof(typeof(*rsp_payload), optical_elmt_desc);
ql_dbg(ql_dbg_init, vha, 0x0181,
"Reducing RSP payload length to %u bytes...\n",
rsp_payload_length);
}
rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els),
&rsp_els_dma, GFP_KERNEL);
if (!rsp_els) {
ql_log(ql_log_warn, vha, 0x0183,
"Failed allocate dma buffer ELS RSP.\n");
goto dealloc;
}
rsp_payload = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_payload),
&rsp_payload_dma, GFP_KERNEL);
if (!rsp_payload) {
ql_log(ql_log_warn, vha, 0x0184,
"Failed allocate dma buffer ELS RSP payload.\n");
goto dealloc;
}
sfp = dma_alloc_coherent(&ha->pdev->dev, SFP_RTDI_LEN,
&sfp_dma, GFP_KERNEL);
stat = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stat),
&stat_dma, GFP_KERNEL);
/* Prepare Response IOCB */
rsp_els->entry_type = ELS_IOCB_TYPE;
rsp_els->entry_count = 1;
rsp_els->sys_define = 0;
rsp_els->entry_status = 0;
rsp_els->handle = 0;
rsp_els->nport_handle = purex->nport_handle;
rsp_els->tx_dsd_count = cpu_to_le16(1);
rsp_els->vp_index = purex->vp_idx;
rsp_els->sof_type = EST_SOFI3;
rsp_els->rx_xchg_address = purex->rx_xchg_addr;
rsp_els->rx_dsd_count = 0;
rsp_els->opcode = purex->els_frame_payload[0];
rsp_els->d_id[0] = purex->s_id[0];
rsp_els->d_id[1] = purex->s_id[1];
rsp_els->d_id[2] = purex->s_id[2];
rsp_els->control_flags = cpu_to_le16(EPD_ELS_ACC);
rsp_els->rx_byte_count = 0;
rsp_els->tx_byte_count = cpu_to_le32(rsp_payload_length);
put_unaligned_le64(rsp_payload_dma, &rsp_els->tx_address);
rsp_els->tx_len = rsp_els->tx_byte_count;
rsp_els->rx_address = 0;
rsp_els->rx_len = 0;
/* Prepare Response Payload */
rsp_payload->hdr.cmd = cpu_to_be32(0x2 << 24); /* LS_ACC */
rsp_payload->hdr.len = cpu_to_be32(le32_to_cpu(rsp_els->tx_byte_count) -
sizeof(rsp_payload->hdr));
/* Link service Request Info Descriptor */
rsp_payload->ls_req_info_desc.desc_tag = cpu_to_be32(0x1);
rsp_payload->ls_req_info_desc.desc_len =
cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_req_info_desc));
rsp_payload->ls_req_info_desc.req_payload_word_0 =
cpu_to_be32p((uint32_t *)purex->els_frame_payload);
/* Link service Request Info Descriptor 2 */
rsp_payload->ls_req_info_desc2.desc_tag = cpu_to_be32(0x1);
rsp_payload->ls_req_info_desc2.desc_len =
cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_req_info_desc2));
rsp_payload->ls_req_info_desc2.req_payload_word_0 =
cpu_to_be32p((uint32_t *)purex->els_frame_payload);
rsp_payload->sfp_diag_desc.desc_tag = cpu_to_be32(0x10000);
rsp_payload->sfp_diag_desc.desc_len =
cpu_to_be32(RDP_DESC_LEN(rsp_payload->sfp_diag_desc));
if (sfp) {
/* SFP Flags */
memset(sfp, 0, SFP_RTDI_LEN);
rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 0x7, 2, 0);
if (!rval) {
/* SFP Flags bits 3-0: Port Tx Laser Type */
if (sfp[0] & BIT_2 || sfp[1] & (BIT_6|BIT_5))
sfp_flags |= BIT_0; /* short wave */
else if (sfp[0] & BIT_1)
sfp_flags |= BIT_1; /* long wave 1310nm */
else if (sfp[1] & BIT_4)
sfp_flags |= BIT_1|BIT_0; /* long wave 1550nm */
}
/* SFP Type */
memset(sfp, 0, SFP_RTDI_LEN);
rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 0x0, 1, 0);
if (!rval) {
sfp_flags |= BIT_4; /* optical */
if (sfp[0] == 0x3)
sfp_flags |= BIT_6; /* sfp+ */
}
rsp_payload->sfp_diag_desc.sfp_flags = cpu_to_be16(sfp_flags);
/* SFP Diagnostics */
memset(sfp, 0, SFP_RTDI_LEN);
rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 0x60, 10, 0);
if (!rval) {
__be16 *trx = (__force __be16 *)sfp; /* already be16 */
rsp_payload->sfp_diag_desc.temperature = trx[0];
rsp_payload->sfp_diag_desc.vcc = trx[1];
rsp_payload->sfp_diag_desc.tx_bias = trx[2];
rsp_payload->sfp_diag_desc.tx_power = trx[3];
rsp_payload->sfp_diag_desc.rx_power = trx[4];
}
}
/* Port Speed Descriptor */
rsp_payload->port_speed_desc.desc_tag = cpu_to_be32(0x10001);
rsp_payload->port_speed_desc.desc_len =
cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_speed_desc));
rsp_payload->port_speed_desc.speed_capab = cpu_to_be16(
qla25xx_fdmi_port_speed_capability(ha));
rsp_payload->port_speed_desc.operating_speed = cpu_to_be16(
qla25xx_fdmi_port_speed_currently(ha));
/* Link Error Status Descriptor */
rsp_payload->ls_err_desc.desc_tag = cpu_to_be32(0x10002);
rsp_payload->ls_err_desc.desc_len =
cpu_to_be32(RDP_DESC_LEN(rsp_payload->ls_err_desc));
if (stat) {
rval = qla24xx_get_isp_stats(vha, stat, stat_dma, 0);
if (!rval) {
rsp_payload->ls_err_desc.link_fail_cnt =
cpu_to_be32(le32_to_cpu(stat->link_fail_cnt));
rsp_payload->ls_err_desc.loss_sync_cnt =
cpu_to_be32(le32_to_cpu(stat->loss_sync_cnt));
rsp_payload->ls_err_desc.loss_sig_cnt =
cpu_to_be32(le32_to_cpu(stat->loss_sig_cnt));
rsp_payload->ls_err_desc.prim_seq_err_cnt =
cpu_to_be32(le32_to_cpu(stat->prim_seq_err_cnt));
rsp_payload->ls_err_desc.inval_xmit_word_cnt =
cpu_to_be32(le32_to_cpu(stat->inval_xmit_word_cnt));
rsp_payload->ls_err_desc.inval_crc_cnt =
cpu_to_be32(le32_to_cpu(stat->inval_crc_cnt));
rsp_payload->ls_err_desc.pn_port_phy_type |= BIT_6;
}
}
/* Portname Descriptor */
rsp_payload->port_name_diag_desc.desc_tag = cpu_to_be32(0x10003);
rsp_payload->port_name_diag_desc.desc_len =
cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_name_diag_desc));
memcpy(rsp_payload->port_name_diag_desc.WWNN,
vha->node_name,
sizeof(rsp_payload->port_name_diag_desc.WWNN));
memcpy(rsp_payload->port_name_diag_desc.WWPN,
vha->port_name,
sizeof(rsp_payload->port_name_diag_desc.WWPN));
/* F-Port Portname Descriptor */
rsp_payload->port_name_direct_desc.desc_tag = cpu_to_be32(0x10003);
rsp_payload->port_name_direct_desc.desc_len =
cpu_to_be32(RDP_DESC_LEN(rsp_payload->port_name_direct_desc));
memcpy(rsp_payload->port_name_direct_desc.WWNN,
vha->fabric_node_name,
sizeof(rsp_payload->port_name_direct_desc.WWNN));
memcpy(rsp_payload->port_name_direct_desc.WWPN,
vha->fabric_port_name,
sizeof(rsp_payload->port_name_direct_desc.WWPN));
/* Bufer Credit Descriptor */
rsp_payload->buffer_credit_desc.desc_tag = cpu_to_be32(0x10006);
rsp_payload->buffer_credit_desc.desc_len =
cpu_to_be32(RDP_DESC_LEN(rsp_payload->buffer_credit_desc));
rsp_payload->buffer_credit_desc.fcport_b2b = 0;
rsp_payload->buffer_credit_desc.attached_fcport_b2b = cpu_to_be32(0);
rsp_payload->buffer_credit_desc.fcport_rtt = cpu_to_be32(0);
if (ha->flags.plogi_template_valid) {
uint32_t tmp =
be16_to_cpu(ha->plogi_els_payld.fl_csp.sp_bb_cred);
rsp_payload->buffer_credit_desc.fcport_b2b = cpu_to_be32(tmp);
}
if (rsp_payload_length < sizeof(*rsp_payload))
goto send;
/* Optical Element Descriptor, Temperature */
rsp_payload->optical_elmt_desc[0].desc_tag = cpu_to_be32(0x10007);
rsp_payload->optical_elmt_desc[0].desc_len =
cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc));
/* Optical Element Descriptor, Voltage */
rsp_payload->optical_elmt_desc[1].desc_tag = cpu_to_be32(0x10007);
rsp_payload->optical_elmt_desc[1].desc_len =
cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc));
/* Optical Element Descriptor, Tx Bias Current */
rsp_payload->optical_elmt_desc[2].desc_tag = cpu_to_be32(0x10007);
rsp_payload->optical_elmt_desc[2].desc_len =
cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc));
/* Optical Element Descriptor, Tx Power */
rsp_payload->optical_elmt_desc[3].desc_tag = cpu_to_be32(0x10007);
rsp_payload->optical_elmt_desc[3].desc_len =
cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc));
/* Optical Element Descriptor, Rx Power */
rsp_payload->optical_elmt_desc[4].desc_tag = cpu_to_be32(0x10007);
rsp_payload->optical_elmt_desc[4].desc_len =
cpu_to_be32(RDP_DESC_LEN(*rsp_payload->optical_elmt_desc));
if (sfp) {
memset(sfp, 0, SFP_RTDI_LEN);
rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 0, 64, 0);
if (!rval) {
__be16 *trx = (__force __be16 *)sfp; /* already be16 */
/* Optical Element Descriptor, Temperature */
rsp_payload->optical_elmt_desc[0].high_alarm = trx[0];
rsp_payload->optical_elmt_desc[0].low_alarm = trx[1];
rsp_payload->optical_elmt_desc[0].high_warn = trx[2];
rsp_payload->optical_elmt_desc[0].low_warn = trx[3];
rsp_payload->optical_elmt_desc[0].element_flags =
cpu_to_be32(1 << 28);
/* Optical Element Descriptor, Voltage */
rsp_payload->optical_elmt_desc[1].high_alarm = trx[4];
rsp_payload->optical_elmt_desc[1].low_alarm = trx[5];
rsp_payload->optical_elmt_desc[1].high_warn = trx[6];
rsp_payload->optical_elmt_desc[1].low_warn = trx[7];
rsp_payload->optical_elmt_desc[1].element_flags =
cpu_to_be32(2 << 28);
/* Optical Element Descriptor, Tx Bias Current */
rsp_payload->optical_elmt_desc[2].high_alarm = trx[8];
rsp_payload->optical_elmt_desc[2].low_alarm = trx[9];
rsp_payload->optical_elmt_desc[2].high_warn = trx[10];
rsp_payload->optical_elmt_desc[2].low_warn = trx[11];
rsp_payload->optical_elmt_desc[2].element_flags =
cpu_to_be32(3 << 28);
/* Optical Element Descriptor, Tx Power */
rsp_payload->optical_elmt_desc[3].high_alarm = trx[12];
rsp_payload->optical_elmt_desc[3].low_alarm = trx[13];
rsp_payload->optical_elmt_desc[3].high_warn = trx[14];
rsp_payload->optical_elmt_desc[3].low_warn = trx[15];
rsp_payload->optical_elmt_desc[3].element_flags =
cpu_to_be32(4 << 28);
/* Optical Element Descriptor, Rx Power */
rsp_payload->optical_elmt_desc[4].high_alarm = trx[16];
rsp_payload->optical_elmt_desc[4].low_alarm = trx[17];
rsp_payload->optical_elmt_desc[4].high_warn = trx[18];
rsp_payload->optical_elmt_desc[4].low_warn = trx[19];
rsp_payload->optical_elmt_desc[4].element_flags =
cpu_to_be32(5 << 28);
}
memset(sfp, 0, SFP_RTDI_LEN);
rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa2, 112, 64, 0);
if (!rval) {
/* Temperature high/low alarm/warning */
rsp_payload->optical_elmt_desc[0].element_flags |=
cpu_to_be32(
(sfp[0] >> 7 & 1) << 3 |
(sfp[0] >> 6 & 1) << 2 |
(sfp[4] >> 7 & 1) << 1 |
(sfp[4] >> 6 & 1) << 0);
/* Voltage high/low alarm/warning */
rsp_payload->optical_elmt_desc[1].element_flags |=
cpu_to_be32(
(sfp[0] >> 5 & 1) << 3 |
(sfp[0] >> 4 & 1) << 2 |
(sfp[4] >> 5 & 1) << 1 |
(sfp[4] >> 4 & 1) << 0);
/* Tx Bias Current high/low alarm/warning */
rsp_payload->optical_elmt_desc[2].element_flags |=
cpu_to_be32(
(sfp[0] >> 3 & 1) << 3 |
(sfp[0] >> 2 & 1) << 2 |
(sfp[4] >> 3 & 1) << 1 |
(sfp[4] >> 2 & 1) << 0);
/* Tx Power high/low alarm/warning */
rsp_payload->optical_elmt_desc[3].element_flags |=
cpu_to_be32(
(sfp[0] >> 1 & 1) << 3 |
(sfp[0] >> 0 & 1) << 2 |
(sfp[4] >> 1 & 1) << 1 |
(sfp[4] >> 0 & 1) << 0);
/* Rx Power high/low alarm/warning */
rsp_payload->optical_elmt_desc[4].element_flags |=
cpu_to_be32(
(sfp[1] >> 7 & 1) << 3 |
(sfp[1] >> 6 & 1) << 2 |
(sfp[5] >> 7 & 1) << 1 |
(sfp[5] >> 6 & 1) << 0);
}
}
/* Optical Product Data Descriptor */
rsp_payload->optical_prod_desc.desc_tag = cpu_to_be32(0x10008);
rsp_payload->optical_prod_desc.desc_len =
cpu_to_be32(RDP_DESC_LEN(rsp_payload->optical_prod_desc));
if (sfp) {
memset(sfp, 0, SFP_RTDI_LEN);
rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 20, 64, 0);
if (!rval) {
memcpy(rsp_payload->optical_prod_desc.vendor_name,
sfp + 0,
sizeof(rsp_payload->optical_prod_desc.vendor_name));
memcpy(rsp_payload->optical_prod_desc.part_number,
sfp + 20,
sizeof(rsp_payload->optical_prod_desc.part_number));
memcpy(rsp_payload->optical_prod_desc.revision,
sfp + 36,
sizeof(rsp_payload->optical_prod_desc.revision));
memcpy(rsp_payload->optical_prod_desc.serial_number,
sfp + 48,
sizeof(rsp_payload->optical_prod_desc.serial_number));
}
memset(sfp, 0, SFP_RTDI_LEN);
rval = qla2x00_read_sfp(vha, sfp_dma, sfp, 0xa0, 84, 8, 0);
if (!rval) {
memcpy(rsp_payload->optical_prod_desc.date,
sfp + 0,
sizeof(rsp_payload->optical_prod_desc.date));
}
}
send:
ql_dbg(ql_dbg_init, vha, 0x0183,
"Sending ELS Response to RDP Request...\n");
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0184,
"-------- ELS RSP -------\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0185,
rsp_els, sizeof(*rsp_els));
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0186,
"-------- ELS RSP PAYLOAD -------\n");
ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0187,
rsp_payload, rsp_payload_length);
rval = qla2x00_issue_iocb(vha, rsp_els, rsp_els_dma, 0);
if (rval) {
ql_log(ql_log_warn, vha, 0x0188,
"%s: iocb failed to execute -> %x\n", __func__, rval);
} else if (rsp_els->comp_status) {
ql_log(ql_log_warn, vha, 0x0189,
"%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n",
__func__, rsp_els->comp_status,
rsp_els->error_subcode_1, rsp_els->error_subcode_2);
} else {
ql_dbg(ql_dbg_init, vha, 0x018a, "%s: done.\n", __func__);
}
dealloc:
if (stat)
dma_free_coherent(&ha->pdev->dev, sizeof(*stat),
stat, stat_dma);
if (sfp)
dma_free_coherent(&ha->pdev->dev, SFP_RTDI_LEN,
sfp, sfp_dma);
if (rsp_payload)
dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_payload),
rsp_payload, rsp_payload_dma);
if (rsp_els)
dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els),
rsp_els, rsp_els_dma);
}