/*static char *SCCSID = "@(#)vpb.h	6.2 91/04/29";*/
/*      SCCSID = @(#)vpb.h	6.2 91/04/29
 *
 *
 ****   Volume Parameter Block - VPB
 *
 *   A VPB is used in the system to store information about a particular
 *   volume that is in use in the system. A volume is defined as a medium
 *   in a block device and the information on its surface that differentiates
 *   it from every other volume.
 *
 *   We keep VPBs in a segment managed by BMP. That way, we only need to
 *   worry about the records that are in use, and BMP takes care of the
 *   free list. The VPBs in use in the system are kept in the form of a
 *   linked list.
 *
 *   Every time that we encounter a new volume, i.e the VPB that we built for
 *   the volume does not match any of the VPBs already in the system, we
 *   allocate a new entry in the segment and fill it in with the relevant data
 *   from the medium. Every time that we are done with a VPB, i.e. its
 *   refcount goes to zero, we free it.
 *
 *
 ***    VPB comparison note
 *
 *   The volid code will compare two VPBs VPBIDLEN bytes beginning at VPB_ID
 *   testing for equality.  Make sure that VPBIDLEN contains things that are
 *   initialized in GenhVPB (volume.asm).
 *
 *
 ***    Layout of a VPB
 *
 *   The VPB is divided into three parts:
 *          - A part used by the kernel irrespective of the type of
 *            file system. This is private to the kernel
 *          - A part that is used by all file systems and is independent
 *            of the type of a particular file system. This is passed to
 *            an IFS for certain FS calls.
 *          - A part that is specific to the file sytem that is using the
 *            VPB. This is generally set out as a "work area" that the
 *            file system can use as it pleases. This is passed to the IFS
 *            for certain FS calls.
 *
 *   The layout of the VPB is as follows:
 *
 *          -----------------------------
 *          |   Private to Kernel       |
 *          |                           |
 *          |                           |
 *          |                           |
 *          -----------------------------
 *          |   File system dependent   |
 *          |                           |
 *          |         vpb_fsd           |
 *          |                           |
 *          -----------------------------
 *          | File system independent   |
 *          |                           |
 *          |         vpb_fsi           |
 *          |                           |
 *          -----------------------------
 *
 *
 ***    Accessing various fields in the VPB
 *
 * The fields in the different structures are accessed as follows:
 *      e.g. To access the field vpdFAT_cluster_mask, you would do
 *           something like...
 *
 *                  mov     al,es:[di.vpb_fsd].vpdFAT_cluster_mask
 *
 */
#define VPBTEXTLEN          12  // Length of printable ID for users

/* XLATOFF */

/*
 * An hVPB is acutally the offset of the vpb struct.
 */
typedef unsigned short  HVPB;

/* XLATON */

/* These fields are used in conjunction with the routines Volume_Access_Lock
 * and Volume_Access_Unlock to prevent race conditions between certain
 * directory and file operations.  The values are hardwired into the code so
 * DO NOT change them.
 */
#define VPB_ACC_EXCL    0x8000          // exclusive access to a volume
#define VPB_ACC_SHARE   1               // shared access to a volume
#define VPB_ALLOC_EXCL  0x8000
#define VPB_ALLOC_SHARE 1

/*  Size of work area in the VPB file system dependent area
 *
 * NOTE: The spec states a certain size, but if it turns out that the FAT file
 *      system specific data requires more space than stated in the spec,
 *      we allocate more space in the structure and use ERRNZs to ensure
 *      that we don't make it smaller than what is in the spec AND smaller
 *      than that required for the FAT file system.
 */
#define SPECVPDWORKAREASIZE 36          // Size of work area in spec.
#define VPDWORKAREASIZE     64          // Size of file system dependent work area

/* ASM
.errnz  (not (VPDWORKAREASIZE ge SPECVPDWORKAREASIZE))
 */

/* The following structure defines the file system independent part of the
 *  VPB. This structure is used by all file systems irrespective of the type
 *  of file system.
 *
 *  WARNING The first 2 fields of this structure are used to detect if a
 *         volume has changed. They should be kept together, or else the
 *         code in GenhVPB in VOLUME.ASM should be modified.
 *
 *  WARNING:  If this structure changes, be sure to propagate the changes to
 *           FSD.H (and be sure the spec is correct!).
 */
struct vpbfsi {
    ULONG       vpi_ID;                 // 32 bit unique ID of file
                                        // (See UNREAD_IDx, DAMAGED_IDx below.)
    struct dpb *vpi_pDPB;               // Drive volume is in
    USHORT      vpi_cbSector;           // Size of physical sector in bytes
    ULONG       vpi_totsec;             // Total number of sectors on medium
    USHORT      vpi_trksec;             // Sectors per track on medium
    USHORT      vpi_nhead;              // Number of heads in device
    BYTE        vpi_text [VPBTEXTLEN];  // printable ID for users
    ULONG       vpi_pDCS;               // device capability struc
    ULONG       vpi_pVCS;               // volume characteristic struc
    UCHAR       vpi_drive;              // drive (0=A)
    UCHAR       vpi_unit;               // unit
    USHORT      vpi_flags;              // flags for memory restrictions
};

/* VPI_FLAGS Definitions: */

#define VPB_NONCONTIG_ALLOWED   2       // the FSD for this volume can handle
                                        // non contig memory for IO requests.

#define VPB_ABOVE16M_ALLOWED    1       // The DD for this volume can access
                                        // phys.memory above 16 MB.

/*
 * The following structure defines the file system dependent part of the
 *  VPB. This structure is used by file systems as they see fit.
 */
struct vpbfsd {
    BYTE        vpd_work [VPDWORKAREASIZE];
};

/*
 * Structure layout of the Volume Parameter Block (VPB)
 */
struct vpb {
    // Fields used by kernel for all file systems
    USHORT      vpb_flink;              // handle of forward link
    USHORT      vpb_blink;              // handle of back link
    USHORT      vpb_ref_count;          // count of objects that point to VPB
    USHORT      vpb_search_count;       // count of searches that point to VPB
    BYTE        vpb_first_access;       // initialized to -1 to force a media
    USHORT      vpb_signature;          // Signature specifying VPB validity
    BYTE        vpb_flags;              // flags (bits 7,6,3-0 defined below)
    BYTE        vpb_fMisc;              // More flags (bit 7 defined below)
    ULONG       vpb_FSC;                // Pointer to the file system control
                                        // block (FSC).
    // Fields used for file system dependent work
    struct vpbfsd       vpb_fsd;

    // Fields used for file system independent work
    struct vpbfsi       vpb_fsi;
};


/* The following structure defines the file system dependent part of the
 *  VPB for the FAT file system. It is used by the internal FAT file system
 *  in the kernel.
 */
struct vpdFATFS {
    BYTE        vpdFAT_cluster_mask;    // Sectors/cluster - 1
    BYTE        vpdFAT_cluster_shift;   // Log2 of sectors/cluster
    USHORT      vpdFAT_first_FAT;       // Starting record of FATs
    BYTE        vpdFAT_FAT_count;       // Number of FATs for this drive
    USHORT      vpdFAT_root_entries;    // Number of directory entries
    ULONG       vpdFAT_first_sector;    // First sector of first cluster
    USHORT      vpdFAT_max_cluster;     // Number of clusters on drive + 1
    USHORT      vpdFAT_FAT_size;        // Number of records occupied by FAT
    ULONG       vpdFAT_dir_sector;      // Starting record of directory
    BYTE        vpdFAT_media;           // Media byte (duplicate of VPB)
    USHORT      vpdFAT_next_free;       // Cluster # of last allocated cluster
    USHORT      vpdFAT_free_cnt;        // Count of free clusters, -1 if unknown
    BYTE        vpdFAT_FATentrysize;    // 12 or 16 - can you guess why ??? @@
    ULONG       vpdFAT_IDsector;        // sector number of ID
    USHORT      vpdFAT_minEOF;          // minimum EOF cluster value:
                                        // 12-bit -> FF8, 16-bit -> FFF8
    USHORT      vpdFAT_access;          // whether rmdir XOR mov dir XOR (chdir
                                        // mkdir OR mov file OR create)* has
                                        // access to volume
    USHORT      vpdFAT_accwait;         // who's waiting for access
    USHORT      vpdFAT_alloc;           // whether disk cluster alloc OR release
    USHORT      vpdFAT_eaflags;         // flags for EA usage
    USHORT      vpdFAT_eareaders;       // number of threads with pending reads
    USHORT      vpdFAT_eawaiters;       // number of threads waiting to run
    USHORT      vpdFAT_eahandles;       // number of handles in EAOffTable
    ULONG       vpdFAT_pEASFT;          // SFT for "EA DATA. SF"
    ULONG       vpdFAT_pBadSector;      // Ptr for Bad sectors data
    ULONG       vpdFAT_pClusBitMap;     // Ptr to free cluster bit map
    ULONG       vpdFAT_pNextFreeBitMap; // Ptr to next free bit map position
    USHORT      vpdFAT_cNextFreeBitMap; // Count of dwords remaining in bit map
};

/*
 * Flag definitions for vpdFAT_eaflags
 */
#define eavpb_fileopen          0x0001  // the EA file on this volume is open
#define eavpb_changing          0x0002  // the EA file is changing
#define eavpb_dooropen          0x0004  // the drive door has been opened

/* The size of the file system dependent area reserved in the VPB should be AT
 * LEAST as big as the largest area that we will need. For now, we set it to be
 * at least as big as that used by the FAT file system - this may change.
 */
/* ASM
.errnz  (VPDWORKAREASIZE lt size vpdFATFS)
 */

#define NULLVPB         0x0000

/*
 * The following size is used in GenhVPB to compare areas of different VPBs
 * to see if they match. If they do, then they are assumed to be the same.
 *
 * NOTE that this range is different now than it was for OS/2 version 1.0.
 * We really only need to compare the "unique" 32-bit ID and the DPB pointer
 * to see if the VPBs are the same.
 */

#define VPBIDLEN        vpi_cbSector-vpi_ID

/*  Make sure that the ID and the pDPB fields are contiguous */
/* ASM
.errnz (vpi_pDPB - vpi_ID - 4)
.errnz (vpi_cbSector - vpi_pDPB - 4)
 */

/*
 * vpb_signature can not be at beginning of struct since this is where
 * BMP puts its link.
 */
/* ASM
.ERRE vpb_signature
 */

/*
 * VPB validity signatures
 */
#define VPB_VALID       0x444A
#define VPB_INVALID     0x4A47

/*
 * Predefined values for vpb_ID field
 *
 * Unique ID for vpb_ID field for unreadable media
 */
#define UNREAD_ID1      0x4A52
#define UNREAD_ID2      0x534E

/* Unique ID for vpb_ID field for damaged volume (recognized by IFS but cannot
 * be normally mounted).
 */
#define DAMAGED_ID1     0x0000
#define DAMAGED_ID2     0x0000

//; flag bits
#define VPBCHECK        0x01    // a volume ID check is going on for this VPB
#define VPBNEWBOOT      0x02    // new format disk
#define VPBMOUNT        0x04    // Mount in progress
#define VPBFORMATMOUNT  0x08    // FormatMount done, not cleared
                                // This flag is set on close if a format
                                // mount was done (with an SFT), and was
                                // not cleared (by RedetermineMedia).
                                // This will force a volume check (see
                                // WhatVolume).

#define VPBINVALID      0x10    // volume formatted - old vpb invalid
#define VPBINITCACHE    0x20    // Initializing Cache Data

//; This bit is set by beginFormat Ioctl call; and reset by RedetermineMedia
//; IOCTL call and also by w_close if w_close finds the sf_format_mount bit to
//; be set in the SFT. As long as this bit is set, GenhVPB will not be called
//; by all of the volume checking code (WhatVolume etc). i.e. a new VPB will
//; not be generated

#define VPBSETVID   0x40        // vid set is in progress

//; Flag for serializing cluster allocation on 12-bit FAT media

#define VPBALLOCATE 0x80        // cluster allocation in progress

//;  ProcBlock Keys for Volume alloc locks

#define VPB_ALLOC_EXCL_KEY      0x1234
#define VPB_ALLOC_SHARE_KEY     0x5678

//; vpb_fMisc flag definitions

#define VPB_FM_WRITEABLE        0x01    // Set if we know volume can be written
#define VPB_FM_UNKNOWN          0x02    // Set if no FATs and not claimed by FSD
#define VPB_REMOTE_DRIVE        0x04    // set for attaches of remote drives

#define VPB_FM_ALLOCSHWAIT      0x08    // Set if somebody wants alloc access
                                        // so that they can get some disk
                                        // clusters for this volume
#define VPB_FM_ALLOCEXWAIT      0x10    // excl.access wait for somebody who
                                        // wants to release some clusters
#define VPB_FM_INITCACHE_ERROR  0x20    // Error initializing cache
#define VPB_FM_INITCACHE_DONE   0x40

// Commands to FS_MOUNT

#define FSM_MOUNT       0
#define FSM_VOLREMOVED  1
#define FSM_UNMOUNT     2
#define FSM_FORMAT      3               // forced mount (for format only)

/*
 * Number of VPBs to grow when BMP has to grow the segment.
 *
 * BUGBUG 02-Jun-1988 RajenS - Temporary high number to pre-allocate
 *
 * This is to avoid frequent InternalErrors when BMP tries to grow the segment
 * when we are holding a buffer. This should be fixed in the volume manager
 * so that we free the buffer if we know that BMP will grow the segment, and
 * then re-get the buffer after the BMP_Get call returns.
 */
#define VPB_GRODELT     20              // Number of VPBs to allocate at a time

// equates for media byte  (used by int 21 1b/1ch calls)
#define FSD_MEDIA_BYTE  0x0F0           // This is the media byte we return
                                        // for FSD controlled volumes
/* ASM
;***    VPBContext - Set up pointer to a VPB
;
;       VPBContext sets up a pointer to a volume parameter block.
;       Indx is the VPB "handle" (BMP offset) on input, and will
;       contain the VPB offset on output.  It is used by VPBContext
;       only for consistency checking.  Sel is the selector to use,
;       it will be set to point to the BMP segment where the VPBs
;       reside.
;
;       NOTE    The special argument NOCHECK is for use in volume code
;               where we're about to call BMP, and don't care about the
;               handle.  Do not use NOCHECK anywhere else.
;
;       ENTRY   sel     = segment register to seg
;               indx    = index register to verify if checking turned on
;               nocheck = non-blank means NEVER check
;
;       EXIT    sel     = GDT_VPB, assume sel:nothing

VPBContext  macro  sel,indx,nocheck

        push    GSEL GDT_VPB
        pop     sel

IFB     <nocheck>
        chkvselhd sel,indx
ENDIF

    ASSUME sel:NOTHING

        endm


;***    chkvselhd - check vpb handle/index
;
;       Check that sel:indx points to a "reasonable" VPB.  This means that
;       the signature matches and it's in the BMP segment.  It doesn't
;       mean that the VPB is actually valid.
;
;       This checking can be turned on and off by changing "VOLPTRCHK".
;
;       WARNING The procedure this macro calls does "popf" rather than
;               "popff", do not invoke this macro with interrupts off.
;

IFDEF VOLPTRCHK
        IF2
                IFNDEF  chkvselhdprc
                        extrn   chkvselhdprc:FAR
                ENDIF
        ENDIF

        chkvselhd MACRO sel,indx
        ifdif <sel>,<es>                ;; not already in es
        ifdif <sel>,<ES>
                push    es
                push    sel
                pop     es              ;; es:indx -> supposed VPB
        endif
        endif

        ifdif <indx>,<bp>               ;; not already in bp
        ifdif <indx>,<BP>
                push    bp
                mov     bp,indx         ;; es:bp -> supposed VPB
        endif
        endif

                call    FAR PTR chkvselhdprc

        ifdif <indx>,<bp>               ;; not already in bp
        ifdif <indx>,<BP>
                pop     bp
        endif
        endif

        ifdif <sel>,<es>                ;; not already in es
        ifdif <sel>,<ES>
                pop     es
        endif
        endif
        ENDM
ELSE
        chkvselhd MACRO sel,indx
        ENDM
ENDIF
*/


/*      Disk Map
 *  MSDOS partitions the disk into 4 sections:
 *
 * logical sec 0:   +-------------------+
 *      |           | boot/reserved     |
 *      |           +-------------------+
 *      |           |  File allocation  |
 *      v           |      table(s)     |
 *                  |  (multiple copies |
 *                  |     are kept)     |
 *                  +-------------------+
 *                  |     Directory     |
 *                  +-------------------+
 *                  |     File space    |
 *                  +-------------------+
 *                  |   Unaddressable   |
 *                  |  (to end of disk) |
 *                  +-------------------+
 *
 * All partition boundaries are sector boundaries.  The size of the FAT is
 * dependent on the size of the medium.
 *
 * Logical sector implies that there may be other "hidden" sectors that are
 * not treated as part of an MS-DOS partition but are on the disk for other
 * reasons. An example of this might be the Master Boot Partition on the IBM
 * hard disks. The kernel only deals in logical sectors. It is up to the disk
 * device driver to deal with physical sectors.
 */
