/*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.      */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = OPINIT.C
 *
 * DESCRIPTIVE NAME = Initialization routines for Optical Device Manager
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include "oph.h"

VOID   NEAR Build_UnitCBs (void);
VOID   BuildIORB_UnitControl(USHORT, USHORT);
VOID   NEAR InitCBPool (void);
VOID   NEAR GetInitParms (PRPINITIN);
VOID   NEAR GetProductID (NPUNITCB);
VOID   NEAR init_submit_cdb (NPUNITCB, NPIORB_CDB);
void   NEAR RegisterWithRM(UCHAR FirstDrive, UCHAR NumDrives);

typedef struct InfoSegGDT FAR *PInfoSegGDT;
#define MSG_REPLACEMENT_STRING 1178


struct vendor_id_entry vendor_id_table [] =
{
          "IBM     ",  IBM,
          "MaxOptix",  MAXTOR,
          "MELCO   ",  MELCO,
          "RICOH   ",  RICOH,
          "SONY    ",  SONY,
          "PINNACLE",  PINNACLE,
          "OTHER   ",  OTHER
};

struct product_id_entry product_id_table [] =
{
   { "MD3125A", ERIMO1},
   { "MD3125B", ERIMOPRIME},
   { "MTA-3127", TOPCAT},

};

char    NeedsModeSelectProductId [] = "MD3125";

/* Drive capabilities table */

struct drive_caps_entry drive_caps_table [] =
{
   {ERIMO1,  0},
};


#define VENDOR_ID_COUNT sizeof(vendor_id_table) /         \
                         sizeof(struct vendor_id_entry)

#define PRODUCT_ID_COUNT sizeof(product_id_table) /       \
                         sizeof(struct product_id_entry)

#define DRIVE_CAPS_COUNT sizeof(drive_caps_table) /       \
                         sizeof(struct drive_caps_entry)

/*
** Init data allocated at the end of the data segment.
*/

USHORT          InitData=0;

UCHAR           InitTimeIORB[sizeof(IORB_CDB)]={0};

#define MAX_DT_ADAPTERS  8
#define MAX_DT_UNITS     56
#define MAX_DT_SIZE (sizeof(DEVICETABLE) + ((MAX_DT_ADAPTERS-1) * 2) +        \
              (MAX_DT_ADAPTERS * (sizeof(ADAPTERINFO)-sizeof(UNITINFO))) +    \
              (MAX_DT_UNITS * sizeof(UNITINFO))  )

UCHAR           ScratchBuffer2[MAX_DT_SIZE]={0};       /*Scratch buffer */

USHORT          ReserveDriveLetters = 0;


static UCHAR HeaderIDMsg[] =                                    \
"\n\r"                                                          \
"IBM OS/2 OPTICAL.DMD (960509)";


static UCHAR ProductIDMsg[] =                                   \
"                                ";

MSGTABLE  HeaderMsgParm = { MSG_REPLACEMENT_STRING,
                            1,
                            HeaderIDMsg,
                          };


MSGTABLE  ProductIDMsgParm = { MSG_REPLACEMENT_STRING,
                               1,
                               ProductIDMsg,
                              };

/****************************************************************************
 *
 * FUNCTION NAME = InitializeDevice
 *
 * DESCRIPTION   = initialize the target device
 *
 *                 VOID InitializeDevice(NPUNITCB pUnitCB)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *
 * OUTPUT        = USHORT          - error status word
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT InitializeDevice (pUnitCB,subfunc)

NPUNITCB pUnitCB;
NPSUB subfunc;
{
    USHORT        i, IORBError=0;                                      /*V@91985*/
    NPIORB_CDB    pIORB;
    struct ModeSelectParmList NEAR *pDescriptor;
    union ADD_ReadDiskInfo_Data NEAR *pCDBData;

    /*
    ** Issue Test Unit Ready to clear any pending check conditions. Retry
    ** up to 5 times, if still check condition, then return device error
    */
    for (i = 0; i <= 4; i++)
      {
      IORBError=0;      // reset error code to 0
      BuildCDB_TestUnitReady (pUnitCB, (NPIORB_CDB FAR *) &pIORB);
      (*subfunc)(pUnitCB, pIORB);

      if(pIORB->apt.iorbh.Status & IORB_ERROR)
        {

        IORBError = MapSenseData ((NPIORB)pIORB);                     /*V@91985*/

        if ( (IORBError == STDON + STERR + ERROR_I24_NOT_READY) ||    /*V@91985*/
           (IORBError == STDON + STERR + ERROR_I24_SECTOR_NOT_FOUND) )
          break;                                                    /*V@91985*/
        } /* endif */
//    else
//      {
//      break;
//      } /* endelse */

      }

    if (i > 4 && IORBError)
       return (STDON + STERR + ERROR_I24_GEN_FAILURE);

    BuildCDB_ReadCapacity(pUnitCB, (NPIORB_CDB FAR *) &pIORB);
    (*subfunc)(pUnitCB, pIORB);

    /*
    ** Then issue a Request Sense Command
    */
    BuildCDB_RequestSense ( pUnitCB, (NPIORB_CDB FAR *) &pIORB);
    (*subfunc)(pUnitCB, pIORB);

    /*
    ** Get the inquiry data
    */
    BuildCDB_Inquiry(pUnitCB, (NPIORB_CDB FAR *) &pIORB);
    (*subfunc)(pUnitCB, pIORB);

    pUnitCB->DeviceInfo.Installed=TRUE;

    /*
    ** Get the vendor and product id code from the inquiry data
    */

    GetProductID (pUnitCB);

   return (STDON);

}

/****************************************************************************
 *
 * FUNCTION NAME = Strncmp
 *
 * DESCRIPTION   = string compare
 *
 *                 Strncmp (NPBYTE string1, NPBYTE string2, USHORT length)
 *
 *                 This is like the standard C function, except it is boolean
 *
 * INPUT         = string1         - string 1
 *                 string2         - string 2
 *                 length          - length of string
 *
 * OUTPUT        = BOOLEAN, 0 if equal, 1 if not equal
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL Strncmp ( string1, string2, length )

UCHAR   *string1, *string2;
USHORT  length;

{
    BOOL    equal = FALSE;

    while ( length-- > 0 )
    {
        if ( *string1++ != *string2++ )
        {
            equal = TRUE;
            break;
        }
    }
    return ( equal );
}


/****************************************************************************
 *
 * FUNCTION NAME = GetProductID
 *
 * DESCRIPTION   = get product id code
 *
 *                 VOID   GetProductID  (NPUNITCB pUnitCB)
 *
 * INPUT         = pUnitCB          - pointer to UnitCB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID GetProductID (pUnitCB)

NPUNITCB pUnitCB;
{

   USHORT n, rc, product_id_length;

   pUnitCB->DeviceInfo.vendor_id_code = 0;
   pUnitCB->DeviceInfo.product_id_code = 0;
   for ( n = 0; n < VENDOR_ID_COUNT; ++n)
     {
     if(!Strncmp(pUnitCB->InquiryData.vendor_id,
                  vendor_id_table[n].vendor_id_string,
                  8 ))
       {
       pUnitCB->DeviceInfo.vendor_id_code =
                             vendor_id_table[n].vendor_id_code;
       break;
       }
     }
   switch(pUnitCB->DeviceInfo.vendor_id_code)
     {
     case IBM:
       pUnitCB->DeviceInfo.FormatTime=ERIMO_TOTAL_FORMATTING_TIME;
       // if NOT one of the Erimo family drives
       // make it NOT IBM vendor type
       pUnitCB->DeviceInfo.lock_status_supported = TRUE;
//     if(Strncmp ( pUnitCB->InquiryData.product_id, NeedsModeSelectProductId, strlen(NeedsModeSelectProductId) ) )
//       {
//       pUnitCB->DeviceInfo.vendor_id_code=OTHER;
//       }
       break;
     case PINNACLE:
       pUnitCB->DeviceInfo.FormatTime=ERIMO_TOTAL_FORMATTING_TIME;
       break;
     default:
       pUnitCB->DeviceInfo.FormatTime=TOTAL_FORMATTING_TIME;
       break;
     } /* endswitch */

   pUnitCB->DeviceInfo.BuildBPBOffMedium = TRUE;

   pUnitCB->CurrentBPB = DefaultBPB;

   product_id_length = 7;

   for ( n = 0; n < PRODUCT_ID_COUNT; ++n)
     {
     if(!Strncmp(pUnitCB->InquiryData.product_id,
                  product_id_table[n].product_id_string,
                  product_id_length ))
       {
       pUnitCB->DeviceInfo.product_id_code =
                           product_id_table[n].product_id_code;


       if(pUnitCB->DeviceInfo.vendor_id_code==IBM)
         {
         if ( pUnitCB->DeviceInfo.product_id_code == ERIMO1 )
           {
           pUnitCB->CurrentBPB = ErimoDefaultBPB;
           pUnitCB->DeviceInfo.lock_status_supported = FALSE;
           }
         if (!Strncmp ( pUnitCB->InquiryData.product_id, NeedsModeSelectProductId, strlen(NeedsModeSelectProductId) ) )
           {
           pUnitCB->DeviceInfo.needs_mode_select = TRUE;
           }
         } /* endif */
       break;
       }
     }

}

/****************************************************************************
 *
 * FUNCTION NAME = DriveInit
 *
 * DESCRIPTION   = Initialization for OPTICAL.DMD
 *
 * INPUT         = pRP           - pointer to Request Packet
 *                 pUnitCB       - pointer to Unit Control Block
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT near DriveInit(pRP, pUnitCB)

PRPINITIN  pRP;
NPUNITCB   pUnitCB;
{
  USHORT     rc, i, DriveCount;
  PRPINITOUT pRPO = (PRPINITOUT) pRP;   /* Output for Init RP             */

  extern CMDFUNC near functable[];


  /*
  ** Initialize various variables
  */
  CDFlags |= CDF_INIT_TIME;             /* Turn on init time flag         */

  Device_Help = pRP->DevHlpEP;          /* Save ptr to devhelp function   */
  FirstDriveNumber = pRP->DriveNum;     /* First Drive Number             */

  pDataSeg = (PVOID) &pDataSeg;         /* Set up pointer to data segment */
  OFFSETOF(pDataSeg) = 0;

  /*
  ** Get the init parms specified on the BASEDEV= command line
  */
  GetInitParms(pRP);

  /*
  ** Save away the physical and linear addresses of our data segment
  */
  rc = DevHelp_VirtToPhys(pDataSeg, (PULONG) &ppDataSeg);

  rc = DevHelp_VirtToLin((USHORT) (SELECTOROF(pDataSeg)),
                         (ULONG) (OFFSETOF(pDataSeg)),
                         (PLIN) &plDataSeg);

  /*
  ** Put init data at end of _DATA since it'll get discarded later
  */
  PoolSize = INIT_POOL_SIZE;

  FreePoolSpace = INIT_POOL_SIZE;

  Build_UnitCBs();                   /* Build unit control blocks      */

  if (NumDrives == 0)                   /* If no drives, then deinstall   */
  {
     if (ReserveDriveLetters == 0)
     {
        pRPO->Unit = 0;
        pRPO->CodeEnd = 0;
        pRPO->DataEnd = 0;
        ZeroFSGS();
        if (CDFlags & CDF_QUIET)
           return(STDON + STERR + ERROR_I24_QUIET_INIT_FAIL);
        else
           return(STDON + STERR + ERROR_I24_GEN_FAILURE);
     }
     else
     {
        UnitCB_Head = 0;


        pRP->Unit = (CHAR) ReserveDriveLetters;
        pRPO->BPBArray = (PVOID) InitBPBArray;
        for (i = 0; i < ReserveDriveLetters; i++)
           InitBPBArray[i] = &DefaultBPB;

        /*
        ** Return the end of the code and data segments
        */
        pRPO->CodeEnd = (USHORT) DriveInit;
        pRPO->DataEnd = (USHORT) FirstUnitCB;

        CodeBreakAddress = (USHORT) DriveInit;
        DataBreakAddress = (USHORT) FirstUnitCB;
     }
  }
  else                                  /* At least 1 Optical drive exists */
  {
     InitCBPool ();                     /* Initialize the Control Block pool */

     /*
     ** Set up the return parameters for the INIT packet.
     */
     if (ReserveDriveLetters > NumDrives)
        DriveCount = ReserveDriveLetters;
     else
        DriveCount = NumDrives;

     pRP->Unit = (CHAR) DriveCount;     /* Return number of logical drives */

     pRPO->BPBArray = (PVOID) InitBPBArray;

     for (i = 0; i < DriveCount; i++)
        InitBPBArray[i] = &DefaultBPB;

     /*
     ** Return the end of the code and data segments
     */
     pRPO->CodeEnd = (USHORT) DriveInit;
     pRPO->DataEnd = (USHORT) pNextFreeCB;

     CodeBreakAddress = (USHORT) DriveInit;
     DataBreakAddress = (USHORT) pNextFreeCB;

  }
  /*
  ** Dont allow another INIT command to come in
  */
  functable[CMDInit].Strat1Near = CmdErr;     /* Patch strat1 table to disable inits */
  functable[CMDInitBase].Strat1Near = CmdErr; /* Patch strat1 table to disable inits */
  CDFlags &= ~CDF_INIT_TIME;          /* Turn off init time flag             */
  CDFlags |= CDF_INIT_COMPLETE;       /* set init processing done            */  //SD@135221

  return(STDON);                      /* Done with init, so return           */

}


/****************************************************************************
 *
 * FUNCTION NAME = Build_UnitCBs
 *
 * DESCRIPTION   = Build Unit Control Blocks (UnitCBs)
 *
 *                 This routine issues the GetAdapterDeviceTable command
 *                 to each Adapter Device Driver and builds the unit control
 *                 blocks from each Adapter Device Table returned.  Each unit
 *                 control block (UnitCB) represents a physical device unit
 *                 which the device manager manages.
 *
 *                 VOID Build_UnitCS()
 *
 *                 NOTES: UnitCBs built for each Optical target.
 *                        NumDrives = Number of UnitCBs built
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

void Build_UnitCBs()

{
  USHORT                rc;
  NPUNITCB              pUnitCB;         /* Pointer to current UnitCB    */
  NPIORB_CONFIGURATION  pIORB;           /* ptr to IORB                  */
  DEVICETABLE           *pDeviceTable;   /* ptr to device table          */
  NPADAPTERINFO         pAdapterInfo;    /* near ptr to AdapterInfo      */
  USHORT                i, j, k, l,m;    /* Index pointers               */
  USHORT                FilterADDHandle; /* Filter Handle                */
  NPBYTE                pInquiryData;
  struct
  DevClassTableStruc far *pDriverTable;  /* ptr to registered ADD EPs    */
  VOID (FAR * DriverEP) ();              /* Driver entry point           */
  VOID (FAR * DriverEPF)();              /* Filter Driver entry point    */

  (NPUNITCB)pNextFreeCB = FirstUnitCB;   /* Next free is first unit CB   */
  UnitCB_Head = FirstUnitCB;             /* Init UnitCB head pointer     */
  pUnitCB = UnitCB_Head;                 /* Point to first UnitCB        */
  NumUnitCBs = 0;                        /* Init UnitCB count            */


  /*
  ** Get the adapter device tables for each adapter driver and create
  ** the unit control blocks (UnitCBs) from the returned tables.
  */

  rc = DevHelp_GetDOSVar((USHORT) DHGETDOSV_DEVICECLASSTABLE, 1,
                         (PPVOID) &pDriverTable);

  NumDrivers = pDriverTable->DCCount;

  pDeviceTable = (DEVICETABLE *) ScratchBuffer2;

  for (i = 0; i < NumDrivers; i++)
  {
     pIORB = (NPIORB_CONFIGURATION) InitTimeIORB;
     pIORB->iorbh.Length = sizeof(IORB_CONFIGURATION);
     pIORB->iorbh.CommandCode = IOCC_CONFIGURATION;
     pIORB->iorbh.CommandModifier = IOCM_GET_DEVICE_TABLE;
     pIORB->iorbh.Status = 0;
     pIORB->iorbh.ErrorCode = 0;
     pIORB->iorbh.RequestControl = IORB_ASYNC_POST;
     pIORB->iorbh.NotifyAddress = &InitPost;
     pIORB->pDeviceTable = (PVOID) pDeviceTable;
     pIORB->DeviceTableLen = sizeof(ScratchBuffer2);

     OFFSETOF(DriverEP) =  pDriverTable->DCTableEntries[i].DCOffset;
     SELECTOROF(DriverEP) = pDriverTable->DCTableEntries[i].DCSelector;

     f_ZeroCB((PBYTE)pDeviceTable, sizeof(ScratchBuffer2));

     (*DriverEP) ((PVOID)(pIORB));

     while ( !(pIORB->iorbh.Status & IORB_DONE) )  /* Wait till done */
     ;

     for (j = 0; j < pDeviceTable->TotalAdapters; j++)
     {
        pAdapterInfo =  pDeviceTable->pAdapter[j];

        for (k = 0; k < pAdapterInfo->AdapterUnits; k++)
        {
           /*
           ** Only allocate DISK type devices which are not defective
           ** and which dont suppress DASD manager support.
           */
           if ( (pAdapterInfo->UnitInfo[k].UnitType == UIB_TYPE_OPTICAL_MEMORY) &&
                ! (pAdapterInfo->UnitInfo[k].UnitFlags & UF_DEFECTIVE) )
           {
              /*
              ** Allocate the unit if it's not already allocated
              ** Wait until the request comes back from ADD.
              */

              BuildIORB_UnitControl (IOCM_ALLOCATE_UNIT,
                                     pAdapterInfo->UnitInfo[k].UnitHandle);

              FilterADDHandle = pAdapterInfo->UnitInfo[k].FilterADDHandle;

              if ( !FilterADDHandle )
              {
                 (*DriverEP) ((PVOID)(pIORB));
              }
              else
              {
                 OFFSETOF(DriverEPF) =
                     pDriverTable->DCTableEntries[FilterADDHandle-1].DCOffset;
                 SELECTOROF(DriverEPF) =
                     pDriverTable->DCTableEntries[FilterADDHandle-1].DCSelector;

                 (*DriverEPF) ((PVOID)(pIORB));
              }

              while ( !(pIORB->iorbh.Status & IORB_DONE) )  /* Wait till done */
              ;

              /*
              ** If allocation succeeded then add unit to unit tables
              */
              if ( !(pIORB->iorbh.Status & IORB_ERROR) )
              {

                 pUnitCB->UnitInfo = pAdapterInfo->UnitInfo[k];

                 /*
                 ** Save the callable entry point of the adapter driver. If
                 ** the unit is being filtered, use the entry point of the
                 ** filter driver.
                 */
                 if (FilterADDHandle == 0)
                     pUnitCB->AdapterDriverEP = DriverEP;
                 else
                 {
                    OFFSETOF(pUnitCB->AdapterDriverEP)   =
                                               OFFSETOF(DriverEPF);
                    SELECTOROF(pUnitCB->AdapterDriverEP) =
                                               SELECTOROF(DriverEPF);
                 }

                 /*
                 ** Set the bus interface type.
                 */
                 if ((pAdapterInfo->AdapterDevBus & 0x00FF) ==
                                                AI_DEVBUS_ST506)
                    pUnitCB->DeviceInfo.interface_type = INTERFACE_ATAPI;
                 else
                    pUnitCB->DeviceInfo.interface_type = INTERFACE_SCSI;

                 /*
                 ** Initialize device.  If failure then deallocate unit
                 */

                 if (InitializeDevice(pUnitCB,init_submit_cdb) & STERR)
                 {
                    BuildIORB_UnitControl (IOCM_DEALLOCATE_UNIT,
                                     pAdapterInfo->UnitInfo[k].UnitHandle);

                    (*pUnitCB->AdapterDriverEP) ((PVOID)(pIORB));

                    while ( !(pIORB->iorbh.Status & IORB_DONE) )
                    ;
                 }
                 else
                 {
                    pUnitCB->AdapterNumber = NumAdapters + j;
                    pUnitCB->MaxHWSGList = pAdapterInfo->MaxHWSGList;

                    if (pAdapterInfo->AdapterFlags & AF_HW_SCATGAT)
                       pUnitCB->Flags |= UCF_HW_SCATGAT;

                    if (pAdapterInfo->AdapterFlags & AF_16M)
                       pUnitCB->Flags |= UCF_16M;

                    if (pAdapterInfo->AdapterFlags & AF_CHS_ADDRESSING)
                       pUnitCB->Flags |= UCF_CHS_ADDRESSING;

                    /*
                    ** Display vendor, product id and revision code
                    ** if /V parm specified on command line.
                    */
                    if (CDFlags & CDF_VERBOSE)
                    {
                       if (NumUnitCBs == 0)
                          DevHelp_Save_Message( (NPBYTE) &HeaderMsgParm);

                       pInquiryData = &pUnitCB->InquiryData.vendor_id[0];

                       ProductIDMsg[0]=pUnitCB->UnitInfo.UnitSCSITargetID+0x30;

                       for (l = 0; l < 8; l++)
                          ProductIDMsg[l+2] = *(pInquiryData+l);

                       for (l = 8; l < 24; l++)
                          ProductIDMsg[l+3] = *(pInquiryData+l);

                       for (l = 24; l < 28; l++)
                          ProductIDMsg[l+4] = *(pInquiryData+l);

                       DevHelp_Save_Message( (NPBYTE) &ProductIDMsgParm);
                    }

                    /*
                    ** Increment drive count and get next one
                    */


                    pUnitCB->LogDriveNum = NumUnitCBs;
                    NumUnitCBs ++;
                    NumDrives++;
                    pUnitCB->pNextUnitCB = pUnitCB + 1;
                    pUnitCB++;

                 }
              }
           }
        }  /* end unit loop */
     }  /* end adapter loop */
     NumAdapters += pDeviceTable->TotalAdapters;
  }  /* end driver loop */

  (NPUNITCB) pNextFreeCB = pUnitCB;     /* Update next free control blk ptr */
  (pUnitCB-1)->pNextUnitCB = 0;
}



/****************************************************************************
 *
 * FUNCTION NAME = BuildIORB_UnitControl
 *
 * DESCRIPTION   = This routine build a unit control IORB.
 *
 *                 VOID Build_UnitControl(USHORT command_modifier,
 *                                                 USHORT unit_handle);
 *
 * INPUT         = command_modifier   - IORB command modifier code
 *                 unit_handle        - unit handle
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID BuildIORB_UnitControl (command_modifier, unit_handle)

USHORT     command_modifier;
USHORT     unit_handle;

{
   NPIORB_UNIT_CONTROL pIORB;

   pIORB = (NPIORB_UNIT_CONTROL) InitTimeIORB;

   pIORB->iorbh.Length = sizeof(IORB_UNIT_CONTROL);
   pIORB->iorbh.CommandCode = IOCC_UNIT_CONTROL;
   pIORB->iorbh.CommandModifier = command_modifier;
   pIORB->iorbh.Status = 0;
   pIORB->iorbh.ErrorCode = 0;
   pIORB->iorbh.UnitHandle = unit_handle;
   pIORB->iorbh.RequestControl = IORB_ASYNC_POST;
   pIORB->iorbh.NotifyAddress = &InitPost;
   pIORB->Flags = 0;

   pIORB->pUnitInfo = 0;
   pIORB->UnitInfoLen = 0;
}



/****************************************************************************
 *
 * FUNCTION NAME = init_submit_cdb
 *
 * DESCRIPTION   = init time submit cdb routine
 *
 *                 VOID init_submit_cdb (NPUNITCB pUnitCB, NPIORB_CDB pIORB)
 *
 * INPUT         = pUnitCB         - pointer to UnitCB
 *                 pIORB           - pointer to IORB
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID init_submit_cdb(pUnitCB, pIORB)

NPUNITCB pUnitCB;
NPIORB_CDB pIORB;
{

    /*
    **  If ATAPI command, change CDB command length to 12.
    */

    if ( (pUnitCB->DeviceInfo.interface_type == INTERFACE_ATAPI) &&
         (pIORB->apt.iorbh.CommandCode == IOCC_ADAPTER_PASSTHRU) )
    {
       pIORB->apt.ControllerCmdLen = ATAPI_CDB_LENGTH;
    }


    /*
    ** Submit CDB.  Wait till done.
    */

    pIORB->apt.iorbh.NotifyAddress = &InitPost;

    (*pUnitCB->AdapterDriverEP) ((PVOID) (pIORB));

    while ( !(pIORB->apt.iorbh.Status & IORB_DONE) )
       DevHelp_ProcBlock( (ULONG) pIORB, (ULONG) 200, WAIT_IS_INTERRUPTABLE );

}

/****************************************************************************
 *
 * FUNCTION NAME = InitPost
 *
 * DESCRIPTION   = Dummy notification callout for ADDs during init processing
 *
 *                 VOID FAR InitPost(PIORB pIORB)
 *
 * INPUT         = pIORB           - pointer to IORB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID FAR InitPost(pIORB)

PIORB pIORB;
{

}


/****************************************************************************
 *
 * FUNCTION NAME = InitCBPool
 *
 * DESCRIPTION   = Initialize the control block pool
 *
 *                 Initializes the control block pool which is used for IORB,
 *                 CWA and FTDB allocation.
 *
 *                 USHORT InitCBPool ()
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID InitCBPool ()
{
   NPUNITCB pUnitCB;
   NPBYTE   pCB;
   NPIORBH  pIORB;
   USHORT   NumCBs, CBSize, i;
   USHORT   NumIORBs = 0;

   /*
   ** Calculate the size of the Pool
   */

   CBSize = sizeof(IORB_CDB);

   /*
   ** Calculate the number of IORBs to allocate by summing the
   ** Queuing Counts in each UnitCB.
   */
   NumIORBs = NumDrives * MAX_IORBS_PER_DRIVE;
   if (NumIORBs > MAX_IORBS_PER_POOL)
      NumIORBs = MAX_IORBS_PER_POOL;

   NumCBs = NumIORBs;

   FreePoolSpace = (USHORT) &InitData - (USHORT) pNextFreeCB;

   /*
   **  Make sure Pool Size isnt greater than available space left in
   **  the data segment.
   */
   if ( ((ULONG)NumCBs * CBSize) < (ULONG)FreePoolSpace)
      PoolSize = NumCBs * CBSize;
   else
   {
      NumCBs = FreePoolSpace / CBSize;
      PoolSize = NumCBs * CBSize;
   }

   /*
   ** Initialize the Control Block Pool
   */

   CB_FreeList = pNextFreeCB;

   pCB = CB_FreeList;

   for (i = 0; i < NumCBs; i++)
   {

      ((NPIORBH) pCB)->pNxtIORB = (PIORBH) (pCB + CBSize);
      pCB += CBSize;
   }

   ((NPIORBH) (pCB - CBSize))->pNxtIORB = 0;    /* Zero terminate list */

   pNextFreeCB = pCB;


   /*
   ** Allocate one dedicated IORB to each Unit
   */

   pCB = CB_FreeList;

   for (pUnitCB = UnitCB_Head, i = 0; i < NumUnitCBs; i++, pUnitCB++)
   {
      pUnitCB->pDedicatedIORB = (NPIORBH) pCB;
      ((NPIORBH) pCB)->pNxtIORB = 0;
      pCB += CBSize;
   }

   CB_FreeList = pCB;          /* Free List now starts past dedicated IORBs */


}
/******************************************************************************
*
*   SUBROUTINE NAME:    Atoi
*
*   DESCRIPTIVE NAME:   ascii to integer
*
*   FUNCTION:   convert ascii to integer
*
*   NOTES:
*
*   ENTRY POINT:    Atoi
*       LINKAGE:    Call near
*
*   PARAMETERS:     string
*
*   RETURN-NORMAL:  number
*
*   RETURN-ERROR:   none
*
*   EFFECTS:
*
*   PUBLIC REFERENCES:
*       ROUTINES:
*       DATA:
*
*   PSEUDOCODE:
*
*       Convert the digits from right to left by subtracting '0',
*       multiplying by 10 exp position, and accumulating the value.
*
******************************************************************************/

USHORT Atoi  ( PUCHAR string)        /* convert alpha to int */
{
    USHORT  factor = 1;
    USHORT  number = 0;
    UCHAR   c;

    while ( c = *string ){                      /* find end of string */
        if ( c > '9'  ||  c < '0' )
            break;
        ++string;
    }
    while ( c = *--string ){
        if ( c > '9'  ||  c < '0' )
            break;
        number += ( c - '0' ) * factor;
        factor *= 10;
    }

    return ( number );
}

/****************************************************************************
 *
 * FUNCTION NAME = GetInitParms
 *
 * DESCRIPTION   = Get init parms from BASEDEV command line
 *
 *                 VOID GetInitParms (PRPINITIN pRP);
 *
 * INPUT         = pRP              - Pointer to init request packet
 *
 * OUTPUT        = VOID
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID GetInitParms (pRP)

PRPINITIN pRP;

{
   PSZ    pCmdString;
   PSZ    pCmdStringStart;
   USHORT i;
   UCHAR  CmdParm;
   BYTE   n;

   pCmdStringStart = pRP->InitArgs;

   if (pRP->rph.Cmd == CMDInitBase)
      OFFSETOF(pCmdStringStart)=((PDDD_PARM_LIST)pRP->InitArgs)->cmd_line_args;

   pCmdString = pCmdStringStart;

   /*
   ** Fold characters to upper case
   */
   for (i = 0; *pCmdString != 0 && i < 40; i++, pCmdString++)
   {
      if (*pCmdString >= 'a' &&  *pCmdString <= 'z')
         *pCmdString = *pCmdString - ('a' - 'A');
   }


   pCmdString = pCmdStringStart;

   for (i = 0; *pCmdString != 0 && i < 40; i++, pCmdString++)
   {
      if (*pCmdString == '/' || *pCmdString=='-')
      {
         pCmdString++;
         switch (*pCmdString)
         {
            case 'Q':
                CDFlags |= CDF_QUIET;              /* Turn on quiet flag */
                break;

            case 'V':
                CDFlags |= CDF_VERBOSE;            /* Turn on verbose flag */
                break;

            case 'A':
            case 'a':
                MinimumAllowedADCvalue = Atoi ( ++pCmdString );
                break;

            case 'D':
            case 'd':
                MaxAllowedDefectListSize = Atoi ( ++pCmdString );
                break;

            case 'L':
            case 'l':
                ForceLowLevelFormat = TRUE;
                break;

            case 'N':
            case 'n':
                NumDrives |= Atoi ( ++pCmdString );
                break;

            case 'T':
            case 't':
                LaserTimeoutValue = Atoi ( ++pCmdString );
                break;

             case 'U':
             case 'u':
                 Unconditional_Install = TRUE;
                 break;

            case 'R':
                pCmdString++;
                if( *pCmdString == 'b' )
                  {
                  n = Atoi (++pCmdString) << 8;
                  }

                if (n < 23)
                   ReserveDriveLetters = n;

                break;

         }
      }
   }
}

