/*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 = FLTIORB.C
 *
 * DESCRIPTIVE NAME = Common IORB processor for CD-ROM filter drivers
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   Filters SCSI-2 Command Descriptor Blocks and routes
 *             them to the vendor unique filter routines.
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include "flthdr.h"

USHORT FilterRequest (PIORB);
VOID ProcessNextState (PIORB_CDB, USHORT);
VOID _loadds FAR Filter_NotifyDoneIORB (PIORB_CDB);

/****************************************************************************
 *
 * FUNCTION NAME = Filter_IORB
 *
 * DESCRIPTION   = Filters IORB Requests from OS2CROM.DMD
 *
 *                 Filter_IORB (PIORB_CDB pIORB)
 *
 * INPUT         = pIORB        - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID _loadds FAR Filter_IORB (pIORB)

PIORB pIORB;
{
   USHORT action_code;
   NPUNITCB pUnitCB;
   USHORT (NEAR *pRoutine)(PIORB_CDB);
   PIORB_FLTWORK pFilter_workspace;

   /* Handle the Get Device Table call.  Since we are just filtering */
   /* requests, return a table with no unit info.                    */

   if (pIORB->CommandCode == IOCC_CONFIGURATION)
   {
      if (pIORB->CommandModifier == IOCM_GET_DEVICE_TABLE)
      {
        ((PIORB_CONFIGURATION)pIORB)->pDeviceTable->ADDLevelMajor = 1;
        ((PIORB_CONFIGURATION)pIORB)->pDeviceTable->ADDLevelMinor = 0;
        ((PIORB_CONFIGURATION)pIORB)->pDeviceTable->ADDHandle = FilterADDHandle;
        ((PIORB_CONFIGURATION)pIORB)->pDeviceTable->TotalAdapters = 0;
      }

      pIORB->Status = IORB_DONE;
      pIORB->ErrorCode = 0;
      if (pIORB->RequestControl & IORB_ASYNC_POST)
         (pIORB->NotifyAddress) ( (PIORB) pIORB);
      return;
   }

   if (pIORB->UnitHandle >= NumCDROMDrives)
   {
      pIORB->Status = IORB_DONE + IORB_ERROR;
      pIORB->ErrorCode = IOERR_UNIT_NOT_ALLOCATED;
      if (pIORB->RequestControl & IORB_ASYNC_POST)
         (pIORB->NotifyAddress) ( (PIORB) pIORB);
      return;
   }

   /* Replace unit handle for filter with unit handle for the ADD */

   pUnitCB = &UnitCBTable[pIORB->UnitHandle];
   pIORB->UnitHandle = pUnitCB->ADDUnitHandle;

   if ( ( (USHORT) pRoutine = FilterRequest (pIORB)) != 0)
   {
      pFilter_workspace = (PIORB_FLTWORK) ((PIORB_CDB)pIORB)->filter_workspace;

      pFilter_workspace->CDM_NotifyAddress = pIORB->NotifyAddress;
      pFilter_workspace->pUnitCB = pUnitCB;

      action_code = (pRoutine) ( (PIORB_CDB) pIORB);
      ProcessNextState ( (PIORB_CDB) pIORB, action_code);
      return;
   }
   else            /* Call the ADD for any requests which aren't filtered.    */
   {
      (pUnitCB->AdapterDriverEP) (pIORB);
      return;
   }
}

/****************************************************************************
 *
 * FUNCTION NAME = FilterRequest
 *
 * DESCRIPTION   = See if this request should be filtered
 *
 *                 FilterRequest (PIORB_CDB pIORB)
 *
 * INPUT         = pIORB      - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT FilterRequest (pIORB)

PIORB pIORB;
{
   USHORT (NEAR *SCSI_Group0_Table[])() =
   {
       { 0                          },      /*  0x00 - Test Unit Ready        */
       { 0                          },      /*  0x01 - Rezero Unit            */
       { 0                          },      /*  0x02 -                        */
       { 0                          },      /*  0x03 - Request Sense          */
       { 0                          },      /*  0x04 -                        */
       { 0                          },      /*  0x05 -                        */
       { 0                          },      /*  0x06 -                        */
       { 0                          },      /*  0x07 -                        */
       { Filter_Read_6              },      /*  0x08 - Read (6)               */
       { 0                          },      /*  0x09 -                        */
       { 0                          },      /*  0x0A - Write (6)              */
       { Filter_Seek_6              },      /*  0x0B - Seek (6)               */
       { 0                          },      /*  0x0C -                        */
       { 0                          },      /*  0x0D -                        */
       { 0                          },      /*  0x0E -                        */
       { 0                          },      /*  0x0F -                        */
       { 0                          },      /*  0x10 -                        */
       { 0                          },      /*  0x11 -                        */
       { 0                          },      /*  0x12 -  Inquiry               */
       { 0                          },      /*  0x13 -                        */
       { 0                          },      /*  0x14 -                        */
       { Filter_ModeSelect          },      /*  0x15 -  Mode Select (6)       */
       { 0                          },      /*  0x16 -  Reserve               */
       { 0                          },      /*  0x17 -  Release               */
       { 0                          },      /*  0x18 -                        */
       { 0                          },      /*  0x19 -                        */
       { 0                          },      /*  0x1A -  Mode Sense            */
       { Filter_StartStopUnit       },      /*  0x1B -  Start/Stop Unit       */
       { 0                          },      /*  0x1C -  Receive Diagnostic    */
       { 0                          },      /*  0x1D -  Send Diagnostic       */
       { Filter_PreventAllowRemoval },      /*  0x1E -  Prevent/Allow Removal */
       { 0                          },      /*  0x1F -                        */
   };

   USHORT (NEAR *SCSI_Group1_Table[])() =
   {
       { 0                          },      /*  0x20 -                        */
       { 0                          },      /*  0x21 -                        */
       { 0                          },      /*  0x22 -                        */
       { 0                          },      /*  0x23 -                        */
       { 0                          },      /*  0x24 -                        */
       { 0                          },      /*  0x25 - Read Capacity          */
       { 0                          },      /*  0x26 -                        */
       { 0                          },      /*  0x27 -                        */
       { 0                          },      /*  0x28 - Read (10)              */
       { 0                          },      /*  0x29 -                        */
       { 0                          },      /*  0x2A - Write (10)             */
       { Filter_Seek_10             },      /*  0x2B - Seek (10)              */
       { 0                          },      /*  0x2C -                        */
       { 0                          },      /*  0x2D -                        */
       { 0                          },      /*  0x2E - Write & Verify (10)    */
       { 0                          },      /*  0x2F - Verify (10)            */
   };


   USHORT (NEAR *SCSI_Group2_Table[])() =
   {
       { 0                          },      /*  0x40 -                        */
       { 0                          },      /*  0x41 -                        */
       { Filter_ReadSubChannel      },      /*  0x42 -  Read sub-channel      */
       { Filter_ReadTOC             },      /*  0x43 -  Read TOC              */
       { Filter_ReadHeader          },      /*  0x44 -  Read Header           */
       { 0                          },      /*  0x45 -  Play Audio (10)       */
       { 0                          },      /*  0x46 -                        */
       { Filter_PlayAudio_MSF       },      /*  0x47 -  Play Audio MSF        */
       { 0                          },      /*  0x48 -  Play Audio Track/Index*/
       { 0                          },      /*  0x49 -  Play Audio Track Rel. */
       { 0                          },      /*  0x4A -                        */
       { Filter_Pause_Resume        },      /*  0x4B -  Pause/Resume          */
       { 0                          },      /*  0x4C -                        */
       { 0                          },      /*  0x4D -                        */
       { 0                          },      /*  0x4E -                        */
       { 0                          },      /*  0x4F -                        */
   };


/* USHORT (NEAR *SCSI_Group5_Table[])() =
** {
**     { Filter_PlayAudio_12        },          0xA5 -  Play Audio (12)
**     { Filter_CmdError            },          0xA6 -
**     { Filter_CmdError            },          0xA7 -
**     { Filter_Read_12             },          0xA8 -  Read (12)
**     { Filter_PlayAudio_Track_12  },          0xA9 -  Play Audio Track (12)
** };
*/

   UCHAR command;
   USHORT (NEAR *pRoutine)();
   struct SCSI_command FAR * pCDB;

   pRoutine = 0;

   if (pIORB->CommandCode == IOCC_ADAPTER_PASSTHRU &&
       pIORB->CommandModifier == IOCM_EXECUTE_CDB)
   {
      pCDB = (struct SCSI_command FAR *)
             ((PIORB_ADAPTER_PASSTHRU)pIORB)->pControllerCmd;

      command = pCDB->byte_0;

      if (command >= 0 && command <= 0x1F)
         pRoutine =  SCSI_Group0_Table[command];
      else
         if (command >= 0x20 && command <= 0x2F)
            pRoutine =  SCSI_Group1_Table[command-0x20];
         else
            if (command >= 0x40 && command <= 0x4F)
               pRoutine =  SCSI_Group2_Table[command-0x40];
/*          else
**             if (command >= 0xA5 && command <= 0xA9)
**                pRoutine = SCSI_Group5_Table[command-0xA5];
*/
            else
               pRoutine = 0;

   }
   return((USHORT)pRoutine);
}


/****************************************************************************
 *
 * FUNCTION NAME = Filter_NotifyDoneIORB
 *
 * DESCRIPTION   = Filter notification routine
 *
 *                 Filter_NotifyDoneIORB (PIORB_CDB pIORB)
 *
 * INPUT         = pIORB     - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID _loadds FAR Filter_NotifyDoneIORB (pIORB)

PIORB_CDB pIORB;

{
   USHORT action_code;
   PIORB_FLTWORK pFilter_workspace;

   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;

   if ( (pIORB->apt.iorbh.Status & IORB_ERROR) &&
        ( !(pIORB->apt.iorbh.Status & IORB_RECOV_ERROR) ) &&
        ( !(pFilter_workspace->flags & FWF_SKIP_ERROR_CHECK) ) )
   {
      pFilter_workspace->flags = 0;
      action_code = NOTIFY_CDM;
   }
   else
   {
      pFilter_workspace->flags = 0;
      action_code = (pFilter_workspace->completion_address) (pIORB);
   }
   ProcessNextState (pIORB, action_code);
   return;
}

/****************************************************************************
 *
 * FUNCTION NAME = ProcessNextState
 *
 * DESCRIPTION   = Process next state of the request
 *
 *                 ProcessNextState (PIORB_CDB pIORB)
 *
 * INPUT         = pIORB    - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID ProcessNextState (pIORB, action_code)

PIORB_CDB  pIORB;
USHORT action_code;
{

   NPUNITCB pUnitCB;
   PIORB_FLTWORK pFilter_workspace;

   pFilter_workspace = (PIORB_FLTWORK) pIORB->filter_workspace;

   pUnitCB = pFilter_workspace->pUnitCB;

   switch (action_code)
   {
      case CALL_ADD_AND_RET:
         pIORB->apt.iorbh.Status = 0;
         pIORB->apt.iorbh.ErrorCode = 0;
         (pUnitCB->AdapterDriverEP) ((PIORB)pIORB);
         break;

      case CALL_ADD_AND_NOTIFY_FILTER:
         (PVOID) pIORB->apt.iorbh.NotifyAddress=(PVOID) Filter_NotifyDoneIORB;
         pIORB->apt.iorbh.Status = 0;
         pIORB->apt.iorbh.ErrorCode = 0;
         (pUnitCB->AdapterDriverEP) ((PIORB)pIORB);
         break;

      case CALL_ADD_AND_NOTIFY_CDM:
         pIORB->apt.iorbh.NotifyAddress = pFilter_workspace->CDM_NotifyAddress;
         pIORB->apt.iorbh.Status = 0;
         pIORB->apt.iorbh.ErrorCode = 0;
         (pUnitCB->AdapterDriverEP) ((PIORB)pIORB);
         break;

      case NOTIFY_CDM:
          pIORB->apt.iorbh.NotifyAddress = pFilter_workspace->CDM_NotifyAddress;
          pIORB->apt.iorbh.Status |= IORB_DONE;
          (pIORB->apt.iorbh.NotifyAddress) ( (PIORB) pIORB);
          break;

      case NOTIFY_CDM_WITH_ERROR:
         pIORB->apt.iorbh.Status = IORB_DONE + IORB_ERROR;
         pIORB->apt.iorbh.ErrorCode = IOERR_CMD_NOT_SUPPORTED;
         pIORB->apt.iorbh.NotifyAddress = pFilter_workspace->CDM_NotifyAddress;
         (pIORB->apt.iorbh.NotifyAddress) ( (PIORB) pIORB);
         break;
    }
}

