/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _BCACHEFS_DATA_EC_IO_H
#define _BCACHEFS_DATA_EC_IO_H

struct ec_bio {
	struct bch_dev		*ca;
	struct ec_stripe_buf	*buf;
	size_t			idx;
	int			rw;
	u64			submit_time;
	struct bio		bio;
};

enum bch_stripe_buf_err {
	STRIPE_BUF_PRE_RECOV,
	STRIPE_BUF_POST_RECOV,
};

struct ec_stripe_buf {
	struct closure		io;
	struct bch_fs		*c;

	/* might not be buffering the entire stripe: */
	unsigned		offset;
	unsigned		size;
	s16			err[2][BCH_BKEY_PTRS_MAX];
	void			*data[BCH_BKEY_PTRS_MAX];

	/* Stale when we read the stripe key, i.e. alloc inconsistency */
	unsigned long		stale[BITS_TO_LONGS(BCH_BKEY_PTRS_MAX)];

	struct bch_csum		csum_good[BCH_BKEY_PTRS_MAX];
	struct bch_csum		csum_bad[BCH_BKEY_PTRS_MAX];

	struct bkey_i_stripe	key;
	u64			pad[255];
};

static inline unsigned ec_nr_failed(struct ec_stripe_buf *buf,
				    enum bch_stripe_buf_err e)
{
	struct bch_stripe *v = &buf->key.v;

	unsigned nr_failed = 0;
	for (unsigned i = 0; i < v->nr_blocks; i++)
		nr_failed += buf->err[e][i] != 0;
	return nr_failed;
}

void bch2_ec_stripe_buf_exit(struct ec_stripe_buf *);
int __bch2_ec_stripe_buf_init(struct bch_fs *, struct ec_stripe_buf *, unsigned, unsigned);

static inline int bch2_ec_stripe_buf_init(struct bch_fs *c,
			      struct ec_stripe_buf *buf,
			      unsigned offset, unsigned size)
{
	closure_init(&buf->io, NULL);
	return __bch2_ec_stripe_buf_init(c, buf, offset, size);
}

DEFINE_FREE(ec_stripe_buf_free, struct ec_stripe_buf *, bch2_ec_stripe_buf_exit(_T); kfree(_T));

void bch2_ec_generate_ec(struct ec_stripe_buf *);
void bch2_ec_generate_checksums(struct ec_stripe_buf *);

int bch2_stripe_buf_validate_msg(struct bch_fs *, struct ec_stripe_buf *, bool);

void bch2_ec_block_io(struct bch_fs *, struct ec_stripe_buf *, blk_opf_t, unsigned);
void bch2_ec_block_io_range(struct bch_fs *, struct ec_stripe_buf *, blk_opf_t, unsigned,
			    unsigned, unsigned);
void bch2_stripe_buf_read(struct bch_fs *, struct ec_stripe_buf *);

struct bch_read_bio;
int bch2_ec_read_extent(struct btree_trans *, struct bch_read_bio *,
			struct bkey_s_c, struct printbuf *);

#endif /* _BCACHEFS_DATA_EC_IO_H */

