void qla24xx_process_purex_rdp()

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);
}