/*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 = "%w% %e%";*/
/**************************************************************************
 *
 * SOURCE FILE NAME = FL2FMT.C
 *
 * DESCRIPTIVE NAME = IBM2FLPY.ADD - Adapter Driver for ABIOS Diskette
 *
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : Routines to implement the format function.
 *
 *
 *
*/

#define INCL_NOBASEAPI
#define INCL_NOPMAPI
#include <os2.h>
#include <dhcalls.h>
#include <strat2.h>     /* needed to keep reqpkt.h happy */
#include <reqpkt.h>
#include <scb.h>        /* needed to keey abios.h happy */
#include <abios.h>
#include <iorb.h>
#include <addcalls.h>
#include "fl2def.h"
#include "fl2proto.h"
#include "fl2data.h"


/*****************************************************************************/
/*                                                                           */
/*   Routine     : Format                                                    */
/*                                                                           */
/*   Description : This routine issues a an ABIOS Set Media Type to          */
/*                 prepare for a Format operation.                           */
/*                                                                           */
/*****************************************************************************/

VOID NEAR Format()
{

   NPABRB_DSKT_SETMEDIATYPE pRB = (NPABRB_DSKT_SETMEDIATYPE)RequestBlock;
   PFORMAT_CMD_TRACK        pCmd;
   USHORT                   BlkSize;
   USHORT                   FormatGapLen;
   USHORT                   SectorSizeCode;


   /*---------------------------------------------------*/           /*@V82589*/
   /* Changes for Defect 82589                          */           /*@V82589*/
   /*                                                   */           /*@V82589*/
   /* 1.) Issue Set Media Type at FORMAT rather than    */           /*@V82589*/
   /*     when geometry is provided.                    */           /*@V82589*/
   /* 2.) Support FORMAT IORB which provides GAP Length */           /*@V82589*/
   /*     and BlockSize directly.                       */           /*@V82589*/
   /*---------------------------------------------------*/           /*@V82589*/

   pCmd = (PFORMAT_CMD_TRACK)((PIORB_FORMAT)pHeadIORB)->pFormatCmd;

   if ( pCmd->Flags & FF_FMTGAPLEN )
      {
         SectorSizeCode = BlkSizeToN(pCmd->BlockSize);
         FormatGapLen   = pCmd->FmtGapLength;

         if ( SectorSizeCode == -1 )
            {
               pHeadIORB->Status   |= IORB_ERROR;
               pHeadIORB->ErrorCode = IOERR_MEDIA_NOT_SUPPORTED;
               IORBDone();
               return;
            }
      }
   else
      {
         BlkSize        = Drive[pHeadIORB->UnitHandle].Geometry[MEDIA].BytesPerSector;
         SectorSizeCode = BlkSizeToN(BlkSize);
         FormatGapLen   = Drive[pHeadIORB->UnitHandle].FormatGap;
      }



   Drive[pHeadIORB->UnitHandle].SectorSizeCode = SectorSizeCode;


   pRB->abrbh.Function  = ABFC_DSKT_SET_MEDIA_TYPE;
   pRB->abrbh.Unit      = pHeadIORB->UnitHandle;
   pRB->abrbh.RC        = ABRC_START;
   pRB->SectorsPerTrack = pCmd->cTrackEntries;
   pRB->BlockSize       = SectorSizeCode;
   pRB->Reserved_1      = 0;
   pRB->cTracks         = Drive[pHeadIORB->UnitHandle].Geometry[MEDIA].TotalCylinders;
   pRB->FillByte        = Drive[pHeadIORB->UnitHandle].FillByte;
   pRB->FormatGap       = FormatGapLen;

   CompletionRoutine = Format2;
   Retry = 0;
   Stage = ABIOS_EP_START;
   NextStage();
}


/*****************************************************************************/
/*                                                                           */
/*   Routine     : Format2                                                   */
/*                                                                           */
/*   Description : If a verify phase is required this routine will issue     */
/*                 a Set Device Parameters if the current sector size        */
/*                 does not match the sector size the diskette is being      */
/*                 formatted to.                                             */
/*                                                                           */
/*****************************************************************************/

VOID FAR Format2()
{
   NPABRB_DSKT_SETDEVPARMS pRB = (NPABRB_DSKT_SETDEVPARMS) RequestBlock;
   PFORMAT_CMD_TRACK       pCmd;
   USHORT                  SectorSizeCode;
   USHORT                  BlkSize;

   if ( pRB->abrbh.RC != ABRC_COMPLETEOK )
      {
         pHeadIORB->ErrorCode = TranslateErrorCode( pRB->abrbh.RC );
         pHeadIORB->Status   |= IORB_ERROR;

         Drive[pHeadIORB->UnitHandle].Flags.UnknownMedia = TRUE;

         StartTimer( pHeadIORB->UnitHandle,
                     Drive[pHeadIORB->UnitHandle].MotorOffDelay ,TurnOffMotor );

         IORBDone();
         return;
      }

   /*---------------------------------------------------*/           /*@V82589*/
   /* Changes for Defect 82589                          */           /*@V82589*/
   /*                                                   */           /*@V82589*/
   /* 1.) Issue Set Device Parms is verify phase is     */           /*@V82589*/
   /*     required and the current sector size for      */           /*@V82589*/
   /*     the device does not match the specified by    */           /*@V82589*/
   /*     the IORB or current media geometry            */           /*@V82589*/
   /*---------------------------------------------------*/           /*@V82589*/

   pCmd = (PFORMAT_CMD_TRACK)((PIORB_FORMAT)pHeadIORB)->pFormatCmd;

   if ( !(pCmd->Flags & FF_VERIFY) )
      {
         pRB->abrbh.RC = ABRC_COMPLETEOK;
         Format3();
         return;
      }

   if ( pCmd->Flags & FF_FMTGAPLEN )
      {
         BlkSize = pCmd->BlockSize;
      }
   else
      {
         BlkSize = Drive[pHeadIORB->UnitHandle].Geometry[MEDIA].BytesPerSector;
      }

   SectorSizeCode = BlkSizeToN( BlkSize );

   if ( Drive[pHeadIORB->UnitHandle].SectorSizeCode != SectorSizeCode )
      {
         Drive[pHeadIORB->UnitHandle].SectorSizeCode = SectorSizeCode;

         pRB->abrbh.Function = ABFC_SET_DEVICE_PARMS;
         pRB->abrbh.Unit     = pHeadIORB->UnitHandle;
         pRB->abrbh.RC       = ABRC_START;
         pRB->BlockSize      = SectorSizeCode;
         pRB->ReadGap        = Drive[pHeadIORB->UnitHandle].ReadGap;
         pRB->DataLen        = Drive[pHeadIORB->UnitHandle].DataLen;

         CompletionRoutine   = Format3;
         Retry = 0;
         Stage = ABIOS_EP_START;
         NextStage();
      }
   else
      {
         pRB->abrbh.RC = ABRC_COMPLETEOK;
         Format3();
      }

}


/*****************************************************************************/
/*                                                                           */
/*   Routine     : Format3                                                   */
/*                                                                           */
/*   Description : This routine sets up the ABIOS request block to           */
/*                 do a format operation.                                    */
/*                                                                           */
/*****************************************************************************/

VOID FAR Format3()
{
   PIORB_FORMAT        pIORB  = (PIORB_FORMAT)pHeadIORB;
   NPABRB_DSKT_FMT     pRB    = (NPABRB_DSKT_FMT)RequestBlock;
   NPGEOMETRY          pGeometry;
   PFORMAT_CMD_TRACK   pCmd;
   union
      {
         CHS_ADDR CHS;
         ULONG    RBA;
      } Addr;

   if ( pRB->abrbh.RC != ABRC_COMPLETEOK )
      {
         pHeadIORB->ErrorCode = TranslateErrorCode( pRB->abrbh.RC );
         pHeadIORB->Status   |= IORB_ERROR;

         Drive[pHeadIORB->UnitHandle].Flags.UnknownMedia = TRUE;

         StartTimer( pHeadIORB->UnitHandle,
                     Drive[pHeadIORB->UnitHandle].MotorOffDelay ,TurnOffMotor );

         IORBDone();
         return;
      }

   pCmd      = (PFORMAT_CMD_TRACK)pIORB->pFormatCmd;
   pGeometry = &(Drive[pHeadIORB->UnitHandle].Geometry[MEDIA]);

   /* Transfer track table from the S/G List to the DMA buffer */
   XferData.Mode          = SGLIST_TO_BUFFER;
   XferData.cSGList       = pIORB->cSGList;
   XferData.pSGList       = pIORB->pSGList;
   XferData.pBuffer       = pDMABuffer;
   XferData.iSGList       = 0;
   XferData.SGOffset      = 0;
   XferData.numTotalBytes = pCmd->cTrackEntries * 4;
   if ( f_ADD_XferBuffData( &XferData ) )
      {
         pHeadIORB->Status   |= IORB_ERROR;
         pHeadIORB->ErrorCode = IOERR_CMD_SGLIST_BAD;
         IORBDone();
         return;
      }

   /* Calculate initial CHS */
   if ( pHeadIORB->RequestControl & IORB_CHS_ADDRESSING )
      Addr.RBA = pCmd->RBA;
   else if ( f_ADD_ConvRBAtoCHS( pCmd->RBA, pGeometry, (PCHS_ADDR)&Addr ) )
      {
         pHeadIORB->Status   |= IORB_ERROR;
         pHeadIORB->ErrorCode = IOERR_RBA_ADDRESSING_ERROR;
         IORBDone();
         return;
      }

   pRB->abrbh.Function = ABFC_DSKT_FORMAT;              /* DSKT */
   pRB->abrbh.Unit     = pHeadIORB->UnitHandle;
   pRB->ppFormatTable  = ppDMABuffer;
   pRB->Subfunction    = 0;
   pRB->Cylinder       = Addr.CHS.Cylinder;
   pRB->Head           = Addr.CHS.Head;

   NextFormatStep();
}


/*****************************************************************************/
/*                                                                           */
/*   Routine     : NextFormatStep                                            */
/*                                                                           */
/*   Description : This routine calls NextStage to do a format function.     */
/*                 If a verify is required after the format, then this       */
/*                 routine is called a second time to do the verify.         */
/*                                                                           */
/*****************************************************************************/

VOID NEAR NextFormatStep()
{
  NPABRB_DSKT_RWV pRB = (NPABRB_DSKT_RWV)RequestBlock;

   pRB->abrbh.RC   = ABRC_START;
   pRB->Reserved_1 = 0;           /* +10H reserved field           */
   pRB->Reserved_2 = 0L;          /* +16H and +18H reserved fields */
   pRB->Reserved_3 = 0;           /* +1EH reserved field           */

   CompletionRoutine = FormatComplete;
   Retry = 0;
   Stage = ABIOS_EP_START;
   NextStage();


   // Begin @V90657.
   // Patch for ABIOS DMA handling of formatting track with 128 byte sectors
   // removed because of unpredictable results on MCA machines.
   // End @V90657.
}


/*****************************************************************************/
/*                                                                           */
/*   Routine     : FormatComplete                                            */
/*                                                                           */
/*   Description : This routine is called when ABIOS completes the           */
/*                 format operation.  If a verify is requested then          */
/*                 NextFormatStep is called again to do the verify.          */
/*                                                                           */
/*****************************************************************************/

VOID FAR FormatComplete()
{
   PIORB_FORMAT pIORB  = (PIORB_FORMAT)pHeadIORB;
   NPABRB_DSKT_RWV pRB = (NPABRB_DSKT_RWV)RequestBlock;
   PFORMAT_CMD_TRACK pCmd;

   pCmd = (PFORMAT_CMD_TRACK)pIORB->pFormatCmd;

   if ( pRB->abrbh.RC == ABRC_COMPLETEOK )
      {
         if ( pRB->abrbh.Function == ABFC_DSKT_FORMAT )   /* DSKT */
            {
               /* If verify is requested */
               if ( pCmd->Flags & FF_VERIFY )
                  {
                     /* Setup the ABIOS request block for verify */
                     pRB->abrbh.Function = ABFC_DSKT_VERIFY;
                     pRB->cSectors       = SectorCnt
                                         = pCmd->cTrackEntries;
                     pRB->Sector         = 1; /* Start at first sector */
                     NextFormatStep();
                     return;
                  }
            }
      }
   else
      {
         pHeadIORB->ErrorCode = TranslateErrorCode( pRB->abrbh.RC );
         pHeadIORB->Status   |= IORB_ERROR;
      }

   if ( pHeadIORB->ErrorCode == IOERR_MEDIA_CHANGED ||
        pHeadIORB->ErrorCode == IOERR_MEDIA_NOT_PRESENT )
      Drive[pHeadIORB->UnitHandle].Flags.UnknownMedia = TRUE;

   /*----------------------------------------------*/               /*@V106310*/
   /* Reset MediaNotFormatted on successful format */               /*@V106310*/
   /* of Cyl/Head 0,0                              */               /*@V106310*/
   /*----------------------------------------------*/               /*@V106310*/
   if ( !(pHeadIORB->Status & IORB_ERROR) )                         /*@V106310*/
   {                                                                /*@V106310*/
     if ( !pRB->Cylinder && !pRB->Head )                            /*@V106310*/
     {                                                              /*@V106310*/
       Drive[pHeadIORB->UnitHandle].Flags.MediaNotFormatted = FALSE;/*@V106310*/
     }                                                              /*@V106310*/
   }                                                                /*@V106310*/

   StartTimer( pHeadIORB->UnitHandle,
               Drive[pHeadIORB->UnitHandle].MotorOffDelay ,TurnOffMotor );

   IORBDone();
}
