/*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.      */
/*                                                                           */
/*****************************************************************************/
/* SCCSID = %W% %E% */
/**************************************************************************
 *
 * SOURCE FILE NAME = S506IORB.C
 *
 * DESCRIPTIVE NAME = IBM1S506.ADD - Adapter Driver for ST506/IDE DASD
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : IORB Routine/Processing
 *
 * Purpose:
 *
 *
 *
 *
 *
*//*
 * Edit History for defect # 148406:
 *
 * Edit    Date    Comments
 * ----- --------  -------------------------------------------------------------
 * [003] 01-19-96  Add code to return the register assignments for
 *                 the Bus Master DMA ports. This information is used
 *                 by the Bus Master DMA ATAPI CD-ROM filter to
 *                 determine the address of the BM registers. /jlh
 */


#define INCL_NOBASEAPI
#define INCL_NOPMAPI
#define INCL_INITRP_ONLY

#include "os2.h"
#include "dskinit.h"

#include "iorb.h"
#include "reqpkt.h"
#include "dhcalls.h"
#include "addcalls.h"

#include "s506cons.h"
#include "s506type.h"
#include "s506ext.h"
#include "s506pro.h"
#include "s506regs.h"                                               /*@V147576*/


/*------------------------------*/
/* ADDEntryPoint                */
/* -------------                */
/*                              */
/* ADD IORB command entry.      */
/*                              */
/*------------------------------*/


VOID FAR  _loadds ADDEntryPoint( PIORBH pIORB )
{
  PIORBH        pFirstIORB;
  PIORBH        pLastIORB;
  NPACB         npACB;
  NPUCB         npUCB;

  pFirstIORB = pIORB;

  /*------------------------------------------*/
  /* Queue IORB commands which dont address a */
  /* specific unit to ACB 0 Unit 0            */
  /*------------------------------------------*/
  if( pFirstIORB->CommandCode == IOCC_CONFIGURATION )
  {
     pFirstIORB->UnitHandle = (USHORT)ACBPtrs[0].npACB->UnitCB;
  }

  npUCB = (NPUCB)pFirstIORB->UnitHandle;

#ifdef CHECK_HANDLES
  {
     // Since this driver uses a lot of near pointers, it is possible
     // to get a     UnitHandle and use it for a while before trapping
     // or worse continuing.  This check and the one below for the ACB
     // confirm the resulting pointer are referencing valid internal
     // structures.
     // Validate the unit handle.
     int a, u;

     if( npUCB )
     {
        for( a = 0; a < cAdapters; a++ )
        {
           for( u = 0; u < MAX_UNITS; u++ )
           {
              if( npUCB == (NPUCB)(&(ACBPtrs[a].npACB->UnitCB[u])) )
              {
                 goto goodUCB;
              }
           }
        }
     }

     // This is an invalid UCB.
     _asm
     {
        push   ax
        push   bx
        mov    ax, npUCB
        mov    bx, 1
        int    3
        pop    bx
        pop    ax
     }

goodUCB:

     npACB = npUCB->npACB;

     // Validate the ACB pointer.
     if( npACB )
     {
        if( npACB == ACBPtrs[a].npACB )
        {
           goto goodACB;
        }
     }

     // This is an invalid ACB.
     _asm
     {
        push   ax
        push   bx
        mov    ax, npACB
        mov    bx, 2
        int    3
        pop    bx
        pop    ax
     }

goodACB:
     ;
  }
#else
  npACB = npUCB->npACB;
#endif

  pLastIORB = PreProcessIORBs( npACB, npUCB, &pFirstIORB );         /*@V87325*/

  DISABLE
  if( pFirstIORB )                                                  /*@V147576*/
  {                                                                 /*@V147576*/
     /*------------------------------------------------*/
     /* Add non-preprocessed IORBs to end of the ACB Q */
     /*------------------------------------------------*/
     if( !npACB->pHeadIORB )
     {
        npACB->pHeadIORB = pFirstIORB;
     }
     else
     {
        npACB->pFootIORB->pNxtIORB = pFirstIORB;
     }

     /*--------------------------------------*/
     /* Point to the last IORB on the ACB Q  */
     /*--------------------------------------*/
     npACB->pFootIORB = pLastIORB;
  }

  /*                                                                  @V127556
  ** Check if there is any work on the queue, try to restart the      @V127556
  ** state machine.                                                   @V127556
  ** Work could have been added to the current ACB only by adding     @V159979
  ** onto the normal work queue and/or onto the suspend queue,        @V159979
  ** check both to see if we should restart the state machine.        @V159979
  */                                                                /*@V127556*/
  if( npACB->pHeadIORB || npACB->pSuspendHead )                     /*@V127556*//*@V159979*/
  {                                                                 /*@V127556*/
     /*                                                               @V147576
     ** Restart the state machine.                                    @V147576
     */                                                             /*@V147576*/
     if( !(npACB->Flags & ACBF_SM_ACTIVE) )                         /*@V87325*/
     {
       npACB->Flags |= ACBF_SM_ACTIVE;                              /*@V147576*/
       ENABLE
#ifdef DEBUG
       if( npACB->pIORB )
       {
          _asm int 3
       }
#endif
       StartSM( npACB );                                            /*@V147576*/
     }
  }                                                                 /*@V147576*/

  ENABLE
}


/*                                                                    @V147576
** NextIORB                                                           @VVVVVVV
**
** Called from StartState() with interrupts disabled so additional,
** synchronized processing may be done in StartState() upon return.
** Prepair the ACB to process the next IORB on its queue.
**
** Return 0 if there is another IORB to process.
** Return 1 if the queue is empty.
*/
USHORT NEAR NextIORB( NPACB npACB, NPHWRESOURCE npHWR )
{
   USHORT Flags;

#ifdef DEBUG
  if ( npACB->pIORB )                                               /*@V87325*/
  {                                                                 /*@V87325*/
    if ( !( npACB->pIORB->Status & IORB_DONE ) )                    /*@V87325*/
    {                                                               /*@V87325*/
       _asm int 3                                                   /*@V87325*/
    }                                                               /*@V87325*/
  }                                                                 /*@V87325*/
#endif

  /*---------------------------------------------------------------*/
  /* Get the next IORB from the HWResoure queue of suspended IORBs */
  /* or from the ACB's IORB queue of waiting requests.  First try  */
  /* to get a suspend IORB and then try for one on the ACB queue.  */
  /*
  /* If there are any IORBs on the suspend queue and if there are  */
  /* no IORBs on the ACB's queue or if the suspend count is        */
  /* counted down then grant the suspend request.  Otherwise       */
  /* decrement the suspend count.                                  */
  /*                                                               */
  /* If there are no suspend IORBs to process then process an IORB */
  /* from the ACB's queue.                                         */
  /*---------------------------------------------------------------*/

  if( npACB->pSuspendHead )
  {                                                                 /*@V87325*/
     if( !npACB->pHeadIORB )                                        /*@V87325*/
     {                                                              /*@V87325*/
        npACB->CountUntilSuspend = 0;
     }                                                              /*@V87325*/
     else if( npACB->CountUntilSuspend )
     {                                                              /*@V87325*/
        npACB->CountUntilSuspend--;
     }                                                              /*@V87325*/
                                                                    /*@V87325*/
     if( !npACB->CountUntilSuspend )
     {                                                              /*@V87325*/
        npACB->pIORB = npACB->pSuspendHead;
        if( !(npACB->pSuspendHead = (npACB->pSuspendHead)->pNxtIORB) )
        {
           npACB->pSuspendFoot = 0;
        }
        else  /* Setup defered count for next suspend request */
        {
           Flags = ((PIORB_DEVICE_CONTROL)npACB->pSuspendHead)->Flags;
           if( Flags & DC_SUSPEND_IMMEDIATE )
              npACB->CountUntilSuspend = IMMEDIATE_COUNT;
           else
              npACB->CountUntilSuspend = DEFERRED_COUNT;
        }
     }                                                              /*@V87325*/
     else
     {
        /*------------------------------------------*/
        /* Process an IORB from the ACB's Queue     */
        /*------------------------------------------*/
        if( npACB->pIORB = npACB->pHeadIORB )
        {
           if ( !(npACB->pHeadIORB = npACB->pIORB->pNxtIORB) )
           {
              npACB->pFootIORB = 0;
           }
        }
     }                                                              /*@V87325*/
  }
  else
  {
     /*------------------------------------------*/
     /* Process an IORB from the ACB's Queue     */
     /*------------------------------------------*/
     if( npACB->pIORB = npACB->pHeadIORB )
     {
        if ( !(npACB->pHeadIORB = npACB->pIORB->pNxtIORB) )
        {
           npACB->pFootIORB = 0;
        }
     }
  }

  if( npACB->pIORB )
  {
     npACB->IORBError  = 0;
     npACB->IORBStatus = 0;
     return( FALSE );
  }
  else
  {
     return( TRUE );
  }                                                                 /*@AAAAAAA*/
}                                                                   /*@V147576*/


/*--------------------------------------------------------------*/
/*  GetDeviceTable()                                            */
/*                                                              */
/*  Handles an IOCM_GET_DEVICETABLE request                     */
/*                                                              */
/*  Called from PreProcessIORBs(); this IORB is not placed on   */
/*  the ACB's IORB queue.                                       */
/*--------------------------------------------------------------*/

VOID NEAR GetDeviceTable( NPACB npACB, PIORB pNewIORB )             /*@V108783*/
{
  PIORB_CONFIGURATION pIORB = (PIORB_CONFIGURATION)pNewIORB;        /*@V108783*/
  USHORT              LengthNeeded;
  USHORT              i, j;
  PADAPTERINFO        pADPT;
  PUNITINFO           pUI, pUI2;
  PDEVICETABLE        pDT;
  NPACB               npACBP;

  LengthNeeded = sizeof(DEVICETABLE) + cAdapters * sizeof(ADAPTERINFO) +
                 (cUnits * sizeof(UNITINFO));

  if ( pIORB->DeviceTableLen < LengthNeeded )
  {
    pNewIORB->ErrorCode = IOERR_CMD_SYNTAX;
    pNewIORB->Status   |= IORB_ERROR;
    return;
  }

  pDT = pIORB->pDeviceTable;

  pDT->ADDLevelMajor = ADD_LEVEL_MAJOR;
  pDT->ADDLevelMinor = ADD_LEVEL_MINOR;
  pDT->ADDHandle     = ADDHandle;
  pDT->TotalAdapters = cAdapters;

  pADPT = (PADAPTERINFO) (((PBYTE)(pDT+1)) +
                                 (cAdapters-1) * sizeof(NPADAPTERINFO));

  for ( i = 0; i < cAdapters; i++ )
  {
    pDT->pAdapter[i]  = (NPADAPTERINFO) pADPT;

    memcpy( pADPT->AdapterName, AdapterName, sizeof(AdapterName) );

    npACBP = ACBPtrs[i].npACB;

    pADPT->AdapterUnits         = npACBP->cUnits;
    pADPT->AdapterDevBus        = AI_DEVBUS_ST506 | AI_DEVBUS_16BIT;
    pADPT->AdapterIOAccess      = AI_IOACCESS_PIO;
    pADPT->AdapterHostBus       = AI_HOSTBUS_ISA | AI_BUSWIDTH_16BIT;
    pADPT->AdapterSCSITargetID  = 0;
    pADPT->AdapterSCSILUN       = 0;
    pADPT->AdapterFlags         = AF_16M | AF_HW_SCATGAT;
    pADPT->MaxHWSGList          = 0;
    pADPT->MaxCDBTransferLength = 0L;

    for ( j=0; j < npACBP->cUnits; j++ )
    {
      pUI = &pADPT->UnitInfo[j];

      if ( !(pUI2=npACBP->UnitCB[j].pUnitInfo) ) /* If unit info was not changed */
      {
        setmem( (PBYTE) pUI, sizeof(UNITINFO), 0 );

        pUI->AdapterIndex     = i;
        pUI->UnitIndex        = j;
        pUI->UnitHandle       = (USHORT) &npACBP->UnitCB[j];
        pUI->FilterADDHandle  = 0;

        if (npACBP->UnitCB[j].Flags & UCBF_ATAPIDEVICE)            /*@V87325*/
          pUI->UnitType         = UIB_TYPE_ATAPI;                  /*@V87325*/
        else                                                       /*@V87325*/
          pUI->UnitType         = UIB_TYPE_DISK;

        pUI->QueuingCount     = 3;
        pUI->UnitFlags        = UF_NOSCSI_SUPT;

        /*                                                            @V155162
        ** This is for docking/swapping support.  Transfer the        @V155162
        ** FORCE and NOTPRRESENT flags only if the unit's             @V155162
        ** presense is being forced from the command line.            @V155162
        */                                                          /*@V155162*/
        pUI->UnitSCSITargetID  =  32 + (i* npACBP->cUnits) + j;
        if( npACBP->UnitCB[j].Flags & UCBF_FORCE )                  /*@V155162*/
        {                                                           /*@V155162*/
           pUI->UnitFlags |= UF_FORCE;                              /*@V155162*/
           if( npACBP->UnitCB[j].Flags & UCBF_NOTPRESENT )          /*@V155162*/
           {                                                        /*@V155162*/
              pUI->UnitFlags |= UF_NOTPRESENT;                      /*@V155162*/
           }                                                        /*@V155162*/
        }                                                           /*@V155162*/

        if ( npACBP->UnitCB[j].Flags & UCBF_NODASDSUPPORT )
        {
          pUI->UnitFlags |= UF_NODASD_SUPT;
        }
                                                                    /*@V151345*/
        if ( npACBP->UnitCB[j].Flags & UCBF_REMOVABLE     )         // srd removable disk
        {
          pUI->UnitFlags |= UF_REMOVABLE;                           // set removable attribute
        }
      }
      else  /* Pass back the changed unit info */
      {
        *pUI = *pUI2;
      }

    }
    pADPT = (PADAPTERINFO) (pUI+1);
  }
}


/*------------------------------------------*/
/*  CompleteInit()                          */
/*                                          */
/*                                          */
/*------------------------------------------*/

VOID NEAR CompleteInit(NPACB npACB)
{
  USHORT        i;
  UCHAR         rc;                                                 /*@V129765*/

  for (i=0; i < cAdapters; i++ )
  {
    if ( ACBPtrs[i].npACB->Flags & ACBF_PS2IDEPORT )
    {
      SetupPS2IDEPort( ACBPtrs[i].npACB->IOPorts[FI_PDAT], ON );    /*@V147576*//*@V153916*/
      break;
    }

    /*                                                                @V129765
    ** Perform any required OEM specific PCI initializations.         @V129765
    */                                                              /*@V129765*/
    if( ACBPtrs[i].npACB->PCIInfo.Present )                         /*@V134423*/
       ConfigurePCI( ACBPtrs[i].npACB, PCIC_INIT_COMPLETE );        /*@V147576*/
  }

  BIOSActive = 0;
#ifdef DEBUG
  if( npACB->State == ACBS_INTERRUPT )
  {
     _asm int 3
  }
#endif
  npACB->State = ACBS_DONE;                                         /*@V147576*/
}


/*------------------------------------------*/
/*  AllocateUnit()                          */
/*                                          */
/*  Mark a drive as allocated               */
/*                                          */
/*------------------------------------------*/

VOID NEAR AllocateUnit(NPACB npACB)
{
  PIORB         pIORB;
  NPUCB         npUCB;

  pIORB = npACB->pIORB;
  npUCB = (NPUCB) pIORB->UnitHandle;

  if ( npUCB->Flags & UCBF_ALLOCATED )
  {
    npACB->IORBStatus |= IORB_ERROR;                                /*@V147576*/
    npACB->IORBError  = IOERR_UNIT_ALLOCATED;                       /*@V147576*/
  }
  else
  {
    npUCB->Flags |= UCBF_ALLOCATED;
  }

#ifdef DEBUG
  if( npACB->State == ACBS_INTERRUPT )
  {
     _asm int 3
  }
#endif
  npACB->State = ACBS_DONE;                                         /*@V147576*/
}


/*------------------------------------------*/
/*  DeallocateUnit()                        */
/*                                          */
/*  Deallocate a previously allocated drive */
/*                                          */
/*------------------------------------------*/

VOID NEAR DeallocateUnit(NPACB npACB)
{
  PIORB         pIORB;
  NPUCB         npUCB;

  pIORB = npACB->pIORB;
  npUCB = (NPUCB) pIORB->UnitHandle;

  if ( !(npUCB->Flags & UCBF_ALLOCATED) )
  {
    /* Unit not allocated */
    npACB->IORBStatus |= IORB_ERROR;                                /*@V147576*/
    npACB->IORBError  = IOERR_UNIT_NOT_ALLOCATED;                   /*@V147576*/
  }
  else
  {
    npUCB->Flags &= ~UCBF_ALLOCATED;
  }

#ifdef DEBUG
  if( npACB->State == ACBS_INTERRUPT )
  {
     _asm int 3
  }
#endif
  npACB->State = ACBS_DONE;                                         /*@V147576*/
}


/*------------------------------------------*/
/*  ChangeUnitInfo()                        */
/*                                          */
/*  Store pointer to new UNITINFO structure */
/*                                          */
/*------------------------------------------*/

VOID NEAR ChangeUnitInfo( NPACB npACB )
{

  PIORB         pIORB;
  NPUCB         npUCB;

  pIORB = npACB->pIORB;
  npUCB = (NPUCB) pIORB->UnitHandle;

  if ( !npUCB->Flags & UCBF_ALLOCATED )
  {
    /* Unit not allocated */
    npACB->IORBStatus |= IORB_ERROR;                                /*@V147576*/
    npACB->IORBError  = IOERR_UNIT_NOT_ALLOCATED;                   /*@V147576*/
  }
  else
  {
    /* Save the Unit Info pointer */
    npUCB->pUnitInfo = ((PIORB_UNIT_CONTROL) pIORB)->pUnitInfo;
  }

#ifdef DEBUG
  if( npACB->State == ACBS_INTERRUPT )
  {
     _asm int 3
  }
#endif
  npACB->State = ACBS_DONE;                                         /*@V147576*/
}


/*--------------------------------------------------------------*/
/*  GetGeometry()                                               */
/*                                                              */
/*  Handles IOCM_GET_DEVICE_GEOMETRY and                        */
/*  IOCM_GET_MEDIA_GEOMETRY which both return the same geometry */
/*  for Fixed Media Devices.                                    */
/*                                                              */
/*  The Logical (INT 13) geometry is always returned. However,  */
/*  cylinder and sector counts ARE NOT bounded by INT 13        */
/*  limits.                                                     */
/*--------------------------------------------------------------*/

VOID NEAR GetGeometry(NPACB npACB)
{

  NPGEOMETRY npGeometry;

  PIORB         pIORB;
  NPUCB         npUCB;

  pIORB = npACB->pIORB;
  npUCB = (NPUCB) pIORB->UnitHandle;

  *((PIORB_GEOMETRY) pIORB)->pGeometry = npUCB->LogGeom;

#ifdef DEBUG
  if( npACB->State == ACBS_INTERRUPT )
  {
     _asm int 3
  }
#endif
  npACB->State = ACBS_DONE;                                         /*@V147576*/
}


/*--------------------------------------------------------------*/
/*  GetUnitStatus()                                             */
/*                                                              */
/*                                                              */
/*--------------------------------------------------------------*/

VOID NEAR GetUnitStatus( NPACB npACB, USHORT Status )
{
  PIORB_UNIT_STATUS pIORB;
  NPUCB             npUCB;

  pIORB = (PIORB_UNIT_STATUS) npACB->pIORB;
  npUCB = (NPUCB) pIORB->iorbh.UnitHandle;

  /*                                                                  @V157085
  ** Set the ready flag for removable media.                          @V157085
  */                                                                /*@V157085*/
  if(Status & FX_ERROR)                                             /*@V157085*/
    {                                                               /*@V157085*/
    npUCB->Flags &= ~UCBF_READY;                                    /*@V157085*/
    } /* endif */                                                   /*@V157085*/
  else                                                              /*@V157085*/
    {                                                               /*@V157085*/
    npUCB->Flags |= UCBF_READY;                                     /*@V157085*/
    } /* endelse */                                                 /*@V157085*/

  pIORB->UnitStatus |= US_POWER
                           | ((npUCB->Flags & UCBF_READY) ? US_READY : 0);

  // If this is being faked, it is not ready and not powered        /*@V149971*/
  if (npUCB->Flags & UCBF_NOTPRESENT) pIORB->UnitStatus = 0;        /*@V149971*/
  else if( Status & FX_ERROR )                                      /*@V162789*/
  {                                                                 /*@V162789*/
     /*                                                               @V162789
     ** Interpret the device's current status register, if the        @V162789
     ** preceding operation failed then interpret that to mean        @V162789
     ** the media is not present.                                     @V162789
     */                                                             /*@V162789*/
     pIORB->UnitStatus = US_MEDIA_UNKNOWN;                          /*@V162789*/
     npACB->IORBStatus |= IORB_ERROR;                               /*@V162789*/
     npACB->IORBError = MapError( npACB );                          /*@V157085*/
     if( (npACB->UnitCB[npACB->UnitId].Flags & UCBF_REMOVABLE) &&   /*@V157085*/
         (npACB->IORBError == IOERR_UNIT_NOT_READY) )               /*@V157085*/
     {                                                              /*@V157085*/
        npACB->IORBStatus = IORB_ERROR;                             /*@V157085*/
     } /* endif */                                                  /*@V157085*/
  }                                                                 /*@V162789*/
  else                                                              /*@V162789*/
  {                                                                 /*@V162789*/
     pIORB->UnitStatus |= US_DEFECTIVE;                             /*@V162789*/
  }                                                                 /*@V162789*/

#ifdef DEBUG
  if( npACB->State == ACBS_INTERRUPT )
  {
     _asm int 3
  }
#endif
  npACB->State = ACBS_DONE;                                         /*@V147576*/
}


/*--------------------------------------------------------------*/  /*@V87325*/
/*  GetQueueStatus()                                            */  /*@VVVVVV*/
/*                                                              */
/*  Called from PreProcessIORBs(); this IORB is not placed on   */
/*  the ACB's IORB queue.                                       */
/*--------------------------------------------------------------*/

VOID NEAR GetQueueStatus( NPACB npACB, PIORB pIORB )
{
   PIORB_DEVICE_CONTROL pDCIORB;
   NPUCB                npUCB;

   pDCIORB = (PIORB_DEVICE_CONTROL)pIORB;
   npUCB = (NPUCB) pDCIORB->iorbh.UnitHandle;

   pDCIORB->QueueStatus = (ULONG)npACB->pHeadIORB;
}

/*--------------------------------------------------------------*/
/*  GetUnitResources()                                          */
/*                                                              */
/*                                                              */
/*--------------------------------------------------------------*/


VOID NEAR GetUnitResources( NPACB npACB )
{
  PIORB_RESOURCE    pIORB   = (PIORB_RESOURCE) npACB->pIORB;
  PRESOURCE_ENTRY   pREHead = pIORB->pResourceEntry;
  PBYTE             pRE;
  USHORT            ReqLength;

  PIRQ_ENTRY        pIRQ;
  PPORT_ENTRY       pPort;

  ReqLength = sizeof(RESOURCE_ENTRY) +
              sizeof(IRQ_ENTRY) + (2 * sizeof(PORT_ENTRY));

  if ( ReqLength <= pIORB->ResourceEntryLen ) /* Valid request */
  {
     setmem( (PBYTE) pREHead, 0, pIORB->ResourceEntryLen );

     /* The resource entry structure contains pointers to variable length
        arrays.  Because of this, the called driver must manage the structure
        and its contents. This is accomplished by using the pRE pointer.
        It initially points to the first non-used byte in the Resource Entry
        buffer.  Each time a resource entry is added, the it is incremented
        by the size of the latest entry.
     */

     /*point directly after resource entry structure */
     pRE = (PBYTE) (pREHead+1);

     /* Update Resource Entry structure  */
     pREHead->cIRQ_Entries = 1;
     pREHead->npIRQ_Entry = (NPIRQ_ENTRY)pRE;

     pIRQ = (PIRQ_ENTRY) pRE;
     pRE  = (PBYTE)      (pIRQ+1);           /* point past current structure */

     pIRQ->IRQ_Flags = RE_ADAPTER_RESOURCE | IRQ_RISING_EDGE_TRIGGERED;
     pIRQ->IRQ_Value = npACB->IntLevel;

     /* Update Resource Entry structure  */
     pREHead->cPort_Entries = 2;
     pREHead->npPort_Entry = (NPPORT_ENTRY)pRE;

     pPort = (PPORT_ENTRY) pRE;
     pRE   = (PBYTE)       (pPort+1);        /* point past current structure */

     pPort->Port_Flags = RE_ADAPTER_RESOURCE;
     pPort->StartPort  = npACB->IOPorts[0];
     pPort->cPorts     = 8;

     pPort = (PPORT_ENTRY) pRE;
     pRE   = (PBYTE)       (pPort+1);        /* point past current structure */

     pPort->Port_Flags = RE_ADAPTER_RESOURCE;
     pPort->StartPort  = npACB->IOPorts[8];
     pPort->cPorts     = 2;

     /* Begin [003] Return bus master DMA register base/count if valid */

     ReqLength += sizeof(PORT_ENTRY);       /* one more port entry */
     if ( (npACB->BMDMA_SGListCount ) &&
          (ReqLength <= pIORB->ResourceEntryLen) )
     {
        pREHead->cPort_Entries++;           /* one more port entry */

        pPort = (PPORT_ENTRY) pRE;
        pRE   = (PBYTE)       (pPort+1);    /* point past current structure */

        pPort->Port_Flags = RE_ADAPTER_RESOURCE;
        pPort->StartPort = npACB->BMICOM;   /* command port is base */
        pPort->cPorts = 8;                  /* 8 ports per channel */
     }

     /* End [003] */

     pREHead->Max_Resource_Entry = RE_PORT; /* Establish last table entry
                                           position                          */

  }
  else
  {
     npACB->IORBStatus |= IORB_ERROR;                               /*@V147576*/
     npACB->IORBError  = IOERR_CMD_SYNTAX;                          /*@V147576*/
  }

  npACB->State = ACBS_DONE;                                         /*@V147576*/
}                                                                  /*AAAAAAA*/
                                                                   /*@V87325*/


/*--------------------------------------------------------------*/
/*  CmdNotSupported()                                           */
/*                                                              */
/*                                                              */
/*--------------------------------------------------------------*/

VOID NEAR CmdNotSupported(NPACB npACB)
{
  PIORB         pIORB;                                              /*@V151345*/

  pIORB = npACB->pIORB;                                             /*@V151345*/

  npACB->IORBStatus |= IORB_ERROR;                                  /*@V147576*/
  npACB->IORBError  = IOERR_CMD_NOT_SUPPORTED;                      /*@V147576*/

  npACB->State = ACBS_DONE;                                         /*@V147576*/
}


/*--------------------------------------------------------------*/
/*  IORBDone()                                                  */
/*                                                              */
/*                                                              */
/*--------------------------------------------------------------*/

VOID NEAR IORBDone( NPACB npACB, PIORB pIORB )                      /*@V147576*/
{
   /*                                                                  @V157085
   ** If a removable media has changed then ignore any error that      @V157085
   ** may have occured and report the changed media error.             @V157085
   ** Report media changed only once.                                  @V157085
   */                                                                /*@V157085*/
   DISABLE                                                           /*@V157085*/
   if( npACB->UnitCB[npACB->UnitId].Flags & UCBF_MEDIA_CHANGED )     /*@V157085*/
   {                                                                 /*@V157085*/
      npACB->npUCB->Flags &= ~UCBF_MEDIA_CHANGED;                    /*@V157085*/
      pIORB->ErrorCode = IOERR_MEDIA_CHANGED;                        /*@V157085*/
      pIORB->Status    = IORB_ERROR;                                 /*@V157085*/
   } /* endif */                                                     /*@V157085*/
   else                                                              /*@V157085*/
   {                                                                 /*@V157085*/
      pIORB->ErrorCode = npACB->IORBError;                           /*@V147576*/
      pIORB->Status    = npACB->IORBStatus;                          /*@V147576*/
   }                                                                 /*@V157085*/
   ENABLE                                                            /*@V157085*/

#ifdef DEBUG_STOP_ON_IORB_ERROR
   if( pIORB->ErrorCode || pIORB->Status )
   {
      // For easy view from the debugger, make the address of the
      // IORB visable.
      _asm
      {
         push ds
         push ax
         lds  ax, pIORB
         int 3
         pop ax
         pop ds
      }
   }
#endif

   npACB->pIORB = 0;                                                 /*@V87325*/

   pIORB->Status |= IORB_DONE;

   if ( pIORB->RequestControl & IORB_ASYNC_POST )
   {
 #ifdef DEBUG
      if( !pIORB->NotifyAddress )
      {
         _asm int 3
      }
 #endif
     pIORB->NotifyAddress( pIORB );
   }
}

/*--------------------------------------------------------------*/  /*@V147576*/
/*  PreProcessedIORBDone()                                      */  /*@VVVVVVV*/
/*                                                              */
/*  Preprocessed requests can complete while another, non-pre-  */
/*  processed request is processing on the ACB.  For this       */
/*  the IORBDone processing cannot change the ACB's current     */
/*  request information and must operate only on the IORB.      */
/*                                                              */
/*--------------------------------------------------------------*/
VOID NEAR PreProcessedIORBDone( PIORB pIORB )
{
#ifdef DEBUG_STOP_ON_IORB_ERROR
   if( pIORB->ErrorCode || pIORB->Status )
   {
      // For easy view from the debugger, make the address of the
      // IORB visable.
      _asm
      {
         push ds
         push ax
         lds  ax, pIORB
         int 3
         pop ax
         pop ds
      }
   }
#endif

   pIORB->Status |= IORB_DONE;

   if ( pIORB->RequestControl & IORB_ASYNC_POST )
   {
#ifdef DEBUG
      if( !pIORB->NotifyAddress )
      {
         _asm int 3
      }
#endif
      pIORB->NotifyAddress( pIORB );
   }                                                                /*@VAAAAAA*/
}                                                                   /*@V147576*/

/*--------------------------------------------------------------*/  /*@V149971*/
/*                                                              */  /*@V149971*/
/* GetChangeLine()/GetMediaSense()/GetLockStatus()/             */  /*@V149971*/
/* LockMedia()/UnLockMedia()/EjectMedia():                      */  /*@V149971*/
/*                                                              */  /*@V149971*/
/* Support routines for removable media                         */  /*@V149971*/
/*                                                              */  /*@V149971*/
/*--------------------------------------------------------------*/  /*@V149971*/

VOID NEAR GetChangeLine( NPACB npACB )                              /*@V149971*/
{                                                                   /*@VVVVVVV*/
  PIORB_UNIT_STATUS pIORB;
  NPUCB         npUCB;

  pIORB = (PIORB_UNIT_STATUS) npACB->pIORB;
  npUCB = (NPUCB) pIORB->iorbh.UnitHandle;

  if ( npUCB->Flags & UCBF_FORCE )
  {
    if ( npUCB->Flags & UCBF_CHANGED )
    {
      pIORB->UnitStatus = US_CHANGELINE_ACTIVE;
      npUCB->Flags &= ~UCBF_CHANGED;
    }
  }
  else
  {
    npACB->IORBStatus |= IORB_ERROR;
    npACB->IORBError  = IOERR_CMD_NOT_SUPPORTED;
  }
  npACB->State = ACBS_DONE;                                         /*@VAAAAAA*/
}                                                                   /*@V149971*/

VOID NEAR GetMediaSense( NPACB npACB )                              /*@V149971*/
{                                                                   /*@VVVVVVV*/
  PIORB_UNIT_STATUS pIORB;
  NPUCB         npUCB;

  pIORB = (PIORB_UNIT_STATUS) npACB->pIORB;
  npUCB = (NPUCB) pIORB->iorbh.UnitHandle;

  if ( npUCB->Flags & UCBF_FORCE )
  {
    pIORB->UnitStatus = US_MEDIA_UNKNOWN;
  }
  else
  {
    npACB->IORBStatus |= IORB_ERROR;
    npACB->IORBError  = IOERR_CMD_NOT_SUPPORTED;
  }
  npACB->State = ACBS_DONE;                                         /*@VAAAAAA*/
}                                                                   /*@V149971*/

VOID NEAR GetLockStatus( NPACB npACB )                              /*@V149971*/
{                                                                   /*@VVVVVVV*/
  PIORB_UNIT_STATUS pIORB;
  NPUCB         npUCB;

  pIORB = (PIORB_UNIT_STATUS) npACB->pIORB;
  npUCB = (NPUCB) pIORB->iorbh.UnitHandle;

  if ( npUCB->Flags & UCBF_FORCE )
  {
    if ( npUCB->Flags & UCBF_LOCKED )
    {
      pIORB->UnitStatus = US_LOCKED;
    }
  }
  else
  {
    npACB->IORBStatus |= IORB_ERROR;
    npACB->IORBError  = IOERR_CMD_NOT_SUPPORTED;
  }
  npACB->State = ACBS_DONE;                                         /*@VAAAAAA*/
}                                                                   /*@V149971*/

VOID NEAR LockMedia( NPACB npACB )                                  /*@V149971*/
{                                                                   /*@VVVVVVV*/
  PIORB         pIORB;
  NPUCB         npUCB;

  pIORB = npACB->pIORB;
  npUCB = (NPUCB) pIORB->UnitHandle;

  if ( !npUCB->Flags & UCBF_FORCE )
  {
    npACB->IORBStatus |= IORB_ERROR;
    npACB->IORBError  = IOERR_CMD_NOT_SUPPORTED;
  }
  else
  {
    npUCB->Flags |= UCBF_LOCKED;
  }
  npACB->State = ACBS_DONE;                                         /*@VAAAAAA*/
}                                                                   /*@V149971*/

VOID NEAR UnLockMedia( NPACB npACB )                                /*@V149971*/
{                                                                   /*@VVVVVVV*/
  PIORB         pIORB;
  NPUCB         npUCB;

  pIORB = npACB->pIORB;
  npUCB = (NPUCB) pIORB->UnitHandle;

  if ( !npUCB->Flags & UCBF_FORCE )
  {
    npACB->IORBStatus |= IORB_ERROR;
    npACB->IORBError  = IOERR_CMD_NOT_SUPPORTED;
  }
  else
  {
    npUCB->Flags &= ~UCBF_LOCKED;
  }
  npACB->State = ACBS_DONE;                                         /*@VAAAAAA*/
}                                                                   /*@V149971*/

VOID NEAR EjectMedia( NPACB npACB )                                 /*@V149971*/
{                                                                   /*@VVVVVVV*/
  PIORB         pIORB;
  NPUCB         npUCB;

  pIORB = npACB->pIORB;
  npUCB = (NPUCB) pIORB->UnitHandle;

  if ( !npUCB->Flags & UCBF_FORCE )
  {
    npACB->IORBStatus |= IORB_ERROR;
    npACB->IORBError  = IOERR_CMD_NOT_SUPPORTED;
  }
  else
  {
    npUCB->Flags |= UCBF_CHANGED;
  }
  npACB->State = ACBS_DONE;                                         /*@VAAAAAA*/
}                                                                   /*@V149971*/
