From: Quinn Tran <qutran@xxxxxxxxxxx> Latest FC adapter from Marvell has the ability to encrypt data in flight (EDIF) feature. This feature require an application (ex: ipsec, etc) to act as an authenticator. This patch add 2 new BSG calls: QL_VND_SC_GET_FCINFO: Application from time to time can request for a list of all FC ports or a single device that support secure connection. If driver sees a new or old device has came onto the switch, this call is used to check for the WWPN. QL_VND_SC_GET_STATS: Application request for various statistic count of each FC port. Signed-off-by: Larry Wisneski <Larry.Wisneski@xxxxxxxxxxx> Signed-off-by: Duane Grigsby <duane.grigsby@xxxxxxxxxxx> Signed-off-by: Rick Hicksted Jr <rhicksted@xxxxxxxxxxx> Signed-off-by: Quinn Tran <qutran@xxxxxxxxxxx> Signed-off-by: Nilesh Javali <njavali@xxxxxxxxxxx> --- drivers/scsi/qla2xxx/qla_def.h | 2 + drivers/scsi/qla2xxx/qla_edif.c | 182 ++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index ac3b9b39d741..9c921381d020 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2574,6 +2574,8 @@ typedef struct fc_port { uint16_t app_started:1; uint16_t secured_login:1; uint16_t app_sess_online:1; + uint16_t rekey_cnt; // num of times rekeyed + uint8_t auth_state; /* cureent auth state */ uint32_t tx_rekey_cnt; uint32_t rx_rekey_cnt; // delayed rx delete data structure list diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c index 38d79ef2e700..fd39232fa68d 100644 --- a/drivers/scsi/qla2xxx/qla_edif.c +++ b/drivers/scsi/qla2xxx/qla_edif.c @@ -258,6 +258,182 @@ qla_edif_app_stop(scsi_qla_host_t *vha, struct bsg_job *bsg_job) return rval; } +/* + * event that the app needs fc port info (either all or individual d_id) + */ +static int +qla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job) +{ + int32_t rval = 0; + int32_t num_cnt = 1; + struct fc_bsg_reply *bsg_reply = bsg_job->reply; + struct app_pinfo_req app_req; + struct app_pinfo_reply *app_reply; + port_id_t tdid; + + ql_dbg(ql_dbg_edif, vha, 0x911d, "%s app get fcinfo\n", __func__); + + sg_copy_to_buffer(bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, &app_req, + sizeof(struct app_pinfo_req)); + + num_cnt = app_req.num_ports; /* num of ports alloc'd by app */ + + app_reply = kzalloc((sizeof(struct app_pinfo_reply) + + sizeof(struct app_pinfo) * num_cnt), GFP_KERNEL); + if (!app_reply) { + SET_DID_STATUS(bsg_reply->result, DID_ERROR); + rval = -1; + } else { + struct fc_port *fcport = NULL, *tf; + uint32_t pcnt = 0; + + list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) { + if (!(fcport->flags & FCF_FCSP_DEVICE)) + continue; + + tdid = app_req.remote_pid; + + ql_dbg(ql_dbg_edif, vha, 0x2058, + "APP request entry - portid=%02x%02x%02x.\n", + tdid.b.domain, tdid.b.area, tdid.b.al_pa); + + /* Ran out of space */ + if (pcnt > app_req.num_ports) + break; + + if (tdid.b24 != 0 && tdid.b24 != fcport->d_id.b24) + continue; + + app_reply->ports[pcnt].remote_type = + VND_CMD_RTYPE_UNKNOWN; + if (fcport->port_type & (FCT_NVME_TARGET | FCT_TARGET)) + app_reply->ports[pcnt].remote_type |= + VND_CMD_RTYPE_TARGET; + if (fcport->port_type & (FCT_NVME_INITIATOR | FCT_INITIATOR)) + app_reply->ports[pcnt].remote_type |= + VND_CMD_RTYPE_INITIATOR; + + app_reply->ports[pcnt].remote_pid = fcport->d_id; + + ql_dbg(ql_dbg_edif, vha, 0x2058, + "Found FC_SP fcport - nn %8phN pn %8phN pcnt %d portid=%02x%02x%02x.\n", + fcport->node_name, fcport->port_name, pcnt, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa); + + switch (fcport->edif.auth_state) { + case VND_CMD_AUTH_STATE_ELS_RCVD: + if (fcport->disc_state == DSC_LOGIN_AUTH_PEND) { + fcport->edif.auth_state = VND_CMD_AUTH_STATE_NEEDED; + app_reply->ports[pcnt].auth_state = + VND_CMD_AUTH_STATE_NEEDED; + } else { + app_reply->ports[pcnt].auth_state = + VND_CMD_AUTH_STATE_ELS_RCVD; + } + break; + default: + app_reply->ports[pcnt].auth_state = fcport->edif.auth_state; + break; + } + + memcpy(app_reply->ports[pcnt].remote_wwpn, + fcport->port_name, 8); + + app_reply->ports[pcnt].remote_state = + (atomic_read(&fcport->state) == + FCS_ONLINE ? 1 : 0); + + pcnt++; + + if (tdid.b24 != 0) + break; /* found the one req'd */ + } + app_reply->port_count = pcnt; + SET_DID_STATUS(bsg_reply->result, DID_OK); + } + + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, app_reply, + sizeof(struct app_pinfo_reply) + sizeof(struct app_pinfo) * num_cnt); + + kfree(app_reply); + + return rval; +} + +/* + * return edif stats (TBD) to app + */ +static int32_t +qla_edif_app_getstats(scsi_qla_host_t *vha, struct bsg_job *bsg_job) +{ + int32_t rval = 0; + struct fc_bsg_reply *bsg_reply = bsg_job->reply; + uint32_t ret_size, size; + + struct app_sinfo_req app_req; + struct app_stats_reply *app_reply; + + sg_copy_to_buffer(bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, &app_req, + sizeof(struct app_sinfo_req)); + if (app_req.num_ports == 0) { + ql_dbg(ql_dbg_async, vha, 0x911d, + "%s app did not indicate number of ports to return\n", + __func__); + SET_DID_STATUS(bsg_reply->result, DID_ERROR); + rval = -1; + } + + size = sizeof(struct app_stats_reply) + + (sizeof(struct app_sinfo) * app_req.num_ports); + + if (size > bsg_job->reply_payload.payload_len) + ret_size = bsg_job->reply_payload.payload_len; + else + ret_size = size; + + app_reply = kzalloc(size, GFP_KERNEL); + if (!app_reply) { + SET_DID_STATUS(bsg_reply->result, DID_ERROR); + rval = -1; + } else { + struct fc_port *fcport = NULL, *tf; + uint32_t pcnt = 0; + + list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) { + if (fcport->edif.enable) { + if (pcnt > app_req.num_ports) + break; + + app_reply->elem[pcnt].rekey_count = + fcport->edif.rekey_cnt; + app_reply->elem[pcnt].tx_bytes = + fcport->edif.tx_bytes; + app_reply->elem[pcnt].rx_bytes = + fcport->edif.rx_bytes; + + memcpy(app_reply->elem[pcnt].remote_wwpn, + fcport->port_name, 8); + + pcnt++; + } + } + app_reply->elem_count = pcnt; + SET_DID_STATUS(bsg_reply->result, DID_OK); + } + + bsg_reply->reply_payload_rcv_len = + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, app_reply, ret_size); + + kfree(app_reply); + + return rval; +} + int32_t qla_edif_app_mgmt(struct bsg_job *bsg_job) { @@ -304,6 +480,12 @@ qla_edif_app_mgmt(struct bsg_job *bsg_job) case QL_VND_SC_APP_STOP: rval = qla_edif_app_stop(vha, bsg_job); break; + case QL_VND_SC_GET_FCINFO: + rval = qla_edif_app_getfcinfo(vha, bsg_job); + break; + case QL_VND_SC_GET_STATS: + rval = qla_edif_app_getstats(vha, bsg_job); + break; default: ql_dbg(ql_dbg_edif, vha, 0x911d, "%s unknown cmd=%x\n", __func__, -- 2.19.0.rc0