/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = CDIORB.C
 *
 * DESCRIPTIVE NAME = IORB managment routines for OS/2 CD-ROM Manager
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   Handles allocation, initialization, and freeing of
 *             I/O request blocks (IORBs) used to communicate with
 *             Adapter Device Drivers (ADDs).
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include "cdh.h"
#include "cdsony.h"
#include "cdchinon.h"
#include "necdb.h"
#include "tocdb.h"


/****************************************************************************
 *
 * FUNCTION NAME = AllocIORB
 *
 * DESCRIPTION   = Allocates an IORB.
 *
 *                 USHORT AllocIORB  (NPUNITCB pUnitCB, NPIORB *pIORB)
 *
 * INPUT         = pUnitCB           - UnitCB requesting allocation
 *                 pIORB             - returned pointer to IORB
 *
 * OUTPUT        = USHORT            = 0, IORB allocated
 *                                   ! 0 , IORB not allocated
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT  AllocIORB(pUnitCB, pIORB)

NPUNITCB pUnitCB;
NPIORB   FAR *pIORB;

{
   USHORT rc = 0;

   PUSHFLAGS;
   DISABLE;                            /* Make sure interrupts are disabled */

   /*
   ** Try allocating the dedicated IORB for the requesting unit
   */
   if ( !(pUnitCB->Flags & UCF_IORB_ALLOCATED) )
   {
      pUnitCB->Flags |= UCF_IORB_ALLOCATED;
      *pIORB = pUnitCB->pDedicatedIORB;
   }
   else
   {
     /*
     ** Dedicated IORB already allocated, so get an IORB from the pool.
     */
     if (CB_FreeList != 0)
     {
       *pIORB = (NPIORBH) CB_FreeList;           /* Get IORB from free list */
       CB_FreeList = (NPBYTE) (*pIORB)->pNxtIORB; /* Update free list head  */
     }
     else
       rc = 1;
   }
   /*
   ** Zero fill IORB
   */
   if (rc == 0)
      f_ZeroCB((PBYTE)*pIORB, sizeof(IORB_CDB));

   POPFLAGS;
   return(rc);
}


/****************************************************************************
 *
 * FUNCTION NAME = AllocIORB_Wait
 *
 * DESCRIPTION   = Allocate an IORB, wait until one is available
 *
 *       Allocates an IORB from the Control Block pool and block if one
 *       is not available.
 *
 *       VOID AllocIORB_Wait  (NPUNITCB pUnitCB, NPIORB *pIORB)
 *
 * INPUT         = pUnitCB           - UnitCB requesting allocation
 *                 pIORB             - returned pointer to IORB
 * OUTPUT        =
 *                 VOID
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID  AllocIORB_Wait (pUnitCB, pIORB)

NPUNITCB pUnitCB;
NPIORBH  FAR *pIORB;

{
   USHORT Allocated = FALSE;

   PUSHFLAGS;
   DISABLE;

   /*
   ** If init time, then grab the init time iorb
   */
   if (CDFlags & CDF_INIT_TIME)
      *pIORB = (NPIORBH) InitTimeIORB;

   /*
   ** Try allocating the dedicated IORB for the requesting unit
   */
   else if ( !(pUnitCB->Flags & UCF_IORB_ALLOCATED) )
   {
      pUnitCB->Flags |= UCF_IORB_ALLOCATED;
      *pIORB = pUnitCB->pDedicatedIORB;
   }

   else
   {
      do
      {
         if (CB_FreeList != 0)             /* Allocate from free list       */
         {
            *pIORB = (NPIORBH) CB_FreeList;
            CB_FreeList = (NPBYTE) (*pIORB)->pNxtIORB;       /* Update free */
            Allocated = TRUE;                                /*   list head */
         }
         else                         /* else wait till control block free  */
         {
            PoolSem++;                /* Indicate at least 1 thread blocked */
            DevHelp_ProcBlock((ULONG) ppDataSeg, (ULONG)-1, 0);
            DISABLE;
            PoolSem--;                /* Indicate at least 1 thread blocked */
         }
      } while (Allocated == FALSE);
   }

   ENABLE;
   /*
   ** Zero fill the IORB
   */
   f_ZeroCB((PBYTE)*pIORB, sizeof(IORB_CDB) );

   POPFLAGS;
}


/****************************************************************************
 *
 * FUNCTION NAME = FreeIORB
 *
 * DESCRIPTION   = Free an IORB.
 *
 *                 VOID FreeIORB  (NPUNITCB pUnitCB, NPIORB pIORB)
 *
 * INPUT         = pUnitCB           - UnitCB requesting deallocation
 *                 pIORB             - IORB to deallocate
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID  FreeIORB (pUnitCB, pIORB)

NPUNITCB    pUnitCB;
NPIORB_CDB  pIORB;

{
   USHORT AwakeCount;

   PUSHFLAGS;
   DISABLE;

   /*
   ** If the IORB being freed is the unit's dedicated IORB, then simply
   ** clear the UCF_IORB_ALLOCATED flag in the UnitCB, otherwise return
   ** the IORB to the free pool.
   */
   if (pIORB == (NPIORB_CDB) pUnitCB->pDedicatedIORB)
      pUnitCB->Flags &= ~UCF_IORB_ALLOCATED;
   else
   {
      pIORB->apt.iorbh.pNxtIORB = (NPIORBH) CB_FreeList;
      CB_FreeList = (NPBYTE) pIORB;
   }

   /*
   ** If anyone waiting on the pool, then wake them up
   */
   if (PoolSem)
   {
      DevHelp_ProcRun((ULONG)ppDataSeg, &AwakeCount);
   }

   POPFLAGS;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildIORB_DeviceControl
 *
 * DESCRIPTION   = Setup a Device Control IORB
 *
 *       This routine allocates and sets up a Device Control IORB command
 *
 *       BuildIORB_DeviceControl (NPUNITCB pUnitCB, USHORT command_modifier,
 *                                                  NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB          - pointer to UnitCB
 *                 command_modifier - IORB command modifier
 *                 pIORBOut         - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildIORB_DeviceControl (pUnitCB, command_modifier, pIORBOut)

NPUNITCB   pUnitCB;
USHORT     command_modifier;
NPIORB FAR *pIORBOut;

{
    NPIORB pIORB;

    AllocIORB_Wait(pUnitCB, (NPIORB FAR *) &pIORB);

    pIORB->Length = sizeof(IORB_DEVICE_CONTROL);
    pIORB->UnitHandle = pUnitCB->UnitInfo.UnitHandle;
    pIORB->CommandCode = IOCC_DEVICE_CONTROL;
    pIORB->CommandModifier = command_modifier;
    pIORB->RequestControl = IORB_ASYNC_POST;
    pIORB->NotifyAddress = &NotifyDoneIORB;

    *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildIORB_Read
 *
 * DESCRIPTION   = Setup IORB for a Read
 *
 *     BuildIORB_Read (NPUNITCB pUnitCB, ULONG LBA, ULONG transfer_length,
 *                       ULONG transfer_addr, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 LBA             - logical block address
 *                 block_length    - block_length
 *                 transfer_length - count of blocks to transfer
 *                 transfer_addr   - transfer address
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildIORB_Read (pUnitCB, LBA, block_length, transfer_length,
                                                 transfer_addr, pIORBOut)

NPUNITCB   pUnitCB;
ULONG      LBA;
USHORT     block_length;
USHORT     transfer_length;
ULONG      transfer_addr;
NPIORB_EXECUTEIO FAR *pIORBOut;

{
   NPIORB_EXECUTEIO pIORB;
   NPIORB_DMWORK pDMWork;

   AllocIORB_Wait(pUnitCB, (NPIORB FAR *) &pIORB);

   pDMWork = (NPIORB_DMWORK) &(pIORB->iorbh.DMWorkSpace);

   pIORB->iorbh.Length = sizeof(IORB_EXECUTEIO);
   pIORB->iorbh.UnitHandle = pUnitCB->UnitInfo.UnitHandle;
   pIORB->iorbh.CommandCode = IOCC_EXECUTE_IO;
   pIORB->iorbh.CommandModifier = IOCM_READ;
   pIORB->iorbh.RequestControl = IORB_ASYNC_POST;
   pIORB->iorbh.NotifyAddress = &NotifyDoneIORB;

   /*
   ** Setup the scatter/gather list
   */
   pIORB->cSGList = 1;
   pIORB->pSGList = (PVOID) pIORB;
   OFFSETOF(pIORB->pSGList) = (USHORT) ( &(pDMWork->SGList) );
   pIORB->ppSGList =
          (ULONG) (ppDataSeg + (ULONG) ((USHORT) &(pDMWork->SGList)) );

   pDMWork->SGList.ppXferBuf = transfer_addr;
   pDMWork->SGList.XferBufLen = transfer_length * block_length;

   /*
   ** Set up the rest of the EXECUTE_IO IORB
   */
   pIORB->RBA = LBA;
   pIORB->BlockCount = transfer_length;
   pIORB->BlockSize = block_length;

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildIORB_PassthruCDB
 *
 * DESCRIPTION   = Setup a passthru IORB for a CDB
 *
 *    This routine allocates and sets up a CDB passthru IORB
 *
 *    BuildIORB_PassthruCDB (NPUNITCB pUnitCB, ULONG data_length, ULONG ppData,
 *                                                     NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 data_length     - length of data to transfer
 *                 ppData          - physical address of data buffer
 *                 pIORBOut        - pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildIORB_PassthruCDB (pUnitCB, data_length, ppData, pIORBOut)

NPUNITCB        pUnitCB;
ULONG           data_length;
ULONG           ppData;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB    pIORB;
   NPIORB_DMWORK pDMWork;


   AllocIORB_Wait(pUnitCB, (NPIORB FAR *) &pIORB);

   pDMWork = (NPIORB_DMWORK) &(pIORB->apt.iorbh.DMWorkSpace);

   *pIORB = default_iorb_cdb;

    pIORB->apt.iorbh.UnitHandle = pUnitCB->UnitInfo.UnitHandle;
    pIORB->apt.iorbh.NotifyAddress = &NotifyDoneIORB;

    /*
    ** The pointers to the scat/gather list are always set up even
    ** if no scatter/gather list is needed.  We use the scatter/gather
    ** count field to indicate if the list should be used.  This is
    ** done this way, because some commands require a scat/gat list
    ** in the filter, but not by the CD-ROM Device Manager.
    */
    pIORB->apt.pSGList = (PVOID) pIORB;
    OFFSETOF(pIORB->apt.pSGList) = (USHORT) ( &(pDMWork->SGList) );
    pIORB->apt.ppSGLIST =
          (ULONG) (ppDataSeg + (ULONG) ((USHORT) &(pDMWork->SGList)) );

    pDMWork->SGList.ppXferBuf =
                 (ULONG)(ppDataSeg+(ULONG)((USHORT)&(pIORB->CDB_data)));

   /*
   ** If data transfer involved, set scatter/gather count to 1
   */
   if (data_length != 0)
   {
      pIORB->apt.cSGList = 1;
      pDMWork->SGList.XferBufLen = data_length;

      if (ppData != -1)
         pDMWork->SGList.ppXferBuf = ppData;
   }

   /*
   ** Fill in the pointer to the SCSI CDB
   */
   pIORB->apt.pControllerCmd = (PVOID) pIORB;
   OFFSETOF(pIORB->apt.pControllerCmd) = (USHORT) ( &(pIORB->CDB) );
   pIORB->apt.ppSCB =
          (ULONG) (ppDataSeg + (ULONG) ((USHORT) &(pIORB->CDB)) );

   /*
   ** Set up the pointers to the status block and sense data block
   */
   (USHORT) pIORB->apt.iorbh.pStatusBlock = (USHORT) ( &(pIORB->status_block) );
   pIORB->apt.iorbh.StatusBlockLen = sizeof(SCSI_STATUS_BLOCK);

   pIORB->status_block.ReqSenseLen = sizeof(struct Sense_Data);
   pIORB->status_block.SenseData = (PVOID) pIORB;
   OFFSETOF(pIORB->status_block.SenseData) = (USHORT) (&(pIORB->sense_data));

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_TestUnitReady
 *
 * DESCRIPTION   = Setup CDB for Test Unit Ready
 *
 *        BuildCDB_TestUnitReady (NPUNITCB pUnitCB, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_TestUnitReady(pUnitCB, pIORBOut)

NPUNITCB pUnitCB;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_TestUnitReady NEAR *pCDB;

  /*
  ** Build a CDB passthru IORB
  */
   BuildIORB_PassthruCDB(pUnitCB, 0, 0, (NPIORB_CDB FAR *) &pIORB);

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_TestUnitReady);

   pCDB = (struct CDB_TestUnitReady NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_TEST_UNIT_READY;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_RezeroUnit
 *
 * DESCRIPTION   = Setup CDB for Rezero Unit command
 *
 *        BuildCDB_RezeroUnit (NPUNITCB pUnitCB, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_RezeroUnit(pUnitCB, pIORBOut)

NPUNITCB pUnitCB;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_RezeroUnit NEAR *pCDB;

  /*
  ** Build a CDB passthru IORB
  */
   BuildIORB_PassthruCDB(pUnitCB, 0, 0, (NPIORB_CDB FAR *) &pIORB);

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_RezeroUnit);

   pCDB = (struct CDB_RezeroUnit NEAR * ) &(pIORB->CDB);
   pCDB->OpCode = SCSI_REZERO_UNIT;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_RequestSense
 *
 * DESCRIPTION   = Setup CDB for Request Sense Command
 *
 *        BuildCDB_RequestSense (NPUNITCB pUnitCB, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_RequestSense(pUnitCB, pIORBOut)

NPUNITCB pUnitCB;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB    pIORB;
   struct CDB_RequestSense NEAR *pCDB;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB(pUnitCB,
                         sizeof(struct Sense_Data),
                         -1L,
                         (NPIORB_CDB FAR *) &pIORB);

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_RezeroUnit);
   pIORB->apt.Flags = PT_DIRECTION_IN;

   /*
   ** Setup CDB
   */
   pCDB = (struct CDB_RequestSense NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_REQUEST_SENSE;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
   pCDB->alloc_length = sizeof(struct Sense_Data);

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_Read_6
 *
 * DESCRIPTION   = Setup CDB for Read (6) command
 *
 *      BuildCDB_Read_6 (NPUNITCB pUnitCB, ULONG LBA, ULONG transfer_length,
 *                        ULONG transfer_addr, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 LBA             - logical block address
 *                 block_length    - block_length
 *                 transfer_length - count of blocks to transfer
 *                 transfer_addr   - transfer address
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_Read_6 (pUnitCB, LBA, block_length, transfer_length,
                                                  transfer_addr, pIORBOut)

NPUNITCB   pUnitCB;
ULONG      LBA;
USHORT     block_length;
USHORT     transfer_length;
ULONG      transfer_addr;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_Read_6   NEAR *pCDB;

   union ULONGB  ul_LBA;
   union USHORTB us_transfer_length;

   ul_LBA.dword = LBA;
   us_transfer_length.word = transfer_length;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB ( pUnitCB,
                           (ULONG) transfer_length * block_length,
                           transfer_addr,
                           (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_Read_6);
   pIORB->apt.Flags = PT_DIRECTION_IN;

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_Read_6 NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_READ_6;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;

   pCDB->LBA_msb            = ul_LBA.ulbytes.byte_2;
   pCDB->LBA.usbytes.byte_0 = ul_LBA.ulbytes.byte_1;
   pCDB->LBA.usbytes.byte_1 = ul_LBA.ulbytes.byte_0;

   pCDB->transfer_length = us_transfer_length.usbytes.byte_0;

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_Read_10
 *
 * DESCRIPTION   = Setup CDB for Read (10) command
 *
 *      BuildCDB_Read_10 (NPUNITCB pUnitCB, ULONG LBA, ULONG transfer_length,
 *                        ULONG transfer_addr, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 LBA             - logical block address
 *                 block_length    - block_length
 *                 transfer_length - count of blocks to transfer
 *                 transfer_addr   - transfer address
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_Read_10 (pUnitCB, LBA, block_length, transfer_length,
                                                   transfer_addr, pIORBOut)

NPUNITCB   pUnitCB;
ULONG      LBA;
USHORT     block_length;
USHORT     transfer_length;
ULONG      transfer_addr;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_Read_10  NEAR *pCDB;

   union ULONGB  ul_LBA;
   union USHORTB us_transfer_length;

   ul_LBA.dword = LBA;
   us_transfer_length.word = transfer_length;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB ( pUnitCB,
                           (ULONG) transfer_length * block_length,
                           transfer_addr,
                           (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_Read_10);
   pIORB->apt.Flags = PT_DIRECTION_IN;

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_Read_10 NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_READ_10;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;

   pCDB->LBA.ulbytes.byte_0 = ul_LBA.ulbytes.byte_3;
   pCDB->LBA.ulbytes.byte_1 = ul_LBA.ulbytes.byte_2;
   pCDB->LBA.ulbytes.byte_2 = ul_LBA.ulbytes.byte_1;
   pCDB->LBA.ulbytes.byte_3 = ul_LBA.ulbytes.byte_0;

   pCDB->transfer_length.usbytes.byte_0 = us_transfer_length.usbytes.byte_1;
   pCDB->transfer_length.usbytes.byte_1 = us_transfer_length.usbytes.byte_0;

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_Seek_6
 *
 * DESCRIPTION   = Setup CDB for Seek (6) command
 *
 *      BuildCDB_Seek_6 (NPUNITCB pUnitCB, USHORT address_mode,
 *                                         ULONG LBA, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 address_mode    - address mode
 *                 LBA             - logical block address
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_Seek_6 (pUnitCB, LBA, pIORBOut)

NPUNITCB   pUnitCB;
ULONG      LBA;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;
   struct CDB_Seek_6   NEAR *pCDB;

   union ULONGB ul_LBA;

   ul_LBA.dword = LBA;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB(pUnitCB, 0, 0, (NPIORB_CDB FAR *) &pIORB);

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_Seek_6);

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_Seek_6 NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_SEEK_6;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;

   pCDB->LBA_msb            = ul_LBA.ulbytes.byte_2;
   pCDB->LBA.usbytes.byte_0 = ul_LBA.ulbytes.byte_1;
   pCDB->LBA.usbytes.byte_1 = ul_LBA.ulbytes.byte_0;

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_Seek_10
 *
 * DESCRIPTION   = Setup CDB for Seek (10) command
 *
 *     BuildCDB_Seek_10 (NPUNITCB pUnitCB, USHORT address_mode,
 *                                         ULONG LBA, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 address_mode    - address mode
 *                 LBA             - logical block address
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_Seek_10(pUnitCB, LBA, pIORBOut)

NPUNITCB   pUnitCB;
ULONG      LBA;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;
   struct CDB_Seek_10  NEAR *pCDB;

   union ULONGB ul_LBA;

   ul_LBA.dword = LBA;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB(pUnitCB, 0, 0, (NPIORB_CDB FAR *) &pIORB);

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_Seek_10);

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_Seek_10 NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_SEEK_10;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;

   pCDB->LBA.ulbytes.byte_0 = ul_LBA.ulbytes.byte_3;
   pCDB->LBA.ulbytes.byte_1 = ul_LBA.ulbytes.byte_2;
   pCDB->LBA.ulbytes.byte_2 = ul_LBA.ulbytes.byte_1;
   pCDB->LBA.ulbytes.byte_3 = ul_LBA.ulbytes.byte_0;

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_Inquiry
 *
 * DESCRIPTION   = Setup SCSI Inquiry Command Descriptor Block
 *
 *         This routine builds a SCSI Inquiry CDB.
 *
 *         BuildCDB_Inquiry (NPUNITCB pUnitCB, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_Inquiry(pUnitCB, pIORBOut)

NPUNITCB    pUnitCB;
NPIORB_CDB  FAR *pIORBOut;                     /* ptr to IORB              */
{
  NPIORB_CDB  pIORB;                           /* ptr to IORB              */

  struct
  CDB_Inquiry *pCDB;                           /* ptr to CDB               */

  /*
  ** Build a CDB passthru IORB
  */
  BuildIORB_PassthruCDB (pUnitCB,
               sizeof(struct Inquiry_Data),
               (ULONG) (ppDataSeg+(ULONG)((USHORT)&(pUnitCB->InquiryData))),
               (NPIORB_CDB FAR *) &pIORB );

  pIORB->apt.ControllerCmdLen = sizeof(struct CDB_Inquiry);
  pIORB->apt.Flags |= PT_DIRECTION_IN;

  /*
  ** Setup the CDB
  */
  pCDB = (struct CDB_Inquiry NEAR *) &pIORB->CDB;
  pCDB->OpCode = SCSI_INQUIRY;
  pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
  pCDB->alloc_length = sizeof(struct Inquiry_Data);

  *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_ModeSelect
 *
 * DESCRIPTION   = Setup CDB for Mode Select command
 *
 *                 Note: This routine should not be called by an ATAPI
 *                       device since the 6 byte command is not supported.
 *
 *      BuildCDB_ModeSelect (NPUNITCB pUnitCB, USHORT density_code,
 *                           USHORT block_length, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 density_code    - density code
 *                 block_length    - block_length
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_ModeSelect(pUnitCB, density_code, block_length, pIORBOut)

NPUNITCB   pUnitCB;
USHORT     density_code;
USHORT     block_length;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;
   USHORT parm_length;

   struct CDB_ModeSelect  NEAR *pCDB;
   struct ModeSelectBlockError NEAR *pDescriptor;

   if (pUnitCB->DeviceInfo.Audio.capabilities & DCAPS_MODE_WITH_ERR_RECOV)
      parm_length = sizeof(struct ModeSelectBlockError);
   else
      parm_length = sizeof(struct ModeSelectHdr) +
                    sizeof(struct BlockDescriptor);

  /*
  ** Build a CDB passthru IORB
  */
   BuildIORB_PassthruCDB (pUnitCB,
                          parm_length,
                          -1L,
                         (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_ModeSelect);

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_ModeSelect NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_MODE_SELECT;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
   pCDB->PF = 1;
   pCDB->parm_length = parm_length;

   /*
   ** Set up the Mode Parameter Header
   */
   pDescriptor = (struct ModeSelectBlockError NEAR *) &(pIORB->CDB_data);
   pDescriptor->ModeSelectHdr.mode_data_length = 0;
   pDescriptor->ModeSelectHdr.medium_type = CD_MEDIUM_DEFAULT;
   pDescriptor->ModeSelectHdr.device_specific_parm = 0;
   pDescriptor->ModeSelectHdr.block_descriptor_len =
                                            sizeof(struct BlockDescriptor);

   /*
   ** Setup the Mode Parameter Block Descriptor
   */
   pDescriptor->BlockDescriptor.density_code = (UCHAR) density_code;

   pDescriptor->BlockDescriptor.block_count_0  = 0;
   pDescriptor->BlockDescriptor.block_count_1  = 0;
   pDescriptor->BlockDescriptor.block_count_2  = 0;

   pDescriptor->BlockDescriptor.block_length_2 =
                                              (UCHAR) (block_length);
   pDescriptor->BlockDescriptor.block_length_1 =
                                              (UCHAR) (block_length >> 8);
   pDescriptor->BlockDescriptor.block_length_0 = 0;

   /*
   ** Append Read Error Recovery Page if required
   */
   if (pUnitCB->DeviceInfo.Audio.capabilities & DCAPS_MODE_WITH_ERR_RECOV)
   {
      if (block_length == 2048)
      {
         pDescriptor->ReadError.error_parm = 0;      /* Default Error Recov */
         pDescriptor->ReadError.retry_count = 0x08;
      }
      else
      {
         pDescriptor->ReadError.error_parm = 0x01;   /* Disable L-EC        */
         pDescriptor->ReadError.retry_count = 0x00;
      }

      pDescriptor->ReadError.page_code = PAGE_READ_ERROR;
      pDescriptor->ReadError.reserved_1 = 0;
      pDescriptor->ReadError.PS = 0;
      pDescriptor->ReadError.page_length = 0x06;
      pDescriptor->ReadError.reserved_2 = 0;
      pDescriptor->ReadError.reserved_3 = 0;
      pDescriptor->ReadError.reserved_4 = 0;
      pDescriptor->ReadError.reserved_5 = 0;
   }

   *pIORBOut = pIORB;
}

/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_ModeSelect_6
 *
 * DESCRIPTION   = Build CDB for 6 byte Mode Select Command
 *
 *        BuildCDB_ModeSelect_6 (NPUNITCB pUnitCB, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_ModeSelect_6 (pUnitCB, pIORBOut)

NPUNITCB   pUnitCB;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_ModeSelect  NEAR *pCDB;
   struct ModeSelectHdr NEAR *pModeSelectHdr;

  /*
  ** Build a CDB passthru IORB
  */
   BuildIORB_PassthruCDB (pUnitCB,
                sizeof(struct ModeSelectParmList),
                -1L,
                (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_ModeSelect);

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_ModeSelect NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_MODE_SELECT;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
   pCDB->PF = 1;
   pCDB->parm_length = sizeof(struct ModeSelectParmList);

   /*
   ** Set up the Mode Parameter Header
   */
   pModeSelectHdr = (struct ModeSelectHdr NEAR *) &(pIORB->CDB_data);
   pModeSelectHdr->mode_data_length = 0;
   pModeSelectHdr->medium_type = CD_MEDIUM_DEFAULT;
   pModeSelectHdr->device_specific_parm = 0;
   pModeSelectHdr->block_descriptor_len = 0;


   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_ModeSelect_10
 *
 * DESCRIPTION   = Build CDB for 10 byte Mode Select Command
 *
 *        BuildCDB_ModeSelect_10 (NPUNITCB pUnitCB, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_ModeSelect_10 (pUnitCB, pIORBOut)

NPUNITCB   pUnitCB;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_ModeSelect_10  NEAR *pCDB;
   struct ModeSelectHdr_10 NEAR *pModeSelectHdr;

  /*
  ** Build a CDB passthru IORB
  */
   BuildIORB_PassthruCDB (pUnitCB,
                sizeof(struct ModeSelectParmList_10),
                -1L,
                (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_ModeSelect_10);

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_ModeSelect_10 NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_MODE_SELECT_10;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
   pCDB->PF = 1;
   pCDB->parm_length.usbytes.byte_0 = 0;
   pCDB->parm_length.usbytes.byte_1 = sizeof(struct ModeSelectParmList_10);

   /*
   ** Set up the Mode Parameter Header
   */
   pModeSelectHdr = (struct ModeSelectHdr_10 NEAR *) &(pIORB->CDB_data);
   pModeSelectHdr->mode_data_length.word = 0;
   pModeSelectHdr->medium_type = CD_MEDIUM_DEFAULT;
   pModeSelectHdr->device_specific_parm = 0;
   pModeSelectHdr->block_descriptor_len.word = 0;


   *pIORBOut = pIORB;
}
/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_AudioControl
 *
 * DESCRIPTION   = Build CDB for audio control
 *
 *        Build a Mode Select command for the CD-ROM Audio Control page.
 *
 *        BuildCDB_AudioControl (NPUNITCB pUnitCB, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_AudioControl(pUnitCB, pIORBOut)

NPUNITCB   pUnitCB;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct Page_AudioCtrl NEAR *pDescriptor;
   struct Channel *channel;
   struct Audio   *audio;

   audio = &pUnitCB->DeviceInfo.Audio;
   channel = &audio->channel;

   /*
   ** Setup up the Mode Select CDB and Mode Parameter Header for either
   ** the 6 byte Mode Select or 10 byte Mode Select.  ATAPI devices
   ** only support the 10 byte Mode Select.
   */

   if (pUnitCB->DeviceInfo.interface_type == INTERFACE_ATAPI)
   {
      BuildCDB_ModeSelect_10 (pUnitCB, (NPIORB_CDB FAR *) &pIORB);
      (NPBYTE) pDescriptor = (NPBYTE) &(pIORB->CDB_data)
                                      + sizeof(struct ModeSelectHdr_10);
   }
   else
   {
      BuildCDB_ModeSelect_6 (pUnitCB, (NPIORB_CDB FAR *) &pIORB);
      (NPBYTE) pDescriptor = (NPBYTE) &(pIORB->CDB_data)
                                      + sizeof(struct ModeSelectHdr);
   }

   /*
   ** Setup the Audio Control page parameters
   */
   pDescriptor->page_code = PAGE_AUDIO_CONTROL;
   pDescriptor->page_length = sizeof(struct Page_AudioCtrl) - 2;
   pDescriptor->Immed = 1;

   pDescriptor->output0_select = channel->input_0+1;
   pDescriptor->output0_volume = channel->volume_0;
   pDescriptor->output1_select = channel->input_1+1;
   pDescriptor->output1_volume = channel->volume_1;

   pDescriptor->output2_select = 0;
   pDescriptor->output2_volume = 0;
   pDescriptor->output3_select = 0;
   pDescriptor->output3_volume = 0;

   /*
   ** Adjust the audio control parms based on the audio support features
   ** of the drive.
   */
   /*
   ** If the volume is set to zero and the drive supports muting, then
   ** set the channel select to mute.
   */
   if (channel->input_0 > 1 || channel->volume_0 == 0)
   {
      if (audio->capabilities & DCAPS_MUTE)
      {
         pDescriptor->output0_select = CDROM_MUTE;
      }
      else
      {
         pDescriptor->output0_volume = 0;
      }
   }

   if (channel->input_1 > 1 || channel->volume_1 == 0)
   {
      if (audio->capabilities & DCAPS_MUTE)
      {
         pDescriptor->output1_select = CDROM_MUTE;
      }
      else
      {
         pDescriptor->output1_volume = 0;
      }
   }

   /*
   ** If the drive doesnt support independent volume levels, make sure
   ** the volume levels for each channel are the same.
   */
   if ( ! (audio->capabilities & DCAPS_INDEPENDENT_VOLUME_LEVELS) )
   {
      if ( channel->volume_0 > channel->volume_1 )
      {
         pDescriptor->output0_volume = channel->volume_0;
         pDescriptor->output1_volume = channel->volume_0;
      }
      else
      {
         pDescriptor->output0_volume = channel->volume_1;
         pDescriptor->output1_volume = channel->volume_1;
      }
   }
   /*
   ** If the drive doesnt support variable volume settings, then make sure
   ** the volume is set to the max setting of 0xFF.
   */
   if ( !(audio->capabilities & DCAPS_VARIABLE_VOLUME) )
   {
      if (pDescriptor->output0_volume > 0)
          pDescriptor->output0_volume  = 0xFF;

      if (pDescriptor->output1_volume > 0)
          pDescriptor->output1_volume  = 0xFF;
   }

   /*
   ** If the request has channels 1 and 2 swapped, and the drive doesnt
   ** support channel swapping, then unswap the channels so the request
   ** completes without error.
   */
   if (audio->capabilities & DCAPS_NO_CHANNEL_SWAP)
   {
      if ( (pDescriptor->output0_select == 2) &&
           (pDescriptor->output1_select == 1) )
      {
         pDescriptor->output0_select = 1;
         pDescriptor->output1_select = 2;
      }
   }

   /*
   ** Save the actual volume settings in the UnitCB
   */
   pUnitCB->DeviceInfo.Audio.channel.volume_0 =
         pDescriptor->output0_volume;

   pUnitCB->DeviceInfo.Audio.channel.volume_1 =
         pDescriptor->output1_volume;

   if (pDescriptor->output0_select == 0)
      pUnitCB->DeviceInfo.Audio.channel.volume_0 = 0;

   if (pDescriptor->output1_select == 0)
      pUnitCB->DeviceInfo.Audio.channel.volume_1 = 0;

   /*
   ** Make audio page changes for Panasonic 501 drive.
   ** Left and right channels are reversed on this drive.
   */
   if (pUnitCB->DeviceInfo.product_id_code == PANASONIC_501)
   {
      pDescriptor->page_code = 0x2E;
      pDescriptor->output1_volume  = 0x00;

      if ( (pDescriptor->output0_select == 0) &&
           (pDescriptor->output1_select == 2) )
      {
         pDescriptor->output0_select = 1;
         pDescriptor->output1_select = 0;;
      }
      else
      {
         if ( (pDescriptor->output0_select == 1) &&
              (pDescriptor->output1_select == 0) )
         {
            pDescriptor->output0_select = 0;
            pDescriptor->output1_select = 2;;
         }
      }
   }

   *pIORBOut = pIORB;
}

/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_SenseCapabilities
 *
 * DESCRIPTION   = Build CDB for Mode Sense of Capabilities Page
 *
 *        Build a Mode Sense command for the CD-ROM Capabilities page.
 *
 *        BuildCDB_SenseCapabilities (NPUNITCB pUnitCB, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_SenseCapabilities (pUnitCB, pIORBOut)

NPUNITCB   pUnitCB;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;
   struct CDB_ModeSense_10  NEAR *pCDB;

  /*
  ** Build a CDB passthru IORB
  */

   BuildIORB_PassthruCDB(pUnitCB,
                        sizeof(struct CapabilitiesParmList_10),
                        -1L,
                        (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_ModeSense_10);
   pIORB->apt.Flags |= PT_DIRECTION_IN;

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_ModeSense_10 NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_MODE_SENSE_10;
   pCDB->DBD = 0;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
   pCDB->page_code = PAGE_CAPABILITIES;
   pCDB->PC = PC_DEFAULT;
   pCDB->alloc_length.usbytes.byte_0 = 0;
   pCDB->alloc_length.usbytes.byte_1 = sizeof(struct CapabilitiesParmList_10);
   pCDB->control = 0;

   *pIORBOut = pIORB;

}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_PreventAllowRemoval
 *
 * DESCRIPTION   = Setup CDB for Prevent Allow Media Removal
 *
 *                 BuildCDB_PreventAllowRemoval (NPUNITCB pUnitCB,  flag,
 *                                               NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 flag            - prevent-allow flag
 *                                   0 = allow medium removal
 *                                   1 = prevent medium removal
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_PreventAllowRemoval (pUnitCB, flag, pIORBOut)

NPUNITCB pUnitCB;
USHORT   flag;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_PreventAllowRemoval NEAR *pCDB;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB(pUnitCB, 0, 0, (NPIORB_CDB FAR *) &pIORB);

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_PreventAllowRemoval);

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_PreventAllowRemoval NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_LOCK_UNLOCK;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;

   pCDB->prevent = flag;

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_ReadCapacity
 *
 * DESCRIPTION   = Setup CDB for Read Capacity Command
 *
 *      BuildCDB_ReadCapacity (NPUNITCB pUnitCB, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_ReadCapacity(pUnitCB, pIORBOut)

NPUNITCB        pUnitCB;
NPIORB_CDB FAR *pIORBOut;

{
  NPIORB_CDB pIORB;

  struct CDB_ReadCapacity *pCDB;               /* ptr to CDB               */

  /*
  ** Build a CDB passthru IORB
  */
  BuildIORB_PassthruCDB(pUnitCB,
                        sizeof(struct ReadCapacity_Data),
                        -1L,
                        (NPIORB_CDB FAR *) &pIORB );

  pIORB->apt.ControllerCmdLen = sizeof(struct CDB_ReadCapacity);
  pIORB->apt.Flags |= PT_DIRECTION_IN;

  /*
  ** Setup the CDB
  */
  pCDB = (struct CDB_ReadCapacity NEAR *) &pIORB->CDB;
  pCDB->OpCode = SCSI_READ_CAPACITY;
  pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
  pCDB->RelAdr = 0;
  pCDB->LBA.dword = 0;
  pCDB->PMI = 0;
  pCDB->control = 0;

  *pIORBOut = pIORB;

}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_ReadSubChannel
 *
 * DESCRIPTION   = Setup CDB for Read Sub-Channel command
 *
 *        BuildCDB_ReadSubChannel (NPUNITCB pUnitCB, USHORT data_format,
 *                                                 NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 data_format     - Sub-channel data format to return
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_ReadSubChannel(pUnitCB, data_format, pIORBOut)

NPUNITCB        pUnitCB;
USHORT          data_format;
NPIORB_CDB FAR *pIORBOut;

{
  NPIORB_CDB pIORB;
  struct CDB_ReadSubChannel *pCDB;               /* ptr to CDB               */
  UCHAR data_size;

  /*
  ** Build a CDB passthru IORB
  */
  switch (data_format)
  {
     case RSC_Q_SUB_CHANNEL:
        data_size = sizeof(struct SubQ_Channel_Data);
        break;

     case RSC_CURRENT_POSITION:
        data_size = sizeof(struct SubChannel_Position);
        break;

     case RSC_MEDIA_CAT_NUM:
        data_size = sizeof(struct SubChannel_Media_Cat);
        break;

     case RSC_TRACK_ISRC:
        data_size = sizeof(struct SubChannel_ISRC);
        break;
  }


  BuildIORB_PassthruCDB(pUnitCB,
                        (ULONG) data_size,
                        -1L,
                        (NPIORB_CDB FAR *) &pIORB);

  pIORB->apt.ControllerCmdLen = sizeof(struct CDB_ReadSubChannel);
  pIORB->apt.Flags |= PT_DIRECTION_IN;

  /*
  ** Setup the CDB
  */
  pCDB = (struct CDB_ReadSubChannel NEAR *) &pIORB->CDB;
  pCDB->OpCode = SCSI_READ_SUB_CHAN;
  pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
  pCDB->MSF = 1;
  pCDB->SubQ = 1;
  pCDB->data_format = (UCHAR) data_format;
  pCDB->track_number = 0;
  pCDB->control = 0;
  pCDB->alloc_length.usbytes.byte_0 = 0;
  pCDB->alloc_length.usbytes.byte_1 = data_size;


  *pIORBOut = pIORB;

}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_ReadTOC
 *
 * DESCRIPTION   = Setup CDB for Read TOC command
 *
 *      BuildCDB_ReadCapacity (NPUNITCB pUnitCB, USHORT track_number,
 *                                               USHORT count,
 *                                               NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 track_number    - track number
 *                 count           - count of descriptors to return
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID  BuildCDB_ReadTOC (pUnitCB, track_number, count, pIORBOut)

NPUNITCB pUnitCB;
USHORT   track_number;
USHORT   count;
NPIORB_CDB FAR *pIORBOut;

{
  NPIORB_CDB pIORB;
  USHORT alloc_length;

  struct CDB_ReadTOC *pCDB;               /* ptr to CDB               */

  /*
  ** Build a CDB passthru IORB
  */
  alloc_length =  sizeof(struct TOC_Hdr) +
                  (sizeof(struct TOC_Descriptor) * count);

  BuildIORB_PassthruCDB(pUnitCB,
                        (ULONG) alloc_length,
                        -1L,
                        (NPIORB_CDB FAR *) &pIORB );

  pIORB->apt.ControllerCmdLen = sizeof(struct CDB_ReadTOC);
  pIORB->apt.Flags |= PT_DIRECTION_IN;

  /*
  ** Setup the CDB
  */
  pCDB = (struct CDB_ReadTOC NEAR *) &pIORB->CDB;
  pCDB->OpCode = SCSI_READ_TOC;
  pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
  pCDB->MSF = 1;
  pCDB->starting_track = track_number;
  pCDB->alloc_length.usbytes.byte_0 = 0;
  pCDB->alloc_length.usbytes.byte_1 = alloc_length;
  pCDB->control = 0;

  *pIORBOut = pIORB;


  if (pUnitCB->DeviceInfo.product_id_code == HITACHI_3750)
       DevHelp_ProcBlock( (ULONG) ppDataSeg, (ULONG) 500, 0);

}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_ReadHeader
 *
 * DESCRIPTION   = Setup CDB for Read Header command
 *
 *     BuildCDB_ReadHeader (NPUNITCB pUnitCB, ULONG LBA, NPIORB FAR *pIORB);
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 LBA             - Sub-channel data format to return
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_ReadHeader (pUnitCB, LBA, pIORBOut)

NPUNITCB   pUnitCB;
ULONG      LBA;
NPIORB_CDB FAR *pIORBOut;
{

  NPIORB_CDB pIORB;

  struct CDB_ReadHeader *pCDB;               /* ptr to CDB               */

  /*
  ** Build a CDB passthru IORB
  */
  BuildIORB_PassthruCDB(pUnitCB,
                        sizeof(struct ReadHeader_Data),
                        -1L,
                        (NPIORB_CDB FAR *) &pIORB );

  pIORB->apt.ControllerCmdLen = sizeof(struct CDB_ReadHeader);
  pIORB->apt.Flags |= PT_DIRECTION_IN;

  /*
  ** Setup the CDB
  */
  pCDB = (struct CDB_ReadHeader NEAR *) &pIORB->CDB;
  pCDB->OpCode = SCSI_READ_HEADER;
  pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
  pCDB->MSF = 0;
  pCDB->LBA.dword = LBA;
  pCDB->alloc_length.usbytes.byte_0 = 0;
  pCDB->alloc_length.usbytes.byte_1 = sizeof(struct ReadHeader_Data);
  pCDB->control = 0;

  *pIORBOut = pIORB;

}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_PauseResume
 *
 * DESCRIPTION   = Setup CDB for Pause Resume command
 *       BuildCDB_PauseResume (NPUNITCB pUnitCB,  resume_flag,
 *                                               NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 resume_flag     - 1 = resume, 0 = pause
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_PauseResume (pUnitCB, resume_flag, pIORBOut)

NPUNITCB pUnitCB;
USHORT   resume_flag;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_PauseResume NEAR *pCDB;

  /*
  ** Build a CDB passthru IORB
  */
   BuildIORB_PassthruCDB(pUnitCB, 0, 0, (NPIORB_CDB FAR *) &pIORB);

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_PauseResume);

   pCDB = (struct CDB_PauseResume NEAR * ) &(pIORB->CDB);
   pCDB->OpCode = SCSI_PAUSE_RESUME;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
   pCDB->resume = resume_flag;

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_StartStopUnit
 *
 * DESCRIPTION   = Setup CDB for Start Stop Unit command
 *
 *       BuildCDB_StartStopUnit (NPUNITCB pUnitCB,  flag,
 *                                               NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 flag            - start-stop flag
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_StartStopUnit (pUnitCB, type, pIORBOut)

NPUNITCB pUnitCB;
USHORT   type;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_StartStopUnit NEAR *pCDB;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB(pUnitCB, 0, 0, (NPIORB_CDB FAR *) &pIORB);

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_StartStopUnit);

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_StartStopUnit NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SCSI_START_STOP_UNIT;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;


   switch (type)
   {
      case CDBF_START:
         pCDB->start = 1;
         pCDB->LoEj = 0;
         break;

      case CDBF_EJECT:
         pCDB->start = 0;
         pCDB->LoEj = 1;
         break;

      case CDBF_CLOSE_TRAY:
         pCDB->start = 1;
         pCDB->LoEj = 1;
         break;
   }


   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = BuildCDB_PlayAudio_MSF
 *
 * DESCRIPTION   = Setup CDB for Play Audio MSF
 *
 *       BuildCDB_PlayAudio_MSF (NPUNITCB pUnitCB, AddressType start,
 *                                                 AddressType end,
 *                                                 NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 start           - starting address in MSF format
 *                 end             - ending address in MSF format
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildCDB_PlayAudio_MSF (pUnitCB, start, end, pIORBOut)

NPUNITCB pUnitCB;
union AddressType start;
union AddressType end;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_PlayAudio_MSF NEAR *pCDB;

  /*
  ** Build a CDB passthru IORB
  */
   BuildIORB_PassthruCDB(pUnitCB, 0, 0, (NPIORB_CDB FAR *) &pIORB);

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_PlayAudio_MSF);

   pCDB = (struct CDB_PlayAudio_MSF NEAR * ) &(pIORB->CDB);
   pCDB->OpCode = SCSI_PLAY_MSF;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;

   pCDB->starting_M = start.ul_redbook.min;
   pCDB->starting_S = start.ul_redbook.sec;
   pCDB->starting_F = start.ul_redbook.frame;

   pCDB->ending_M =   end.ul_redbook.min;
   pCDB->ending_S =   end.ul_redbook.sec;
   pCDB->ending_F =   end.ul_redbook.frame;

   *pIORBOut = pIORB;
}
/*
** ** The following commands are **
** ** ATAPI unique.              **
*/

/****************************************************************************
 *
 * FUNCTION NAME = ATAPI_BuildCDB_ReadCD
 *
 * DESCRIPTION   = Setup CDB for ATAPI Read CD command
 *
 *  ATAPI_BuildCDB_ReadCD (NPUNITCB pUnitCB, ULONG LBA, ULONG transfer_length,
 *                     ULONG transfer_addr, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 LBA             - logical block address
 *                 transfer_length - count of blocks to transfer
 *                 transfer_addr   - transfer address
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID ATAPI_BuildCDB_ReadCD (pUnitCB, LBA, transfer_length, transfer_addr,
                                                             pIORBOut)

NPUNITCB   pUnitCB;
ULONG      LBA;
USHORT     transfer_length;
ULONG      transfer_addr;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CDB_ReadCD  NEAR *pCDB;

   union ULONGB  ul_LBA;
   union USHORTB us_transfer_length;

   ul_LBA.dword = LBA;
   us_transfer_length.word = transfer_length;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB ( pUnitCB,
                           (ULONG) transfer_length * 2352,
                           transfer_addr,
                           (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct CDB_ReadCD);
   pIORB->apt.Flags = PT_DIRECTION_IN;

   /*
   ** Setup the CDB
   */
   pCDB = (struct CDB_ReadCD NEAR *) &(pIORB->CDB);
   pCDB->OpCode = ATAPI_READ_CD;
   pCDB->data_type = RCD_TYPE_ANY;

   pCDB->LBA.ulbytes.byte_0 = ul_LBA.ulbytes.byte_3;
   pCDB->LBA.ulbytes.byte_1 = ul_LBA.ulbytes.byte_2;
   pCDB->LBA.ulbytes.byte_2 = ul_LBA.ulbytes.byte_1;
   pCDB->LBA.ulbytes.byte_3 = ul_LBA.ulbytes.byte_0;

   pCDB->transfer_length_msb = 0;
   pCDB->transfer_length = us_transfer_length.usbytes.byte_1;
   pCDB->transfer_length_lsb = us_transfer_length.usbytes.byte_0;

   pCDB->error_flag = RCD_ERRFLG_NONE;
   pCDB->edc_ecc = 1;
   pCDB->user_data = 1;
   pCDB->headers = RCD_HEADER_ALL;
   pCDB->sync = 1;
   pCDB->subchannel = RCD_SUB_NONE;


   *pIORBOut = pIORB;
}




/*
** ** The following commands are **
** ** vendor unique.             **
*/

/****************************************************************************
 *
 * FUNCTION NAME = Sony_BuildCDB_Read_CDDA
 *
 * DESCRIPTION   = Setup CDB for Read CD-DA command
 *
 *  Sony_BuildCDB_Read_CDDA (NPUNITCB pUnitCB, ULONG LBA, ULONG transfer_length,
 *                     ULONG transfer_addr, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 LBA             - logical block address
 *                 transfer_length - count of blocks to transfer
 *                 transfer_addr   - transfer address
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID Sony_BuildCDB_Read_CDDA (pUnitCB, LBA, transfer_length, transfer_addr,
                                                             pIORBOut)

NPUNITCB   pUnitCB;
ULONG      LBA;
USHORT     transfer_length;
ULONG      transfer_addr;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct Sony_CDB_Read_CDDA  NEAR *pCDB;

   union ULONGB  ul_LBA;
   union USHORTB us_transfer_length;

   ul_LBA.dword = LBA;
   us_transfer_length.word = transfer_length;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB ( pUnitCB,
                           (ULONG) transfer_length * 2352,
                           transfer_addr,
                           (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct Sony_CDB_Read_CDDA);
   pIORB->apt.Flags = PT_DIRECTION_IN;

   /*
   ** Setup the CDB
   */
   pCDB = (struct Sony_CDB_Read_CDDA NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SONY_READ_CDDA;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;

   pCDB->LBA.ulbytes.byte_0 = ul_LBA.ulbytes.byte_3;
   pCDB->LBA.ulbytes.byte_1 = ul_LBA.ulbytes.byte_2;
   pCDB->LBA.ulbytes.byte_2 = ul_LBA.ulbytes.byte_1;
   pCDB->LBA.ulbytes.byte_3 = ul_LBA.ulbytes.byte_0;

   pCDB->transfer_length.ulbytes.byte_0 = 0;
   pCDB->transfer_length.ulbytes.byte_1 = 0;
   pCDB->transfer_length.ulbytes.byte_2 = us_transfer_length.usbytes.byte_1;
   pCDB->transfer_length.ulbytes.byte_3 = us_transfer_length.usbytes.byte_0;

   pCDB->sub_code = CDDA_SUBCODE_2352;

   *pIORBOut = pIORB;
}


/****************************************************************************
 *
 * FUNCTION NAME = Sony_BuildCDB_Read_CDXA
 *
 * DESCRIPTION   = Setup CDB for Read CD-XA command
 *
 *  Sony_BuildCDB_Read_CDXA (NPUNITCB pUnitCB, ULONG LBA, ULONG transfer_length,
 *                     ULONG transfer_addr, NPIORB_CDB FAR *pIORBOut)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 LBA             - logical block address
 *                 block_length    - block_length
 *                 transfer_length - count of blocks to transfer
 *                 transfer_addr   - transfer address
 *                 pIORBOut        - returned pointer to IORB
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID Sony_BuildCDB_Read_CDXA (pUnitCB, LBA, block_length, transfer_length,
                                       transfer_addr, format, pIORBOut)

NPUNITCB   pUnitCB;
ULONG      LBA;
USHORT     block_length;
USHORT     transfer_length;
ULONG      transfer_addr;
USHORT     format;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct Sony_CDB_Read_CDXA  NEAR *pCDB;

   union ULONGB  ul_LBA;
   union USHORTB us_transfer_length;

   ul_LBA.dword = LBA;
   us_transfer_length.word = transfer_length;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB ( pUnitCB,
                           (ULONG) transfer_length * block_length,
                           transfer_addr,
                           (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct Sony_CDB_Read_CDXA);
   pIORB->apt.Flags = PT_DIRECTION_IN;

   /*
   ** Setup the CDB
   */
   pCDB = (struct Sony_CDB_Read_CDXA NEAR *) &(pIORB->CDB);
   pCDB->OpCode = SONY_READ_CDXA;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;

   pCDB->LBA.ulbytes.byte_0 = ul_LBA.ulbytes.byte_3;
   pCDB->LBA.ulbytes.byte_1 = ul_LBA.ulbytes.byte_2;
   pCDB->LBA.ulbytes.byte_2 = ul_LBA.ulbytes.byte_1;
   pCDB->LBA.ulbytes.byte_3 = ul_LBA.ulbytes.byte_0;

   pCDB->transfer_length.ulbytes.byte_0 = 0;
   pCDB->transfer_length.ulbytes.byte_1 = 0;
   pCDB->transfer_length.ulbytes.byte_2 = us_transfer_length.usbytes.byte_1;
   pCDB->transfer_length.ulbytes.byte_3 = us_transfer_length.usbytes.byte_0;

   pCDB->format = format;

   *pIORBOut = pIORB;
}



;/***************************************************************************
;*
;* FUNCTION NAME = Tosh_BuildCDB_ReadDiskInfo
;*
;* DESCRIPTION   = Setup CDB for Toshiba Read Disk Info
;*
;*                 Tosh_BuildCDB_ReadDiskInfo (NPUNITCB pUnitCB, USHORT type,
;*                                             NPIORB_CDB FAR *pIORBOut)
;*
;* INPUT         = pUnitCB         - pointer to UnitCB
;*                 type            - type of disc info to retrieve
;*                 pIORBOut        - returned pointer to IORB
;*
;* OUTPUT        =
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

VOID Tosh_BuildCDB_ReadDiskInfo (pUnitCB, type, pIORBOut)

NPUNITCB   pUnitCB;
USHORT     type;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct TOSH_CDB_ReadDiskInfo  NEAR *pCDB;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB ( pUnitCB,
                           sizeof(union TOSH_ReadDiskInfo_Data),
                           -1L,
                           (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct TOSH_CDB_ReadDiskInfo);
   pIORB->apt.Flags = PT_DIRECTION_IN;

   /*
   ** Setup the CDB
   */
   pCDB = (struct TOSH_CDB_ReadDiskInfo NEAR *) &(pIORB->CDB);

   pCDB->OpCode = TOSH_READ_DISK_INFO;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
   pCDB->type = type;
   pCDB->track_number = 0;


   *pIORBOut = pIORB;
}


;/***************************************************************************
;*
;* FUNCTION NAME = Chinon_BuildCDB_GetLastSession
;*
;* DESCRIPTION   = Setup CDB for Chinon Get Last Session address
;*
;*                 Chinon_BuildCDB_GetLastSession (NPUNITCB pUnitCB,
;*                                                 NPIORB_CDB FAR *pIORBOut)
;*
;* INPUT         = pUnitCB         - pointer to UnitCB
;*                 pIORBOut        - returned pointer to IORB
;*
;* OUTPUT        =
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

VOID Chinon_BuildCDB_GetLastSession (pUnitCB, pIORBOut)

NPUNITCB   pUnitCB;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct CHINON_CDB_GetLastSession  NEAR *pCDB;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB ( pUnitCB,
                           sizeof(struct CHINON_LastSessionData),
                           -1L,
                           (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct CHINON_CDB_GetLastSession);
   pIORB->apt.Flags = PT_DIRECTION_IN;

   /*
   ** Setup the CDB
   */
   pCDB = (struct CHINON_CDB_GetLastSession NEAR *) &(pIORB->CDB);

   pCDB->OpCode = CHINON_GET_LAST_SESSION;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;


   *pIORBOut = pIORB;
}


;/***************************************************************************
;*
;* FUNCTION NAME = NEC_BuildCDB_GetLastSession
;*
;* DESCRIPTION   = Setup CDB for NEC Get Last Session address
;*
;*                 NEC_BuildCDB_GetLastSession (NPUNITCB pUnitCB,
;*                                                 NPIORB_CDB FAR *pIORBOut)
;*
;* INPUT         = pUnitCB         - pointer to UnitCB
;*                 pIORBOut        - returned pointer to IORB
;*
;* OUTPUT        =
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

VOID NEC_BuildCDB_GetLastSession (pUnitCB, pIORBOut)

NPUNITCB   pUnitCB;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   NEC_CDB_ReadTOC NEAR *pCDB;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB ( pUnitCB,
                           sizeof(NEC_DATA_PointInfo) +
                           sizeof(NEC_DATA_Point),
                           -1L,
                           (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(NEC_CDB_ReadTOC);
   pIORB->apt.Flags = PT_DIRECTION_IN;

   /*
   ** Setup the CDB
   */
   pCDB = (NEC_CDB_ReadTOC NEAR *) &(pIORB->CDB);

   pCDB->OpCode = NEC_READ_TOC;
   pCDB->data_type = NEC_POINT_INFO;
   pCDB->TNO = 0xB0;

   *pIORBOut = pIORB;
}


;/***************************************************************************
;*
;* FUNCTION NAME = ADD_BuildCDB_ReadDiskInfo
;*
;* DESCRIPTION   = Setup CDB for Read Disk Info
;*
;*                  ADD_BuildCDB_ReadDiskInfo (NPUNITCB pUnitCB, USHORT type,
;*                                             NPIORB_CDB FAR *pIORBOut)
;*
;* INPUT         = pUnitCB         - pointer to UnitCB
;*                 type            - type of disc info to retrieve
;*                 pIORBOut        - returned pointer to IORB
;*
;* OUTPUT        =
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

VOID ADD_BuildCDB_ReadDiskInfo (pUnitCB, type, pIORBOut)

NPUNITCB   pUnitCB;
USHORT     type;
NPIORB_CDB FAR *pIORBOut;

{
   NPIORB_CDB pIORB;

   struct ADD_CDB_ReadDiskInfo  NEAR *pCDB;

   /*
   ** Build a CDB passthru IORB
   */
   BuildIORB_PassthruCDB ( pUnitCB,
                           sizeof(union ADD_ReadDiskInfo_Data),
                           -1L,
                           (NPIORB_CDB FAR *) &pIORB );

   pIORB->apt.ControllerCmdLen = sizeof(struct ADD_CDB_ReadDiskInfo);
   pIORB->apt.Flags = PT_DIRECTION_IN;

   /*
   ** Setup the CDB
   */
   pCDB = (struct ADD_CDB_ReadDiskInfo NEAR *) &(pIORB->CDB);

   pCDB->OpCode = ADD_READ_DISK_INFO;
   pCDB->LUN = pUnitCB->UnitInfo.UnitSCSILUN;
   pCDB->type = type;


   *pIORBOut = pIORB;
}

