|
@@ -257,6 +257,8 @@ static void fc_rport_work(struct work_struct *work)
|
|
|
struct fc_rport_operations *rport_ops;
|
|
|
struct fc_rport_identifiers ids;
|
|
|
struct fc_rport *rport;
|
|
|
+ struct fc4_prov *prov;
|
|
|
+ u8 type;
|
|
|
|
|
|
mutex_lock(&rdata->rp_mutex);
|
|
|
event = rdata->event;
|
|
@@ -306,6 +308,15 @@ static void fc_rport_work(struct work_struct *work)
|
|
|
case RPORT_EV_FAILED:
|
|
|
case RPORT_EV_LOGO:
|
|
|
case RPORT_EV_STOP:
|
|
|
+ if (rdata->prli_count) {
|
|
|
+ mutex_lock(&fc_prov_mutex);
|
|
|
+ for (type = 1; type < FC_FC4_PROV_SIZE; type++) {
|
|
|
+ prov = fc_passive_prov[type];
|
|
|
+ if (prov && prov->prlo)
|
|
|
+ prov->prlo(rdata);
|
|
|
+ }
|
|
|
+ mutex_unlock(&fc_prov_mutex);
|
|
|
+ }
|
|
|
port_id = rdata->ids.port_id;
|
|
|
mutex_unlock(&rdata->rp_mutex);
|
|
|
|
|
@@ -1643,9 +1654,9 @@ 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;
|
|
|
- u32 fcp_parm;
|
|
|
- u32 roles = FC_RPORT_ROLE_UNKNOWN;
|
|
|
+ struct fc4_prov *prov;
|
|
|
|
|
|
FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
|
|
|
fc_rport_state(rdata));
|
|
@@ -1679,46 +1690,41 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
|
|
|
pp->prli.prli_len = htons(len);
|
|
|
len -= sizeof(struct fc_els_prli);
|
|
|
|
|
|
- /* reinitialize remote port roles */
|
|
|
- rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
|
|
|
-
|
|
|
/*
|
|
|
* Go through all the service parameter pages and build
|
|
|
* response. If plen indicates longer SPP than standard,
|
|
|
* use that. The entire response has been pre-cleared above.
|
|
|
*/
|
|
|
spp = &pp->spp;
|
|
|
+ mutex_lock(&fc_prov_mutex);
|
|
|
while (len >= plen) {
|
|
|
spp->spp_type = rspp->spp_type;
|
|
|
spp->spp_type_ext = rspp->spp_type_ext;
|
|
|
- spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
|
|
|
- resp = FC_SPP_RESP_ACK;
|
|
|
-
|
|
|
- switch (rspp->spp_type) {
|
|
|
- case 0: /* common to all FC-4 types */
|
|
|
- break;
|
|
|
- case FC_TYPE_FCP:
|
|
|
- fcp_parm = ntohl(rspp->spp_params);
|
|
|
- if (fcp_parm & FCP_SPPF_RETRY)
|
|
|
- rdata->flags |= FC_RP_FLAGS_RETRY;
|
|
|
- rdata->supported_classes = FC_COS_CLASS3;
|
|
|
- if (fcp_parm & FCP_SPPF_INIT_FCN)
|
|
|
- roles |= FC_RPORT_ROLE_FCP_INITIATOR;
|
|
|
- if (fcp_parm & FCP_SPPF_TARG_FCN)
|
|
|
- roles |= FC_RPORT_ROLE_FCP_TARGET;
|
|
|
- rdata->ids.roles = roles;
|
|
|
-
|
|
|
- spp->spp_params = htonl(lport->service_params);
|
|
|
- break;
|
|
|
- default:
|
|
|
- resp = FC_SPP_RESP_INVL;
|
|
|
- break;
|
|
|
+ resp = 0;
|
|
|
+
|
|
|
+ if (rspp->spp_type < FC_FC4_PROV_SIZE) {
|
|
|
+ prov = fc_active_prov[rspp->spp_type];
|
|
|
+ if (prov)
|
|
|
+ resp = prov->prli(rdata, plen, rspp, spp);
|
|
|
+ prov = fc_passive_prov[rspp->spp_type];
|
|
|
+ if (prov) {
|
|
|
+ passive = prov->prli(rdata, plen, rspp, spp);
|
|
|
+ if (!resp || passive == FC_SPP_RESP_ACK)
|
|
|
+ resp = passive;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!resp) {
|
|
|
+ if (spp->spp_flags & FC_SPP_EST_IMG_PAIR)
|
|
|
+ resp |= FC_SPP_RESP_CONF;
|
|
|
+ else
|
|
|
+ resp |= FC_SPP_RESP_INVL;
|
|
|
}
|
|
|
spp->spp_flags |= resp;
|
|
|
len -= plen;
|
|
|
rspp = (struct fc_els_spp *)((char *)rspp + plen);
|
|
|
spp = (struct fc_els_spp *)((char *)spp + plen);
|
|
|
}
|
|
|
+ mutex_unlock(&fc_prov_mutex);
|
|
|
|
|
|
/*
|
|
|
* Send LS_ACC. If this fails, the originator should retry.
|
|
@@ -1887,6 +1893,79 @@ int fc_rport_init(struct fc_lport *lport)
|
|
|
}
|
|
|
EXPORT_SYMBOL(fc_rport_init);
|
|
|
|
|
|
+/**
|
|
|
+ * fc_rport_fcp_prli() - Handle incoming PRLI for the FCP initiator.
|
|
|
+ * @rdata: remote port private
|
|
|
+ * @spp_len: service parameter page length
|
|
|
+ * @rspp: received service parameter page
|
|
|
+ * @spp: response service parameter page
|
|
|
+ *
|
|
|
+ * Returns the value for the response code to be placed in spp_flags;
|
|
|
+ * Returns 0 if not an initiator.
|
|
|
+ */
|
|
|
+static int fc_rport_fcp_prli(struct fc_rport_priv *rdata, u32 spp_len,
|
|
|
+ const struct fc_els_spp *rspp,
|
|
|
+ struct fc_els_spp *spp)
|
|
|
+{
|
|
|
+ struct fc_lport *lport = rdata->local_port;
|
|
|
+ u32 fcp_parm;
|
|
|
+
|
|
|
+ fcp_parm = ntohl(rspp->spp_params);
|
|
|
+ rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
|
|
|
+ if (fcp_parm & FCP_SPPF_INIT_FCN)
|
|
|
+ rdata->ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
|
|
|
+ if (fcp_parm & FCP_SPPF_TARG_FCN)
|
|
|
+ rdata->ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
|
|
|
+ if (fcp_parm & FCP_SPPF_RETRY)
|
|
|
+ rdata->flags |= FC_RP_FLAGS_RETRY;
|
|
|
+ rdata->supported_classes = FC_COS_CLASS3;
|
|
|
+
|
|
|
+ if (!(lport->service_params & FC_RPORT_ROLE_FCP_INITIATOR))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ spp->spp_flags |= rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * OR in our service parameters with other providers (target), if any.
|
|
|
+ */
|
|
|
+ fcp_parm = ntohl(spp->spp_params);
|
|
|
+ spp->spp_params = htonl(fcp_parm | lport->service_params);
|
|
|
+ return FC_SPP_RESP_ACK;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * FC-4 provider ops for FCP initiator.
|
|
|
+ */
|
|
|
+struct fc4_prov fc_rport_fcp_init = {
|
|
|
+ .prli = fc_rport_fcp_prli,
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * fc_rport_t0_prli() - Handle incoming PRLI parameters for type 0
|
|
|
+ * @rdata: remote port private
|
|
|
+ * @spp_len: service parameter page length
|
|
|
+ * @rspp: received service parameter page
|
|
|
+ * @spp: response service parameter page
|
|
|
+ */
|
|
|
+static int fc_rport_t0_prli(struct fc_rport_priv *rdata, u32 spp_len,
|
|
|
+ const struct fc_els_spp *rspp,
|
|
|
+ struct fc_els_spp *spp)
|
|
|
+{
|
|
|
+ if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR)
|
|
|
+ return FC_SPP_RESP_INVL;
|
|
|
+ return FC_SPP_RESP_ACK;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * FC-4 provider ops for type 0 service parameters.
|
|
|
+ *
|
|
|
+ * This handles the special case of type 0 which is always successful
|
|
|
+ * but doesn't do anything otherwise.
|
|
|
+ */
|
|
|
+struct fc4_prov fc_rport_t0_prov = {
|
|
|
+ .prli = fc_rport_t0_prli,
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* fc_setup_rport() - Initialize the rport_event_queue
|
|
|
*/
|