#ifndef DEFS_H
#define DEFS_H

#include <req.h>
#ifdef TESTING
struct scsi_lu{
	void* private;
};
#include <hint_data.h>
#else
#include "scsi.h"
#include <hint_data.h>
#endif

/* ngssd */
typedef struct ngssd_struct{
	int counter;
	int hint_counter;
	int handled_counter;

	pthread_mutex_t mutex;
	pthread_cond_t  cond;
	int mutex_count;
	pthread_t       thread;

	req_t* queued;
	req_t* current;

	/* deferred requests queue*/
	pthread_mutex_t nandbus_defer_mutex;
	req_t* nandbusDeferred; /* reqs with no nandbus */

	void *lu;
	bool_t shutdown;
} ngssd_t ;

/* tm */
#include <nand.h>

#define TM_SECTOR_SIZE        (NAND_PAGE_SIZE) /* assume sector = page for now*/
#define TM_SECTORS_PER_PAGE   (NAND_PAGE_SIZE / TM_SECTOR_SIZE)
#define TM_SECTORS_PER_BLOCK  (NAND_PAGES_PER_ERASE_UNIT * TM_SECTORS_PER_PAGE)

#define TM_MIN_EMPTY_BLOCKS_PER_CHIP (2)
#define TM_MIN_EMPTY_BLOCKS (NAND_CHIP_COUNT * TM_MIN_EMPTY_BLOCKS_PER_CHIP)

#define TM_BLOCK_COUNT      (NAND_BLOCK_COUNT - CH_BLOCK_COUNT)
#define TM_BLOCKS_PER_CHIP         ((NAND_BLOCK_COUNT - CH_BLOCK_COUNT) / NAND_CHIP_COUNT)
#define TM_MIN_SPARE_BLOCKS_PER_CHIP SET_MAX(2, (TM_BLOCKS_PER_CHIP * 2 / 8)) /*spare blocks, besides empty ones*/
#define TM_MIN_SPARE_BLOCKS          (TM_MIN_SPARE_BLOCKS_PER_CHIP * NAND_CHIP_COUNT)

#define TM_SECTOR_BLOCK_COUNT      (NAND_BLOCK_COUNT - CH_BLOCK_COUNT - TM_MIN_EMPTY_BLOCKS - TM_MIN_SPARE_BLOCKS)
#define TM_SECTOR_BLOCKS_PER_CHIP  (TM_SECTOR_BLOCK_COUNT / NAND_CHIP_COUNT)

/* chunks */
#define CH_CHUNK_SIZE         HINT_DATA_SIZE
#define CH_CHUNKS_PER_PAGE    (NAND_PAGE_SIZE / CH_CHUNK_SIZE)
#define CH_CHUNKS_PER_BLOCK   (CH_CHUNKS_PER_PAGE * NAND_PAGES_PER_ERASE_UNIT)

#define CH_SECTORS_PER_CHUNK  (CH_CHUNK_SIZE / sizeof(ch_addr))
#define CH_BLOCK_COUNT_BASE   (2 * NAND_CHIP_COUNT)

#define CH_MAX_CHUNK_COUNT    ((NAND_PAGE_COUNT /  CH_SECTORS_PER_CHUNK))


#define TM_SECTORS_PER_CHIP (TM_SECTOR_BLOCKS_PER_CHIP * TM_SECTORS_PER_BLOCK)
#define TM_SECTOR_COUNT     ((uint64_t)(TM_SECTORS_PER_BLOCK * TM_SECTOR_BLOCK_COUNT))

#define TM_BITMAP_SIZE      (TM_SECTOR_COUNT / sizeof(uint8_t))

#define NAND_PAGE_COUNT_EXTERNAL (TM_SECTOR_COUNT * TM_SECTORS_PER_PAGE)

#define TM_ADDR_EMPTY (0xffffffff)


#define CH_BLOCK_COUNT        SET_MAX(CH_BLOCK_COUNT_BASE, ((CH_MAX_CHUNK_COUNT<CH_CHUNKS_PER_BLOCK || (2 * (CH_MAX_CHUNK_COUNT / CH_CHUNKS_PER_BLOCK)) <  NAND_CHIP_COUNT)?NAND_CHIP_COUNT:(2 * (CH_MAX_CHUNK_COUNT / CH_CHUNKS_PER_BLOCK)))) /* lots of spares*/
#define CH_BLOCKS_PER_CHIP    (CH_BLOCK_COUNT / NAND_CHIP_COUNT)

#define CH_CHUNK_COUNT_BASE   (TM_SECTOR_COUNT / CH_SECTORS_PER_CHUNK)
#define CH_CHUNK_COUNT        ((TM_SECTOR_COUNT % CH_SECTORS_PER_CHUNK == 0)?CH_CHUNK_COUNT_BASE:CH_CHUNK_COUNT_BASE+1)

#define CH_BUFFER_ENTRIES             (CH_CHUNKS_PER_PAGE*2)
#define CH_TM_RECLAIM_BUFFER_ENTRIES  (NAND_CHIP_COUNT*CH_CHUNKS_PER_PAGE + CH_BUFFER_ENTRIES)

typedef uint32_t ch_addr;
#endif
