/*static char *SCCSID = "@(#)asyncio.h	6.6 92/01/31";*/
/***************************************************************************\
*									    *
*   ASYNCIO.H								    *
*									    *
*		      HPFS Command Chaining support API			    *
*			       Header File				    *
*									    *
*									    *
* Copyright notice goes here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! *
*									    *
*									    *
*									    *
*   Note:								    *
*	This file requires strat2.h to be included before it		    *
*									    *
*	HISTORY								    *
*									    *
*   23-Oct-1989 19:06:31 by Jon Parati [jonpa]	Wrote it		    *
*									    *
\***************************************************************************/

/***************************************************************************\
*
* Structure definitions:
*
\***************************************************************************/
typedef struct {
    PB_Read_Write   RWReq;	/* Read Write request block	*/
    SG_Descriptor   SGList[1];	/* Scatter-gather list		*/
} LISTENT;

typedef LISTENT FAR *PLISTENT;

typedef struct {
    Req_List_Header ELHdr;	/* execution-list header	    */
    LISTENT	    IOReq;	/* the I/O Request list starts here */
} EXECLIST;

typedef EXECLIST FAR *PEXECLIST;
typedef PEXECLIST FAR *PPEXECLIST;


typedef struct _LCKHAND {
    struct _LCKHAND FAR *plhNext;
    BYTE    abLockHand[12];
} LCKHAND;

typedef LCKHAND FAR *PLCKHAND;


typedef struct IOHANDLE { /* IOHANDLE*/
#ifdef DEBUG
    BYTE sig [4];	/* PIC signature for assertion checking */
#endif
    PVOLTAB  pvol;	/* pointer to volume table entry for the logical *
			 * volume this chain is intended for		 */
    PLISTENT preqCurr;	/* pointer to last request added by QDiskOp.	 *
			 * NULL if none made yet			 */
    PLCKHAND plhChain;	/* Lock handle chain for UnlockIOPages		 */
    SHORT    cbLeft;	/* Number of bytes left in this list		 */
    SHORT    cbTotal;	/* Total Number of bytes in this list		 */
    PVOID    semDone;	/* Wait chain for ExecIO and AUTOFLUSH blocking	 */
    USHORT   usFlags;	/* copy of flags passed to GetIOHead()		 */

    /*
     * Beginning of information used by qread/qwrite-type callers.
     * These are not set or used by the async I/O routines.  The lazy
     * writer code also ignores this stuff.
     */
    BYTE     bBitForThisOp;	/* Single bit used to indicate this op.  */
    BYTE     bDummy;		/* Reserved for future use.		 */
    struct IOHANDLE far *piohNext;	/* Next IOH on chain.		 */
    PNOTEREC pNoteRec;		/* NoteRec for this request.		 */
    PVOID    pVirtData;		/* Virtual addr of data itself.		 */
#ifdef DEBUG
    struct IOHANDLE far *pioh; /* debug link for pending I/O requests	 */
				/* (see QRead/QWrite).			 */
#endif
    /* End of information used by qread/qwrite-type callers. */

} IOHANDLE;

typedef IOHANDLE FAR *PIOH;

#ifdef DEBUG
#define SIGIOH "I/OH"
#endif


/*
 * Function prototype for notify routines
 */
typedef void   (PASCAL FAR *PFNV)();
#define FNV	VOID PASCAL FAR

/*
 * Private structure for allocation
 */
typedef struct IOHEXL { /* IOHEXL*/
    IOHANDLE	ioh;
    EXECLIST	exl;
} IOHEXL;

typedef IOHEXL FAR *PIOHEXL;


/***************************************************************************\
*
* Macros and defines
*
\***************************************************************************/


#define BEGIN_NOTIFY( name, pxlh, erc )					\
	FNV name( void ) { PEXECLIST pxlh; UINT erc = InitNfy( &pxlh ); \
	lprintf( LMOD_NTFY, "Start Notify: p=%p", pxlh ); {

#define END_NOTIFY  } lprintf( LMOD_NTFY, "End Notify" ); }

/* Size of Scatter/Gather list (parameter to GetIOHand) */
#define ONESGLIST 1

/* RWSGLIST is used in QRead & QWrite - need enough s/g entries to
 * handle full 64K segment - might not be page aligned, so add 1)
 */
#define RWSGLIST (0x10000 / PAGESIZE) + 2    /* 18 entries with 4K pages */

/* Command codes for QDiskOp */
#define QDO_READ      PB_READ_X
#define QDO_WRITE     PB_WRITE_X
#define QDO_WRITEV    PB_WRITEV_X
#define QDO_RET_HOTFIX	0x8000
#define QDO_NO_HOTFIX	0x4000

/* Error code bits for QDiskOp and ExecIOH */
#define QDERR_LISTFULL	  0x01
#define QDERR_AUTOFLUSH	  0x02
#define QDERR_READ	  0x04
#define QDERR_WRITE	  0x08
#define QDERR_GPFAULT	  0x10
#define QDERR_NO_MEMORY	  0x20
#define QDERR_INTERRUPT	  0x40
#define QDERR_HOTFIX	  0x80


/* Notify bits */
#define IONFY_ERROR	RH_NOTIFY_ERROR
#define IONFY_COMPLETE	RH_NOTIFY_DONE

#if (RH_NOTIFY_ERROR != RLH_Notify_Err) || (RH_NOTIFY_DONE != RLH_Notify_Done)
#   error RLH_ notify bits have changed value
#endif

/* Flags for GetIOHand */
#define GIH_INORDER   RLH_Exe_Req_Seq
#define GIH_ABORTERR  RLH_Abort_Err
#define GIH_PHYSADDR  (0x4000)
#define GIH_AUTOFLUSH (0x8000)

#define GIH_HIFLAGS   (GIH_PHYSADDR | GIH_AUTOFLUSH) /* HPFS internal flags*/

#if (GIH_INORDER | GIH_ABORTERR) & GIH_HIFLAGS != 0
#error RLH flags in strat2.h have changed
#endif

/***************************************************************************\
*
* I/O API Macros
*
\***************************************************************************/
/*
 * BOOL IsAsyncIOable( LSN vlsn )
 *
 *  Used to determine if a device driver supports Strategy2 interface
 *
 *  Parameter:
 *	vlsn	a lsn with the volume bits set to the volume to be tested
 *
 *  returns	TRUE if the device driver supports Strategy2 interface
 *		FALSE if not
 *
 *  IsAsyncIOable returns TRUE if the device driver supports Strategy2
 *  interface or FALSE if not.  Only the volume bit field of the
 *  vlsn passed in need to be valid, the sector number itself will not
 *  be used.
 */
#define ASYNC_PACKETS
#ifdef ASYNC_PACKETS
#   define IsAsyncIOable( vlsn ) (VolPtr[IVOLFROMLSN(vlsn)]->pfncStrategy2 != NULL)
#else
#   define IsAsyncIOable( vlsn ) FALSE
#endif

/*
 * BOOL IsSCBcapable( LSN vlsn )
 *
 *  Used to determine if a volume supports command-chaining and scatter/gather
 *
 *  Parameter:
 *	 vlsn:	a lsn with the volume bits set to the volume to be tested
 *
 *  returns	TRUE if the volume supports command-chaining and scatter/gather
 *		FALSE if not
 *
 *  IsSCBcapable returns TRUE if the volume supports command-chaining and
 *  scatter/gather or FALSE if not.  Only the volume bit field of the
 *  vlsn passed in need to be valid, the sector number itself will not
 *  be used.
 */
#define ASYNC_PACKETS
#ifdef ASYNC_PACKETS
#   define IsSCBcapable( vlsn ) (VolPtr[IVOLFROMLSN(vlsn)]->SCBcapable != NULL)
#else
#   define IsSCBcapable( vlsn ) FALSE
#endif

/*
 *
 *  PEXECLIST GetIOListHead( PIOH pioh );
 *
 *  Returns the head of the execution-list associated with pioh
 *
 *  Parameter:
 *	pioh	pointer to the IOHandle that describes the reqested Exec-List
 *
 *  GetIOListHead returns a pointer to the head of the execution-list
 *  that pioh is associated with.  This can be useful for stepping through
 *  the list to find which request caused an error.  For the definition
 *  of an Execution-List header see the Cruser I/O Work Book Appendix A.
 *
 */
#define GetIOListHead( pioh ) (& (((PIOHEXL)(pioh))->exl) )

/*
 *
 *  PLISTENT FirstIOReq( PEXECLIST pxlh );
 *
 *  Returns a pointer to the first I/O Request packet header in an execution-list
 *
 *  Parameter:
 *	pxlh	Pointer to the head of an execution-list
 *
 *  FirstIOReq returns the pointer to the first I/O request in an execution-list.
 *  This pointer can be used in conjucntion with NextIOReq to step through
 *  the entire execution-list, looking at each I/O request packet separatly.
 *  To get the head of an execution list, use GetIOListHead.
 *
 */
#define FirstIOReq( pxlh )  ( &((pxlh)->IOReq) )

/*
 *
 *  PLISTENT NextIOReq( PLISTENT preq );
 *
 *  Returns a pointer to the next request in the execution-list
 *
 *  Parameter:
 *	preq	Pointer to a request entry in an execution-list
 *
 *  NextIOReq returns a pointer to the next I/O request entry in an
 *  execution-list.  To get a pointer to the first I/O request in a list,
 *  use GetIOListHead to get a pointer to the list header and use FirstIOReq
 *  on that pointer.  Stepping through an execution-list is useful to find
 *  which I/O request caused an error reported by ExecIOH.  For the
 *  definition of an execution list entry header see the Cruser I/O Work
 *  Book Appendix A.
 *
 */
#define NextIOReq( preq )   (PLISTENT)BUMP_PTR(preq,(preq)->RWReq.RqHdr.Length)

/*
 *
 *  BOOL IsLastIOReq( PLISTENT preq );
 *
 *  Returns TRUE if this is the last request in the list
 *
 *  Parameter:
 *	preq	Pointer to a request entry in an execution-list
 *
 *  IsLastReq Returns TRUE if this is the last request in the list,
 *  FALSE otherwise
 *
 */
#define IsLastReq( preq )   ((preq)->RWReq.RqHdr.Length == RH_LAST_REQ)

/*
 *  PIOH IOHFromListHead( PEXECLIST pxlh );
 *
 *  Called to get the IOHandle associated with an execution-list
 *
 *  Parameter:
 *	pxlh	    Pointer to the execution-list header
 *
 *  IOHFromListHead is usually called within notify procedures to
 *  get the IO Handle associated with the execution-list that
 *  was passed into the notify procedure.  This is useful so
 *  that RelIOHand can be called once the IO for an execution-list
 *  has been asynchronously completed.  To get the IOHandle if you
 *  have a pointer to an individual IORequest in an execution-list,
 *  first call HeadFromIOReq to get the list head and then call
 *  IOHFromListHead.
 *
 */
#define IOHFromListHead( pxlh ) ((PIOH)BUMP_PTR( pxlh, -sizeof(IOHANDLE) ))

/*
 *
 *  PEXECLIST  HeadFromIOReq( PLISTENT preq );
 *
 *  Returns the execution-list header for the list that the IO request is in
 *
 *  Paramter:
 *	preq	Pointer to a request entry in an execution-list
 *
 *  HeadFromIOReq is used to the the execution-list header for the list
 *  that contains the IO Request packet pointed to by the preq parameter.
 *  This pointer can be the pointer passed into a notify routine set
 *  by SetOpNotify.
 *
 */
#define HeadFromIOReq( preq )					\
	    (PEXECLIST)BUMP_PTR( preq, -((preq)->RWReq.RqHdr.Head_Offset) )


/***************************************************************************\
*
* Prototypes
*
\***************************************************************************/

extern VOID AIOInit( PVOLTAB pvol );

extern PIOH GetIOHand(ULONG flFlags,USHORT cReqHdrs,
		      USHORT cSGPerReq, PFRAME pfrm);

extern UINT QDiskOp( PIOH pioh, BYTE pri, USHORT usOp,
	      LSN lsnStart, USHORT cSects,
	      PBYTE pbData, PBYTE pbEventFlags, PFRAME pfrm );

extern VOID SetOpNotify( PIOH pioh, BYTE fFlags, PFNV pfnNotify );

extern VOID SetListNotify( PIOH pioh, BYTE fFlags, PFNV pfnvNotify );

extern UINT ExecIOH( PIOH pioh, BOOL fBlock, PFRAME pfrm );

extern VOID UnlockIOHPages( PIOH pioh, PFRAME pfrm );

extern VOID ResetIOH( PIOH pioh, ULONG flFlags );

extern VOID RelIOHand( PIOH pioh );

extern UINT InitNfy( PPEXECLIST ppxlh );

extern VOID CallAsyncIO( PEXECLIST pxlh, PFNV pStrat2 );
