Commit 386b97b4 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by Martin K. Petersen
Browse files

scsi: libfc: Rework PRLI handling



PRLI is only required if the port is acting as an initiator; ports
which support target functionality only do not need to send PRLI.
At the same time the PRLI state is only used if the port initiated
a PRLI transfer; if we received a PRLI request we should _not_
change the state as this would cause our PRLI response to be dropped.
And when we receive a PRLI response we need to check if an image
pair has been established; if not the remote port cannot act as a
target for us and we need to disable target functionality.

Signed-off-by: default avatarHannes Reinecke <hare@suse.com>
Acked-by: default avatarJohannes Thumshirn <jth@kernel.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 7c5a51b8
Loading
Loading
Loading
Loading
+38 −18
Original line number Diff line number Diff line
@@ -1126,7 +1126,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
	u32 roles = FC_RPORT_ROLE_UNKNOWN;
	u32 fcp_parm = 0;
	u8 op;
	u8 resp_code = 0;
	enum fc_els_spp_resp resp_code;

	FC_RPORT_DBG(rdata, "Received a PRLI %s\n", fc_els_resp_type(fp));

@@ -1158,8 +1158,8 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
			goto out;

		resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK);
		FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n",
			     pp->spp.spp_flags);
		FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x spp_type 0x%x\n",
			     pp->spp.spp_flags, pp->spp.spp_type);
		rdata->spp_type = pp->spp.spp_type;
		if (resp_code != FC_SPP_RESP_ACK) {
			if (resp_code == FC_SPP_RESP_CONF)
@@ -1177,13 +1177,26 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
		if (fcp_parm & FCP_SPPF_CONF_COMPL)
			rdata->flags |= FC_RP_FLAGS_CONF_REQ;

		prov = fc_passive_prov[FC_TYPE_FCP];
		/*
		 * Call prli provider if we should act as a target
		 */
		prov = fc_passive_prov[rdata->spp_type];
		if (prov) {
			memset(&temp_spp, 0, sizeof(temp_spp));
			prov->prli(rdata, pp->prli.prli_spp_len,
				   &pp->spp, &temp_spp);
		}

		/*
		 * Check if the image pair could be established
		 */
		if (rdata->spp_type != FC_TYPE_FCP ||
		    resp_code != FC_SPP_RESP_ACK ||
		    !(pp->spp.spp_flags & FC_SPP_EST_IMG_PAIR)) {
			/*
			 * Nope; we can't use this port as a target.
			 */
			fcp_parm &= ~FCP_SPPF_TARG_FCN;
		}
		rdata->supported_classes = FC_COS_CLASS3;
		if (fcp_parm & FCP_SPPF_INIT_FCN)
			roles |= FC_RPORT_ROLE_FCP_INITIATOR;
@@ -1236,6 +1249,15 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
		return;
	}

	/*
	 * And if the local port does not support the initiator function
	 * there's no need to send a PRLI, either.
	 */
	if (!(lport->service_params & FCP_SPPF_INIT_FCN)) {
		    fc_rport_enter_ready(rdata);
		    return;
	}

	FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n",
		     fc_rport_state(rdata));

@@ -1926,7 +1948,6 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
	unsigned int len;
	unsigned int plen;
	enum fc_els_spp_resp resp;
	enum fc_els_spp_resp passive;
	struct fc_seq_els_data rjt_data;
	struct fc4_prov *prov;

@@ -1976,15 +1997,21 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
		resp = 0;

		if (rspp->spp_type < FC_FC4_PROV_SIZE) {
			enum fc_els_spp_resp active = 0, passive = 0;

			prov = fc_active_prov[rspp->spp_type];
			if (prov)
				resp = prov->prli(rdata, plen, rspp, spp);
				active = prov->prli(rdata, plen, rspp, spp);
			prov = fc_passive_prov[rspp->spp_type];
			if (prov) {
			if (prov)
				passive = prov->prli(rdata, plen, rspp, spp);
				if (!resp || passive == FC_SPP_RESP_ACK)
			if (!active || passive == FC_SPP_RESP_ACK)
				resp = passive;
			}
			else
				resp = active;
			FC_RPORT_DBG(rdata, "PRLI rspp type %x "
				     "active %x passive %x\n",
				     rspp->spp_type, active, passive);
		}
		if (!resp) {
			if (spp->spp_flags & FC_SPP_EST_IMG_PAIR)
@@ -2005,13 +2032,6 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
	fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
	lport->tt.frame_send(lport, fp);

	switch (rdata->rp_state) {
	case RPORT_ST_PRLI:
		fc_rport_enter_ready(rdata);
		break;
	default:
		break;
	}
	goto drop;

reject_len: