diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index d3aec1959394..1bcc5e11d2c0 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -122,6 +122,7 @@ static const char *fc_lport_state_names[] = { [LPORT_ST_RSNN_NN] = "RSNN_NN", [LPORT_ST_RSPN_ID] = "RSPN_ID", [LPORT_ST_RFT_ID] = "RFT_ID", + [LPORT_ST_RFF_ID] = "RFF_ID", [LPORT_ST_SCR] = "SCR", [LPORT_ST_READY] = "Ready", [LPORT_ST_LOGO] = "LOGO", @@ -1034,6 +1035,7 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) case LPORT_ST_RSNN_NN: case LPORT_ST_RSPN_ID: case LPORT_ST_RFT_ID: + case LPORT_ST_RFF_ID: case LPORT_ST_SCR: case LPORT_ST_DNS: case LPORT_ST_FLOGI: @@ -1070,7 +1072,7 @@ static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp, mutex_lock(&lport->lp_mutex); - if (lport->state < LPORT_ST_RNN_ID || lport->state > LPORT_ST_RFT_ID) { + if (lport->state < LPORT_ST_RNN_ID || lport->state > LPORT_ST_RFF_ID) { FC_LPORT_DBG(lport, "Received a name server response, " "but in state %s\n", fc_lport_state(lport)); if (IS_ERR(fp)) @@ -1101,6 +1103,9 @@ static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp, fc_lport_enter_ns(lport, LPORT_ST_RFT_ID); break; case LPORT_ST_RFT_ID: + fc_lport_enter_ns(lport, LPORT_ST_RFF_ID); + break; + case LPORT_ST_RFF_ID: fc_lport_enter_scr(lport); break; default: @@ -1235,6 +1240,10 @@ static void fc_lport_enter_ns(struct fc_lport *lport, enum fc_lport_state state) cmd = FC_NS_RFT_ID; size += sizeof(struct fc_ns_rft); break; + case LPORT_ST_RFF_ID: + cmd = FC_NS_RFF_ID; + size += sizeof(struct fc_ns_rff_id); + break; default: fc_lport_error(lport, NULL); return; @@ -1317,6 +1326,7 @@ static void fc_lport_timeout(struct work_struct *work) case LPORT_ST_RSNN_NN: case LPORT_ST_RSPN_ID: case LPORT_ST_RFT_ID: + case LPORT_ST_RFF_ID: fc_lport_enter_ns(lport, lport->state); break; case LPORT_ST_SCR: diff --git a/include/scsi/fc/fc_fcp.h b/include/scsi/fc/fc_fcp.h index 5d38f1989f37..29ecb0b02b09 100644 --- a/include/scsi/fc/fc_fcp.h +++ b/include/scsi/fc/fc_fcp.h @@ -196,4 +196,10 @@ struct fcp_srr { __u8 srr_resvd2[3]; /* reserved */ }; +/* + * Feature bits in name server FC-4 Features object. + */ +#define FCP_FEAT_TARG (1 << 0) /* target function supported */ +#define FCP_FEAT_INIT (1 << 1) /* initiator function supported */ + #endif /* _FC_FCP_H_ */ diff --git a/include/scsi/fc/fc_ns.h b/include/scsi/fc/fc_ns.h index f4d354eb26b9..e7d3ac497d7d 100644 --- a/include/scsi/fc/fc_ns.h +++ b/include/scsi/fc/fc_ns.h @@ -46,10 +46,11 @@ enum fc_ns_req { FC_NS_GID_FT = 0x0171, /* get IDs by FC4 type */ FC_NS_GPN_FT = 0x0172, /* get port names by FC4 type */ FC_NS_GID_PT = 0x01a1, /* get IDs by port type */ - FC_NS_RFT_ID = 0x0217, /* reg FC4 type for ID */ FC_NS_RPN_ID = 0x0212, /* reg port name for ID */ FC_NS_RNN_ID = 0x0213, /* reg node name for ID */ + FC_NS_RFT_ID = 0x0217, /* reg FC4 type for ID */ FC_NS_RSPN_ID = 0x0218, /* reg symbolic port name */ + FC_NS_RFF_ID = 0x021f, /* reg FC4 Features for ID */ FC_NS_RSNN_NN = 0x0239, /* reg symbolic node name */ }; @@ -178,4 +179,14 @@ struct fc_ns_rspn { char fr_name[]; } __attribute__((__packed__)); +/* + * RFF_ID request - register FC-4 Features for ID. + */ +struct fc_ns_rff_id { + struct fc_ns_fid fr_fid; /* port ID object */ + __u8 fr_resvd[2]; + __u8 fr_feat; /* FC-4 Feature bits */ + __u8 fr_type; /* FC-4 type */ +} __attribute__((__packed__)); + #endif /* _FC_NS_H_ */ diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h index ab2260cb149c..8eb0a0fc0a71 100644 --- a/include/scsi/fc_encode.h +++ b/include/scsi/fc_encode.h @@ -32,6 +32,7 @@ struct fc_ct_req { struct fc_ns_gid_ft gid; struct fc_ns_rn_id rn; struct fc_ns_rft rft; + struct fc_ns_rff_id rff; struct fc_ns_fid fid; struct fc_ns_rsnn snn; struct fc_ns_rspn spn; @@ -131,6 +132,17 @@ static inline int fc_ct_fill(struct fc_lport *lport, ct->payload.rft.fts = lport->fcts; break; + case FC_NS_RFF_ID: + ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rff_id)); + hton24(ct->payload.rff.fr_fid.fp_fid, + fc_host_port_id(lport->host)); + ct->payload.rff.fr_type = FC_TYPE_FCP; + if (lport->service_params & FCP_SPPF_INIT_FCN) + ct->payload.rff.fr_feat = FCP_FEAT_INIT; + if (lport->service_params & FCP_SPPF_TARG_FCN) + ct->payload.rff.fr_feat |= FCP_FEAT_TARG; + break; + case FC_NS_RNN_ID: ct = fc_ct_hdr_fill(fp, op, sizeof(struct fc_ns_rn_id)); hton24(ct->payload.rn.fr_fid.fp_fid, diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 67ce9fa1fee4..2936fbae41e4 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -62,6 +62,7 @@ * @LPORT_ST_DNS: Waiting for name server remote port to become ready * @LPORT_ST_RPN_ID: Register port name by ID (RPN_ID) sent * @LPORT_ST_RFT_ID: Register Fibre Channel types by ID (RFT_ID) sent + * @LPORT_ST_RFF_ID: Register FC-4 Features by ID (RFF_ID) sent * @LPORT_ST_SCR: State Change Register (SCR) sent * @LPORT_ST_READY: Ready for use * @LPORT_ST_LOGO: Local port logout (LOGO) sent @@ -75,6 +76,7 @@ enum fc_lport_state { LPORT_ST_RSNN_NN, LPORT_ST_RSPN_ID, LPORT_ST_RFT_ID, + LPORT_ST_RFF_ID, LPORT_ST_SCR, LPORT_ST_READY, LPORT_ST_LOGO,