/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1992 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 source code is provided to you solely for       */
/*    the purpose of assisting you in your development of OS/2 device        */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Developer Connection Device Driver       */
/*    Source Kit for OS/2. This Copyright statement may not be removed.      */
/*                                                                           */
/*****************************************************************************/
/*static char *SCCSID = "src/dev/dasd/os2dasd/dmstrat2.c, dsdm, r206, 6a.585 93/07/15";*/
#define SCCSID  "src/dev/dasd/os2dasd/dmstrat2.c, dsdm, r206, 6a.585 93/07/15"

/**************************************************************************
 *
 * SOURCE FILE NAME = DMSTRAT2.C
 *
 * DESCRIPTIVE NAME = OS2DASD.DMD - OS/2 DASD Device Manager
 *                    Strategy 2 interface for OS/2 DASD Manager
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION  Provides validation and routing of Strategy 2 requests
 *              received from the OS/2 Kernel and/or Installable File
 *              Systems.
 *
 *
*/
#include "dmh.h"
#include "dmfault.h"


/*---------------------------------------------------*/
/* Forward Function References and pragma statements */
/*---------------------------------------------------*/

VOID NEAR ValidateReqList (PReq_List_Header, NPVOLCB FAR *);
VOID ExecReqList (PReq_List_Header, NPUNITCB);


/*------------------------------------------------------------------------
;
;** DMStrat2 - Strategy2 Request List Entry Point
;
;   Processes Strategy2 request lists
;
;   USHORT DMStrat2    (PReq_List_Header pRLH)
;
;   ENTRY:    pRLH             - Request List Header
;
;   RETURN:   VOID
;
------------------------------------------------------------------------*/
VOID _loadds FAR DMStrat2 ()

{
   PReq_List_Header pRLH;
   NPVOLCB pVolCB;

   _asm { mov word ptr pRLH[0], bx };
   _asm { mov word ptr pRLH[2], es };

   pRLH->Lst_Status = 0;
   pRLH->y_Done_Count = 0;              /* Zero out request done count */

   /* Validate the request list */

   ValidateReqList(pRLH, (NPVOLCB FAR *) &pVolCB);

   /* If request list not aborted from validate, then execute the list */

   if ( !(pRLH->Lst_Status & RLH_All_Req_Done) )
   {
      if ( IsTraceOn() )
         Trace(TRACE_STRAT2 | TRACE_ENTRY, pRLH, pVolCB);

      pVolCB->Flags &= ~vf_ForceRdWrt;
// d159983      /* 154306 */
// d159983      if (pRLH->Request_Control & RLH_Phys_Addr) { /* only do this first time */
// d159983         DevHelp_VirtToPhys(pRLH,&(pRLH->y_PhysAddr));
// d159983         pRLH->Request_Control &= ~RLH_Phys_Addr;
// d159983      } else {
// d159983         pRLH->y_PhysAddr = VirtToPhys((PBYTE)pRLH); /*Store phys addr of RLH*/
// d159983      }

      /* Start d159983 */

      if (*pInterruptLevel == (UCHAR)-1)
      {
         DevHelp_VirtToPhys(pRLH,&(pRLH->y_PhysAddr));
         if (pRLH->Request_Control & RLH_Phys_Addr) /* only do this first time */
         {
           pRLH->Request_Control &= ~RLH_Phys_Addr;
         }
      }
      else
      {
         pRLH->y_PhysAddr = VirtToPhys((PBYTE)pRLH); /*Store phys addr of RLH*/
      }

      /* End d159983 */

      /* See if Fault Tolerance is enabled */

      if (DDFlags & DDF_FT_ENABLED)
         f_FT_ExecReqList (pRLH, pVolCB->pUnitCB);
      else
         ExecReqList (pRLH, pVolCB->pUnitCB);
   }
}

/*------------------------------------------------------------------------
;
;** ExecReqList - Execute Strategy2 Request List
;
;   Executes Strategy2 request lists
;
;   USHORT ExecReqList    (PReq_List_Header pRLHIn, pUnitCB);
;
;   ENTRY:    pRLHIn       - Request List Header
;             pUnitCB      - Pointer to UnitCB
;
;   RETURN:   VOID
;
------------------------------------------------------------------------*/
VOID ExecReqList (pRLHIn, pUnitCB)

PReq_List_Header pRLHIn;
NPUNITCB pUnitCB;
{
   USHORT  i, Count;

   _segment ReqSeg;
   Req_List_Header _based(ReqSeg) *pRLH;
   PB_Read_Write _based(ReqSeg) *pRLE;

   NPIORB pIORB;                            /* d159983 */

   ReqSeg = SELECTOROF(pRLHIn);

   (USHORT) pRLH = OFFSETOF(pRLHIn);
   (USHORT) pRLE = (USHORT) pRLH + sizeof(Req_List_Header);

    /* Start d159983 */

    /*
     * A fast path when the conditions of the IF statement below
     * are met.
     */

    DISABLE;

    if (pRLH->Count == 1
        &&
        pUnitCB->NumReqsWaiting == 0
        &&
        pUnitCB->NumReqsInProgress < pUnitCB->QueueDepth)
    {
      pIORB = 0;

      if (pUnitCB->Flags & UCF_IORB_ALLOCATED)
      {
        AllocIORB(pUnitCB, (NPIORB FAR *) &pIORB);
      }
      else
      {
        pUnitCB->Flags |= UCF_IORB_ALLOCATED;
        pIORB = pUnitCB->pDedicatedIORB;
        f_ZeroCB((PBYTE)pIORB, MAX_IORB_SIZE);
      }

      if (pIORB)
      {
        pRLH->Lst_Status   &= ~RLH_Req_Not_Queued;
        pRLH->Lst_Status   |= RLH_All_Req_Queued;
        pRLE->RqHdr.Status  = RH_QUEUED;
        pRLE->RqHdr.Waiting = 0;
        pUnitCB->NumReqsInProgress++;
        NumReqsInProgress++;

        ENABLE;

        SetupIORB(pUnitCB, (PBYTE)pRLE, pIORB);

        CallADD(pUnitCB, pIORB);

        return;
      }
    }

    ENABLE;

    /* End   d159983 */

   /* Loop through the list */

   Count = pRLH->Count;
   for (i = 0; i < Count; i++)
   {
      if (pRLE->RqHdr.Status == RH_NOT_QUEUED)
      {
         PutPriorityQueue_RLE (pUnitCB, pRLE);

         /* Only queue one at a time if Execute in Sequence specified */

         if (pRLH->Request_Control & RLH_Exe_Req_Seq)
            break;
      }
      OFFSETOF(pRLE) = OFFSETOF(pRLE) + pRLE->RqHdr.Length;
   }

   DISABLE;                                                          /*120311*/
   if (pRLH->y_Done_Count != pRLH->Count)                            /*120311*/
   {                                                                 /*120311*/
      pRLH->Lst_Status &= ~RLH_Req_Not_Queued;
      pRLH->Lst_Status |= RLH_All_Req_Queued;
      ENABLE;                                                        /*120311*/
   }                                                                 /*120311*/
   else                                                              /*120311*/
   {                                                                 /*120311*/
      ENABLE;                                                        /*120311*/
      NotifyRLH(pRLH);                                               /*120311*/
   }                                                                 /*120311*/

   SubmitRequestsToADD(pUnitCB);
}


/*------------------------------------------------------------------------
;
;** ValidateReqList -  Validate a Strategy-2 request list
;
;   Verify the Request List Header has a valid unit number.  Verify
;   each Request List Entry has a valid command code and that the
;   I/O is within the partition boundaries.
;
;   USHORT ValidateReqList (PReq_List_Header pRLHIn, NPVOLCB *pVolCB_Addr)
;
;   ENTRY:    pRLHIn           - Request List Header
;             pVolCB_Addr      - returned pointer to VolCB
;
;   RETURN:   VOID
;
------------------------------------------------------------------------*/
VOID  ValidateReqList (pRLHIn, pVolCB_Addr)

PReq_List_Header pRLHIn;
NPVOLCB FAR *pVolCB_Addr;

{
   USHORT  rc, i, Count;
   NPVOLCB pVolCB;

   _segment ReqSeg;
   Req_List_Header _based(ReqSeg) *pRLH;
   PB_Read_Write _based(ReqSeg) *pRLE;

   ReqSeg = SELECTOROF(pRLHIn);
   (USHORT) pRLH = OFFSETOF(pRLHIn);

   /* First validate the Request List Header.  Make sure the header    */
   /* contains a valid unit number.  If the unit is for a floppy drive,*/
   /* make sure the floppy disk doesnt need to be changed.             */

   rc = 0;
   if (Get_VolCB_Addr(pRLH->Block_Dev_Unit, (NPVOLCB FAR *) pVolCB_Addr)
            == ERROR)

      rc = STDON + STERR + ERROR_I24_BAD_UNIT;

   else
   {
      pVolCB = *pVolCB_Addr;

      /*--------------------------------------------------------------*/
      /*  If it's for a psuedo-drive which is not currently mapped to */
      /*  it's associated unit, then a disk swap is needed.           */
      /*--------------------------------------------------------------*/

      if  (pVolCB->pUnitCB->UnitInfo.UnitFlags & UF_REMOVABLE)
      {
         if (CheckPseudoChange(pRLH->Block_Dev_Unit, pVolCB) == -1)
            rc = STDON + STERR + ERROR_I24_DISK_CHANGE;

         else if  ( (!(pVolCB->Flags & vf_ForceRdWrt)) &&
              (pVolCB->Flags & vf_UncertainMedia) )
         {
            rc = STDON + STERR + ERROR_I24_UNCERTAIN_MEDIA;
         }
      }
   }

   /* If the Request List Header had an error, then return an error for  */
   /* all entries in the list.                                           */

   if (rc & STERR)
   {
      pRLH->Lst_Status |= RLH_Unrec_Error;

      (USHORT) pRLE = (USHORT) pRLH + sizeof(Req_List_Header);
      Count = pRLH->Count;
      for (i = 0; i < Count; i++)
      {
         pRLE->Blocks_Xferred = 0;
         pRLE->RqHdr.Status = RH_UNREC_ERROR;
         pRLE->RqHdr.Error_Code = (UCHAR) rc;
         NotifyRLE(pRLE);
         OFFSETOF(pRLE) = OFFSETOF(pRLE) + pRLE->RqHdr.Length;
      }
      return;
   }

   /* The Request List Header is ok. Make sure each request in the  */
   /* list has a valid command code and the I/O fails within the    */
   /* partition boundary.                                           */

   (USHORT) pRLE = (USHORT) pRLH + sizeof(Req_List_Header);
   Count = pRLH->Count;

   for (i = 0; i < Count; i++)
   {
      rc = 0;

      /* Copy the Block_Dev_Unit from the RLH to each RLE   */
      ((PRHFT)pRLE)->Block_Dev_Unit = pRLH->Block_Dev_Unit;
      ((PRHFT)pRLE)->ftdb.FT_Flags = 0;

      if (pRLE->RqHdr.Command_Code == PB_READ_X ||
          pRLE->RqHdr.Command_Code == PB_WRITE_X ||
          pRLE->RqHdr.Command_Code == PB_WRITEV_X)
        ;
      else if (pRLE->RqHdr.Command_Code == PB_PREFETCH_X)
      {
         if ( !(pVolCB->pUnitCB->UnitInfo.UnitFlags & UF_PREFETCH) )
            rc = ERROR_I24_BAD_COMMAND;
      }
      else
         rc = ERROR_I24_BAD_COMMAND;

      if (rc == 0)
      {
         if (CheckWithinPartition(pVolCB, pRLE->Start_Block,
                                            pRLE->Block_Count) & STERR)
            rc = ERROR_I24_SECTOR_NOT_FOUND;
      }

      /* If the Request List Entry had an error notify the file system */

      if (rc != 0)
      {
         pRLE->RqHdr.Status = RH_UNREC_ERROR;
         pRLE->RqHdr.Error_Code = (UCHAR) rc;
         pRLE->Blocks_Xferred = 0;
         NotifyRLE(pRLE);

         /* Abort the list and return if Abort_Err specified */

         if (pRLH->Request_Control & RLH_Abort_Err)
         {
            AbortReqList(pRLH);
            return;
         }
      }
      OFFSETOF(pRLE) = OFFSETOF(pRLE) + pRLE->RqHdr.Length;
   } /* end for */
}

/*------------------------------------------------------------------------
;
;** AbortReqList -  Abort the request list
;
;   Abort the reqeust list when Abort on Error is specified.
;
;   VOID AbortReqList (PReq_List_Header pRLHIn)
;
;   ENTRY:    pRLH             - Request List Header
;
;   RETURN:   VOID
;
------------------------------------------------------------------------*/
VOID AbortReqList (pRLHIn)

PReq_List_Header pRLHIn;

{
   USHORT i, Count;

   _segment ReqSeg;
   Req_List_Header _based(ReqSeg) *pRLH;
   PB_Read_Write _based(ReqSeg) *pRLE;

   ReqSeg = SELECTOROF(pRLHIn);
   (USHORT) pRLH = OFFSETOF(pRLHIn);

   pRLH->Lst_Status |= RLH_Unrec_Error;

   (USHORT) pRLE = (USHORT) pRLH + sizeof(Req_List_Header);
   Count = pRLH->Count;

   for (i = 0; i < Count; i++)
   {
      if ( !(pRLE->RqHdr.Status & RH_DONE) )
      {
         pRLE->Blocks_Xferred = 0;
         pRLE->RqHdr.Status |= RH_ABORTED;
         pRLE->RqHdr.Error_Code = 0;
         NotifyRLE(pRLE);
      }
      OFFSETOF(pRLE) = OFFSETOF(pRLE) + pRLE->RqHdr.Length;
   }
}


/*------------------------------------------------------------------------
;
;** NotifyRLE - Notification callout for Request Lists
;
;   Perform notification callouts to the filesystem when a
;   Request List Entry is done.  Also, do the final Request List
;   notification callout when the entire list is complete.
;
;   USHORT NotifyRLE (PB_Read_Write pRLEIn)
;
;   ENTRY:    pRLEIn           - Request List Entry
;
;   RETURN:   BOOL      (d156407 - changed from VOID)
;
; NOTE : d156407 - after the final notify callback is made, OS2DASD can no
;        longer access the RLH/RLE.  Therefore, we must know via local
;        state variables, what we need to do after the callback.
------------------------------------------------------------------------*/
/* d156407 VOID NotifyRLE (pRLEIn) */
BOOL NotifyRLE (pRLEIn)

PPB_Read_Write pRLEIn;

{
   _segment ReqSeg;
   Req_List_Header _based(ReqSeg) *pRLH;
   PB_Read_Write _based(ReqSeg) *pRLE;
   BOOL fNotifyDone = FALSE;                                        /*d156407*/
   BOOL fNotifyError = FALSE;                                       /*d156407*/
   BOOL fAllDone = FALSE;                                           /*d156407*/

   ReqSeg = SELECTOROF(pRLEIn);
   (USHORT) pRLE = OFFSETOF(pRLEIn);

   /* Make sure this request is not already done */

   DISABLE;
   if (pRLE->RqHdr.Status & (RH_DONE | RH_ABORTED) )
   {
      ENABLE;
      return(fAllDone);
   }

   /* Set the status field to RH_DONE and do notification callouts */
   /* if required.                                                 */

   pRLE->RqHdr.Status |= RH_DONE;

/* d156407   ENABLE;  stay disabled, because we can nest interrupts */

   pRLH = (PReq_List_Header) pRLE;
   OFFSETOF(pRLH) = OFFSETOF(pRLE) - (USHORT) pRLE->RqHdr.Head_Offset;

   /*
    * Start d156407 comments...
    *
    * We increment y_Done_Count now, because if the file system uses RLE
    * notification and not RLH, then it is possible that we are
    * about to do the last RLE notification.
    *
    * We also set a flag if RLH/Unrecoverable error notification is required.
    * If not required,then it is possible that we are about to do the last
    * RLE notification.
    *
    * AFTER THE LAST NOTIFICATION, WE CANNOT READ OR WRITE THE RLH OR RLE.
    *
    * End d156407 comments...
    */

   pRLH->y_Done_Count ++;                                           /*d156407*/
   if (pRLH->y_Done_Count == pRLH->Count)                           /*d156407*/
   {                                                                /*d156407*/
     ENABLE;                                                        /*d156407*/
     fAllDone = TRUE;                                               /*d156407*/
//@183028   pRLH->Lst_Status &= ~(RLH_Req_Not_Queued | RLH_All_Req_Queued);/*d156407*/
//@183028   pRLH->Lst_Status |= RLH_All_Req_Done;                          /*d156407*/
     if (pRLH->Request_Control & RLH_Notify_Done)                   /*d156407*/
     {                                                              /*d156407*/
       fNotifyDone = TRUE;                                          /*d156407*/
     }                                                              /*d156407*/
   }                                                                /*d156407*/


   /* If there's an error, see if we should notify on errors */

   if ( (pRLE->RqHdr.Status & RH_RECOV_ERROR) &&
        ( !(pRLH->Lst_Status & RLH_Unrec_Error) ) )
      pRLH->Lst_Status |= RLH_Rec_Error;

// d156407
// d156407   We do not want to trace with interrupts disabled.
// d156407   We moved this down below.
// d156407
// d156407   if (TraceFlags != 0)                                              /*@V85908*/
// d156407      Trace((USHORT) (TRACE_STRAT2 | TRACE_ASYNCDONE | TRACE_RLE),   /*@V85908*/
// d156407            (PBYTE)   pRLE,                                          /*@V85908*/
// d156407            (NPVOLCB) 0);                                            /*@V85908*/

   if (pRLE->RqHdr.Status & RH_UNREC_ERROR)
   {
     /* Notify with error */

      pRLH->Lst_Status |= RLH_Unrec_Error;

      if (pRLH->Request_Control & RLH_Notify_Err)                   /*d156407*/
      {                                                             /*d156407*/
        fNotifyError = TRUE;                                        /*d156407*/
      }                                                             /*d156407*/
                                                                    /*d156407*/
      ENABLE;                                                       /*d156407*/

      if (TraceFlags != 0)                                              /*@V85908*/
         Trace((USHORT) (TRACE_STRAT2 | TRACE_ASYNCDONE | TRACE_RLE),   /*@V85908*/
               (PBYTE)   pRLE,                                          /*@V85908*/
               (NPVOLCB) 0);                                            /*@V85908*/

      if (pRLE->RqHdr.Req_Control & (RH_NOTIFY_ERROR | RH_NOTIFY_DONE) )
         FSD_Notify((PBYTE)pRLE, pRLE->RqHdr.Notify_Address, 1);

   }
   else if (pRLE->RqHdr.Req_Control &  RH_NOTIFY_DONE)
   {
        ENABLE;

        if (TraceFlags != 0)                                              /*@V85908*/
           Trace((USHORT) (TRACE_STRAT2 | TRACE_ASYNCDONE | TRACE_RLE),   /*@V85908*/
                 (PBYTE)   pRLE,                                          /*@V85908*/
                 (NPVOLCB) 0);                                            /*@V85908*/

         /* Notify with no with error */

         FSD_Notify((PBYTE)pRLE, pRLE->RqHdr.Notify_Address, 0);
   }
   else
   {
     ENABLE;                                                        /*d156407*/

     if (TraceFlags != 0)                                              /* 162170 */
        Trace((USHORT) (TRACE_STRAT2 | TRACE_ASYNCDONE | TRACE_RLE),   /* 162170 */
              (PBYTE)   pRLE,                                          /* 162170 */
              (NPVOLCB) 0);                                            /* 162170 */
   }

   /* Increment the requests completed count in the request list header. */
   /* If all the requests in the list are done, or an error occurred,    */
   /* then call the list notification routine if required.               */

/* d156407   pRLH->y_Done_Count ++; moved this above */

/* d156407   if (pRLH->y_Done_Count == pRLH->Count)  */

/* @183028   if (fAllDone) */
   if ((fAllDone) &&                                               /*@183028*/
       (pRLH->Lst_Status & RLH_All_Req_Queued))                    /*@183028*/
   {                                                                 /*@V85908*/
    pRLH->Lst_Status &= ~(RLH_Req_Not_Queued | RLH_All_Req_Queued);
    pRLH->Lst_Status |= RLH_All_Req_Done;

    if (TraceFlags != 0)                                           /*@V85908*/
       Trace((USHORT) (TRACE_STRAT2 | TRACE_ASYNCDONE),            /*@V85908*/
             (PBYTE)   pRLH,                                       /*@V85908*/
             (NPVOLCB) 0);                                         /*@V85908*/

/* d156407      if (pRLH->Request_Control & RLH_Notify_Done) */
      if (fNotifyDone)
      {
         /* List notify when done */

         FSD_Notify((PBYTE)pRLH,                                     /*@V71660*/
                           pRLH->Notify_Address,
                           (pRLH->Lst_Status & RLH_Unrec_Error) ? 1 : 0 );

      }
/* d156407     else if ( (pRLH->Lst_Status & RLH_Unrec_Error) &&    */       /*@V71660*/
/* d156407               (pRLH->Request_Control & RLH_Notify_Err) ) */
      else if (fNotifyError)
      {
            /* List notify on error */

         FSD_Notify((PBYTE)pRLH, pRLH->Notify_Address, 1);
      }
   }                                                                 /*@V85908*/
   return(fAllDone);                                                 /*d156407*/
}

/*------------------------------------------------------------------------
;
;** NotifyRLH - Notification callout for Request List Headers
;
;   Perform notification callouts to the filesystem when the final
;   Request List is complete
;
;   USHORT NotifyRLH (PReq_List_Header pRLH)
;
;   ENTRY:    pRLH           - Request List Header
;
;   RETURN:   VOID
;
;   Note:  The code for this function was pulled from the last several
;          lines of NotifyRLE.  This was required for defect 120311.
;
------------------------------------------------------------------------*/
VOID FAR NotifyRLH (pRLH)

PReq_List_Header pRLH;
{

    pRLH->Lst_Status &= ~(RLH_Req_Not_Queued | RLH_All_Req_Queued);
    pRLH->Lst_Status |= RLH_All_Req_Done;

    if (TraceFlags != 0)                                           /*@V85908*/
       Trace((USHORT) (TRACE_STRAT2 | TRACE_ASYNCDONE),            /*@V85908*/
             (PBYTE)   pRLH,                                       /*@V85908*/
             (NPVOLCB) 0);                                         /*@V85908*/

    if (pRLH->Request_Control & RLH_Notify_Done)
    {
       /* List notify when done */

       FSD_Notify((PBYTE)pRLH,                                     /*@V71660*/
                         pRLH->Notify_Address,
                         (pRLH->Lst_Status & RLH_Unrec_Error) ? 1 : 0 );

    }
    else if ( (pRLH->Lst_Status & RLH_Unrec_Error) &&             /*@V71660*/
              (pRLH->Request_Control & RLH_Notify_Err) )
    {
          /* List notify on error */

       FSD_Notify((PBYTE)pRLH, pRLH->Notify_Address, 1);
    }
}

/*------------------------------------------------------------------------
;
;** DD_ChgPriority - Change the priority of a Request List Entry
;
;   Change the priority of a Request List Entry
;
;   USHORT DD_ChgPriority   (PPB_ReadWrite pRLE, UCHAR Priority)
;
;   ENTRY:    pRLE             - Request List Entry
;             Priority         - Priority
;
;   RETURN:   USHORT           - Return Code
;                                  0 = No error, priority changed
;                                  1 = Error, priority not changed since
;                                      request no longer on queue
; ------------------------------------------------------------------------*/
USHORT  DD_ChgPriority (pRLE, Priority)

PPB_Read_Write pRLE;
UCHAR  Priority;

{
   USHORT rc;
   PReq_List_Header pRLH;
   NPVOLCB pVolCB;

   /* If same priority as before then no need to change */

   if (pRLE->RqHdr.Priority == Priority)
      rc = 0;
   else if (pRLE->RqHdr.Status == RH_NOT_QUEUED)
   {
      pRLE->RqHdr.Priority = Priority;
      rc = 0;
   }
   else if (pRLE->RqHdr.Status != RH_QUEUED)
      rc = 1;

   else   /* Request is already queued.  Move to new Priority queue. */
   {
      pRLH = (PReq_List_Header) pRLE;
      OFFSETOF(pRLH) = OFFSETOF(pRLE) - (USHORT) pRLE->RqHdr.Head_Offset;
      Get_VolCB_Addr(pRLH->Block_Dev_Unit, (NPVOLCB FAR *)&pVolCB);
      if (RemovePriorityQueue(pVolCB->pUnitCB, pRLE) == NO_ERROR)
      {
         pRLE->RqHdr.Priority = Priority;
         PutPriorityQueue_RLE (pVolCB->pUnitCB, pRLE);
         rc = 0;
      }
      else
         rc = 1;
   }

   return(rc);
}

/*------------------------------------------------------------------------
;
;** DD_SetFSDInfo - Set FSD callout addresses.
;
;   Entry point for FSD to inform us of it's FSD_EndofInt and
;   FSD_AccValidate entry points.
;
;   USHORT DD_SetFSDInfo  (PSet_FSD_Info pFSDInfo)
;
;   ENTRY:    pFSDInfo         - FSD info structure
;
;   RETURN:   USHORT           - Return Code
;                                  0 = No error, FSD info changed
;                                  1 = Error, FSD info not changed
; ------------------------------------------------------------------------*/
USHORT _loadds FAR DD_SetFSDInfo ()

{
   FSDInfo FAR *pFSDInfo;
   USHORT rc;

   _asm { mov word ptr pFSDInfo[0], bx };
   _asm { mov word ptr pFSDInfo[2], es };

   /* Can only set FSDInfo callout addresses once. */

   if (pFSD_EndofInt != 0 || pFSD_AccValidate != 0)
   {
      rc = 1;
      _asm {stc};
   }
   else
   {
      pFSD_EndofInt = pFSDInfo->FSD_EndofInt;
      pFSD_AccValidate = pFSDInfo->FSD_AccValidate;
      rc = 0;
      _asm {clc};
   }

   return(rc);
}





