home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cdrom.zip / DDK / BASE / SRC / DEV / DASD / CDROM / ATAPI / atapiism.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-10  |  50.2 KB  |  1,540 lines

  1. /* SCCSID = %W% %E% */
  2. /**************************************************************************
  3.  *
  4.  * SOURCE FILE NAME =     ATAPIISM.C
  5.  *
  6.  * DESCRIPTIVE NAME =     ATAPI Inner State Machine
  7.  *
  8.  *
  9.  * Copyright : COPYRIGHT IBM CORPORATION, 1991, 1992
  10.  *             LICENSED MATERIAL - PROGRAM PROPERTY OF IBM
  11.  *             REFER TO COPYRIGHT INSTRUCTION FORM#G120-2083
  12.  *             RESTRICTED MATERIALS OF IBM
  13.  *             IBM CONFIDENTIAL
  14.  *
  15.  * VERSION = 1.0
  16.  *
  17.  * DATE
  18.  *
  19.  * DESCRIPTION :
  20.  *
  21.  * Purpose:
  22.  *
  23.  *
  24.  *
  25.  *
  26.  *
  27.  * CHANGE ACTIVITY =
  28.  *   DATE      FLAG        APAR   CHANGE DESCRIPTION
  29.  *   --------  ----------  -----  --------------------------------------
  30.  *   08/22/94  V@93531     93531   1) Suspend/Resume logic passes IRQ handler
  31.  *                                 address. 2) DRQ polling is not valid while
  32.  *                                 BSY bit set.
  33.  *   04/05/96  @V151168            Merged warm dock/swap code.
  34.  *   05/24/96  @V155162            Thinkpad docking/swapping IDE update.
  35.  *   05/25/96  @V155162            Deleted int 3s on potential write commands
  36.  *   04/26/98  @V195083            Added Panasonic PD support.
  37.  ****************************************************************************/
  38. /*
  39.  * Edit History for Feature # 149178:
  40.  *
  41.  * Edit    Date    Comments
  42.  * ----- --------  -------------------------------------------------------------
  43.  * [001] 01-03-96  Added code to setup and complete Bus Master DMA transfers
  44.  *                 when UCBF_BM_DMA flag is set in UCB flags. Code to setup
  45.  *                 scatter/gather tables was copied from S506SM.C source. /jlh
  46.  *
  47.  * [002] 02-06-96  Remove BM IDE Active bit test from IR_COMPLETE case in
  48.  *                 InterruptState. For ATAPI CD-ROM drives this shouldn't be
  49.  *                 an error condition.  The actual xfer may be shorter than
  50.  *                 the programmed length. /mol
  51.  */
  52.  
  53. #define INCL_NOBASEAPI
  54. #define INCL_NOPMAPI
  55. #include "os2.h"
  56. #include "dos.h"
  57. #include "dskinit.h"
  58.  
  59. #include "iorb.h"
  60. #include "addcalls.h"
  61. #include "dhcalls.h"
  62. #include "apmcalls.h"
  63.  
  64. #define INCL_INITRP_ONLY
  65. #include "reqpkt.h"
  66.  
  67. #include "scsi.h"
  68. #include "cdbscsi.h"
  69.  
  70. #include "atapicon.h"
  71. #include "atapireg.h"
  72. #include "atapityp.h"
  73. #include "atapiext.h"
  74. #include "atapipro.h"
  75.  
  76. /*
  77. ╔═════════════════════════════════════════════════════════════════════════════╗
  78. ║                                                                             ║
  79. ║  StartOSMRequest                                                            ║
  80. ║                                                                             ║
  81. ║  Outer State Machine Interface:  This routine initializes the inner state   ║
  82. ║  machine and sets up the outer state machine to go into a WAITSTATE until   ║
  83. ║  the inner state machine finishes the requested operation.                  ║
  84. ║                                                                             ║
  85. ╚═════════════════════════════════════════════════════════════════════════════╝
  86. */
  87. VOID FAR StartOSMRequest ( NPACB npACB )
  88. {
  89.   npACB->ISMState      = ACBIS_START_STATE;
  90.   npACB->ISMDoneReturn = StartOSM;
  91.   if (npACB->suspended)
  92.   {
  93.      _asm INT 3
  94.   }
  95.   StartISM ( npACB );
  96.  
  97. }
  98.  
  99. /*
  100. ╔════════════════════════════════════╗
  101. ║                                    ║
  102. ║  StartISM                          ║
  103. ║                                    ║
  104. ║  Inner State Machine Router        ║
  105. ║                                    ║
  106. ╚════════════════════════════════════╝
  107. */
  108.  
  109. VOID NEAR StartISM( NPACB npACB )
  110. {
  111.    VOID (FAR *ISMDoneReturn)( NPACB );
  112.  
  113.    DISABLE
  114.  
  115.    npACB->ISMUseCount++;
  116.  
  117.    if ( npACB->ISMUseCount == 1 )
  118.    {
  119.       do
  120.       {
  121.          ENABLE
  122.          npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  123.          do
  124.          {
  125.             switch ( npACB->ISMState )
  126.             {
  127.                case ACBIS_START_STATE:
  128.                   ISMStartState ( npACB );
  129.                   break;
  130.  
  131.                case ACBIS_INTERRUPT_STATE:
  132.                   InterruptState( npACB );
  133.                   break;
  134.  
  135.                case ACBIS_WRITE_ATAPI_PACKET_STATE:
  136.                   WriteATAPIPkt( npACB );
  137.                   break;
  138.  
  139.                case ACBIS_COMPLETE_STATE:
  140.                   npACB->ISMFlags |= ACBIF_WAITSTATE;
  141.                   npACB->ISMUseCount = 1;
  142.                   npACB->OSMState = ACBOS_ISM_COMPLETE;
  143.                   break;
  144.  
  145.                default :
  146.                   /* unknown state */
  147.                   npACB->ISMUseCount = 1;
  148.                   npACB->ISMFlags |= ACBIF_WAITSTATE;
  149.                   break;
  150.             }
  151.          }
  152.          while ( !(npACB->ISMFlags & ACBIF_WAITSTATE) );
  153.  
  154.          DISABLE
  155.       }
  156.       while ( --npACB->ISMUseCount );
  157.    }
  158.    ENABLE
  159.  
  160.    if ( npACB->ISMState == ACBIS_COMPLETE_STATE )
  161.    {
  162.       DISABLE
  163.       if (npACB->ISMDoneReturn)
  164.       {
  165.          ISMDoneReturn = npACB->ISMDoneReturn;
  166.          npACB->ISMDoneReturn = 0;
  167.          ENABLE
  168.          (*ISMDoneReturn)( npACB );
  169.       }
  170.       else
  171.          ENABLE
  172.  
  173.    } /* endif */
  174. } /* StartISM */
  175.  
  176. /*
  177. ╔════════════════════════════════════╗
  178. ║                                    ║
  179. ║  ISMStartState                     ║
  180. ║                                    ║
  181. ║  Initializes the Inner State       ║
  182. ║  Machine                           ║
  183. ║                                    ║
  184. ╚════════════════════════════════════╝
  185. */
  186.  
  187. VOID NEAR ISMStartState ( NPACB npACB )
  188. {
  189.    USHORT  Status;
  190.  
  191.    DISABLE
  192.    SelectUnit( npACB, npACB->UnitId );                              /*@V195083*/
  193.  
  194.    if (!( npACB->OSMReqFlags & ACBR_RESET ) &&                      /*V@106915*/
  195.       ( !DRQ_AND_BSY_CLEAR_WAIT( npACB ) ) )                        /*V@93531*/
  196.            /* Max Poll wait time exceeded */
  197.    {
  198.         if( npACB->npUCB->Flags & UCBF_FORCE )                        /*@V151168*//*@V155162*/
  199.         {                                                             /*@V151168*/
  200.             npACB->npUCB->Flags |= UCBF_NOTPRESENT;    //set fake flag  /*@V151168*/
  201.          npACB->IORBError = IOERR_UNIT_NOT_READY;                   /*@V155162*/
  202.          npACB->ISMState = ACBIS_COMPLETE_STATE;                    /*@V155162*/
  203.         }                                                             /*@V151168*/
  204.         else                                                          /*@V151168*/
  205.         {                                                             /*@V151168*/
  206.         npACB->ISMState = ACBIS_COMPLETE_STATE;
  207.         npACB->OSMReqFlags |= ACBR_RESET;  /* Set OSM for reset */
  208.         ENABLE
  209.         return;                                                     /*@V151168*/
  210.       }                                                             /*@V151168*/
  211.    }
  212.    else
  213.    {
  214.       ENABLE
  215.       InitializeISM( npACB );
  216.       /*
  217.       ┌────────────────────────────────────────┐
  218.       │ Do not write packet if unknown command │
  219.       └────────────────────────────────────────┘
  220.       */
  221.       if (npACB->IORBError & IOERR_CMD_NOT_SUPPORTED)
  222.       {
  223.          npACB->ISMState = ACBIS_COMPLETE_STATE;
  224.          npACB->ISMDoneReturn = 0;
  225.       }
  226.       else
  227.  
  228.          if ( !(npACB->ISMFlags & ACBIF_ATA_OPERATION) )
  229.             StartATAPICmd ( npACB );
  230.          else
  231.             StartATACmd ( npACB );
  232.  
  233.    } /* endif */
  234.  
  235. }
  236.  
  237. /*
  238. ╔══════════════════════════════════════╗
  239. ║                                      ║
  240. ║  InterruptState                      ║
  241. ║                                      ║
  242. ║  Routes interrupt generated threads  ║
  243. ║  to the selected interrupt function  ║
  244. ║                                      ║
  245. ╚══════════════════════════════════════╝
  246. */
  247. VOID NEAR InterruptState( NPACB npACB )
  248. {
  249.    USHORT Status;
  250.    USHORT INTReason = 0;                                            /*@V151168*/
  251.    USHORT cXferBytes;
  252.    USHORT cShortBytes;
  253.    USHORT ByteBucket;
  254.    USHORT Port;
  255.    USHORT OddWord;
  256.    USHORT cExtraBytes = 0;
  257.    USHORT Reason = 0;
  258.    USHORT data,port;                                                /* [001] */
  259.    register int loop;                                               /* [001] */
  260.  
  261.    if ( !(npACB->TimerFlags & ACBT_INTERRUPT) )
  262.    {
  263.  
  264.       Status    = GetRegister ( npACB, FI_PSTATUS );
  265.       while ( Status & FX_BUSY )
  266.       {
  267.          Status    = GetRegister ( npACB, FI_PSTATUS );
  268.       }
  269.  
  270.       INTReason = GetRegister ( npACB, FI_PINTREASON );
  271.       npACB->IORegs[FI_PSTATUS]    = Status;
  272.       npACB->IORegs[FI_PINTREASON] = INTReason;
  273.  
  274.  
  275.                               /* ┌─────────────────────────────────────────┐ */
  276.                               /* │Interrupt Reason  (Defined in ATAPIREG.H)│ */
  277.       if (INTReason & IRR_IO) /* │                                         │ */
  278.          Reason  |= IRM_IO;   /* │ IO    DRQ   COD    #define value        │ */
  279.       if (Status & FX_DRQ)    /* │  0     1     1     IR_PKTREADY          │ */
  280.          Reason |= IRM_DRQ;   /* │  1     1     1     IR_MESSAGE           │ */
  281.       if (INTReason & IRR_COD)/* │  1     1     0     IR_XFER_FROM_DEVICE  │ */
  282.          Reason |= IRM_COD;   /* │  0     1     0     IR_XFER_TO_DEVICE    │ */
  283.                               /* │  1     0     1     IR_COMPLETE          │ */
  284.                               /* └─────────────────────────────────────────┘ */
  285.  
  286.       if ( npACB->ISMFlags & ACBIF_ATA_OPERATION )
  287.          Reason = IRM_IO | IRM_DRQ;
  288.  
  289.       /*
  290.       ┌───────────────────────────────────────────────────────────────────────┐
  291.       │ The 1.7 spec indicates that the completion status only relies on the  │
  292.       │ DRQ bit being 0.  If we are in 1.7B compatibility mode and the DRQ    │
  293.       │ bit is 0, set the reason variable to IR_COMPLETE.                     │
  294.       └───────────────────────────────────────────────────────────────────────┘
  295.       */
  296.  
  297.       else if (/*( npACB->npUCB->Capabilities & UCBC_SPEC_REV_17B) && */
  298.                                                          !(Status & FX_DRQ))
  299.          Reason |= IRM_IO | IRM_COD;
  300.  
  301.       /*
  302.       ┌─────────────────────────────────────────────────┐
  303.       │ If there was an error, go to the complete phase │
  304.       └─────────────────────────────────────────────────┘
  305.       */
  306.       if ( Status & FX_ERROR )
  307.          Reason = IR_COMPLETE;
  308.  
  309.       switch (Reason)
  310.       {
  311.          case IR_PKTREADY :
  312.             npACB->ISMState = ACBIS_WRITE_ATAPI_PACKET_STATE;
  313.             npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  314.             break;
  315.  
  316.          case IR_XFER_FROM_DEVICE :
  317.                                                                     /*@V155162*/
  318.             if (npACB->npCmdIO->IOSGPtrs.Mode == SGLIST_TO_PORT)
  319.             {
  320.                // Wrong WAY, expecting to go the opposite direction,/*@V195083*/
  321.                // fix it instead of trapping.                       /*@V195083*/
  322.                 npACB->npCmdIO->IOSGPtrs.Mode == PORT_TO_SGLIST;    /*@V195083*/
  323.             } /* endif */
  324.                                                                     /*@V155162*/
  325.  
  326.             if ( npACB->ISMFlags & ACBIF_ATA_OPERATION )
  327.             {
  328.                cXferBytes = npACB->npCmdIO->cXferBytesRemain;
  329.                npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  330.                npACB->ISMState = ACBIS_COMPLETE_STATE;
  331.  
  332.             }
  333.             else
  334.             {
  335.                npACB->IORegs[FI_PBYTECTH] = GetRegister( npACB, FI_PBYTECTH );
  336.                npACB->IORegs[FI_PBYTECTL] = GetRegister( npACB, FI_PBYTECTL );
  337.  
  338.                cXferBytes = MAKEUSHORT( npACB->IORegs[FI_PBYTECTL],
  339.                                         npACB->IORegs[FI_PBYTECTH]);
  340.             }
  341.  
  342.             if (cXferBytes & 1)
  343.             {
  344.                cXferBytes++;
  345.             }
  346.             /*
  347.             ┌──────────────────────────────────────────────────────────────────┐
  348.             │ If overrun, determine amount of extra bytes to transfer, and set │
  349.             │ IOSGPtrs count to get only the number of bytes we are expecting  │
  350.             └──────────────────────────────────────────────────────────────────┘
  351.             */
  352.  
  353.             if ( cXferBytes > npACB->npCmdIO->cXferBytesRemain )
  354.             {
  355.                cExtraBytes = cXferBytes - npACB->npCmdIO->cXferBytesRemain;
  356.                cXferBytes = npACB->npCmdIO->cXferBytesRemain;
  357.             }
  358.  
  359.             npACB->npCmdIO->IOSGPtrs.numTotalBytes = cXferBytes;
  360.  
  361.             /*
  362.             ┌────────────────────────────────────────────────────────┐
  363.             │ Start the interrupt timer if this is an ATAPI transfer │
  364.             └────────────────────────────────────────────────────────┘
  365.             */
  366.  
  367.             if ( !(npACB->ISMFlags & ACBIF_ATA_OPERATION) )
  368.             {
  369.                DISABLE
  370.                if ( npACB->ISMFlags & ACBIF_INTERRUPT )
  371.                {
  372.                   INT3
  373.                }
  374.                npACB->ISMFlags |= (ACBIF_WAITSTATE | ACBIF_INTERRUPT);
  375.  
  376.                if ( ADD_StartTimerMS((PULONG) &npACB->IRQTimeOutHandle,
  377.                                      (ULONG)  npACB->IRQTimeOut,
  378.                                      (PFN)    IRQTimeOutHandler,
  379.                                      (PVOID)  npACB,
  380.                                      (ULONG)  0                      ) )
  381.                {
  382.                   _asm { int 3 }
  383.                } /* endif */
  384.             }
  385.  
  386.             /*
  387.             ┌─────────────────────────────────────────┐
  388.             │ Device will prepare for next interrupt  │
  389.             │ after last byte is transfered to host   │
  390.             └─────────────────────────────────────────┘
  391.             */
  392.  
  393.             ENABLE
  394.             ADD_XferIOW( &npACB->npCmdIO->IOSGPtrs );
  395.  
  396.             /*
  397.             ┌───────────────────────────────────────────────────┐
  398.             │ if extra bytes remain, put them in the byte bucket│
  399.             └───────────────────────────────────────────────────┘
  400.             */
  401.  
  402.             while ( cExtraBytes )
  403.             {
  404.                inwp( Port , ByteBucket );
  405.                cExtraBytes-=2;
  406.             } /* endwhile */
  407.  
  408.  
  409.             /*
  410.             ┌─────────────────────────────────────┐
  411.             │ Adjust counts to show last transfer │
  412.             └─────────────────────────────────────┘
  413.             */
  414.             npACB->npCmdIO->cXferBytesComplete += cXferBytes;
  415.             npACB->npCmdIO->cXferBytesRemain   -= cXferBytes;
  416.  
  417.             /*
  418.             ┌───────────────────────────────────────────────────────────────┐
  419.             │ If an odd byte count was requested, and we have finished the  │
  420.             │ even portion of the transfer, get the last byte and put it in │
  421.             │ the S/G list.                                                 │
  422.             └───────────────────────────────────────────────────────────────┘
  423.             */
  424.             if ( !(npACB->npCmdIO->cXferBytesRemain) &&
  425.                                       ( npACB->ISMFlags & ACBIF_ODD_BYTE_XFER) )
  426.             {
  427.                inwp(Port, OddWord);
  428.                PutByteInSGList ( npACB, OddWord );
  429.  
  430.                npACB->npCmdIO->cXferBytesComplete++;
  431.             } /* endif */
  432.             break;
  433.  
  434.          case IR_XFER_TO_DEVICE :
  435.                                                                     /*@V155162*/
  436.             if (npACB->npCmdIO->IOSGPtrs.Mode == PORT_TO_SGLIST)
  437.             {
  438.                // Wrong WAY, expecting to go the opposite direction,/*@V195083*/
  439.                // fix it instead of trapping.                       /*@V195083*/
  440.                npACB->npCmdIO->IOSGPtrs.Mode == SGLIST_TO_PORT;     /*@V195083*/
  441.             } /* endif */
  442.                                                                     /*@V155162*/
  443.  
  444.             npACB->IORegs[FI_PBYTECTH] = GetRegister( npACB, FI_PBYTECTH );
  445.             npACB->IORegs[FI_PBYTECTL] = GetRegister( npACB, FI_PBYTECTL );
  446.  
  447.             cXferBytes = MAKEUSHORT( npACB->IORegs[FI_PBYTECTL],
  448.                                      npACB->IORegs[FI_PBYTECTH]);
  449.  
  450.             /*
  451.             ┌──────────────────────────────────────────────────────────────────┐
  452.             │ If underrun, set IOSGPtrs count to send only the number of bytes │
  453.             │ the device is expecting.  Set up cExtraBytes to fill remaining   │
  454.             │ bytes with 0's                                                   │
  455.             └──────────────────────────────────────────────────────────────────┘
  456.             */
  457.  
  458.             if ( cXferBytes > npACB->npCmdIO->cXferBytesRemain )
  459.             {
  460.                cExtraBytes = cXferBytes - npACB->npCmdIO->cXferBytesRemain;
  461.                cXferBytes = npACB->npCmdIO->cXferBytesRemain;
  462.             }
  463.  
  464.             npACB->npCmdIO->IOSGPtrs.numTotalBytes = cXferBytes;
  465.  
  466.             /*
  467.             ┌───────────────────────────┐
  468.             │ Start the interrupt timer │
  469.             └───────────────────────────┘
  470.             */
  471.  
  472.             DISABLE
  473.                if ( npACB->ISMFlags & ACBIF_INTERRUPT )
  474.                {
  475.                   INT3
  476.                }
  477.             npACB->ISMFlags |= (ACBIF_WAITSTATE | ACBIF_INTERRUPT);
  478.             if ( ADD_StartTimerMS((PULONG) &npACB->IRQTimeOutHandle,
  479.                                   (ULONG)  npACB->IRQTimeOut,
  480.                                   (PFN)    IRQTimeOutHandler,
  481.                                   (PVOID)  npACB,
  482.                                   (ULONG)  0                      ) )
  483.             {
  484.                _asm { int 3 }
  485.             } /* endif */
  486.  
  487.             /*
  488.             ┌──────────────────────────────────────────┐
  489.             │ Device will prepare for next interrupt   │
  490.             │ after last byte is transfered from host  │
  491.             └──────────────────────────────────────────┘
  492.             */
  493.  
  494.             ENABLE
  495.             ADD_XferIOW( &npACB->npCmdIO->IOSGPtrs );
  496.  
  497.             /*
  498.             ┌───────────────────────────────────────────────────┐
  499.             │ if device expected more, give it zeros            │
  500.             └───────────────────────────────────────────────────┘
  501.             */
  502.  
  503.             Port = npACB->npCmdIO->IOSGPtrs.iPortAddress;
  504.  
  505.             while ( cExtraBytes )
  506.             {
  507.                outwp( Port , 0 );
  508.                cExtraBytes-=2;
  509.             } /* endwhile */
  510.  
  511.             npACB->npCmdIO->cXferBytesComplete += cXferBytes;
  512.             npACB->npCmdIO->cXferBytesRemain   -= cXferBytes;
  513.  
  514.             break;
  515.  
  516.          case IR_COMPLETE :
  517.  
  518.             /* Begin [001] */
  519.  
  520.             if( ( npACB->ISMFlags & ACBIF_BUSMASTERDMAIO ) )
  521.             {
  522.               npACB->ISMFlags &= ~ACBIF_BUSMASTERDMAIO;
  523.               npACB->npCmdIO->cXferBytesComplete = npACB->npCmdIO->cXferBytesRemain;
  524.               npACB->npCmdIO->cXferBytesRemain = 0;
  525.  
  526.               /* Wait for BM DMA active to go away for a while. */
  527.  
  528.               port = npACB->BMISTA;
  529.               for( loop=256 ; loop ; --loop )
  530.               {
  531.                 inp(port,data);
  532.                 if ( !(data & ACBX_BMISTA_ACTIVE) )
  533.                 {
  534.                   break;
  535.                 }
  536.               }
  537.  
  538. /* Begin [002]
  539.               if ( data & ACBX_BMISTA_ACTIVE )
  540.               {
  541.                 npACB->ISMState = ACBIS_COMPLETE_STATE;
  542.                 npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  543.                 npACB->OSMReqFlags |= ACBR_RESET;
  544.               }
  545.    End [002] */
  546.  
  547.               port = npACB->BMICOM;
  548.               outp ( port, 0 );    /* shut down BM DMA controller */
  549.               port = npACB->BMISTA;
  550.               data &= ( ACBX_BMISTA_INTERRUPT |
  551.                         ACBX_BMISTA_D0DMA |
  552.                         ACBX_BMISTA_D1DMA );
  553.               outp ( port, data ); /* clear BM interrupt flag */
  554.  
  555.               /* Fix so that Bus Master errors will definitely result in retries */
  556.  
  557.               inp ( port, data );
  558.               if ( data & ACBX_BMISTA_ERROR )
  559.               {
  560.                 data &= ( ACBX_BMISTA_ERROR |
  561.                           ACBX_BMISTA_D0DMA |
  562.                           ACBX_BMISTA_D1DMA );
  563.                 outp ( port, data );
  564.                 npACB->ISMState = ACBIS_COMPLETE_STATE;
  565.                 npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  566.                 npACB->OSMReqFlags |= ACBR_RESET;
  567.               }
  568.             }
  569.  
  570.             /* End [001] */
  571.  
  572.             /* if an error, get the error register */
  573.  
  574.             if (Status & FX_ERROR )
  575.             {
  576.                npACB->IORegs[FI_PERROR] = GetRegister( npACB, FI_PERROR );
  577.                npACB->OSMReqFlags |= ACBR_SENSE_DATA;
  578.             }
  579.             else if ( !(npACB->ISMFlags & ACBIF_ATA_OPERATION) &&
  580.                        (npACB->npCmdIO->IOSGPtrs.Mode == PORT_TO_SGLIST))
  581.             {
  582.                /*
  583.                ┌───────────────────────────────────────────────────────────┐
  584.                │ if the device did not give us as many bytes as we asked   │
  585.                │ for fill the remaining portion of the SG List with 0's.   │
  586.                └───────────────────────────────────────────────────────────┘
  587.                */
  588.                while ( npACB->npCmdIO->cXferBytesRemain )
  589.                {
  590.                   if (npACB->npCmdIO->IOSGPtrs.SGOffset ==
  591.                      npACB->npCmdIO->IOSGPtrs.pSGList
  592.                               [npACB->npCmdIO->IOSGPtrs.iSGList].XferBufLen)
  593.                   {
  594.                      npACB->npCmdIO->IOSGPtrs.SGOffset = 0;
  595.                      npACB->npCmdIO->IOSGPtrs.iSGList++;
  596.                   }
  597.  
  598.                   PutByteinSGList ( npACB, 0 );
  599.                   npACB->npCmdIO->cXferBytesComplete++;
  600.                   npACB->npCmdIO->cXferBytesRemain--;
  601.                } /* endwhile */
  602.             } /* end else */
  603.  
  604.  
  605.             npACB->ISMState  = ACBIS_COMPLETE_STATE;
  606.             break;
  607.  
  608.          default :
  609.  
  610. //            INT3
  611.             //BMK if all is 0 then there was an unknown problem     /*@V151168*/
  612.             npACB->IORegs[FI_PSTATUS] = FX_ERROR;                   /*@V151168*/
  613.             //Do a reset                                            /*@V151168*/
  614.             npACB->ISMFlags &= ~ACBIF_WAITSTATE;                    /*@V151168*/
  615.             npACB->OSMReqFlags |= ACBR_RESET;                       /*@V151168*/
  616.  
  617.             npACB->ISMState = ACBIS_COMPLETE_STATE;
  618.             break;
  619.  
  620.       } /* endswitch */
  621.  
  622.    }
  623.    else
  624.    {
  625.       /*
  626.       ┌────────────────────────┐
  627.       │ An Interrupt Timed Out │
  628.       └────────────────────────┘
  629.       */
  630.  
  631.       /* Begin [001] */
  632.  
  633.       if( ( npACB->ISMFlags & ACBIF_BUSMASTERDMAIO ) )
  634.       {
  635.         npACB->ISMFlags &= ~ACBIF_BUSMASTERDMAIO;
  636.         port = npACB->BMICOM;
  637.         outp ( port, 0 );    /* shut down BM DMA controller */
  638.         port = npACB->BMISTA;
  639.         inp( port, data );
  640.         data &= ( ACBX_BMISTA_INTERRUPT |
  641.                   ACBX_BMISTA_D0DMA |
  642.                   ACBX_BMISTA_D1DMA );
  643.         outp( port, data ); /* clear BM interrupt flag */
  644.       }
  645.  
  646.       /* End [001] */
  647.  
  648.       npACB->ISMState = ACBIS_COMPLETE_STATE;
  649.       npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  650.       npACB->OSMReqFlags |= ACBR_RESET;
  651.       // Fake interrupt timeout to get an error                     /*@V151168*/
  652.       npACB->TimerFlags |= ACBT_INTERRUPT;                          /*@V151168*/
  653.    } /* endif */
  654.  
  655. } /* InterruptState */
  656.  
  657. /*
  658. ╔═══════════════════════════════════════╗
  659. ║                                       ║
  660. ║  PutByteInSGList                      ║
  661. ║                                       ║
  662. ║  Puts the next byte from the port     ║
  663. ║  address in the next SGList location  ║
  664. ║                                       ║
  665. ╚═══════════════════════════════════════╝
  666. */
  667. VOID NEAR PutByteInSGList ( NPACB npACB, USHORT Data )
  668. {
  669.    PSCATGATENTRY pSGE;    /* Current S/G List Entry          */
  670.    ULONG         ppDst;   /* Physical Address of Destination */
  671.    PBYTE         pDst;    /* Virtual Address of Destination  */
  672.    USHORT        ModeFlag;
  673.  
  674.    pSGE   = &npACB->npCmdIO->IOSGPtrs.pSGList[npACB->npCmdIO->IOSGPtrs.iSGList];
  675.                                         /* Point to the current entry */
  676.    ppDst  = pSGE->ppXferBuf + npACB->npCmdIO->IOSGPtrs.SGOffset;
  677.                                         /* Offset in current entry */
  678.  
  679.    if ( DevHelp_PhysToVirt( (ULONG)   ppDst,
  680.                              (USHORT)  1,
  681.                              (PVOID)   &pDst,
  682.                              (PUSHORT) &ModeFlag  ) )
  683.    {
  684.       _asm { int 3 }
  685.    }
  686.  
  687.    *pDst = (UCHAR) (Data >> 8); /* Store the Byte   */
  688. }
  689.  
  690. /*
  691. ╔═══════════════════════════════════════╗
  692. ║                                       ║
  693. ║  WriteATAPIPkt                        ║
  694. ║                                       ║
  695. ║  Write ATAPI command packet to data   ║
  696. ║  register                             ║
  697. ║                                       ║
  698. ╚═══════════════════════════════════════╝
  699. */
  700. VOID NEAR WriteATAPIPkt ( NPACB npACB )
  701. {
  702.    USHORT Port,i;
  703.    USHORT Data;
  704.  
  705.    if ( !BSY_CLR_DRQ_SET_WAIT( npACB ) )                             /*V@93531*/
  706.              /* Max Poll wait time exceeded */                       /*V@93531*/
  707.    {                                                                 /*V@93531*/
  708.       npACB->ISMState = ACBIS_COMPLETE_STATE;                        /*V@93531*/
  709.       npACB->OSMReqFlags |= ACBR_RESET;  /* Set OSM for reset */     /*V@93531*/
  710.    }                                                                 /*V@93531*/
  711.    else
  712.    {
  713.       /*
  714.       ┌───────────────────────────┐
  715.       │ Start the interrupt timer │
  716.       └───────────────────────────┘
  717.       */
  718.       DISABLE
  719.       if ( npACB->ISMFlags & ACBIF_INTERRUPT )
  720.       {
  721.          INT3
  722.       }
  723.       npACB->ISMFlags |= (ACBIF_WAITSTATE | ACBIF_INTERRUPT);
  724.       npACB->ISMState = ACBIS_INTERRUPT_STATE;
  725.  
  726.       if ( ADD_StartTimerMS((PULONG) &npACB->IRQTimeOutHandle,
  727.                             (ULONG)  npACB->IRQTimeOut,
  728.                             (PFN)    IRQTimeOutHandler,
  729.                             (PVOID)  npACB,
  730.                             (ULONG)  0                      ) )
  731.       {
  732.          _asm { int 3 }
  733.       } /* endif */
  734.  
  735.       /* Begin [001] Start Bus Master DMA transfer after issuing Packet command */
  736.  
  737.       if( npACB->BM_CommandCode & ACBX_BMICOM_START )
  738.       {
  739.           Port = npACB->BMISTA;           /* addr status reg */
  740.           inp( Port, Data );
  741.           Data &= ( ACBX_BMISTA_INTERRUPT |
  742.                     ACBX_BMISTA_D0DMA |
  743.                     ACBX_BMISTA_D1DMA );
  744.           outp( Port, Data );             /* clear BM interrupt flag */
  745.           Port = npACB->BMICOM;           /* Set port address to BM Command reg */
  746.           Data = npACB->BM_CommandCode;   /* BM controller command */
  747.           outp( Port, Data );             /* Start BM controller */
  748.       }
  749.  
  750.       /* End [001] */
  751.  
  752.       Port = npACB->IOPorts[FI_PDATA];                              /* [001] Moved */
  753.  
  754.       i=0;
  755.       do
  756.       {
  757.          Data = MAKEUSHORT(npACB->npCmdIO->ATAPIPkt[i],
  758.                            npACB->npCmdIO->ATAPIPkt[i+1]);  /*  MAKEUSHORT (h,l)  */
  759.          i+=2;
  760.          outwp( Port, Data );
  761.          IODelay ();
  762.       } while ( i < npACB->npUCB->CmdPacketLength);
  763.  
  764.       ENABLE
  765.  
  766.    }
  767.  
  768. } /* WriteATAPIPkt */
  769.  
  770. /*
  771. ╔════════════════════════════════════╗
  772. ║                                    ║
  773. ║  StartATAPICmd                     ║
  774. ║                                    ║
  775. ║  Write an ATAPI CMD and Paramters  ║
  776. ║                                    ║
  777. ╚════════════════════════════════════╝
  778. */
  779. VOID NEAR StartATAPICmd ( NPACB npACB )
  780. {
  781.    USHORT Port;
  782.    USHORT Data;
  783.    USHORT Status;
  784.    USHORT i;
  785.    USHORT IOMask;
  786.    USHORT Flags;
  787.    USHORT cBytes;
  788.  
  789.    SelectUnit( npACB, npACB->UnitId );                              /*@V195083*/
  790.  
  791.    if (npACB->npUCB->Flags & UCBF_NOTPRESENT)                       /*@V151168*/
  792.    {                                                                /*@V151168*/
  793.       // This is a not-present forced drive, fake the request       /*@V151168*/
  794.       FakeATAPI(npACB);                                             /*@V151168*/
  795.       npACB->ISMFlags &= ~ACBIF_WAITSTATE;                          /*@V151168*/
  796.       npACB->ISMState = ACBIS_COMPLETE_STATE;    // force completion /*@V151168*/
  797.       return;   //done                                              /*@V151168*/
  798.    }                                                                /*@V151168*/
  799.  
  800.    /* Set Drive Select Register */
  801.    npACB->IORegs[FI_PDRVSLCT] =
  802.            DEFAULT_ATAPI_DRV_SLCT_REG | ((npACB->UnitId == 0) ? UNIT0 : UNIT1 );
  803.  
  804.    IOMask = FM_PATAPI_CMD;              /* Registers mask for ATAPI Cmd pkt */
  805.    Flags  = npACB->ISMFlags;
  806.  
  807.    /* Set Feature Register Data ( DMA OFF ) */
  808.    npACB->IORegs[FI_PFEATURE] = DEFAULT_ATAPI_FEATURE_REG & ~DMA_ON;
  809.  
  810.    /* Begin [001] */
  811.  
  812.    if ( npACB->ISMFlags & ACBIF_BUSMASTERDMAIO )
  813.    {
  814.       npACB->IORegs[FI_PFEATURE] |= DMA_ON; /* enable DMA for this xfer */
  815.    }
  816.  
  817.    /* End [001] */
  818.  
  819.    cBytes = npACB->npCmdIO->cXferBytesRemain;
  820.    if ( cBytes > MAX_XFER_BYTES_PER_INTERRUPT )
  821.       cBytes = MAX_XFER_BYTES_PER_INTERRUPT;
  822.  
  823.    /* Set Byte Count registers (Low and High order) */
  824.    npACB->IORegs[FI_PBYTECTH] = cBytes >> 8;
  825.    npACB->IORegs[FI_PBYTECTL] = cBytes & LOW_BYTE_MASK;
  826.  
  827.    /*
  828.    ┌───────────────────────────────────────────────────────────────────────────┐
  829.    │ The LBA bit of the ATAPI Drive Select Register is a reserved bit starting │
  830.    │ in revision 1.2, and therefore must be set to 0.  However, in the earlier │
  831.    │ specs, the LBA bit must be 1.                                             │
  832.    └───────────────────────────────────────────────────────────────────────────┘
  833.    */
  834.  
  835.    if ( npACB->npUCB->Capabilities & UCBC_SPEC_REV_17B)
  836.    {
  837.       npACB->IORegs[FI_PDRVSLCT] |= REV_17B_SET_LBA;
  838.    } /* endif */
  839.  
  840.    /* Set Command Register with ATAPI Command */
  841.    npACB->IORegs[FI_PCMD] = FX_PKTCMD;
  842.  
  843.    if ( npACB->npUCB->Capabilities & UCBC_INTERRUPT_DRQ )
  844.    {
  845.       DISABLE
  846.       if (npACB->ISMFlags & ACBIF_INTERRUPT)
  847.       {
  848.          INT3
  849.       }
  850.       npACB->ISMFlags |= (ACBIF_WAITSTATE | ACBIF_INTERRUPT);
  851.       npACB->ISMState = ACBIS_INTERRUPT_STATE;
  852.  
  853.       /*
  854.       ┌───────────────────────────┐
  855.       │ Start the interrupt timer │
  856.       └───────────────────────────┘
  857.       */
  858.  
  859.       if ( ADD_StartTimerMS((PULONG) &npACB->IRQTimeOutHandle,
  860.                             (ULONG)  npACB->IRQTimeOut,
  861.                             (PFN)    IRQTimeOutHandler,
  862.                             (PVOID)  npACB,
  863.                             (ULONG)  0                      ) )
  864.       {
  865.          _asm { int 3 }
  866.       } /* endif */
  867.       ENABLE
  868.    }
  869.    else
  870.    {
  871.       npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  872.       npACB->ISMState = ACBIS_WRITE_ATAPI_PACKET_STATE;
  873.    }
  874.  
  875.    /*
  876.    ┌──────────────────────────┐
  877.    │ Write selected registers │
  878.    └──────────────────────────┘
  879.    */
  880.    for ( i = FI_PFEATURE; IOMask; i++ )
  881.    {
  882.      IOMask >>= 1;
  883.  
  884.      if ( IOMask & 0x0001 )
  885.      {
  886.        Port = npACB->IOPorts[i];
  887.        Data = npACB->IORegs[i];
  888.        outp( Port, Data);
  889.        IODelay();
  890.      }
  891.    }
  892.  
  893. } /* StartATAPICmd */
  894.  
  895. /*
  896. ╔════════════════════════════════════╗
  897. ║                                    ║
  898. ║  StartATACmd                       ║
  899. ║                                    ║
  900. ║  Write an ATA CMD and Paramters    ║
  901. ║                                    ║
  902. ╚════════════════════════════════════╝
  903. */
  904. VOID NEAR StartATACmd ( NPACB npACB )
  905. {
  906.  
  907.    USHORT Port;
  908.    USHORT Data;
  909.    USHORT Status;
  910.    USHORT i;
  911.    USHORT IOMask;
  912.    USHORT Flags;
  913.  
  914.    SelectUnit( npACB, npACB->UnitId );                              /*@V195083*/
  915.    IOMask = FM_PATA_CMD;              /* Registers mask for ATA Commands */
  916.  
  917.    Flags  = npACB->ISMFlags;
  918.  
  919.    if (npACB->npUCB->Flags & UCBF_NOTPRESENT)                       /*@V151168*/
  920.    {                                                                /*@V151168*/
  921.       // This is a not-present forced drive, fake the request       /*@V151168*/
  922.       FakeATA(npACB);                                               /*@V151168*/
  923.       npACB->ISMFlags &= ~ACBIF_WAITSTATE;                          /*@V151168*/
  924.       npACB->ISMState = ACBIS_COMPLETE_STATE;    // force completion /*@V151168*/
  925.       return;   //done                                              /*@V151168*/
  926.    }                                                                /*@V151168*/
  927.  
  928.    /* Set Drive Select Register */
  929.    npACB->IORegs[FI_PDRVSLCT] =
  930.            DEFAULT_ATAPI_DRV_SLCT_REG | ((npACB->UnitId == 0) ? UNIT0 : UNIT1 );
  931.  
  932.    /* Set Command Register with ATA Command */
  933.    if ( npACB->npUCB->ReqFlags & UCBR_IDENTIFY )
  934.    {
  935.       npACB->IORegs[FI_PCMD] = FX_IDENTIFYDRIVE;
  936.  
  937.       DISABLE
  938.       if (npACB->ISMFlags & ACBIF_INTERRUPT)
  939.       {
  940.          INT3
  941.       }
  942.       npACB->ISMFlags |= (ACBIF_INTERRUPT | ACBIF_WAITSTATE);
  943.       npACB->ISMState = ACBIS_INTERRUPT_STATE;
  944.  
  945.       /*
  946.       ┌───────────────────────────┐
  947.       │ Start the interrupt timer │
  948.       └───────────────────────────┘
  949.       */
  950.  
  951.       if ( ADD_StartTimerMS((PULONG) &npACB->IRQTimeOutHandle,
  952.                             (ULONG)  npACB->IRQTimeOut,
  953.                             (PFN)    IRQTimeOutHandler,
  954.                             (PVOID)  npACB,
  955.                             (ULONG)  0                      ) )
  956.       {
  957.          _asm { int 3 }
  958.       } /* endif */
  959.       ENABLE
  960.  
  961.    }
  962.  
  963.    else if ( npACB->npUCB->ReqFlags & UCBR_RESET )
  964.    {
  965.       npACB->IORegs[FI_PCMD] = FX_SOFTRESET;
  966.       npACB->ISMState = ACBIS_COMPLETE_STATE;
  967.       npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  968.    }
  969.  
  970.    else
  971.    {
  972.       INT3
  973.    }
  974.  
  975.  
  976.    /*
  977.    ┌──────────────────────────┐
  978.    │ Write selected registers │
  979.    └──────────────────────────┘
  980.    */
  981.    for ( i = FI_PFEATURE; IOMask; i++ )
  982.    {
  983.      IOMask >>= 1;
  984.  
  985.      if ( IOMask & 0x0001 )
  986.      {
  987.        Port = npACB->IOPorts[i];
  988.        Data = npACB->IORegs[i];
  989.        outp( Port, Data);
  990.        IODelay();
  991.      }
  992.    }
  993.  
  994. }
  995.  
  996. /*
  997. ╔═══════════════════════════════════════╗
  998. ║                                       ║
  999. ║  InitializeISM                        ║
  1000. ║                                       ║
  1001. ║  Initializes state and flag variables ║
  1002. ║                                       ║
  1003. ╚═══════════════════════════════════════╝
  1004. */
  1005. VOID NEAR InitializeISM ( NPACB npACB )
  1006. {
  1007.      UCHAR                  Opcode;
  1008.      struct CDB_ModeSense_10  NEAR *pModeSenseCmd; /* in order to fix 1.7B drives */
  1009.      struct CDB_PlayAudio_MSF NEAR *pPlayAudioMSFCmd;
  1010.      NPUCB                  npUCB = npACB->npUCB;                   /* [001] */
  1011.      SHORT                  Port,Data;                              /* [001] */
  1012.  
  1013.    if ( !( npACB->ISMFlags & ACBIF_ATA_OPERATION ) )
  1014.    {
  1015.       /*
  1016.       ┌────────────────────────────┐
  1017.       │ set opcode dependent flags │
  1018.       └────────────────────────────┘
  1019.       */
  1020.  
  1021.       Opcode = npACB->npCmdIO->ATAPIPkt[0];
  1022.  
  1023.       npACB->BM_CommandCode = 0;                                    /* [001] */
  1024.  
  1025.       switch( Opcode )
  1026.       {
  1027.          /* Immediate Commands - complete after returning status */
  1028.  
  1029.          case ATAPI_AUDIO_SCAN :
  1030.          case SCSI_PLAY_AUDIO_10 :
  1031.          case SCSI_PLAY_AUDIO_12 :
  1032.          case SCSI_PLAY_MSF :
  1033.          case SCSI_PLAY_TRACK_REL :
  1034.          case SCSI_PLAY_TRACK_REL_12 :
  1035.          case SCSI_SEEK_10 :
  1036.  
  1037.          /* Completion Status Only */
  1038.  
  1039.          case SCSI_START_STOP_UNIT :
  1040.          case SCSI_PAUSE_RESUME :
  1041.          case SCSI_LOCK_UNLOCK :
  1042.          case SCSI_REZERO_UNIT :
  1043.          case ATAPI_SET_CDROM_SPEED :
  1044.          case ATAPI_STOP_PLAYSCAN :
  1045.          case SCSI_TEST_UNIT_READY :
  1046.  
  1047.             npACB->ISMFlags |= (ACBIF_COMPLETION_STATUS_ONLY | ACBIF_WAITSTATE);
  1048.             break;
  1049.  
  1050.          /* Single IO */
  1051.          case SCSI_INQUIRY :
  1052.          case SCSI_READ_CAPACITY :
  1053.          case SCSI_MODE_SENSE_10 :
  1054.          case SCSI_READ_HEADER :
  1055.          case SCSI_READ_SUB_CHAN :
  1056.          case SCSI_READ_TOC :
  1057.          case SCSI_REQUEST_SENSE :
  1058.  
  1059.             npACB->ISMFlags |= (ACBIF_SINGLEIO | ACBIF_WAITSTATE);
  1060.             break;
  1061.  
  1062.          /* Block IO */
  1063.          case SCSI_READ_10 :
  1064.          case SCSI_READ_12 :
  1065.          case ATAPI_READ_CD :
  1066.          case ATAPI_READ_CD_MSF :
  1067.  
  1068.             npACB->ISMFlags |= (ACBIF_MULTIPLEIO | ACBIF_WAITSTATE);
  1069.  
  1070.             /* Begin [001] Determine if DMA capable system/CD-ROM and even length transfer */
  1071.  
  1072.             if ( (!InitActive) &&
  1073.                  !(npACB->ISMFlags & ACBIF_BUSMASTERDMA_FORCEPIO) &&
  1074.                  (npUCB->Flags & UCBF_BM_DMA) &&
  1075.                  !(npACB->npCmdIO->IOSGPtrs.numTotalBytes & 1) )
  1076.             {
  1077.  
  1078.               if( !CreateBMSGList( npACB ) )    /* try and create scatter/gather list */
  1079.               {
  1080.                 /* change transfer setup to Bus Master DMA */
  1081.  
  1082.                 npACB->ISMFlags &= ~ACBIF_MULTIPLEIO;
  1083.                 npACB->ISMFlags |= ACBIF_BUSMASTERDMAIO;
  1084.  
  1085.                 /* Shut down Bus Master DMA controller if active */
  1086.  
  1087.                 Port = npACB->BMISTA;           /* Set port address to BM Status reg */
  1088.                 inp ( Port, Data );
  1089.                 if ( Data & ACBX_BMISTA_ACTIVE )
  1090.                 {
  1091.                   Port = npACB->BMICOM;         /* Set port address to BM Command reg */
  1092.                   outp( Port, 0 );              /* stop Bus Master DMA if active */
  1093.                 }
  1094.                 Port = npACB->BMISTA;           /* set to status reg again */
  1095.                 Data &= ( ACBX_BMISTA_INTERRUPT |
  1096.                           ACBX_BMISTA_D0DMA |
  1097.                           ACBX_BMISTA_D1DMA );
  1098.                 outp ( Port, Data );            /* write to port */
  1099.  
  1100.                 npACB->BM_CommandCode = (ACBX_BMICOM_RW | ACBX_BMICOM_START);
  1101.  
  1102.           #ifdef ENABLE_COUNTERS
  1103. //                  ++npUCB->DeviceCounters.TotalBMReadOperations;
  1104.           #endif
  1105.  
  1106.                 Port = npACB->BMIDTP;           /* address descriptor base register in PIIX */
  1107.                 Data = (USHORT) npACB->BMDMA_SGList;
  1108.                 outwp ( Port, Data );
  1109.                 Port += 2;
  1110.                 Data = (USHORT) (npACB->BMDMA_SGList >> 16);
  1111.                 outwp ( Port, Data );
  1112.  
  1113.                 /*
  1114.                  * Bus Master DMA is now ready for the transfer.  It must be started after the
  1115.                  * command is issued to the drive, to avoid data corruption in case a spurious
  1116.                  * interrupt occurred at the beginning of the xfer and the drive is in an unknown
  1117.                  * state.
  1118.                  */
  1119.  
  1120.               } /* if( !CreateBMSGList( npACB ) ) */
  1121.  
  1122.               npACB->ISMFlags &= ~ACBIF_BUSMASTERDMA_FORCEPIO;
  1123.             }
  1124.  
  1125.             /* End [001] */
  1126.  
  1127.             break;
  1128.  
  1129.          case SCSI_MODE_SELECT_10 :
  1130.             npACB->ISMFlags |= (ACBIF_MULTIPLEIO | ACBIF_WAITSTATE);
  1131.             /*
  1132.             ┌───────────────────────────────────┐
  1133.             │ change default transfer direction │
  1134.             └───────────────────────────────────┘
  1135.             */
  1136.             npACB->npCmdIO->IOSGPtrs.Mode = SGLIST_TO_PORT;
  1137.  
  1138.             break;
  1139.  
  1140.          default :
  1141.             if ( !(npACB->ISMFlags & ACBIF_ATA_OPERATION) )
  1142.             {
  1143.                npACB->ISMFlags |=  ACBIF_WAITSTATE;
  1144.                break;
  1145.             }
  1146.       } /* endswitch */
  1147.  
  1148.       /*
  1149.       ┌───────────────────────────────────────────────┐
  1150.       │ If drive is only revision 1.7B compatible,    │
  1151.       │ change the opcodes to the 1.7B spec's opcodes │
  1152.       │ and fix the inconsistancies in the data       │
  1153.       └───────────────────────────────────────────────┘
  1154.       */
  1155.       if ( npACB->npUCB->Capabilities & UCBC_SPEC_REV_17B)
  1156.       {
  1157.          switch (Opcode)
  1158.          {
  1159.          case ATAPI_AUDIO_SCAN :
  1160.             npACB->npCmdIO->ATAPIPkt[0] = REV_17B_ATAPI_AUDIO_SCAN;
  1161.             break;
  1162.  
  1163.          case ATAPI_SET_CDROM_SPEED :
  1164.             npACB->npCmdIO->ATAPIPkt[0] = REV_17B_ATAPI_SET_CDROM_SPEED;
  1165.             break;
  1166.  
  1167.          case ATAPI_READ_CD :
  1168.             npACB->npCmdIO->ATAPIPkt[0] = REV_17B_ATAPI_READ_CD;
  1169.             break;
  1170.  
  1171.          case ATAPI_READ_CD_MSF :
  1172.             npACB->npCmdIO->ATAPIPkt[0] = REV_17B_ATAPI_READ_CD_MSF;
  1173.             break;
  1174.  
  1175.          case SCSI_PLAY_MSF :
  1176.             pPlayAudioMSFCmd =
  1177.                      (struct CDB_PlayAudio_MSF NEAR *)npACB->npCmdIO->ATAPIPkt;
  1178.             /* silly 1.7B drives want this data in BCD */
  1179.             pPlayAudioMSFCmd->starting_M = x2BCD(pPlayAudioMSFCmd->starting_M);
  1180.             pPlayAudioMSFCmd->starting_S = x2BCD(pPlayAudioMSFCmd->starting_S);
  1181.             pPlayAudioMSFCmd->starting_F = x2BCD(pPlayAudioMSFCmd->starting_F);
  1182.             pPlayAudioMSFCmd->ending_M   = x2BCD(pPlayAudioMSFCmd->ending_M);
  1183.             pPlayAudioMSFCmd->ending_S   = x2BCD(pPlayAudioMSFCmd->ending_S);
  1184.             pPlayAudioMSFCmd->ending_F   = x2BCD(pPlayAudioMSFCmd->ending_F);
  1185.             break;
  1186.  
  1187.          case SCSI_MODE_SENSE_10 :
  1188.             pModeSenseCmd =
  1189.                       (struct CDB_ModeSense_10  NEAR *)npACB->npCmdIO->ATAPIPkt;
  1190.             if (pModeSenseCmd->page_code == PAGE_CAPABILITIES)
  1191.             {
  1192.                pModeSenseCmd->page_code = REV_17B_PAGE_CAPABILITIES;
  1193.             }
  1194.  
  1195.          default :
  1196.             break;
  1197.          } /* endswitch */
  1198.       } /* endif */
  1199.    }
  1200.    /*
  1201.    ┌────────────────────┐
  1202.    │ Odd Byte Transfers │
  1203.    └────────────────────┘
  1204.    */
  1205.    if ( npACB->npCmdIO->IOSGPtrs.numTotalBytes & 1 )  /* Is this an odd byte transfer? */
  1206.    {
  1207.       if (npACB->npCmdIO->IOSGPtrs.Mode == PORT_TO_SGLIST)
  1208.       {
  1209.          npACB->npCmdIO->IOSGPtrs.numTotalBytes -= 1; /* Must be even transfer Amount */
  1210.          npACB->ISMFlags |= ACBIF_ODD_BYTE_XFER;
  1211.       }
  1212.       else
  1213.       {
  1214.          npACB->npCmdIO->IOSGPtrs.numTotalBytes += 1; /* Must be even transfer Amount */
  1215.       } /* endif */
  1216.    } /* endif */
  1217. }
  1218.  
  1219. /*
  1220. ╔════════════════════════════════════╗
  1221. ║                                    ║
  1222. ║  IRQTimeOutHandler                 ║
  1223. ║                                    ║
  1224. ║  Times out the interrupt           ║
  1225. ║                                    ║
  1226. ╚════════════════════════════════════╝
  1227. */
  1228. VOID FAR IRQTimeOutHandler( ULONG TimerHandle, ULONG Parm1, ULONG Parm2 )
  1229. {
  1230.    NPACB         npACB;
  1231.  
  1232.    DISABLE
  1233.    ADD_CancelTimer( TimerHandle );
  1234.  
  1235.    npACB = (NPACB) Parm1;
  1236.  
  1237.    npACB->IRQTimeOutHandle = 0;
  1238.    npACB->ISMFlags &= ~ACBIF_INTERRUPT;
  1239.  
  1240.    npACB->TimerFlags |= ACBT_INTERRUPT; /* Tell interrupt state we timedout */
  1241.  
  1242.    if ( npACB->ISMState == ACBIS_INTERRUPT_STATE )
  1243.    {
  1244.       ENABLE
  1245.       StartISM( npACB );
  1246.    }
  1247.    else
  1248.       ENABLE
  1249. }
  1250.  
  1251. /*
  1252. ╔════════════════════════════════════╗
  1253. ║                                    ║
  1254. ║  AdapterIRQ0                       ║
  1255. ║                                    ║
  1256. ║  Routes received IRQs for Adapter  ║
  1257. ║  0 to generic handler              ║
  1258. ║                                    ║
  1259. ╚════════════════════════════════════╝
  1260. */
  1261. USHORT FAR _loadds AdapterIRQ0()
  1262. {
  1263.    return( AdptInterrupt( ACBPtrs[0].npACB ) );                   /*V@93531*/
  1264. }
  1265.  
  1266. /*
  1267. ╔════════════════════════════════════╗
  1268. ║                                    ║
  1269. ║  AdapterIRQ1                       ║
  1270. ║                                    ║
  1271. ║  Routes received IRQs for Adapter  ║
  1272. ║  1 to generic handler              ║
  1273. ║                                    ║
  1274. ╚════════════════════════════════════╝
  1275. */
  1276. USHORT FAR _loadds AdapterIRQ1()
  1277. {
  1278.    return( AdptInterrupt( ACBPtrs[1].npACB ) );                   /*V@93531*/
  1279. }
  1280.  
  1281. /*
  1282. ╔════════════════════════════════════╗
  1283. ║                                    ║
  1284. ║  AdapterIRQ2                       ║
  1285. ║                                    ║
  1286. ║  Routes received IRQs for Adapter  ║
  1287. ║  2 to generic handler              ║
  1288. ║                                    ║
  1289. ╚════════════════════════════════════╝
  1290. */
  1291. USHORT FAR _loadds AdapterIRQ2()
  1292. {
  1293.    return( AdptInterrupt( ACBPtrs[2].npACB ) );                   /*V@93531*/
  1294. }
  1295.  
  1296. /*
  1297. ╔════════════════════════════════════╗
  1298. ║                                    ║
  1299. ║  AdapterIRQ3                       ║
  1300. ║                                    ║
  1301. ║  Routes received IRQs for Adapter  ║
  1302. ║  3 to generic handler              ║
  1303. ║                                    ║
  1304. ╚════════════════════════════════════╝
  1305. */
  1306. USHORT FAR _loadds AdapterIRQ3()
  1307. {
  1308.    return( AdptInterrupt( ACBPtrs[3].npACB ) );                   /*V@93531*/
  1309. }
  1310.  
  1311. /*
  1312. ╔══════════════════════════════════════╗
  1313. ║                                      ║
  1314. ║  AdptInterrupt                       ║
  1315. ║                                      ║
  1316. ║  Determines if IRQ should be claimed ║
  1317. ║  and sets state flags accordingly    ║
  1318. ║                                      ║
  1319. ╚══════════════════════════════════════╝
  1320. */
  1321. USHORT NEAR AdptInterrupt( NPACB npACB )
  1322. {
  1323.    USHORT     Claimed = 0;
  1324.  
  1325.    if ( npACB )
  1326.    {
  1327.       DISABLE
  1328.  
  1329.       Claimed = 1;
  1330.  
  1331.       /*
  1332.       ┌─────────────────────────────────────────────────────────┐
  1333.       │ Read the controller status register to clear interrupt  │
  1334.       │ in case hardware is setup for level triggered operation │
  1335.       └─────────────────────────────────────────────────────────┘
  1336.       */
  1337.       GetRegister( npACB, FI_PSTATUS );
  1338.  
  1339.       if ( npACB->ISMFlags & ACBIF_INTERRUPT )
  1340.       {
  1341.  
  1342.          npACB->ISMFlags &= ~ACBIF_INTERRUPT;
  1343.  
  1344.          if ( npACB->IRQTimeOutHandle )
  1345.          {
  1346.             ADD_CancelTimer( npACB->IRQTimeOutHandle );
  1347.             npACB->IRQTimeOutHandle = 0;
  1348.          }
  1349.          else
  1350.          {
  1351.             _asm { int 3 }
  1352.          }
  1353.  
  1354.          DevHelp_EOI( npACB->IRQLevel );
  1355.  
  1356.          ENABLE
  1357.          StartISM( npACB );
  1358.       }
  1359.       else
  1360.       {
  1361.          npACB->SpuriousIRQ++;
  1362.  
  1363.          DevHelp_EOI( npACB->IRQLevel );
  1364.       }
  1365.    }
  1366.  
  1367.    return( ~Claimed );
  1368. } /* AdptInterrupt */
  1369.  
  1370. /*
  1371. ╔═════════════════════════════════════════════╗
  1372. ║                                             ║
  1373. ║  GetRegister                                ║
  1374. ║                                             ║
  1375. ║  Get the error data from the error register ║
  1376. ║                                             ║
  1377. ╚═════════════════════════════════════════════╝
  1378. */
  1379. USHORT NEAR GetRegister ( NPACB npACB, USHORT Register )
  1380. {
  1381.    USHORT Port;
  1382.    USHORT Data;
  1383.  
  1384.    Port = npACB->IOPorts[Register];
  1385.    inp ( Port, Data );
  1386.    return ( Data );
  1387.  
  1388. } /* GetRegister */
  1389.  
  1390. /* Begin [001] */
  1391.  
  1392. /*--------------------------------------------*/
  1393. /* CreateBMSGList                             */
  1394. /* --------------                             */
  1395. /*                                            */
  1396. /* Arguments:                                 */
  1397. /*                                            */
  1398. /*                                            */
  1399. /* Actions:                                   */
  1400. /*      Takes OS/2 scatter/gather list and    */
  1401. /*      builds SFF-8038i compatible list for  */
  1402. /*      DMA controller.                       */
  1403. /*                                            */
  1404. /*                                            */
  1405. /* Returns:                                   */
  1406. /*      0 if successful                       */
  1407. /*                                            */
  1408. /*                                            */
  1409. /*--------------------------------------------*/
  1410.  
  1411. int CreateBMSGList( NPACB npACB )
  1412. {
  1413.   USHORT          i;
  1414.   PPRD            pSGL;
  1415.   ULONG           BytesLeft;
  1416.   ULONG           PhysicalSgl;
  1417.   ULONG           PhysicalAddress;
  1418.   ULONG           Length;
  1419.   ULONG           LengthLeftInBoundary;
  1420.   ULONG           DescriptorCount = 0;
  1421.   ULONG           TempLength;
  1422.   PSCATGATENTRY   pSGList;
  1423.  
  1424.   /* get seg:off address of BM DMA scatter/gather table */
  1425.  
  1426.   if ( DevHelp_PhysToVirt( npACB->BMDMA_SGList, npACB->BMDMA_SGListSize,
  1427.                            &pSGL, &i ) )
  1428.   {
  1429.     return ( 1 );                       /* fail it */
  1430.   }
  1431.  
  1432. //  BytesLeft = npACB->BytesToTransfer;
  1433.   BytesLeft = npACB->npCmdIO->cXferBytesRemain;
  1434.  
  1435.   /* process each entry in OS/2 scatter/gather list */
  1436.  
  1437.   pSGList =  npACB->npCmdIO->IOSGPtrs.pSGList;
  1438.   for (i=0; i < npACB->npCmdIO->IOSGPtrs.cSGList; i++,pSGList++)
  1439.   {
  1440.  
  1441.     Length = pSGList->XferBufLen;       /* get length of memory region */
  1442.     PhysicalAddress = pSGList->ppXferBuf;
  1443.  
  1444.     if ( Length > BytesLeft )
  1445.     {
  1446. #ifdef DEBUG_WDCIDEOS
  1447.       {
  1448.         _asm int 3;
  1449.       }
  1450. #endif
  1451.       Length = BytesLeft;               /* Don't set up entry bigger than total */
  1452.     }                                   /* transfer length reported */
  1453.  
  1454.     if( (PhysicalAddress & 1) ||        /* if on odd byte boundary, do PIO */
  1455.         (Length & 1) )                  /* if odd transfer length, do PIO */
  1456.     {
  1457. #ifdef ENABLE_COUNTERS
  1458. //      ++npACB->npUCB->DeviceCounters.ByteMisalignedBuffers;
  1459. #endif
  1460.       return ( 1 );                     /* fail conversion */
  1461.     }
  1462.  
  1463.  
  1464.     while( Length )
  1465.     {
  1466.  
  1467.       pSGL->MR_PhysicalBaseAddress = PhysicalAddress;
  1468.       TempLength = Length;              /* make copy of total length */
  1469.  
  1470.       /* Can't exceed 64KB size per entry in BM DMA SG List */
  1471.  
  1472.       if( TempLength > MR_64K_LIMIT )
  1473.       {
  1474. #ifdef DEBUG_WDCIDEOS
  1475.         {
  1476.           _asm mov ax,1
  1477.           _asm int 3;
  1478.         }
  1479. #endif
  1480.  
  1481.         TempLength = MR_64K_LIMIT;      /* force to max size */
  1482.       }
  1483.  
  1484.       if ( TempLength > BytesLeft )
  1485.       {
  1486. #ifdef DEBUG_WDCIDEOS
  1487.         {
  1488.           _asm mov ax,2
  1489.           _asm int 3;
  1490.         }
  1491. #endif
  1492.  
  1493.         TempLength = BytesLeft;         /* Don't exceed remaining transfer length */
  1494.       }
  1495.  
  1496.       /* Can't cross 64KB boundary so check for it and adjust */
  1497.  
  1498.       LengthLeftInBoundary = MR_64K_LIMIT - (PhysicalAddress & (MR_64K_LIMIT-1));
  1499.       if ( TempLength > LengthLeftInBoundary )
  1500.       {
  1501.         TempLength = LengthLeftInBoundary;
  1502. #ifdef ENABLE_COUNTERS
  1503. //        ++npACB->npUCB->DeviceCounters.ByteMisalignedBuffers;
  1504. #endif
  1505.       }
  1506.  
  1507.       /* Adjust counts */
  1508.  
  1509.       PhysicalAddress += TempLength;
  1510.       Length -= TempLength;
  1511.       BytesLeft -= TempLength;
  1512.  
  1513.       /* Create SGL descriptor entry */
  1514.  
  1515.       pSGL->ByteCountAndEOT = (ULONG) TempLength;
  1516.       ++DescriptorCount;
  1517.       if(BytesLeft == 0)
  1518.       {
  1519.         pSGL->ByteCountAndEOT |= PRD_EOT_FLAG;
  1520.       }
  1521.       else if ( DescriptorCount > npACB->BMDMA_SGListCount )
  1522.       {
  1523. #ifdef DEBUG_WDCIDEOS
  1524.         {
  1525.           _asm mov ax,4
  1526.           _asm int 3;
  1527.         }
  1528. #endif
  1529.         return( 1 );                    /* ran out of descriptors */
  1530.  
  1531.       }
  1532.       pSGL++;
  1533.     } /* while( Length ) */
  1534.   } /* for (i=0; i < npACB->IOSGPtrs.cSGList; i++,pSGList++) */
  1535.  
  1536.   return( 0 );                          /* finished building sg list */
  1537. } /* End of CreateBMSGList */
  1538.  
  1539. /* End [001] */
  1540.