/********************************************************Copyright.IBM*****/
/*                                                                        */
/*                                                                        */
/*      Multi-Protocol Transport Services -buf.h                          */
/*                                                                        */
/*      Licensed Materials - Property of IBM (R)                          */
/*      5622-069                                                          */
/*      (C) Copyright IBM Corp. 1993, All right reserved.                 */
/*      US Government Users Restricted Rights - Use, duplication,         */
/*      disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */
/*                                                                        */
/********************************************************Copyright.IBM*****/




/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:buf.h 12.0$ */
/* $ACIS:buf.h 12.0$ */
/* $Source: /ibm/acis/usr/sys/h/RCS/buf.h,v $ */

#if !defined(lint) && !defined(LOCORE) && defined(RCS_HDRS)
static char *rcsidbuf = "$Header:buf.h 12.0$";
#endif

#if !defined(KERNEL) && !defined(STANDALONE)
#include <sys/nfs_defines.h>
#endif

/*
 * Copyright (c) 1982, 1986 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 *
 *      @(#)buf.h       7.1 (Berkeley) 6/4/86
 */

#ifndef _BUF_
#define _BUF_
/*
 * The header for buffers in the buffer pool and otherwise used
 * to describe a block i/o request is given here.  The routines
 * which manipulate these things are given in bio.c.
 *
 * Each buffer in the pool is usually doubly linked into 2 lists:
 * hashed into a chain by <dev,blkno> so it can be located in the cache,
 * and (usually) on (one of several) queues.  These lists are circular and
 * doubly linked for easy removal.
 *
 * There are currently three queues for buffers:
 *      one for buffers which must be kept permanently (super blocks)
 *      one for buffers containing ``useful'' information (the cache)
 *      one for buffers containing ``non-useful'' information
 *              (and empty buffers, pushed onto the front)
 * The latter two queues contain the buffers which are available for
 * reallocation, are kept in lru order.  When not on one of these queues,
 * the buffers are ``checked out'' to drivers which use the available list
 * pointers to keep track of them in their i/o active queues.
 */

/*
 * Bufhd structures used at the head of the hashed buffer queues.
 * We only need three words for these, so this abbreviated
 * definition saves some space.
 */
struct bufhd
{
        long    b_flags;                /* see defines below */
        struct  buf *b_forw, *b_back;   /* fwd/bkwd pointer in chain */
};
struct buf
{
        long    b_flags;                /* too much goes here to describe */
        struct  buf *b_forw, *b_back;   /* hash chain (2 way street) */
        struct  buf *av_forw, *av_back; /* position on free list if not BUSY */
#define b_actf  av_forw                 /* alternate names for driver queue */
#define b_actl  av_back                 /*    head - isn't history wonderful */
        long    b_bcount;               /* transfer count */
        long    b_bufsize;              /* size of allocated buffer */
#define b_active b_bcount               /* driver queue head: drive active */
        short   b_error;                /* returned after I/O */
        dev_t   b_dev;                  /* major+minor device name */
        union {
            caddr_t b_addr;             /* low order core address */
            int *b_words;               /* words for clearing */
            struct fs *b_fs;            /* superblocks */
            struct csum *b_cs;          /* superblock summary information */
            struct cg *b_cg;            /* cylinder group block */
            struct dinode *b_dino;      /* ilist */
            daddr_t *b_daddr;           /* indirect block */
        } b_un;
        daddr_t b_blkno;                /* block # on device */
        long    b_resid;                /* words not transferred after error */
#define b_errcnt b_resid                /* while i/o in progress: # retries */
        struct  proc *b_proc;           /* proc doing physical or swap I/O */
        int     (*b_iodone)();          /* function called by iodone */
#if defined(VFS) || !defined(COMPAT_43)
        struct vnode *b_vp;             /* vnode associated with block */
#endif
        int     b_pfcent;               /* center page when swapping cluster */
        unsigned long b_bitmap;         /* for RVD */
};

#define BQUEUES         4               /* number of free buffer queues */

#define BQ_LOCKED       0               /* super-blocks &c */
#define BQ_LRU          1               /* lru, useful buffers */
#define BQ_AGE          2               /* rubbish */
#define BQ_EMPTY        3               /* buffer headers with no memory */

#ifdef RVD
#define VDMAXBURST      32
#endif

#ifdef  KERNEL
#ifdef SMALLMEM
#define BUFHSZ  512
#else
#define BUFHSZ  512
#endif SMALLMEM
#define RND     (MAXBSIZE/DEV_BSIZE)
#if     ((BUFHSZ&(BUFHSZ-1)) == 0)
#define BUFHASH(dvp, dblkno)    \
        ((struct buf *)&bufhash[((u_int)(dvp)+(((int)(dblkno))/RND))&(BUFHSZ-1)])
#else
#define BUFHASH(dvp, dblkno)    \
        ((struct buf *)&bufhash[((u_int)(dvp)+(((int)(dblkno))/RND)) % BUFHSZ])
#endif


struct  buf *buf;               /* the buffer pool itself */
char    *buffers;
int     nbuf;                   /* number of buffer headers */
int     bufpages;               /* number of memory pages in the buffer pool */
struct  buf *swbuf;             /* swap I/O headers */
int     nswbuf;
struct  bufhd bufhash[BUFHSZ];  /* heads of hash lists */
struct  buf bfreelist[BQUEUES]; /* heads of available lists */
struct  buf bswlist;            /* head of free swap header list */
struct  buf *bclnlist;          /* head of cleaned page list */

struct  buf *alloc();
struct  buf *realloccg();
struct  buf *baddr();
struct  buf *getblk();
struct  buf *geteblk();
struct  buf *getnewbuf();
struct  buf *bread();
struct  buf *breada();
#ifdef VFS
struct  vnode *bdevvp();
#endif VFS

int minphys();
#ifdef  ibm032
extern int waitfor;                     /* if we are to wait for disk I/O completion */
#endif  ibm032
#endif

/*
 * These flags are kept in b_flags.
 */
#define B_WRITE         0x000000        /* non-read pseudo-flag */
#define B_READ          0x000001        /* read when I/O occurs */
#define B_DONE          0x000002        /* transaction finished */
#define B_ERROR         0x000004        /* transaction aborted */
#define B_BUSY          0x000008        /* not on av_forw/back list */
#define B_PHYS          0x000010        /* physical IO */
#define B_XXX           0x000020        /* was B_MAP, alloc UNIBUS on pdp-11 */
#define B_WANTED        0x000040        /* issue wakeup when BUSY goes off */
#define B_AGE           0x000080        /* delayed write for correct aging */
#define B_ASYNC         0x000100        /* don't wait for I/O completion */
#define B_DELWRI        0x000200        /* write at exit of avail list */
#define B_TAPE          0x000400        /* this is a magtape (no bdwrite) */
#define B_UAREA         0x000800        /* add u-area to a swap operation */
#define B_PAGET         0x001000        /* page in/out of page table space */
#define B_DIRTY         0x002000        /* dirty page to be pushed out async */
#define B_PGIN          0x004000        /* pagein op, so swap() can count it */
#define B_CACHE         0x008000        /* did bread find us in the cache ? */
#define B_INVAL         0x010000        /* does not contain valid info  */
#define B_LOCKED        0x020000        /* locked in core (not reusable) */
#define B_HEAD          0x040000        /* a buffer header, not a buffer */
#define B_BAD           0x100000        /* bad block revectoring in progress */
#define B_CALL          0x200000        /* call b_iodone from iodone */
#ifdef VFS
#define B_NOCACHE       0x400000        /* don't cache block when released */
#endif VFS

#define B_FLAGS_FMT     "\20\1READ\2DONE\3ERROR\4BUSY\5PHYS\6XXX\7WANTED\10AGE\11ASYNC\12DELWRI\13TAPE\14UAREA\15PAGET\16DIRTY\17PGIN\20CACHE\21INVAL\22LOCKED\23HEAD\24BAD\25CALL"

/*
 * Insq/Remq for the buffer hash lists.
 */
#define bremhash(bp) { \
        (bp)->b_back->b_forw = (bp)->b_forw; \
        (bp)->b_forw->b_back = (bp)->b_back; \
}
#define binshash(bp, dp) { \
        (bp)->b_forw = (dp)->b_forw; \
        (bp)->b_back = (dp); \
        (dp)->b_forw->b_back = (bp); \
        (dp)->b_forw = (bp); \
}

/*
 * Insq/Remq for the buffer free lists.
 */
#define bremfree(bp) { \
        (bp)->av_back->av_forw = (bp)->av_forw; \
        (bp)->av_forw->av_back = (bp)->av_back; \
}
#define binsheadfree(bp, dp) { \
        (dp)->av_forw->av_back = (bp); \
        (bp)->av_forw = (dp)->av_forw; \
        (dp)->av_forw = (bp); \
        (bp)->av_back = (dp); \
}
#define binstailfree(bp, dp) { \
        (dp)->av_back->av_forw = (bp); \
        (bp)->av_back = (dp)->av_back; \
        (dp)->av_back = (bp); \
        (bp)->av_forw = (dp); \
}

/*
 * Take a buffer off the free list it's on and
 * mark it as being use (B_BUSY) by a device.
 */
#define notavail(bp) { \
        int x = splbio(); \
        bremfree(bp); \
        (bp)->b_flags |= B_BUSY; \
        (void) splx(x); \
}

#define iodone  biodone
#define iowait  biowait

/*
 * Zero out a buffer's data portion.
 */
#define clrbuf(bp) { \
        blkclr((bp)->b_un.b_addr, (unsigned)(bp)->b_bcount); \
        (bp)->b_resid = 0; \
}

#endif _BUF_
