/*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.                                */
/*                                                                           */
/*****************************************************************************/
/*static char *SCCSID = "src/dev/dasd/os2scsi/scinit.c, scsy, ddk_subset, b_bdd.032 93/03/19";*/
/**************************************************************************
 *
 * SOURCE FILE NAME = SCINIT.C
 *
 * DESCRIPTIVE NAME = OS2SCSI.DMD - OS/2 SCSI.SYS Emulation
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : Initialization routines
 *
 *
 *
*/

#define INCL_NOBASEAPI
#define INCL_NOPMAPI
#include "os2.h"
#include "strat2.h"
#include "reqpkt.h"
#include "devclass.h"
#include "dhcalls.h"
#include "scb.h"
#include "scsi.h"
#include "iorb.h"
#include "scscsi.h"
#include "scgen.h"
#include "scproto.h"



extern    UNITCB         UnitCB[1];            /* UnitCB allocated here       */
extern    PFN            Device_Help;          /* far ptr to devhelp function */
extern    USHORT         NumDrivers;           /* num of adapter drivers      */
extern    USHORT         NumUnitCBs;           /* num of unit control blocks  */
extern    PVOID          pDataSeg;             /* Our data segment pointer    */
extern    ULONG          plDataSeg;            /* Our data segment pointer    */
extern    UCHAR          Pool[];

#define   ERR_FNCALL     ((USHORT) 0xFFFF)     /* Indicates error in fn call. */

/********************** START OF SPECIFICATIONS *****************************
*                                                                           *
* SUBROUTINE NAME:  DriveInit                                               *
*                                                                           *
* DESCRIPTIVE NAME: Device Driver Initialize routine                        *
*                                                                           *
* FUNCTION:  This routine sets up unit control block and sets output        *
*            information required in request packet.                        *
*                                                                           *
* ENTRY POINT:      DriveInit                                               *
*                                                                           *
* LINKAGE:          Call Near                                               *
*                                                                           *
* INPUT:            Pointer to Init Reuqest Packet                          *
*                                                                           *
* EXIT-NORMAL:      Status code in request packet                           *
*                                                                           *
* EXIT-ERROR:       Status code in request packet                           *
*                                                                           *
*********************** END OF SPECIFICATIONS *******************************/

USHORT far f_DriveInit(pRP)
PRPINITIN  pRP;
{
  USHORT     rc;
  NPBYTE     pNextFreeCB;                 /* ptr to next free control blk     */
  PRPINITOUT pRPO = (PRPINITOUT) pRP;     /* Output for Init RP               */


  Device_Help = pRP->DevHlpEP;            /* Save ptr to devhelp function     */
  pDataSeg = (PVOID) &pDataSeg;           /* Set up pointer to data segment   */
  OFFSETOF(pDataSeg) = 0;

  rc = DevHelp_VirtToLin((USHORT) (SELECTOROF(pDataSeg)),
                         (ULONG) (OFFSETOF(pDataSeg)),
                         (PLIN) &plDataSeg);  /* Save lin addr of data seg    */


  NumUnitCBs = Build_UnitCBs();           /* Build unit control blocks        */
  if ((NumUnitCBs!=0) && (NumUnitCBs!=ERR_FNCALL))
  {                                       /* If there's units to control.     */

     pRPO->Unit     = 0;
     pRPO->CodeEnd  = (USHORT)f_DriveInit;/* Set length of code segment       */

     pRPO->DataEnd  = SetAdditionalData();
     pRPO->BPBArray = 0;                  /* Set address of BPB ptr array     */

     return(STDON);                       /* Set status                       */
  }
  else                                    /* no media or Init failure         */
  {
     pRPO->Unit     = 0;                  /* Set zero for the number of unit  */
     pRPO->CodeEnd  = 0;                  /* Set length of code segment       */
     pRPO->DataEnd  = 0;                  /* Set length of data segment       */
     pRPO->BPBArray = 0;                  /* Set address of BPB ptr array     */

     if (NumUnitCBs == 0)                 /* Quiet fail if no units           */
        return( 0x8115 /*ERROR_I24_QUIET_INIT_FAIL*/ );
     else
        return(STDON + STERR);            /* Noisy fail on program exception. */
  }
}


/********************** START OF SPECIFICATIONS *****************************
*                                                                           *
* SUBROUTINE NAME:  Build_UnitCBs                                           *
*                                                                           *
* DESCRIPTIVE NAME: Build Unit Control Blocks  (UnitCBs)                    *
*                                                                           *
* FUNCTION:  This routine issues DevHelp comand to get each device driver's *
*            entry point and IORB device table request for each driver to   *
*            get information about the device.                              *
*            Unit Control Block are created by these information.           *
*                                                                           *
* ENTRY POINT:      Build_UnitCBs                                           *
*                                                                           *
* LINKAGE:          Call Near                                               *
*                                                                           *
* INPUT:                                                                    *
*                                                                           *
* EXIT-NORMAL:      UnitCBs will be filled up for each physical unit.       *
*                   NumUnitCBs = Number of UnitCBs built                    *
*                                                                           *
* EXIT-ERROR:       0                   => No units to support.             *
*                   ERR_FNCALL (0xFFFF) => DevHelp failure.                 *
*                                                                           *
*********************** END OF SPECIFICATIONS *******************************/

unsigned near Build_UnitCBs()

{
  struct DevClassTableStruc far *pDriverTable;  /*  ptr to registered ADD EPs */

  NPIORB                npIORB;          /* far ptr to IORB                   */
  NPIORB_CONFIGURATION  npIORBDT;        /* far ptr to IORB                   */

  NPADAPTERINFO         npAdapterInfo;   /* near ptr to AdapterInfo           */

  void                  (far *DriverEP)(); /* Driver entry point              */

  NPINITDATA            npInitData;      /* Pointer to init data              */

  NPUCB                 npUCB;

  NPQELE                npQEle;

  USHORT                rc;
  USHORT                iAdapter;
  USHORT                iDriver;
  USHORT                UnitIndex;
  USHORT                iUnit = 0;
  USHORT                i;

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

  /*--------------------------------------*/
  /* Position INIT DATA after UNITCB pool */
  /*--------------------------------------*/

  npInitData = (NPINITDATA)((NPBYTE)Pool + (sizeof(UNITCB) * MAX_SCSI_DEVICES));

  npUCB      = UnitCB;

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

  if (!rc)
  {
     /*----------------------------------------------------*/
     /* For each .ADD registered in the DEVICE CLASS TABLE */
     /*----------------------------------------------------*/

     NumDrivers = pDriverTable->DCCount;
     for (iDriver= 0; iDriver < NumDrivers; iDriver++)
     {
        npIORBDT = (NPIORB_CONFIGURATION)(npInitData->ScratchIORB);
        npIORB   = (NPIORB) npIORBDT;
        CLEAR_IORB_BUFF;

        npIORB->Length                 = sizeof(IORB_CONFIGURATION);
        npIORB->CommandCode            = IOCC_CONFIGURATION;
        npIORB->CommandModifier        = IOCM_GET_DEVICE_TABLE;

        npIORBDT->pDeviceTable         = (PDEVICETABLE)(npInitData->ScratchBuffer);
        npIORBDT->DeviceTableLen       = sizeof(npInitData->ScratchBuffer);

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

        (*DriverEP)((PIORB_CONFIGURATION)npIORB);

        if (npIORB->Status & IORB_ERROR)
          continue;

        /*----------------------------------------*/
        /* For each adapter supported by this ADD */
        /*----------------------------------------*/

        for (iAdapter = 0;
             iAdapter < npIORBDT->pDeviceTable->TotalAdapters;
             iAdapter++                                       )
        {
           npAdapterInfo = npIORBDT->pDeviceTable->pAdapter[iAdapter];


           /*------------------------------*/
           /* For each Unit on the adapter */
           /*------------------------------*/

           for (UnitIndex = 0;
                UnitIndex < npAdapterInfo->AdapterUnits;
                UnitIndex++                              )
           {
              if (iUnit > MAX_SCSI_DEVICES )
                continue;

              if (!(npAdapterInfo->UnitInfo[UnitIndex].UnitFlags & UF_NOSCSI_SUPT))
              {
                 npUCB->UnitInfo          = npAdapterInfo->UnitInfo[UnitIndex];
                 npUCB->AdapterDriverEP   = DriverEP;
                 npUCB->Timeout           = DEFAULT_TIMEOUT;
                 npUCB->Index             = iUnit;

                 if (npAdapterInfo->AdapterFlags & AF_IBM_SCB)
                    npUCB->IntUnitFlags    |= IUF_IBM_SCB;

                 npQEle = npUCB->TimeOutQFree = &npUCB->TimeOutQ[0];

                 for (i = 0; i < MAX_TIMEOUT_ENTRIES-1; i++, npQEle++ )
                 {
                    npQEle->Next = npQEle+1;
                 }

                 iUnit++;                /* Increment Index of UnitCB */
                 npUCB++;
              }

           }  /* end unit loop */
        }  /* end adapter loop */
     }  /* end driver loop */

                                         /* => just support MAX */
     return(iUnit);
  }
  else
     return(ERR_FNCALL);
}

