/*****************************************************************************
* 	  Copyright (c) 1988 Thinking Machines Corporation, Inc.,	     *
*		of Cambridge, Mass.   All rights reserved.		     *
*									     *
*  This notice is intended as a precaution against inadvertent publication   *
*  and does not constitute an admission or acknowledgement that publication  *
*  has occurred or constitute a waiver of confidentiality.		     *
*									     *
*  Connection Machine software is the proprietary and confidential property  *
*  of Thinking Machines Corporation.					     *
*****************************************************************************/

#if !defined(lint) && !defined(__SABER__)
static char rcsid_cm_fileserver[] = "$Id: cm_fileserver.h,v 1.50 91/11/19 16:56:04 dvtmc Rel $";
#endif

/*
 * Some useful defines for the CMFS file server
 */ 

/* 
 * What sort of hardware is available?
 */
#ifdef sun
#undef DATAVAULT
#define VMEIO
#define HIPPI
#endif

#ifdef vax
#define DATAVAULT
#undef VMEIO
#undef HIPPI
#endif

#ifdef sgi
#undef DATAVAULT
#define VMEIO
#undef HIPPI
#endif

#if defined(DATAVAULT)
#   define NUMDISKS 32
#else
#   define NUMDISKS 1
#endif

#define BYTESPERBLOCKSTRIPE	(NUMDISKS*CMBLOCKSIZE)
#define BITSPERBLOCKSTRIPE	(NUMDISKS*CMBLOCKSIZE*BITSPERBYTE)
/*#define BYTESPERDISKBLOCK	BYTESPERBLOCKSTRIPE*/

#define STRIPE_SLICE	1024 /* where(bytes) to slice the data on serial ops */

struct fsreq *getreq();
struct fs_request *getfsreq();
struct cm_inode *getinode();
struct fdent *getfdent();
struct fdent *findfp();
struct cm_extent *extlookup();
struct cm_extent *extslot();
unsigned long extlength();
void mkpath();
struct cm_inode *pathsearch();
char *get_hd_error();
extern void logalarm();

char *memalign();

extern int errno;
extern int uniq;

/* Values returned by receive - what caused the select to return */
#define RECEIVE_MESSAGE		1
#define RECEIVE_ERROR		2
#define NEW_CONNECTION		3
#define CONNECTION_REMOVED	4

/* Values for the open_connection data structure */
#define CM_DATAVAULT		1
#define CM_ACCEPTED		2
#define CM_BIND			3
#define CM_BIND2		4 /* fs <-> fs communication */
#define CM_ACCEPTED2		5 /* fs <-> fs communication */


/* Values for the physical_data variable - where is the disk */
#define READ_DATAVAULT		1
#define READ_FILE_SERVER_FILE	2
#define WRITE_DATAVAULT		4
#define WRITE_FILE_SERVER_FILE	8

/* macros */
#define filedesc(uniqueid)	(uniqueid & 0xff)
#define posresp(req, val)	sendresp(req, val, OK, (char *)NULL, 0)
#define negresp(req, val)	sendresp(req, (int)(unsigned char) val, ERROR, (char *)NULL, 0)


struct physdata	{
	daddr_t	diskaddr;	/* Physical disk block address */
	unsigned long	offset;		/* CM word offset within that block */
	unsigned long 	wordsleft;	/* total CM words left in this extent */
};

/* root for each file system; set by main, used by opencreat.c(mkpath) */
extern char *(rootdir[MAX_DIR_COPIES]);

/* is this running on a datavault? */
extern int no_datavault;

/*
 * macros for inquiring about and setting the state of a file system
 * directory structure.
 * Note: it is intended that each copy of the file system will
 * reside on a different disk (for protection in the event of a
 * disk crash) and will be the only thing within the filesystem.
 */
extern int disk_state[MAX_DIR_COPIES];
#define DISK_IS_GOOD(disk_ndx)	(disk_state[disk_ndx] != 0)
#define SET_DISK_GOOD(disk_ndx)	(disk_state[disk_ndx] = 1)
#define SET_DISK_BAD(disk_ndx)	(disk_state[disk_ndx] = 0)

/*
 * pathsearch defines
 */
#define PS_LOOKUP	0	/* (stat) */
#define PS_ENTER	1	/* (open) */
#define PS_DELETE	2	/* (unlink) */

/*
 * These must be signed or else we have problems with division.
 */
extern int bitspercmword;
extern int bytespercmword;	/* derived from bitspercmword */
extern int cmwordsperdiskblock; /* BITSPERDISKBLOCK / bitspercmword */
extern int bitsperblockstripe;
extern int log2bytespercmword;	/* log2(bytespercmword) */

extern long base_diskblock;
extern int striping_factor;

/* shift count for fill_rdwr_cmd_buffer, for location */
extern int log2bytesperblockstripe;
/* shift count for fill_rdwr_cmd_buffer, for count */
extern int log2bytesperlocaldiskblock;
extern int log2striping_factor;

/* have we received the shutdown signal? */
extern int shutdown_requested;

/*
 * take the upper log2(bytes per cm word) bits, shift them
 * to be the lower bits, and mask off any ones that might
 * have arisen if the original hi bit was set
 *
 * i.e. return the bits that get thrown away by CMwordstobytes
 */
#define CMwordstohibytes(offset, log2bytespercmword) \
    ((offset >> (32 - log2bytespercmword)) & ((1 << log2bytespercmword) - 1))

/*
 * How to tell what sort of file server is running.
 */
extern int fs_type;

#define FSTYPE_UNKNOWN 0
#define FSTYPE_DATAVAULT 1
#define FSTYPE_VMEIO 2
#define FSTYPE_FRONT_END 3
#define FSTYPE_DV_SIM 4
#define FSTYPE_HIPPI 5
#define LAST_FSTYPE FSTYPE_HIPPI
#define NUM_FSTYPES LAST_FSTYPE+1

/* assert without string message */

# ifndef NDEBUG
# define _assert(ex)	{if (!(ex)){pralarm(FATAL,"Assertion failed: line, file\n", __LINE__, __FILE__);abort();}}
# define assert(ex)	_assert(ex)
# else
# define _assert(ex)
# define assert(ex)
# endif /* NDEBUG */

/* assert with string message */

# ifndef NDEBUG
#if defined(lint)
/* avoid "constant in condition context" messages due to the while (0) */
#define _assert_str(ex, str)	\
    do { \
	if (!(ex)) { \
	    logalarm(FATAL, "Assertion failed: file %s, line %d, reason: %s", \
		     __FILE__, __LINE__, str); \
	    abort(); \
	} \
    } while (rand() != 0)
#else /* !lint */
#define _assert_str(ex, str)	\
    do { \
	if (!(ex)) { \
	    logalarm(FATAL, "Assertion failed: file %s, line %d, reason: %s", \
		     __FILE__, __LINE__, str); \
	    abort(); \
	} \
    } while (0)
#endif
#define assert_str(ex, str)	_assert_str(ex, str)
#else /* !NDEBUG */
#define _assert_str(ex, str)
#define assert_str(ex, str)
#endif /* NDEBUG */

#if defined(sgi)
#define BLOCKSIZE 1024		/* file system block size */
#endif
 
/* permissions info */
struct perm_info {
    long pi_ruid;		/* real uid */
    long pi_rgid;		/* real gid */
    long pi_gidsetlen;		/* number of valid entries in ai_gidset */
    long pi_gidset[16];		/* group list */
};

/* per connection accounting info (we should rename this struct) */
struct acct_info {
    int ai_valid;		/* is the information valid? */
    long ai_pid;		/* process id */
    char ai_hostname[64];	/* canonical hostname */
    struct perm_info ai_perm;	/* permissions information */
    struct sockaddr_in ai_sockaddr; /* sockaddr of remote end (always valid) */
};

/* accounting information, one per connection */
extern struct acct_info acct_info[];

struct connect_usage {
    long cu_operation[101];	/* how many times has each op. been requested */
    struct timeval cu_stime;	/* system time we used on the user's behalf */
    struct timeval cu_utime;	/* user time we used on the user's behalf */
#if 1
    /* these don't belong here, but... */
    long cu_preads;		/* amount read via iobus (Kbytes) */
    long cu_npreads;		/* number of reads via iobus */
    long cu_pwrites;		/* amount written via iobus (Kbytes) */
    long cu_npwrites;		/* number of writes via iobus */
    long cu_sreads;		/* amount read via ethernet (Kbytes) */
    long cu_nsreads;		/* number of reads via ethernet */
    long cu_swrites;		/* amount written via ethernet (Kbytes) */
    long cu_nswrites;		/* number of writes via ethernet */
#endif
};

extern struct connect_usage connect_usage[];

#define ACCT_IO_UNITS	1024

struct perm_info *get_perm_info();
