/* * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *
*/ #include <linux/bug.h> #include <linux/errno.h> #include <linux/spinlock.h>
constchar *usnic_ib_qp_grp_state_to_string(enum ib_qp_state state)
{ switch (state) { case IB_QPS_RESET: return"Rst"; case IB_QPS_INIT: return"Init"; case IB_QPS_RTR: return"RTR"; case IB_QPS_RTS: return"RTS"; case IB_QPS_SQD: return"SQD"; case IB_QPS_SQE: return"SQE"; case IB_QPS_ERR: return"ERR"; default: return"UNKNOWN STATE";
}
}
int usnic_ib_qp_grp_dump_hdr(char *buf, int buf_sz)
{ return scnprintf(buf, buf_sz, "|QPN\t|State\t|PID\t|VF Idx\t|Fil ID");
}
staticstruct usnic_vnic_res_chunk *
get_qp_res_chunk(struct usnic_ib_qp_grp *qp_grp)
{
lockdep_assert_held(&qp_grp->lock); /* * The QP res chunk, used to derive qp indices, * are just indices of the RQs
*/ return usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
}
res_chunk = get_qp_res_chunk(qp_grp); if (IS_ERR(res_chunk)) {
usnic_err("Unable to get qp res with err %ld\n",
PTR_ERR(res_chunk)); return PTR_ERR(res_chunk);
}
for (i = 0; i < res_chunk->cnt; i++) {
res = res_chunk->res[i];
status = usnic_fwd_enable_qp(qp_grp->ufdev, vnic_idx,
res->vnic_idx); if (status) {
usnic_err("Failed to enable qp %d of %s:%d\n with err %d\n",
res->vnic_idx, qp_grp->ufdev->name,
vnic_idx, status); goto out_err;
}
}
return 0;
out_err: for (i--; i >= 0; i--) {
res = res_chunk->res[i];
usnic_fwd_disable_qp(qp_grp->ufdev, vnic_idx,
res->vnic_idx);
}
return status;
}
staticint disable_qp_grp(struct usnic_ib_qp_grp *qp_grp)
{ int i, vnic_idx; struct usnic_vnic_res_chunk *res_chunk; struct usnic_vnic_res *res; int status = 0;
res_chunk = get_qp_res_chunk(qp_grp); if (IS_ERR(res_chunk)) {
usnic_err("Unable to get qp res with err %ld\n",
PTR_ERR(res_chunk)); return PTR_ERR(res_chunk);
}
for (i = 0; i < res_chunk->cnt; i++) {
res = res_chunk->res[i];
status = usnic_fwd_disable_qp(qp_grp->ufdev, vnic_idx,
res->vnic_idx); if (status) {
usnic_err("Failed to disable rq %d of %s:%d\n with err %d\n",
res->vnic_idx,
qp_grp->ufdev->name,
vnic_idx, status);
}
}
res_chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ); if (IS_ERR(res_chunk)) {
usnic_err("Unable to get %s with err %ld\n",
usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_RQ),
PTR_ERR(res_chunk)); return PTR_ERR(res_chunk);
}
spin_lock(&qp_grp->lock); switch (new_state) { case IB_QPS_RESET: switch (old_state) { case IB_QPS_RESET: /* NO-OP */ break; case IB_QPS_INIT:
release_and_remove_all_flows(qp_grp);
status = 0; break; case IB_QPS_RTR: case IB_QPS_RTS: case IB_QPS_ERR:
status = disable_qp_grp(qp_grp);
release_and_remove_all_flows(qp_grp); break; default:
status = -EINVAL;
} break; case IB_QPS_INIT: switch (old_state) { case IB_QPS_RESET: if (trans_spec) {
qp_flow = create_and_add_flow(qp_grp,
trans_spec); if (IS_ERR_OR_NULL(qp_flow)) {
status = qp_flow ? PTR_ERR(qp_flow) : -EFAULT; break;
}
} else { /* * Optional to specify filters.
*/
status = 0;
} break; case IB_QPS_INIT: if (trans_spec) {
qp_flow = create_and_add_flow(qp_grp,
trans_spec); if (IS_ERR_OR_NULL(qp_flow)) {
status = qp_flow ? PTR_ERR(qp_flow) : -EFAULT; break;
}
} else { /* * Doesn't make sense to go into INIT state * from INIT state w/o adding filters.
*/
status = -EINVAL;
} break; case IB_QPS_RTR:
status = disable_qp_grp(qp_grp); break; case IB_QPS_RTS:
status = disable_qp_grp(qp_grp); break; default:
status = -EINVAL;
} break; case IB_QPS_RTR: switch (old_state) { case IB_QPS_INIT:
status = enable_qp_grp(qp_grp); break; default:
status = -EINVAL;
} break; case IB_QPS_RTS: switch (old_state) { case IB_QPS_RTR: /* NO-OP FOR NOW */ break; default:
status = -EINVAL;
} break; case IB_QPS_ERR:
ib_event.device = &qp_grp->vf->pf->ib_dev;
ib_event.element.qp = &qp_grp->ibqp;
ib_event.event = IB_EVENT_QP_FATAL;
switch (old_state) { case IB_QPS_RESET:
qp_grp->ibqp.event_handler(&ib_event,
qp_grp->ibqp.qp_context); break; case IB_QPS_INIT:
release_and_remove_all_flows(qp_grp);
qp_grp->ibqp.event_handler(&ib_event,
qp_grp->ibqp.qp_context); break; case IB_QPS_RTR: case IB_QPS_RTS:
status = disable_qp_grp(qp_grp);
release_and_remove_all_flows(qp_grp);
qp_grp->ibqp.event_handler(&ib_event,
qp_grp->ibqp.qp_context); break; default:
status = -EINVAL;
} break; default:
status = -EINVAL;
}
spin_unlock(&qp_grp->lock);
if (!status) {
qp_grp->state = new_state;
usnic_info("Transitioned %u from %s to %s",
qp_grp->grp_id,
usnic_ib_qp_grp_state_to_string(old_state),
usnic_ib_qp_grp_state_to_string(new_state));
} else {
usnic_err("Failed to transition %u from %s to %s",
qp_grp->grp_id,
usnic_ib_qp_grp_state_to_string(old_state),
usnic_ib_qp_grp_state_to_string(new_state));
}
switch (trans_type) { case USNIC_TRANSPORT_ROCE_CUSTOM:
*id = qp_flow->usnic_roce.port_num; break; case USNIC_TRANSPORT_IPV4_UDP:
err = usnic_transport_sock_get_addr(qp_flow->udp.sock,
NULL, NULL,
&port_num); if (err) return err; /* * Copy port_num to stack first and then to *id, * so that the short to int cast works for little * and big endian systems.
*/
*id = port_num; break; default:
usnic_err("Unsupported transport %u\n", trans_type); return -EINVAL;
}
return 0;
}
int usnic_ib_qp_grp_create(struct usnic_ib_qp_grp *qp_grp, struct usnic_fwd_dev *ufdev, struct usnic_ib_vf *vf, struct usnic_ib_pd *pd, struct usnic_vnic_res_spec *res_spec, struct usnic_transport_spec *transport_spec)
{ int err; enum usnic_transport_type transport = transport_spec->trans_type; struct usnic_ib_qp_grp_flow *qp_flow;
lockdep_assert_held(&vf->lock);
err = usnic_vnic_res_spec_satisfied(&min_transport_spec[transport],
res_spec); if (err) {
usnic_err("Spec does not meet minimum req for transport %d\n",
transport);
log_spec(res_spec); return err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.