/*
 * nasd_cache.h
 *
 * Was: Structures for cache for on-disk NASD filesystem.
 *
 * Now: Structures for NASD on-disk cache and general internal drive
 *  function catch-all
 *
 * Author: Jim Zelenka 
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1997,1998,1999,2000.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#ifndef _NASD_CACHE_H_
#define _NASD_CACHE_H_

#include <nasd/nasd_options.h>
#include <nasd/nasd_drive_options.h>
#include <nasd/nasd_common.h>
#include <nasd/nasd_threadstuff.h>
#include <nasd/nasd_od.h>
#include <nasd/nasd_sys.h>
#include <nasd/nasd_control.h>
#include <nasd/nasd_shutdown.h>
#include <nasd/nasd_timer.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_drive_types.h>
#include <nasd/nasd_pipe.h>
#include <nasd/nasd_remote.h>

#define NASD_ODC_RECORD_BLOCK_LOCKS  0
#define NASD_ODC_RECORD_BLOCK_WLOCKS 0

typedef nasd_uint32                    nasd_odc_counter_t;
typedef nasd_uint32                    nasd_odc_flags_t;
typedef nasd_uint32                    nasd_odc_bmap_flags_t;

typedef struct nasd_blkrec_s           nasd_blkrec_t;
typedef union  nasd_drive_opholder_u   nasd_drive_opholder_t;
typedef struct nasd_dbg_marker_s       nasd_dbg_marker_t;
typedef struct nasd_odc_ent_s          nasd_odc_ent_t;
typedef struct nasd_odc_exle_s         nasd_odc_exle_t;
typedef struct nasd_odc_exlist_s       nasd_odc_exlist_t;
typedef struct nasd_odc_exlist_ent_s   nasd_odc_exlist_ent_t;
typedef struct nasd_odc_flush_s        nasd_odc_flush_t;
typedef struct nasd_odc_icpart_s       nasd_odc_icpart_t;
typedef struct nasd_odc_nvstate_s      nasd_odc_nvstate_t;
typedef struct nasd_odc_oq_s           nasd_odc_oq_t;
typedef struct nasd_odc_state_s        nasd_odc_state_t;
typedef union  nasd_pagebuf_u          nasd_pagebuf_t;

typedef void (*nasd_io_cbfunc_t)(nasd_odc_ent_t *, void *);

 
 /*
  * nasd_blkrec -
  *   generalization of blkno so we can also use them to support
  * security using precomputed digests
  */

#if NASD_OD_EXT_PTR > 0

#define NASD_HAS_BLOCK_REF 0x1

struct nasd_blkrec_s {
  nasd_blkno_t     blkno;
  nasd_byte_t     *digest;
  nasd_odc_ent_t  *odc_entp;
  nasd_int32       flags;
};

#else /* NASD_OD_EXT_PTR > 0 */

struct nasd_blkrec_s {
  nasd_blkno_t blkno;
};

#endif /* NASD_OD_EXT_PTR > 0 */


/*
 * block types for cache
 */
#define NASD_ODC_T_BOGUS           0 /* bogus */
#define NASD_ODC_T_NODE            1 /* block is a node */
#define NASD_ODC_T_IND             2 /* block of pointers */
#define NASD_ODC_T_FREE            3 /* block is unused */
#define NASD_ODC_T_REFCNT          4 /* refcnt block */
#define NASD_ODC_T_NPT1            5 /* node pagetable block */
#define NASD_ODC_T_DATA            6 /* regular data block */
#define NASD_ODC_T_ANON            7 /* anonymous block */
#define NASD_ODC_T_LAYOUT          8 /* layout info block */
#define NASD_ODC_T_LAYOUT_STATIC   9 /* nonswappable layout info block */
#define NASD_ODC_T_NPT2           10 /* node pagetable block */
#define NASD_ODC_T_NUM            11 /* number of above types */

/*
 * Number of LRU queues.
 * LRUs are prioritized.
 */
#if NASD_DRIVE_BLOCK_REPLACEMENT < 2
#define NASD_ODC_NLRUS 1
#else /* NASD_DRIVE_BLOCK_REPLACEMENT < 2 */
#define NASD_ODC_NLRUS 2
#endif /* NASD_DRIVE_BLOCK_REPLACEMENT < 2 */

/*
 * Note that ordering on these is important!
 */
#define NASD_ODC_LRU_NONE     (-1)
#define NASD_ODC_LRU_COMMON   0
#define NASD_ODC_LRU_USEDDATA 1

/*
 * nasd_dbg_marker
 *
 * For debugging- track when event occurred, where, how often, etc
 */
struct nasd_dbg_marker_s {
  char             *dbg_file;
  int               dbg_line;
  nasd_uint64       dbg_counter;
  nasd_timespec_t   dbg_time;
};
#define NASD_ODC_MARK_DBG(_m_) { \
  NASD_ATOMIC_INC64(&(_m_)->dbg_counter); \
  (_m_)->dbg_file = __FILE__; \
  (_m_)->dbg_line = __LINE__; \
  nasd_gettime(&(_m_)->dbg_time); \
}

/*
 * nasd_odc_nvstate (NVRAM)
 *
 * component of drive state kept in nonvolatile memory
 */
struct nasd_odc_nvstate_s {
  nasd_uint64         key1;                           /* verify sanity of nvram */
  nasd_uint64         key2;                           /* verify sanity of nvram */
  nasd_timespec_t     mod_time;                       /* state modification time */
  nasd_odc_counter_t  dirty_counts[NASD_ODC_T_NUM];   /* how many of each blocktype is dirty (NVRAM) */
};

/*
 * nasd_odc_icpart
 *
 * in-core-only partition statev
 */
struct nasd_odc_icpart_s {
  NASD_DECLARE_RWLOCK(lock)

  /* stuff related to list-of-objects object */
  nasd_blkno_t    last_objlist_npt; /* npt block of last objlist get */
  int             last_objlist_off; /* offset in above npt block */
  int             last_objlist_ind; /* index in npt block */
  nasd_timespec_t last_objlist_get; /* cr_del timestamp on part last objlist read */
  int             last_objlist_fin; /* last objlist read completed list */
};

/*
 * nasd_odc_state
 *
 * Global state of cache.
 */
struct nasd_odc_state_s {
  NASD_DECLARE_MUTEX(lock)
  nasd_odc_nvstate_t  *nvstate;      /* nonvolatile state */
  nasd_od_disk_t      *disk;         /* physical disk structure */
  dev_t                dev;          /* actual device */
  nasd_timespec_t      mod_complete; /* mod_time timestamp of most recent state update completed */
  nasd_odc_icpart_t    parts[NASD_OD_MAXPARTS]; /* in-core partition state */
  int                  cr_ind;       /* create index (rehash performance opt) */
  int                  npt_sz;       /* blocks in one copy of NPT */
};

#define NASD_ODC_LOCK_DISK()   NASD_LOCK_MUTEX(nasd_odc_state->lock)
#define NASD_ODC_UNLOCK_DISK() NASD_UNLOCK_MUTEX(nasd_odc_state->lock)

/*
 * nasd_odc_ent
 *
 * An actual cache entry. Might be a node, an indirect block,
 * or a block of data.
 */
struct nasd_odc_ent_s {
  NASD_DECLARE_MUTEX(lock)
  NASD_DECLARE_RWLOCK(rwlock)
  NASD_DECLARE_COND(cond)          /* wait for block to change state */
  NASD_DECLARE_COND(acond)         /* wait on this for block to allocate */
  nasd_odc_flags_t    data_flags;  /* protected by ent lock */
  nasd_odc_flags_t    lru_flags;   /* protected by LRU, not ent lock */
  nasd_odc_flags_t    io_flags;    /* protected by IO lock */
  nasd_odc_flags_t    dirty_flags; /* protected by dirty lock */
  int                 refcnt;      /* incore refcnt (protected by LRU lock) */
  int                 irefcnt;     /* cache-internal refcnt (protected by LRU lock) */
  int                 ntracks;     /* number of trackers */
  int                 type;        /* block type */
  int                 lru_num;     /* which LRU we're in, if any */
  int                 chances;     /* replacement chances for n-chance */
  nasd_odc_oq_t      *hbucket;     /* hash bucket */
  nasd_odc_ent_t     *hnext;       /* physical hash links */
  nasd_odc_ent_t     *hprev;
  nasd_odc_ent_t     *lhnext;      /* logical hash links */
  nasd_odc_ent_t     *lhprev;
  nasd_odc_ent_t     *dnext;       /* dirty links */
  nasd_odc_ent_t     *dprev;
  nasd_odc_ent_t     *lnext;       /* LRU links (also freelist) */
  nasd_odc_ent_t     *lprev;
  nasd_odc_ent_t     *inext;       /* I/O links */
  nasd_odc_ent_t     *iprev;
  nasd_odc_ent_t     *cnext;       /* I/O internal links (I/O engine) */
  nasd_odc_ent_t     *cprev;
  nasd_odc_ent_t     *onext;       /* object links (lru-lock protected) */
  nasd_odc_ent_t     *oprev;
  nasd_odc_ent_t     *snext;       /* security links (for digests) */
  nasd_odc_ent_t     *sprev;
  nasd_odc_ent_t     *wnext;       /* wire links (lru-lock protected) */
  nasd_odc_ent_t     *wprev;
#if NASD_SECURE_RPCS_ENABLE > 0
  nasd_digest_t       digest;      /* precomputed digest mirror copy */
#endif /* NASD_SECURE_RPCS_ENABLE > 0 */
#if NASD_DRIVE_DEBUG_PHYS_OUTSTANDING > 0
  nasd_odc_ent_t     *knext;       /* debug */
  nasd_odc_ent_t     *kprev;
  nasd_timespec_t     kintime;
  nasd_timespec_t     kouttime;
  void               *kbuf;
#endif /* NASD_DRIVE_DEBUG_PHYS_OUTSTANDING > 0 */
  union {                         /* same structure used for different kinds of data */
    char             *buf;         /* raw bits */
    nasd_od_node_t   *node;        /* on-disk node */
    nasd_blkno_t     *blk;         /* indirect pointers */
    nasd_refcnt_t    *cnt;         /* refcounts */
    nasd_od_pte_t    *pte;         /* node pagetable entry */
  } data;
#if defined(DEC_OSF) && defined(KERNEL)
  vm_page_t           pp;          /* vm page structure of data */
#endif /* DEC_OSF && KERNEL */
#if defined(LINUX) && defined(KERNEL)
  struct buffer_head *rbh;
#endif /* LINUX && KERNEL */
  nasd_io_cbfunc_t    iocb;        /* I/O callback function */
  void               *iocb_arg;    /* I/O callback function arg */
  int                 iopri;       /* I/O priority */
  int                 iodir;       /* read or write */
  nasd_identifier_t   identifier;  /* nasd identifier this block belongs to */
  nasd_offset_t       offset;      /* offset of this block within object */
  nasd_blkno_t        blkno;       /* physical block number on disk */
  nasd_sectno_t       real_sectno; /* physical block number on disk */
  nasd_odc_flush_t   *flushcp;     /* flush controller pointer */
  nasd_odc_flush_t   *nd_flushcp;  /* node logical flush controller pointer */
  nasd_odc_flush_t   *deletecp;    /* delete controller pointer */
  nasd_odc_flush_t   *dt_flushcp;  /* global dirty flush pointer */
  nasd_odc_ent_t     *node_ent;    /* ent containing node for this block */
  nasd_remote_invocation_t *invocation; /* parameters to active disk call pertaining to this object */
#if NASD_ODC_RECORD_BLOCK_LOCKS > 0
  char               *locker_file; /* file of block lock holder */
  int                 locker_line; /* line of block lock holder */
#endif /* NASD_ODC_RECORD_BLOCK_LOCKS > 0 */
#if NASD_ODC_RECORD_BLOCK_WLOCKS > 0
  char               *w_locker_file; /* file of block lock holder */
  int                 w_locker_line; /* line of block lock holder */
#endif /* NASD_ODC_RECORD_BLOCK_WLOCKS > 0 */
#if NASD_NL_REG_SCOREBOARD > 0
  nasd_blkno_t        reg_id;        /* region membership of block */
  nasd_odc_flags_t    reg_flags;
#endif /* NASD_NL_REG_SCOREBOARD > 0 */
#if NASD_IO_TIMERS > 0
  nasd_timer_t        io_subsys_timer;      /* time in logical queue */
  nasd_timer_t        io_outstanding_timer; /* time at driver */
#endif /* NASD_IO_TIMERS > 0 */
#if NASD_DRIVE_DEBUG_RELEASE > 0
  char               *release_file;
  int                 release_line;
#endif /* NASD_DRIVE_DEBUG_RELEASE > 0 */
};

/*
 * nasd_odc_oq
 *
 * Queue of cached NASD blocks.
 */
struct nasd_odc_oq_s {
  NASD_DECLARE_MUTEX(lock)
  char                *lock_file;
  int                  lock_line;
  nasd_odc_ent_t       head; /* head element of list */
  nasd_odc_counter_t   size; /* items in queue */
};

/*
 * nasd_drive_opholder_t
 *
 * Allocated+freed for "large stack" RPCs as
 * sideband storage for local variables
 * (update initialization of nasd_drive_fail_opholder
 * in nasd_drive_rpc_specific_init() when this changes)
 */
union nasd_drive_opholder_u {
  struct {
    nasd_p_create_dr_args_t  in_args;
    nasd_p_create_dr_res_t   out_res;
  } opholder_create;
  struct {
    nasd_blkno_t cur_ref_blk, cur_blk, fn, ln, fb, lb, nb, nb2, nblk;
    nasd_odc_exlist_ent_t *n_exle, *pre_exle;
    nasd_odc_ent_t *re, *ne, *npte, *npte2;
    nasd_layout_hint_t *layout_hint;
    nasd_blkcnt_t prealloc_blocks;
    nasd_timespec_t cur_time;
    nasd_identifier_t newid;
    nasd_nodenum_t nodenum;
    nasd_odc_icpart_t *icp;
    nasd_generation_t gen;
    nasd_od_part_t *part;
    int npti, f, iblk;
    nasd_od_node_t *np;
    nasd_uint32 hi32;
  } opholder_crobj;
  nasd_drive_opholder_t *next;
};

/*
 * nasd_odc_exlist_ent
 *
 * Member of list of disk extents
 */
struct nasd_odc_exlist_ent_s {
  nasd_od_extent_t        range;
  nasd_odc_exlist_ent_t  *next;
  nasd_odc_exlist_ent_t  *prev;
};

/*
 * nasd_odc_exlist
 *
 * List of disk extents
 */
struct nasd_odc_exlist_s {
  NASD_DECLARE_MUTEX(lock)
  nasd_odc_exlist_ent_t    head;
  nasd_blkcnt_t            num;
  int                      hashlen;
  int                      hashdiv;
  nasd_blkno_t             maxval;
  nasd_odc_exlist_ent_t  **hashhints;
  nasd_odc_exlist_t       *next;
};

/*
 * nasd_odc_exle
 *
 * Used to track consumption of block allocation
 */
struct nasd_odc_exle_s {
  nasd_odc_exlist_ent_t  *used;
  nasd_odc_exlist_ent_t  *unused;
  nasd_blkcnt_t           usedc;
  nasd_blkcnt_t           total_usedc;
};

/*
 * nasd_odc_flush
 *
 * Flush controller.
 */
struct nasd_odc_flush_s {
  NASD_DECLARE_MUTEX(lock)
  NASD_DECLARE_COND(cond)     /* condition when counter goes to 0 */
  int                refcnt;
  int                counter; /* number of dirty blocks */
  nasd_odc_flush_t  *next;
};

/*
 * List of unused info pages
 */
union nasd_pagebuf_u {
  nasd_info_page_otw_t   buf;
  nasd_pagebuf_t        *next;
};


#define NASD_ODC_ICPART_LOCK_READ(_icp_)    NASD_LOCK_READ((_icp_)->lock)
#define NASD_ODC_ICPART_UNLOCK_READ(_icp_)  NASD_UNLOCK_READ((_icp_)->lock)
#define NASD_ODC_ICPART_LOCK_WRITE(_icp_)   NASD_LOCK_WRITE((_icp_)->lock)
#define NASD_ODC_ICPART_UNLOCK_WRITE(_icp_) NASD_UNLOCK_WRITE((_icp_)->lock)

/*
 * block status bits for cache (data_flags)
 */
#define NASD_CD_BUSY     0x0001  /* block is busy */
#define NASD_CD_INVALID  0x0002  /* block data contents bogus */
#define NASD_CD_NZ       0x0004  /* block data not yet zero-filled */
#define NASD_CD_MBUSY    0x0008  /* marked busy by lookup, I/O not running */
#define NASD_CD_DELETING 0x0010  /* deleting object (node block) */
#define NASD_CD_SECURITY 0x0020  /* Whatever state it is in is the
                                    result of security processing */
#define NASD_CD_ANONF    0x0040  /* anonymous fetch in progress */
#define NASD_CD_PDIGEST  0x0080  /* precomputed digest present and valid */

/*
 * block status bits for cache protected by LRU lock (lru_flags)
 */
#define NASD_CL_ALLOC    0x0001  /* allocation in progress on block */
#define NASD_CL_NOALLOC  0x0002  /* allocation failed on block */
#define NASD_CL_LRU_Q    0x0004  /* block on LRU */
#define NASD_CL_REMOVING 0x0008  /* in the process of ejecting */
#define NASD_CL_DELETING 0x0010  /* in the process of deleting (node block) */
#define NASD_CL_FALLOC   0x0020  /* force alloc (NOALLOC recovery case) */
#define NASD_CL_AERROR   0x0040  /* hard error on falloc */
#define NASD_CL_WIRED    0x0080  /* wired in cache */
#define NASD_CL_LINDEX   0x0100  /* logically indexed */
#define NASD_CL_GHOST    0x0200  /* ghosted */

/*
 * block status bits for cache protected by dirty lock (dirty_flags)
 */
#define NASD_CR_DIRTY_Q  0x0001  /* block on dirty list */
#define NASD_CR_DIRTYW_Q 0x0002  /* block on dirty-write list */
#define NASD_CR_DIRTY    0x0004  /* block is dirty */

/*
 * block status bits for cache protected by IO lock (io_flags)
 */
#define NASD_CI_DISPATCH 0x0001  /* dispatching I/O */
#define NASD_CI_IOQ      0x0002  /* in I/O queue */
#define NASD_CI_IOHEAD   0x0004  /* debugging- head of coalesce */

/*
 * mode bits for block lookup
 */
#define NASD_ODC_L_FORCE 0x0001 /* must find a block */
#define NASD_ODC_L_BLOCK 0x0002 /* may block */
#define NASD_ODC_L_LOAD  0x0004 /* load (if not already done) */
#define NASD_ODC_L_MLOAD 0x0008 /* mark blocks for loading */
#define NASD_ODC_L_NOPRE 0x0010 /* disable prefetching */

/*
 * mode bits for bmap
 */
#define NASD_ODC_B_FAULT 0x0001 /* fault direct pointers (COW touch) */
#define NASD_ODC_B_ALLOC 0x0002 /* allocate target block (fill-in write) */
#define NASD_ODC_B_ALIGN 0x0004 /* max clustering is to alignment mask */

/*
 * mode bits for nasd_odc_ref_ranges()
 */
#define NASD_ODC_REF_NOFLAGS      0
#define NASD_ODC_REF_EJECT   0x0001 /* eject 0-ref blocks from cache */

/*
 * block status bits for region scoreboard (reg_flags)
 */
#define NASD_ODC_R_VALID 0x0001 /* block is a region member */

/*
 * Never cluster more than this many blocks in any direction.
 * Note that as long as the cluster size is a power of two <=
 * the number of direct blocks, we never need to cluster across
 * indirect blocks. Proof of this is left as an exercise for
 * the reader.
 */
#define NASD_ODC_MAX_CLUSTER 512

/*
 * Priority levels for I/O.
 *
 * Three priority levels of queue. Most stuff should go in medium.
 * High-priority stuff is must-do-now.
 * Low priority stuff is can-wait-indefinitely.
 * RT is "realtime"; should be done now even if it forces out I/Os from
 * other threads that are blocked waiting for I/O to complete.
 */
#define NASD_IO_PRI_RT  0
#define NASD_IO_PRI_HI  1
#define NASD_IO_PRI_MED 2
#define NASD_IO_PRI_LO  3
#define NASD_IO_PRI_NUM 4

/*
 * I/O enqueue functions
 */
#define NASD_IO_ENQ_FUNC_GENERAL 1
#define NASD_IO_ENQ_FUNC_SORTED  2

/*
 * verifiers for nvram state
 */
#define NASD_C_KEY1 nasd_int64cast(0x7a5d3e41c1ea0cac)
#define NASD_C_KEY2 nasd_int64cast(0x0123456789abcdef)

#define NASD_ODC_Q_LOCK(_q_) { \
  NASD_LOCK_MUTEX((_q_)->lock); \
  (_q_)->lock_file = __FILE__; \
  (_q_)->lock_line = __LINE__; \
}
#define NASD_ODC_Q_UNLOCK(_q_) { \
  (_q_)->lock_file = NULL; \
  (_q_)->lock_line = (-1); \
  NASD_UNLOCK_MUTEX((_q_)->lock); \
}

/*
 * head->next is entry most recently added
 * head->prev is oldest entry
 */

#define NASD_ODC_Q_INS_NOLOCK(_q_,_ent_,_nxt_,_prv_) { \
  (_ent_)->_nxt_ = (_q_)->head._nxt_; \
  (_ent_)->_prv_ = &((_q_)->head); \
  (_ent_)->_nxt_->_prv_ = (_ent_); \
  (_ent_)->_prv_->_nxt_ = (_ent_); \
  (_q_)->size++; \
}

#define NASD_ODC_Q_INS(_q_,_ent_,_nxt_,_prv_) { \
  NASD_ODC_Q_LOCK(_q_); \
  NASD_ODC_Q_INS_NOLOCK(_q_,_ent_,_nxt_,_prv_); \
  NASD_ODC_Q_UNLOCK(_q_); \
}

#define NASD_ODC_Q_DEQ_NOLOCK(_ent_,_nxt_,_prv_) { \
  (_ent_)->_nxt_->_prv_ = (_ent_)->_prv_; \
  (_ent_)->_prv_->_nxt_ = (_ent_)->_nxt_; \
  (_ent_)->_prv_ = (_ent_)->_nxt_ = NULL; \
}

/*
 * The tail (oldest) entry in queue is assigned to _ent_
 * and removed from the queue
 */
#define NASD_ODC_Q_DEQ_TAIL_NOLOCK(_q_,_ent_,_nxt_,_prv_) { \
  _ent_ = (_q_)->head._prv_; \
  NASD_ASSERT((_ent_) != (&((_q_)->head))); \
  NASD_ODC_Q_DEQ_NOLOCK(_ent_,_nxt_,_prv_); \
  (_q_)->size--; \
}

#define NASD_ODC_Q_DEQ_TAIL(_q_,_ent_,_nxt_,_prv_) { \
  NASD_ODC_Q_LOCK(_q_); \
  NASD_ODC_Q_DEQ_TAIL_NOLOCK(_q_,_ent_,_nxt_,_prv_); \
  NASD_ODC_Q_UNLOCK(_q_); \
}

#define NASD_ODC_Q_SIZE(_q_) ((_q_)->size)

#define nasd_odc_lru_mutex nasd_odc_lru[0].lock

#define NASD_ODC_LRU_LOCK()    NASD_LOCK_MUTEX(nasd_odc_lru_mutex)
#define NASD_ODC_LRU_UNLOCK()  NASD_UNLOCK_MUTEX(nasd_odc_lru_mutex)

#define NASD_ODC_FREE_LOCK()   NASD_ODC_Q_LOCK(&nasd_odc_unusedq)
#define NASD_ODC_FREE_UNLOCK() NASD_ODC_Q_LOCK(&nasd_odc_unusedq)

#if NASD_ODC_RECORD_BLOCK_LOCKS > 0
#define NASD_ODC_LOCK_BLOCK(_b_) {\
  NASD_LOCK_MUTEX((_b_)->lock); \
  (_b_)->locker_file = __FILE__; \
  (_b_)->locker_line = __LINE__; \
}
#define NASD_ODC_UNLOCK_BLOCK(_b_) { \
  (_b_)->locker_file = NULL; \
  (_b_)->locker_line = 0; \
  NASD_UNLOCK_MUTEX((_b_)->lock); \
}
#define NASD_ODC_TRY_LOCK_BLOCK(_b_)   NASD_TRY_LOCK_MUTEX((_b_)->lock) ? (1,(_b_)->locker_file=__FILE__,(_b_)->locker_line=__LINE__) : 0
#else /* NASD_ODC_RECORD_BLOCK_LOCKS > 0 */
#define NASD_ODC_LOCK_BLOCK(_b_)   NASD_LOCK_MUTEX((_b_)->lock)
#define NASD_ODC_UNLOCK_BLOCK(_b_) NASD_UNLOCK_MUTEX((_b_)->lock)
#define NASD_ODC_TRY_LOCK_BLOCK(_b_)   NASD_TRY_LOCK_MUTEX((_b_)->lock)
#endif /* NASD_ODC_RECORD_BLOCK_LOCKS > 0 */

#define NASD_ODC_RLOCK_BLOCK_DATA(_b_)   NASD_LOCK_READ((_b_)->rwlock)
#define NASD_ODC_RUNLOCK_BLOCK_DATA(_b_) NASD_UNLOCK_READ((_b_)->rwlock)

#if NASD_ODC_RECORD_BLOCK_WLOCKS > 0
#define NASD_ODC_WLOCK_BLOCK_DATA(_b_)   { \
  NASD_LOCK_WRITE((_b_)->rwlock); \
  (_b_)->w_locker_file = __FILE__; \
  (_b_)->w_locker_line = __LINE__; \
}
#define NASD_ODC_WUNLOCK_BLOCK_DATA(_b_) { \
  (_b_)->w_locker_file = NULL; \
  (_b_)->w_locker_line = 0; \
  NASD_UNLOCK_WRITE((_b_)->rwlock); \
}
#else /* NASD_ODC_RECORD_BLOCK_WLOCKS > 0 */
#define NASD_ODC_WLOCK_BLOCK_DATA(_b_)   NASD_LOCK_WRITE((_b_)->rwlock)
#define NASD_ODC_WUNLOCK_BLOCK_DATA(_b_) NASD_UNLOCK_WRITE((_b_)->rwlock)
#endif /* NASD_ODC_RECORD_BLOCK_WLOCKS > 0 */

#define NASD_DIRTY_LOCK()   NASD_LOCK_MUTEX(nasd_odc_dirtyq_lock)
#define NASD_DIRTY_UNLOCK() NASD_UNLOCK_MUTEX(nasd_odc_dirtyq_lock)

#define NASD_U_NOP   0
#define NASD_U_READ  1
#define NASD_U_WRITE 2

/*
 * How many blocks at a time we like to coalesce/kluster to
 * (init-time, not run-time)
 */
#define NASD_ODC_OPCHUNK 16

/*
 * Maximum number of blocks to map in a single call
 */
#define NASD_ODC_MAX_BMAP \
  NASD_MAX(NASD_OD_IPTRS_PER_BLOCK,NASD_OD_DPTRS_PER_BLOCK)

/* cache stat manipulation */
#define NASD_ODC_CSINC(_stat_) \
  NASD_ATOMIC_INC64(&nasd_drive_cache_stats._stat_)
#define NASD_ODC_CSINC_TYPE(_stat_,_type_) \
  NASD_ATOMIC_INC64(&nasd_drive_cache_stats._stat_[_type_])

#define nasd_odc_wait_not_busy(_ent_) { \
  nasd_status_t raise_rc; \
\
  raise_rc = NASD_FAIL; \
  while((_ent_)->data_flags&NASD_CD_BUSY) { \
    if (raise_rc != NASD_SUCCESS) \
      raise_rc = nasd_od_io_try_raise_pri((_ent_), NASD_IO_PRI_MED); \
    NASD_WAIT_COND((_ent_)->cond,(_ent_)->lock); \
  } \
}

#define nasd_odc_wait_not_busy_invalid(_ent_) { \
  nasd_status_t raise_rc; \
\
  raise_rc = NASD_FAIL; \
  while((_ent_)->data_flags&(NASD_CD_BUSY|NASD_CD_INVALID)) { \
    if (raise_rc != NASD_SUCCESS) \
      raise_rc = nasd_od_io_try_raise_pri((_ent_), NASD_IO_PRI_MED); \
    NASD_WAIT_COND((_ent_)->cond,(_ent_)->lock); \
  } \
}

#define NASD_ODC_CHECK_NODE_ENT(_node_ent_) { \
  NASD_ASSERT((_node_ent_)->type == NASD_ODC_T_NODE); \
  NASD_ASSERT((_node_ent_)->onext != NULL); \
  NASD_ASSERT((_node_ent_)->oprev != NULL); \
}

#define NASD_ODC_TYPE_INDEX_LOGICAL(_type_) \
  (((_type_) == NASD_ODC_T_DATA) || ((_type_) == NASD_ODC_T_NODE))

#define NASD_DRIVE_GET_OPHOLDER(_oh_) { \
  NASD_FREELIST_GET(nasd_drive_opholder_freelist,_oh_,next, \
    (nasd_drive_opholder_t *)); \
}

#define NASD_DRIVE_FREE_OPHOLDER(_oh_) { \
  NASD_FREELIST_FREE(nasd_drive_opholder_freelist,_oh_,next); \
}

#define nasd_odc_block_release(_ent_) \
  _nasd_odc_block_release(_ent_,__FILE__,__LINE__)

#define nasd_od_io_enq_sorted(_entlist,_dir_,_pri_) \
  _nasd_od_io_enq_sorted(_entlist,_dir_,_pri_,__FILE__,__LINE__)

#define nasd_od_io_enq(_entlist,_dir_,_pri_) \
  _nasd_od_io_enq(_entlist,_dir_,_pri_,__FILE__,__LINE__)

#define nasd_od_update_nvclock() { \
  nasd_timespec_t _ts; \
  nasd_gettime(&_ts); \
  nasd_odc_state->nvstate->mod_time = _ts; \
}

/*
 * from nasd_cbasic.c
 */
#define PART(_x_) (nasd_odc_state->disk->partitions[(_x_)])
#define DISK (*nasd_odc_state->disk)

extern int nasd_odc_read_regions;
extern int nasd_odc_force_format;
extern int nasd_odc_need_format;
extern int nasd_odc_need_recover;
extern nasd_odc_state_t *nasd_odc_state;
extern int nasd_odc_size, nasd_odc_refblocks, nasd_odc_dirty_autokick;
extern nasd_odc_oq_t nasd_odc_unusedq;
extern nasd_odc_oq_t nasd_odc_lru[NASD_ODC_NLRUS];
extern nasd_odc_oq_t nasd_odc_wireq;
extern nasd_blkcnt_t nasd_od_blocks;
extern void nasd_odc_uninit_ent(nasd_odc_ent_t *ent);
extern nasd_status_t nasd_queue_init(nasd_odc_oq_t *q);
extern nasd_status_t nasd_queue_simple_init(nasd_odc_oq_t *q);
extern void nasd_odc_preinsert(nasd_odc_ent_t *ent);
extern nasd_status_t nasd_cache_init(void);
extern void _nasd_odc_wait_not_busy(nasd_odc_ent_t *ent);
extern void _nasd_odc_wait_not_busy_invalid(nasd_odc_ent_t *ent);
extern nasd_status_t nasd_odc_init_ent(nasd_odc_ent_t *ent,
  int type, int alloc_page);
extern void nasd_odc_shutdown_cache(void *ignored_arg);
extern void nasd_odc_ent_destroy(void *arg);
extern nasd_status_t nasd_odc_alloc_ent(nasd_odc_ent_t **entp);
extern void nasd_odc_free_ent(nasd_odc_ent_t *ent);
extern void nasd_odc_put_ent(nasd_odc_ent_t *ent);


/*
 * from nasd_cblock.c
 */
NASD_DECLARE_EXTERN_COND(nasd_odc_lru_cond)
extern nasd_ctrl_cache_stat_t nasd_drive_cache_stats;
nasd_sectno_t nasd_odc_real_sectno(nasd_blkno_t blkno, int type);
nasd_status_t nasd_odc_block_alloc(nasd_odc_ent_t **entp);
nasd_status_t nasd_odc_block_grab(nasd_odc_ent_t **entp, int blockp);
void nasd_odc_block_ref(nasd_odc_ent_t *ent);
void nasd_odc_block_iref_to_ref(nasd_odc_ent_t *ent);
nasd_status_t _nasd_odc_block_release(nasd_odc_ent_t *ent,
  char *file, int line);
nasd_status_t nasd_odc_block_release_internal(nasd_odc_ent_t *ent,
  int lru_lock_held, char *file, int line);
nasd_status_t nasd_odc_blocksys_init(void);
nasd_status_t nasd_odc_block_lookup(nasd_odc_ent_t *node_ent,
  nasd_blkno_t blkno, int flags, nasd_odc_ent_t **entp,
  nasd_identifier_t nid, nasd_offset_t offset,
  int type, int *creatorp);
nasd_status_t nasd_odc_block_get(nasd_odc_ent_t *node_ent,
  nasd_blkno_t blkno, int flags, nasd_odc_ent_t **entp,
  nasd_identifier_t nid, nasd_offset_t offset,
  int type, nasd_odc_ent_t *ichain);
nasd_status_t nasd_odc_block_lookup_logical(nasd_odc_ent_t *node_ent,
  int flags, nasd_odc_ent_t **entp,
  nasd_identifier_t nid, nasd_offset_t offset,
  int type, int *creatorp);
nasd_status_t nasd_odc_block_get_logical(nasd_odc_ent_t *node_ent,
  int flags, nasd_odc_ent_t **entp,
  nasd_identifier_t nid, nasd_offset_t offset,
  int type, nasd_odc_ent_t *ichain);
nasd_status_t nasd_odc_force_alloc(nasd_odc_ent_t *e,
  nasd_odc_ent_t *node_ent);
nasd_status_t nasd_odc_block_get_part1(nasd_odc_ent_t *node_ent,
  nasd_blkno_t blkno, int flags, nasd_odc_ent_t **entp,
  nasd_identifier_t nid, nasd_offset_t offset,
  int type, nasd_odc_ent_t *ichain, int *crp);
nasd_status_t nasd_odc_block_get_part2(nasd_odc_ent_t *node_ent,
  nasd_blkno_t blkno, int flags, nasd_odc_ent_t **entp,
  nasd_identifier_t nid, nasd_offset_t offset,
  int type, nasd_odc_ent_t *ichain, int *crp);
void nasd_odc_block_eject_real(nasd_odc_ent_t *ent);
void nasd_odc_block_eject(nasd_odc_ent_t *ent);
void nasd_odc_block_eject_by_num(nasd_blkno_t blkno);
void nasd_odc_block_hash_ins(nasd_odc_ent_t *ent);
nasd_status_t nasd_odc_obj_eject(nasd_odc_ent_t *ne);
nasd_status_t nasd_odc_obj_disassoc(nasd_odc_ent_t *ne);

/*
 * from nasd_check.c
 */
nasd_status_t nasd_od_check_startup(void);
nasd_status_t nasd_od_check_npt(void);

/*
 * from nasd_dirty.c
 */
NASD_DECLARE_EXTERN_MUTEX(nasd_odc_dirtyq_lock)
extern int nasd_odc_dirtycnt;
extern int nasd_odc_dirtythread_force;
extern nasd_odc_ent_t nasd_odc_dirtyq;
void nasd_odc_dirty_cleaned_done(void);
nasd_status_t nasd_odc_dirtysys_init(void);
void nasd_odc_dirty_eject(nasd_odc_ent_t *ent);
void nasd_odc_dirty_donewrite(nasd_odc_ent_t *ent);
void nasd_odc_dirty_cb(nasd_odc_ent_t *ent, void *arg);
void nasd_odc_dirty_loop(nasd_threadarg_t ignored);
nasd_status_t nasd_odc_dirty_kick(void);
nasd_status_t nasd_odc_flush_dirty(int force_sync);
nasd_status_t nasd_odc_flush_obj(nasd_odc_ent_t *node_ent);
nasd_odc_flush_t *nasd_odc_flushc_get(void);
void nasd_odc_flushc_free(nasd_odc_flush_t *fl);
nasd_status_t nasd_odc_dirty_ent(nasd_odc_ent_t *ent);
void nasd_odc_dirty_ins_nolock(nasd_odc_ent_t *ent);

/*
 * from nasd_free.c
 */
void nasd_odc_free_verify_hashing(nasd_odc_exlist_t *exl);
nasd_status_t nasd_odc_free_release_blocks_nolock(nasd_odc_exlist_t *exl,
  nasd_odc_exlist_ent_t *release, nasd_blkcnt_t *release_cnt_p);
nasd_status_t nasd_odc_free_release_blocks_to_list(nasd_odc_exlist_t *exl,
  nasd_odc_exlist_ent_t *release, nasd_blkcnt_t *release_cnt_p);
nasd_status_t nasd_odc_exlist_take_chunk(nasd_odc_exlist_t *exl,
  nasd_odc_exlist_ent_t *ent, nasd_blkno_t first, nasd_blkno_t bound_last,
  nasd_blkcnt_t nblocks, nasd_odc_exlist_ent_t **ep, nasd_blkcnt_t *gp);
nasd_status_t nasd_odc_exlist_get_blocks(nasd_odc_exlist_t *exl,
  nasd_blkcnt_t nblocks, nasd_blkno_t first, nasd_blkno_t last,
  int partial_single_range, nasd_odc_exlist_ent_t **exlp,
  nasd_blkcnt_t *blocks_allocated_p);
nasd_status_t nasd_odc_exlist_get_oneblock(nasd_odc_exlist_t *exl,
  nasd_blkno_t first, nasd_blkno_t *blkp);
nasd_status_t nasd_odc_exlist_get_contig(nasd_odc_exlist_t *exl,
  nasd_blkno_t first, nasd_blkcnt_t nblocks, nasd_odc_exlist_ent_t **exlp);
nasd_status_t nasd_odc_exlist_release_oneblock(nasd_odc_exlist_t *exl,
  nasd_blkno_t blknum);
void nasd_odc_shutdown_exlist(void *arg);
nasd_status_t nasd_odc_init_exlist(nasd_odc_exlist_t *exl);
nasd_status_t nasd_odc_destroy_exlist(nasd_odc_exlist_t *exl);
void nasd_odc_shutdown_free_exle(void *arg);
nasd_status_t nasd_odc_exlist_hashify(nasd_odc_exlist_t *exl,
  nasd_blkno_t maxval, int hashbound);
nasd_status_t nasd_odc_exlist_get(nasd_odc_exlist_t **exlp);
void nasd_odc_exlist_free(nasd_odc_exlist_t *exl);
void nasd_odc_shutdown_free_exlist(void *ignored);
nasd_status_t nasd_odc_freeblock_init(void);
nasd_status_t nasd_odc_freeblock_build_lists(void);
void nasd_odc_release_extent_list(nasd_odc_exlist_ent_t *ent);
nasd_status_t nasd_odc_get_extent_list(nasd_odc_exlist_ent_t **exlp);
nasd_status_t nasd_odc_free_release_blocks(nasd_odc_exlist_ent_t *release,
  nasd_blkcnt_t *release_cnt_p);
nasd_status_t nasd_odc_free_get_range(nasd_blkcnt_t nblocks,
  nasd_blkno_t first, nasd_odc_exlist_ent_t **exlp,
  nasd_blkcnt_t *blocks_allocated_t);
nasd_status_t nasd_odc_free_get_range_bounded_partial(nasd_blkcnt_t nblocks,
  nasd_blkno_t first, nasd_blkno_t last, nasd_odc_exlist_ent_t **exlp,
  nasd_blkcnt_t *blocks_allocated_t);
nasd_status_t nasd_odc_free_get_partial_range(nasd_blkcnt_t nblocks,
  nasd_blkno_t first, nasd_odc_exlist_ent_t **exlp);
nasd_status_t nasd_odc_free_release_oneblock(nasd_blkno_t blknum);
void nasd_odc_exlist_dump(nasd_odc_exlist_t *exl);
void nasd_odc_free_dump(void);

/*
 * from nasd_decompose.c
 */
nasd_status_t nasd_od_decompose_id(nasd_identifier_t in_nid,
  int *partnump, nasd_nodenum_t *nodenump, nasd_blkno_t *lvl2_hintp,
  nasd_generation_t *genp);
nasd_status_t nasd_od_decompose_control(nasd_identifier_t in_nid,
  nasd_nodenum_t *nodenump);

/*
 * from nasd_ioqueue.c
 */
extern int nasd_od_ioq_max_outstanding;
extern nasd_sectno_t nasd_od_io_last_completed_sect;
extern int nasd_od_io_ios_outstanding;
extern nasd_status_t nasd_od_ioqueue_init(nasd_od_config_t *config);
extern void _nasd_od_io_enq_sorted(nasd_odc_ent_t *entlist, int dir,
  int pri, char *file, int line);
extern void _nasd_od_io_enq(nasd_odc_ent_t *entlist, int dir,
  int pri, char *file, int line);
extern void _nasd_od_io_deq_next(nasd_odc_ent_t **entlistp, int io_lock_held,
  char *file, int line);
extern nasd_status_t nasd_od_io_try_raise_pri(nasd_odc_ent_t *ent, int newpri);
extern void nasd_od_io_launch_as_necessary(void);
extern void nasd_od_io_flush_block(nasd_odc_ent_t *ent);
extern void nasd_od_io_flush_block_async(nasd_odc_ent_t *ent);
extern void nasd_od_io_flush_block_async_finish(nasd_odc_ent_t *ent);
extern void nasd_od_io_iodone(nasd_odc_ent_t *ent);
extern void nasd_od_io_sync_launch(nasd_sectno_t last_sector);

/*
 * from nasd_obj.c
 */
extern nasd_odc_icpart_t nasd_odc_icparts[NASD_OD_MAXPARTS];
extern char nasd_odc_zeroblk[NASD_OD_BASIC_BLOCKSIZE];
nasd_status_t nasd_od_obj_sysinit(void);
void nasd_odc_get_attr_from_ent(nasd_odc_ent_t *ent,
  nasd_attribute_t *attrp, int node_rwlock_held);
nasd_status_t nasd_obj_deatomize(nasd_odc_ent_t *ne, int partnum);
nasd_status_t nasd_obj_create(int partnum, nasd_attribute_t *in_attr,
  nasd_fieldmask_t in_fieldmask, nasd_identifier_t *out_id,
  nasd_attribute_t *out_attr, int part_lock_held);
nasd_status_t nasd_odc_nodenum_to_blknum(int partnum,
  nasd_nodenum_t in_nodenum, nasd_blkno_t lvl2_hint, nasd_blkno_t *blkp);
nasd_status_t nasd_odc_node_get(nasd_identifier_t nid, int partnum,
  nasd_nodenum_t in_nodenum, nasd_blkno_t lvl2_hint, nasd_odc_ent_t **entp);
nasd_status_t nasd_odc_node_get_from_id(int in_partnum, nasd_identifier_t nid,
  nasd_odc_ent_t **entp);
nasd_status_t nasd_obj_getattr(int partnum, nasd_identifier_t nid,
  nasd_attribute_t *attrp);
nasd_status_t nasd_obj_read_simple(int partnum, nasd_identifier_t nid,
  nasd_offset_t offset, nasd_len_t in_len, nasd_uint64 *bms_targ_p,
  int is_read2, int is_remote,nasd_procpipe_t *byte_pipe, nasd_len_t *out_len,
  nasd_security_context_t *partial);
nasd_status_t nasd_obj_write_simple(int partnum, nasd_identifier_t nid,
  nasd_offset_t offset, nasd_len_t in_len, nasd_procpipe_t *byte_pipe,
  nasd_security_context_t* contextp, nasd_len_t *out_len);
nasd_status_t nasd_obj_setattr(int partnum, nasd_identifier_t nid,
  nasd_attribute_t *in_attrp, nasd_fieldmask_t fieldmask,
  nasd_attribute_t *out_attrp);
nasd_status_t nasd_obj_flush(int partnum, nasd_identifier_t nid);
nasd_status_t nasd_obj_eject(int partnum, nasd_identifier_t nid);
nasd_status_t nasd_obj_remove(int partnum, nasd_identifier_t nid);
nasd_status_t nasd_obj_start_iread(int partnum,
                                   nasd_identifier_t index_nid,
                                   nasd_identifier_t data_nid, int interval,
                                   int offset, int flownum,
                                   nasd_timespec_t earliest_start,
                                   nasd_timespec_t latest_start,
                                   nasd_client_addr_t client_addr,
                                   nasd_index_stream_identifier_t *out_stream_id);
nasd_status_t nasd_obj_stop_iread(nasd_index_stream_identifier_t stream_id);

nasd_status_t nasd_obj_remote_attach(
  int                         partnum,
  nasd_identifier_t           nid,
  nasd_remote_function_name_t name,
  nasd_len_t                  args_len,
  nasd_procpipe_t            *byte_pipe,
  nasd_security_context_t    *contextp);

nasd_status_t
nasd_obj_remote_invoke(
  int                       partnum,
  nasd_identifier_t         nid,
  nasd_offset_t             offset,
  nasd_len_t                in_len,
  nasd_procpipe_t          *byte_pipe,
  nasd_len_t               *out_len,
  nasd_security_context_t  *contextp);

nasd_status_t
nasd_obj_remote_detach(
  int                         partnum,
  nasd_identifier_t           nid);

/*
 * from nasd_control.c
 */
void nasd_obj_control_shutdown(void *arg);
nasd_status_t nasd_obj_control_init(void);
nasd_status_t nasd_read_drive_info(nasd_pagebuf_t *pb, nasd_pagebuf_t *pb_net,
  int partnum, nasd_offset_t offset, nasd_len_t in_len, int is_read2,
  nasd_procpipe_t *byte_pipe, nasd_len_t *out_len);
nasd_status_t nasd_read_part_info(nasd_pagebuf_t *pb, nasd_pagebuf_t *pb_net,
  int partnum, nasd_offset_t offset, nasd_len_t in_len, int is_read2,
  nasd_procpipe_t *byte_pipe, nasd_len_t *out_len);
nasd_status_t nasd_read_part_objs(int partnum, nasd_offset_t offset,
  nasd_len_t in_len, int is_read2,
  nasd_procpipe_t *byte_pipe, nasd_len_t *out_len);
nasd_status_t nasd_obj_control_read_simple(int partnum,
  nasd_nodenum_t ctrl_node, nasd_offset_t offset,
  int is_read2, nasd_len_t in_len,
  nasd_procpipe_t *byte_pipe, nasd_len_t *out_len);
nasd_status_t nasd_obj_control_write_simple(int partnum,
  nasd_nodenum_t ctrl_node, nasd_offset_t offset, nasd_len_t in_len,
  nasd_procpipe_t *byte_pipe, nasd_len_t *out_len);
nasd_status_t nasd_obj_control_getattr(int partnum,
  nasd_nodenum_t ctrl_node, nasd_attribute_t *attrp);


/*
 * from nasd_od_dce.c
 */
void nasd_drive_dce_setup_tcp(void);
void nasd_drive_dce_setup_udp(void);

/*
 * rpc-specific
 */
nasd_status_t nasd_drive_rpc_specific_init(void);
void nasd_drive_rpc_specific_stop(void);
nasd_status_t nasd_drive_rpc_specific_startup(void);
nasd_status_t nasd_drive_rpc_specific_listen(int service_threads,
  nasd_uint16 ipport);
nasd_status_t nasd_drive_rpc_specific_set_stacksize(int stacksize);

/*
 * from nasd_od_ops.c
 */
void nasd_drive_rpc_shutdown_rpc_cnt_lock(void *ignored);
nasd_status_t nasd_drive_rpc_init(void);
void nasd_drive_begin_rpc(nasd_opstat_t *opstat);
void nasd_drive_end_rpc(nasd_opstat_t *opstat);
void nasd_drive_wait_shutdown_rpc(void);
void nasd_drive_stop_rpc(void);
void nasd_drive_shutdown_rpc(void);
nasd_status_t nasd_drive_startup_rpc(void);
nasd_status_t nasd_drive_rpc_listen(int service_threads, nasd_uint16 ipport);
void nasd_drive_dump_opstat(nasd_opstat_t *os, char *name);
nasd_status_t nasd_drive_rpc_set_stacksize(int stacksize);

/*
 * from nasd_diskman.c
 */
extern nasd_shutdown_list_t *nasd_odc_shutdown;
extern nasd_freelist_t *nasd_drive_opholder_freelist;
extern nasd_sectcnt_t nasd_overhead_sects;
extern nasd_sectcnt_t nasd_firstblock_offset;
extern nasd_sectcnt_t nasd_firstref_offset;
extern nasd_sectno_t nasd_diskheader_blk;
extern nasd_sectno_t nasd_diskheader_dup_blk;
extern nasd_status_t nasd_basic_init(void);
extern nasd_status_t nasd_basic_shutdown(void);
extern nasd_status_t nasd_load_diskstate(nasd_od_config_t *config);
extern nasd_status_t nasd_setup_disk(unsigned long num_real_sectors,
  dev_t dev, nasd_od_config_t *config);
extern nasd_status_t nasd_drive_nnpt_expected(nasd_blkcnt_t nblocks,
  int *expectedp);
extern nasd_status_t nasd_format_disk(nasd_od_config_t *config);
extern nasd_status_t nasd_od_create_partition(int partnum,
  nasd_blkcnt_t nblocks, nasd_uint16 min_protection, nasd_key_t part_key,
  nasd_key_t red_key, nasd_key_t black_key, nasd_identifier_t *first_obj_idp);
extern nasd_status_t nasd_od_change_partition(int partnum,
  nasd_blkcnt_t nblocks, nasd_uint16 min_protection,
  nasd_identifier_t first_obj_id);
extern void nasd_od_show_info(void);
extern void nasd_part_modified(int partnum);
extern void nasd_fetch_npt_helper(nasd_odc_ent_t *ichain,
  nasd_odc_ent_t **ents, int nents);
extern nasd_status_t nasd_fetch_npt(void);
extern void nasd_od_shutdown_drive_opholder_freelist(void *ignored);
extern nasd_status_t nasd_drive_rshutdown(
  nasd_drive_rshutdown_flags_t flags);
extern nasd_status_t nasd_drive_getinfo(
  nasd_drive_info_t *info);

/*
 * from nasd_bmap.c
 */
extern nasd_status_t nasd_od_fbmap(nasd_odc_ent_t *node_ent,
  nasd_odc_ent_t *pe, void *blocks, int nblocks,
  nasd_oblkno_t in_lblkno, nasd_oblkno_t in_lblkcnt,
  int level, int partnum, int flags, nasd_odc_exle_t *exl, int *exln,
  int *bp, nasd_blkrec_t *blkrecp, nasd_offset_t *offsetp,
  nasd_blkno_t *last_fb_p);
extern nasd_status_t nasd_od_ibmap(nasd_odc_ent_t *node_ent,
  nasd_odc_ent_t *pe, void *blocks, int nblocks,
  nasd_oblkno_t in_lblkno, nasd_oblkno_t in_lblkcnt,
  int level, nasd_blkcnt_t in_beforemax, nasd_blkcnt_t in_aftermax,
  int partnum, int flags, nasd_blkno_t *firstbp, int *bp, 
  nasd_blkrec_t *blkrecp, nasd_blkcnt_t *blocks_beforep, 
  nasd_blkcnt_t *blocks_afterp, int *zp, int *zpa);
nasd_status_t nasd_od_ibunmap(nasd_odc_ent_t *node_ent,
  nasd_odc_icpart_t *icp, nasd_odc_ent_t *pe,
  void *blocks, int nblocks, nasd_oblkno_t in_lblkno,
  nasd_oblkno_t in_lblkcnt, int level, int partnum, nasd_oblkcnt_t *bp,
  nasd_odc_exlist_t *exl, int *marked);
extern nasd_status_t nasd_od_bmap(nasd_odc_ent_t *ne, nasd_oblkno_t in_lblkno,
  nasd_oblkcnt_t in_lblkcnt, nasd_blkcnt_t in_beforemax,
  nasd_blkcnt_t in_aftermax, int partnum, int flags, nasd_blkrec_t *blkrecp,
  nasd_blkcnt_t *blocks_beforep, nasd_blkcnt_t *blocks_afterp,
  int *blocks_to_alloc);
extern nasd_status_t nasd_od_bunmap(nasd_odc_ent_t *ne,
  nasd_oblkno_t in_lblkno, nasd_oblkcnt_t in_lblkcnt, int partnum);
extern nasd_status_t nasd_od_ibfind_last_block(nasd_odc_ent_t *ne,
  int partnum, void *blocks, int nblocks, int high_ind, int level,
  nasd_blkno_t *out_blk);
extern nasd_status_t nasd_od_bfind_last_block(nasd_odc_ent_t *ne,
  int partnum, nasd_uint64 object_len);

extern nasd_status_t nasd_od_bmap_release(nasd_blkrec_t *blkp,
                                          nasd_blkcnt_t  blkcount,
                                          nasd_odc_flags_t off_flags,
                                          nasd_odc_flags_t on_flags);

/*
 * from nasd_ref.c
 */
nasd_status_t nasd_odc_ref_ranges(int partnum, nasd_odc_exlist_ent_t *in_exle,
  int delta, void *layout_handle, int flags);
nasd_status_t nasd_odc_load_refs(void);

/*
 * from nasd_layout.c (really nasd_drive_tunable.c)
 * (note that prototypes and structures are in nasd_layout.h;
 * this is only exported global vars)
 */
extern int nasd_od_region_blocks;

/*
 * Scoreboard stuff (region-layout specific, but globally
 * called).
 */
nasd_status_t nasd_nl_reg_scoreboard_init(void);
void nasd_nl_reg_init_ent(nasd_odc_ent_t *ent);
void nasd_nl_reg_access_ent(nasd_odc_ent_t *ent);

/*
 * sys-specific stuff
 */
nasd_status_t nasd_odc_io_alloc_page(nasd_odc_ent_t *ent);
void nasd_odc_io_release_page(nasd_odc_ent_t *ent);
nasd_status_t nasd_od_io_go(void);
nasd_status_t nasd_od_write_diskstate(int force_sync);
void nasd_od_io_read_header(nasd_blkno_t sectno, nasd_od_disk_t *disk);
nasd_status_t nasd_od_io_launch(nasd_odc_ent_t *entlist);
void nasd_od_io_sys_flush_block(nasd_odc_ent_t *ent);
void nasd_od_io_sys_flush_block_async(nasd_odc_ent_t *ent);
nasd_status_t nasd_od_sys_rshutdown(nasd_drive_rshutdown_flags_t flags);

#if defined (DEC_OSF) && defined(KERNEL)
#include <nasd/dux/nasd_dux_kernel_drive.h>
#endif /* DEC_OSF && KERNEL */

#if defined (LINUX) && defined(KERNEL)
#include <nasd/linux/nasd_linux_kernel_drive.h>
#endif /* LINUX && KERNEL */

#ifndef KERNEL
#include <nasd/generic/nasd_generic_drive.h>
#endif /* !KERNEL */

#endif /* !_NASD_CACHE_H_ */

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
