/*
 * Copyright (c) 2010 Cisco Systems, Inc.
 *
 * Portions based on drivers/scsi/libfc/fc_fcp.c and subject to the following:
 *
 * Copyright (c) 2007 Intel Corporation. All rights reserved.
 * Copyright (c) 2008 Red Hat, Inc.  All rights reserved.
 * Copyright (c) 2008 Mike Christie
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.
 */
#include <linux/kernel.h>
#include <linux/types.h>
#include <scsi/libfc.h>
#include <scsi/fc_encode.h>
#include "fcst.h"

/*
 * Send read data back to initiator.
 */
int ft_send_read_data(struct scst_cmd *cmd)
{
	struct ft_cmd *fcmd;
	struct fc_frame *fp = NULL;
	struct fc_exch *ep;
	struct fc_lport *lport;
	size_t remaining;
	u32 fh_off = 0;
	u32 frame_off;
	size_t frame_len = 0;
	size_t mem_len;
	u32 mem_off;
	size_t tlen;
	struct page *page;
	int use_sg;
	int error;
	void *to = NULL;
	u8 *from = NULL;
	int loop_limit = 10000;

	fcmd = scst_cmd_get_tgt_priv(cmd);
	ep = fc_seq_exch(fcmd->seq);
	lport = ep->lp;

	frame_off = fcmd->read_data_len;
	tlen = scst_cmd_get_resp_data_len(cmd);
	FT_IO_DBG("oid %x oxid %x resp_len %zd frame_off %u\n",
		  ep->oid, ep->oxid, tlen, frame_off);
	if (tlen <= frame_off)
		return SCST_TGT_RES_SUCCESS;
	remaining = tlen - frame_off;
	if (remaining > UINT_MAX)
		FT_ERR("oid %x oxid %x resp_len %zd frame_off %u\n",
		       ep->oid, ep->oxid, tlen, frame_off);

	mem_len = scst_get_buf_first(cmd, &from);
	mem_off = 0;
	if (!mem_len) {
		FT_IO_DBG("mem_len 0\n");
		return SCST_TGT_RES_SUCCESS;
	}
	FT_IO_DBG("sid %x oxid %x mem_len %zd frame_off %u remaining %zd\n",
		 ep->sid, ep->oxid, mem_len, frame_off, remaining);

	/*
	 * If we've already transferred some of the data, skip through
	 * the buffer over the data already sent and continue with the
	 * same sequence.  Otherwise, get a new sequence for the data.
	 */
	if (frame_off) {
		tlen = frame_off;
		while (mem_len <= tlen) {
			tlen -= mem_len;
			scst_put_buf(cmd, from);
			mem_len = scst_get_buf_next(cmd, &from);
			if (!mem_len)
				return SCST_TGT_RES_SUCCESS;
		}
		mem_len -= tlen;
		mem_off = tlen;
	} else
#ifdef NEW_LIBFC_API
		fcmd->seq = fc_seq_start_next(fcmd->seq);
#else
		fcmd->seq = lport->tt.seq_start_next(fcmd->seq);
#endif

	/* no scatter/gather in skb for odd word length due to fc_seq_send() */
	use_sg = !(remaining % 4) && lport->sg_supp;
	/*
	 * Note: since libfc_function_template.seq_send() sends frames
	 * asynchronously and since the SCST data buffer is freed as soon as
	 * scst_tgt_cmd_done() has been invoked, data has to be copied into
	 * the skb instead of only copying a pointer to the data. To do: defer
	 * invocation of scst_tgt_cmd_done() until sending the data frames
	 * finished once the paged fragment destructor or an equivalent is
	 * upstream.
	 */
	use_sg = false;

	while (remaining) {
		if (!loop_limit) {
			FT_ERR("hit loop limit.  remaining %zx mem_len %zx frame_len %zx tlen %zx\n",
			       remaining, mem_len, frame_len, tlen);
			break;
		}
		loop_limit--;
		if (!mem_len) {
			scst_put_buf(cmd, from);
			mem_len = scst_get_buf_next(cmd, &from);
			mem_off = 0;
			if (!mem_len) {
				FT_ERR("mem_len 0 from get_buf_next\n");
				break;
			}
		}
		if (!frame_len) {
			frame_len = fcmd->max_lso_payload;
			frame_len = min(frame_len, remaining);
			fp = fc_frame_alloc(lport, use_sg ? 0 : frame_len);
			if (!fp) {
				FT_IO_DBG("frame_alloc failed. use_sg %d frame_len %zd\n",
					  use_sg, frame_len);
				break;
			}
			fr_max_payload(fp) = fcmd->max_payload;
			to = fc_frame_payload_get(fp, 0);
			fh_off = frame_off;
		}
		tlen = min(mem_len, frame_len);
		BUG_ON(!tlen);
		BUG_ON(tlen > remaining);
		BUG_ON(tlen > mem_len);
		BUG_ON(tlen > frame_len);

		if (use_sg) {
			page = virt_to_page(from + mem_off);
			get_page(page);
			tlen = min_t(size_t, tlen,
				     PAGE_SIZE - (mem_off & ~PAGE_MASK));
			skb_fill_page_desc(fp_skb(fp),
					   skb_shinfo(fp_skb(fp))->nr_frags,
					   page, offset_in_page(from + mem_off),
					   tlen);
			fr_len(fp) += tlen;
			fp_skb(fp)->data_len += tlen;
			fp_skb(fp)->truesize +=
					PAGE_SIZE << compound_order(page);
			frame_len -= tlen;
			if (skb_shinfo(fp_skb(fp))->nr_frags >= FC_FRAME_SG_LEN)
				frame_len = 0;
		} else {
			memcpy(to, from + mem_off, tlen);
			to += tlen;
			frame_len -= tlen;
		}

		mem_off += tlen;
		mem_len -= tlen;
		frame_off += tlen;
		remaining -= tlen;

		if (frame_len)
			continue;
		fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid,
			       FC_TYPE_FCP,
			       remaining ? (FC_FC_EX_CTX | FC_FC_REL_OFF) :
			       (FC_FC_EX_CTX | FC_FC_REL_OFF | FC_FC_END_SEQ),
			       fh_off);
#ifdef NEW_LIBFC_API
		error = FCST_INJ_SEND_ERR(fc_seq_send(lport, fcmd->seq, fp));
#else
		error = FCST_INJ_SEND_ERR(lport->tt.seq_send(lport, fcmd->seq,
							     fp));
#endif
		if (error) {
			pr_warn("Sending frame with oid %#x oxid %#x resp_len %d failed at frame_off %u / remaining %zu with error code %d  - %s",
				ep->oid, ep->oxid,
				scst_cmd_get_resp_data_len(cmd), frame_off,
				remaining, error, error == -ENOMEM ?
				"retrying" : "giving up");
			return error == -ENOMEM ? SCST_TGT_RES_QUEUE_FULL :
				SCST_TGT_RES_FATAL_ERROR;
		} else
			fcmd->read_data_len = frame_off;
	}
	if (mem_len)
		scst_put_buf(cmd, from);
	if (remaining) {
		FT_IO_DBG("remaining read data %zd\n", remaining);
		return SCST_TGT_RES_QUEUE_FULL;
	}
	return SCST_TGT_RES_SUCCESS;
}

/*
 * Receive write data frame.
 */
void ft_recv_write_data(struct scst_cmd *cmd, struct fc_frame *fp)
{
	struct ft_cmd *fcmd;
	struct fc_frame_header *fh;
	unsigned int bufflen;
	u32 rel_off;
	size_t frame_len;
	size_t mem_len;
	size_t tlen;
	void *from;
	void *to;
	int dir;
	u8 *buf;

	dir = scst_cmd_get_data_direction(cmd);
	if (dir == SCST_DATA_BIDI) {
		mem_len = scst_get_out_buf_first(cmd, &buf);
		bufflen = scst_cmd_get_out_bufflen(cmd);
	} else {
		mem_len = scst_get_buf_first(cmd, &buf);
		bufflen = scst_cmd_get_bufflen(cmd);
	}
	to = buf;

	fcmd = scst_cmd_get_tgt_priv(cmd);
	fh = fc_frame_header_get(fp);

	if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF))
		goto drop;
	rel_off = ntohl(fh->fh_parm_offset);
	frame_len = fr_len(fp);
	if (frame_len <= sizeof(*fh))
		goto drop;
	frame_len -= sizeof(*fh);
	from = fc_frame_payload_get(fp, 0);

	if (rel_off >= bufflen)
		goto drop;
	if (frame_len + rel_off > bufflen)
		frame_len = bufflen - rel_off;

	while (frame_len) {
		if (!mem_len) {
			if (dir == SCST_DATA_BIDI) {
				scst_put_out_buf(cmd, buf);
				mem_len = scst_get_out_buf_next(cmd, &buf);
			} else {
				scst_put_buf(cmd, buf);
				mem_len = scst_get_buf_next(cmd, &buf);
			}
			to = buf;
			if (!mem_len)
				break;
		}
		if (rel_off) {
			if (rel_off >= mem_len) {
				rel_off -= mem_len;
				mem_len = 0;
				continue;
			}
			mem_len -= rel_off;
			to += rel_off;
			rel_off = 0;
		}

		tlen = min(mem_len, frame_len);
		memcpy(to, from, tlen);

		from += tlen;
		frame_len -= tlen;
		mem_len -= tlen;
		to += tlen;
		fcmd->write_data_len += tlen;
	}
	if (mem_len) {
		if (dir == SCST_DATA_BIDI)
			scst_put_out_buf(cmd, buf);
		else
			scst_put_buf(cmd, buf);
	}
	if (fcmd->write_data_len == bufflen) {
		spin_lock(&fcmd->lock);
		if (fcmd->state == FT_STATE_NEED_DATA) {
			fcmd->state = FT_STATE_DATA_IN;
			scst_rx_data(cmd, SCST_RX_STATUS_SUCCESS,
				     SCST_CONTEXT_THREAD);
		}
		spin_unlock(&fcmd->lock);
	}
drop:
	fc_frame_free(fp);
}
