dma_addr_t dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf,
                                             DCP_BUF_SZ, DMA_FROM_DEVICE);
 
+       if (actx->fill % AES_BLOCK_SIZE) {
+               dev_err(sdcp->dev, "Invalid block size!\n");
+               ret = -EINVAL;
+               goto aes_done_run;
+       }
+
        /* Fill in the DMA descriptor. */
        desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE |
                    MXS_DCP_CONTROL0_INTERRUPT |
 
        ret = mxs_dcp_start_dma(actx);
 
+aes_done_run:
        dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128,
                         DMA_TO_DEVICE);
        dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
 
        uint8_t *out_tmp, *src_buf, *dst_buf = NULL;
        uint32_t dst_off = 0;
+       uint32_t last_out_len = 0;
 
        uint8_t *key = sdcp->coh->aes_key;
 
        int ret = 0;
        int split = 0;
-       unsigned int i, len, clen, rem = 0;
+       unsigned int i, len, clen, rem = 0, tlen = 0;
        int init = 0;
+       bool limit_hit = false;
 
        actx->fill = 0;
 
        for_each_sg(req->src, src, nents, i) {
                src_buf = sg_virt(src);
                len = sg_dma_len(src);
+               tlen += len;
+               limit_hit = tlen > req->nbytes;
+
+               if (limit_hit)
+                       len = req->nbytes - (tlen - len);
 
                do {
                        if (actx->fill + len > out_off)
                         * If we filled the buffer or this is the last SG,
                         * submit the buffer.
                         */
-                       if (actx->fill == out_off || sg_is_last(src)) {
+                       if (actx->fill == out_off || sg_is_last(src) ||
+                               limit_hit) {
                                ret = mxs_dcp_run_aes(actx, req, init);
                                if (ret)
                                        return ret;
                                init = 0;
 
                                out_tmp = out_buf;
+                               last_out_len = actx->fill;
                                while (dst && actx->fill) {
                                        if (!split) {
                                                dst_buf = sg_virt(dst);
                                }
                        }
                } while (len);
+
+               if (limit_hit)
+                       break;
+       }
+
+       /* Copy the IV for CBC for chaining */
+       if (!rctx->ecb) {
+               if (rctx->enc)
+                       memcpy(req->info, out_buf+(last_out_len-AES_BLOCK_SIZE),
+                               AES_BLOCK_SIZE);
+               else
+                       memcpy(req->info, in_buf+(last_out_len-AES_BLOCK_SIZE),
+                               AES_BLOCK_SIZE);
        }
 
        return ret;