+/**
+ * Prepare a single security protocol request.
+ *
+ * This function basically translates DPDK security request into one
+ * understandable by MUDSK's SAM. If this is a first request in a session,
+ * it starts the session.
+ *
+ * @param request Pointer to pre-allocated && reset request buffer [Out].
+ * @param src_bd Pointer to pre-allocated source descriptor [Out].
+ * @param dst_bd Pointer to pre-allocated destination descriptor [Out].
+ * @param op Pointer to DPDK crypto operation struct [In].
+ */
+static inline int
+mrvl_request_prepare_sec(struct sam_cio_ipsec_params *request,
+ struct sam_buf_info *src_bd,
+ struct sam_buf_info *dst_bd,
+ struct rte_crypto_op *op)
+{
+ struct mrvl_crypto_session *sess;
+ struct rte_mbuf *src_mbuf, *dst_mbuf;
+ uint16_t segments_nb;
+ int i;
+
+ if (unlikely(op->sess_type != RTE_CRYPTO_OP_SECURITY_SESSION)) {
+ MRVL_LOG(ERR, "MRVL SECURITY: sess_type is not SECURITY_SESSION");
+ return -EINVAL;
+ }
+
+ sess = (struct mrvl_crypto_session *)get_sec_session_private_data(
+ op->sym->sec_session);
+ if (unlikely(sess == NULL)) {
+ MRVL_LOG(ERR, "Session was not created for this device! %d",
+ cryptodev_driver_id);
+ return -EINVAL;
+ }
+
+ request->sa = sess->sam_sess;
+ request->cookie = op;
+ src_mbuf = op->sym->m_src;
+ segments_nb = src_mbuf->nb_segs;
+ /* The following conditions must be met:
+ * - Destination buffer is required when segmented source buffer
+ * - Segmented destination buffer is not supported
+ */
+ if ((segments_nb > 1) && (!op->sym->m_dst)) {
+ MRVL_LOG(ERR, "op->sym->m_dst = NULL!");
+ return -1;
+ }
+ /* For non SG case:
+ * If application delivered us null dst buffer, it means it expects
+ * us to deliver the result in src buffer.
+ */
+ dst_mbuf = op->sym->m_dst ? op->sym->m_dst : op->sym->m_src;
+
+ if (!rte_pktmbuf_is_contiguous(dst_mbuf)) {
+ MRVL_LOG(ERR, "Segmented destination buffer not supported!");
+ return -1;
+ }
+
+ request->num_bufs = segments_nb;
+ for (i = 0; i < segments_nb; i++) {
+ /* Empty source. */
+ if (rte_pktmbuf_data_len(src_mbuf) == 0) {
+ /* EIP does not support 0 length buffers. */
+ MRVL_LOG(ERR, "Buffer length == 0 not supported!");
+ return -1;
+ }
+ src_bd[i].vaddr = rte_pktmbuf_mtod(src_mbuf, void *);
+ src_bd[i].paddr = rte_pktmbuf_iova(src_mbuf);
+ src_bd[i].len = rte_pktmbuf_data_len(src_mbuf);
+
+ src_mbuf = src_mbuf->next;
+ }
+ request->src = src_bd;
+
+ /* Empty destination. */
+ if (rte_pktmbuf_data_len(dst_mbuf) == 0) {
+ /* Make dst buffer fit at least source data. */
+ if (rte_pktmbuf_append(dst_mbuf,
+ rte_pktmbuf_data_len(op->sym->m_src)) == NULL) {
+ MRVL_LOG(ERR, "Unable to set big enough dst buffer!");
+ return -1;
+ }
+ }
+
+ request->dst = dst_bd;
+ dst_bd->vaddr = rte_pktmbuf_mtod(dst_mbuf, void *);
+ dst_bd->paddr = rte_pktmbuf_iova(dst_mbuf);
+
+ /*
+ * We can use all available space in dst_mbuf,
+ * not only what's used currently.
+ */
+ dst_bd->len = dst_mbuf->buf_len - rte_pktmbuf_headroom(dst_mbuf);
+
+
+ request->l3_offset = 0;
+ request->pkt_size = rte_pktmbuf_pkt_len(op->sym->m_src);
+
+ return 0;
+}
+