home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ddkx86v5.zip / DDKX86 / SRC / DEV / DASD / CDROM / ATAPI / ATAPIISM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-14  |  36.9 KB  |  1,182 lines

  1. /*DDK*************************************************************************/
  2. /*                                                                           */
  3. /* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
  4. /*                                                                           */
  5. /*    The following IBM OS/2 WARP source code is provided to you solely for  */
  6. /*    the purpose of assisting you in your development of OS/2 WARP device   */
  7. /*    drivers. You may use this code in accordance with the IBM License      */
  8. /*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
  9. /*    Copyright statement may not be removed.                                */
  10. /*                                                                           */
  11. /*****************************************************************************/
  12. /**************************************************************************
  13.  *
  14.  * SOURCE FILE NAME =     ATAPIISM.C
  15.  *
  16.  * DESCRIPTIVE NAME =     ATAPI Inner State Machine
  17.  *
  18.  *
  19.  *
  20.  * VERSION = 1.0
  21.  *
  22.  * DATE
  23.  *
  24.  * DESCRIPTION :
  25.  *
  26.  * Purpose:
  27.  *
  28.  *
  29.  *
  30.  *
  31.  *
  32. */
  33.  
  34. #define INCL_NOBASEAPI
  35. #define INCL_NOPMAPI
  36. #include "os2.h"
  37. #include "dos.h"
  38. #include "dskinit.h"
  39.  
  40. #include "iorb.h"
  41. #include "addcalls.h"
  42. #include "dhcalls.h"
  43.  
  44. #define INCL_INITRP_ONLY
  45. #include "reqpkt.h"
  46.  
  47. #include "scsi.h"
  48. #include "cdbscsi.h"
  49.  
  50. #include "atapicon.h"
  51. #include "atapireg.h"
  52. #include "atapityp.h"
  53. #include "atapiext.h"
  54. #include "atapipro.h"
  55.  
  56. /*
  57. ╔═════════════════════════════════════════════════════════════════════════════╗
  58. ║                                                                             ║
  59. ║  StartOSMRequest                                                            ║
  60. ║                                                                             ║
  61. ║  Outer State Machine Interface:  This routine initializes the inner state   ║
  62. ║  machine and sets up the outer state machine to go into a WAITSTATE until   ║
  63. ║  the inner state machine finishes the requested operation.                  ║
  64. ║                                                                             ║
  65. ╚═════════════════════════════════════════════════════════════════════════════╝
  66. */
  67. VOID FAR StartOSMRequest ( NPACB npACB )
  68. {
  69.   npACB->ISMState      = ACBIS_START_STATE;
  70.   npACB->ISMDoneReturn = StartOSM;
  71.   if (npACB->suspended)
  72.   {
  73.      _asm INT 3
  74.   }
  75.   StartISM ( npACB );
  76.  
  77. }
  78.  
  79. /*
  80. ╔════════════════════════════════════╗
  81. ║                                    ║
  82. ║  StartISM                          ║
  83. ║                                    ║
  84. ║  Inner State Machine Router        ║
  85. ║                                    ║
  86. ╚════════════════════════════════════╝
  87. */
  88.  
  89. VOID NEAR StartISM( NPACB npACB )
  90. {
  91.    VOID (FAR *ISMDoneReturn)( NPACB );
  92.  
  93.    DISABLE
  94.  
  95.    npACB->ISMUseCount++;
  96.  
  97.    if ( npACB->ISMUseCount == 1 )
  98.    {
  99.       do
  100.       {
  101.          ENABLE
  102.          npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  103.          do
  104.          {
  105.             switch ( npACB->ISMState )
  106.             {
  107.                case ACBIS_START_STATE:
  108.                   ISMStartState ( npACB );
  109.                   break;
  110.  
  111.                case ACBIS_INTERRUPT_STATE:
  112.                   InterruptState( npACB );
  113.                   break;
  114.  
  115.                case ACBIS_WRITE_ATAPI_PACKET_STATE:
  116.                   WriteATAPIPkt( npACB );
  117.                   break;
  118.  
  119.                case ACBIS_COMPLETE_STATE:
  120.                   npACB->ISMFlags |= ACBIF_WAITSTATE;
  121.                   npACB->ISMUseCount = 1;
  122.                   npACB->OSMState = ACBOS_ISM_COMPLETE;
  123.                   break;
  124.  
  125.                default :
  126.                   /* unknown state */
  127.                   npACB->ISMUseCount = 1;
  128.                   npACB->ISMFlags |= ACBIF_WAITSTATE;
  129.                   break;
  130.             }
  131.          }
  132.          while ( !(npACB->ISMFlags & ACBIF_WAITSTATE) );
  133.  
  134.          DISABLE
  135.       }
  136.       while ( --npACB->ISMUseCount );
  137.    }
  138.    ENABLE
  139.  
  140.    if ( npACB->ISMState == ACBIS_COMPLETE_STATE )
  141.    {
  142.       DISABLE
  143.       if (npACB->ISMDoneReturn)
  144.       {
  145.          ISMDoneReturn = npACB->ISMDoneReturn;
  146.          npACB->ISMDoneReturn = 0;
  147.          ENABLE
  148.          (*ISMDoneReturn)( npACB );
  149.       }
  150.       else
  151.          ENABLE
  152.  
  153.    } /* endif */
  154. } /* StartISM */
  155.  
  156. /*
  157. ╔════════════════════════════════════╗
  158. ║                                    ║
  159. ║  ISMStartState                     ║
  160. ║                                    ║
  161. ║  Initializes the Inner State       ║
  162. ║  Machine                           ║
  163. ║                                    ║
  164. ╚════════════════════════════════════╝
  165. */
  166.  
  167. VOID NEAR ISMStartState ( NPACB npACB )
  168. {
  169.    USHORT  Status;
  170.  
  171.    DISABLE
  172.  
  173.    if (!( npACB->OSMReqFlags & ACBR_RESET ) &&                      /*V@106915*/
  174.       ( !DRQ_AND_BSY_CLEAR_WAIT( npACB ) ) )                         /*V@93531*/
  175.            /* Max Poll wait time exceeded */
  176.    {
  177.       npACB->ISMState = ACBIS_COMPLETE_STATE;
  178.       npACB->OSMReqFlags |= ACBR_RESET;  /* Set OSM for reset */
  179.       ENABLE
  180.    }
  181.    else
  182.    {
  183.       ENABLE
  184.       InitializeISM( npACB );
  185.       /*
  186.       ┌────────────────────────────────────────┐
  187.       │ Do not write packet if unknown command │
  188.       └────────────────────────────────────────┘
  189.       */
  190.       if (npACB->IORBError & IOERR_CMD_NOT_SUPPORTED)
  191.       {
  192.          npACB->ISMState = ACBIS_COMPLETE_STATE;
  193.          npACB->ISMDoneReturn = 0;
  194.       }
  195.       else
  196.  
  197.          if ( !(npACB->ISMFlags & ACBIF_ATA_OPERATION) )
  198.             StartATAPICmd ( npACB );
  199.          else
  200.             StartATACmd ( npACB );
  201.  
  202.    } /* endif */
  203.  
  204. }
  205.  
  206. /*
  207. ╔══════════════════════════════════════╗
  208. ║                                      ║
  209. ║  InterruptState                      ║
  210. ║                                      ║
  211. ║  Routes interrupt generated threads  ║
  212. ║  to the selected interrupt function  ║
  213. ║                                      ║
  214. ╚══════════════════════════════════════╝
  215. */
  216. VOID NEAR InterruptState( NPACB npACB )
  217. {
  218.    USHORT Status;
  219.    USHORT INTReason;
  220.    USHORT cXferBytes;
  221.    USHORT cShortBytes;
  222.    USHORT ByteBucket;
  223.    USHORT Port;
  224.    USHORT OddWord;
  225.    USHORT cExtraBytes = 0;
  226.    USHORT Reason = 0;
  227.    USHORT DEBUGONold;
  228.  
  229.    if ( !(npACB->TimerFlags & ACBT_INTERRUPT) )
  230.    {
  231.  
  232.       Status    = GetRegister ( npACB, FI_PSTATUS );
  233.       while ( Status & FX_BUSY )
  234.       {
  235.          Status    = GetRegister ( npACB, FI_PSTATUS );
  236.       }
  237.  
  238.       INTReason = GetRegister ( npACB, FI_PINTREASON );
  239.       npACB->IORegs[FI_PSTATUS]    = Status;
  240.       npACB->IORegs[FI_PINTREASON] = INTReason;
  241.  
  242.  
  243.                               /* ┌─────────────────────────────────────────┐ */
  244.                               /* │Interrupt Reason  (Defined in ATAPIREG.H)│ */
  245.       if (INTReason & IRR_IO) /* │                                         │ */
  246.          Reason  |= IRM_IO;   /* │ IO    DRQ   COD    #define value        │ */
  247.       if (Status & FX_DRQ)    /* │  0     1     1     IR_PKTREADY          │ */
  248.          Reason |= IRM_DRQ;   /* │  1     1     1     IR_MESSAGE           │ */
  249.       if (INTReason & IRR_COD)/* │  1     1     0     IR_XFER_FROM_DEVICE  │ */
  250.          Reason |= IRM_COD;   /* │  0     1     0     IR_XFER_TO_DEVICE    │ */
  251.                               /* │  1     0     1     IR_COMPLETE          │ */
  252.                               /* └─────────────────────────────────────────┘ */
  253.  
  254.       if ( npACB->ISMFlags & ACBIF_ATA_OPERATION )
  255.          Reason = IRM_IO | IRM_DRQ;
  256.  
  257.       /*
  258.       ┌───────────────────────────────────────────────────────────────────────┐
  259.       │ The 1.7 spec indicates that the completion status only relies on the  │
  260.       │ DRQ bit being 0.  If we are in 1.7B compatibility mode and the DRQ    │
  261.       │ bit is 0, set the reason variable to IR_COMPLETE.                     │
  262.       └───────────────────────────────────────────────────────────────────────┘
  263.       */
  264.  
  265.       else if (/*( npACB->npUCB->Capabilities & UCBC_SPEC_REV_17B) && */
  266.                                                          !(Status & FX_DRQ))
  267.          Reason |= IRM_IO | IRM_COD;
  268.  
  269.       /*
  270.       ┌─────────────────────────────────────────────────┐
  271.       │ If there was an error, go to the complete phase │
  272.       └─────────────────────────────────────────────────┘
  273.       */
  274.       if ( Status & FX_ERROR )
  275.          Reason = IR_COMPLETE;
  276.  
  277.       switch (Reason)
  278.       {
  279.          case IR_PKTREADY :
  280.             npACB->ISMState = ACBIS_WRITE_ATAPI_PACKET_STATE;
  281.             npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  282.             break;
  283.  
  284.          case IR_XFER_FROM_DEVICE :
  285.  
  286.             if (npACB->npCmdIO->IOSGPtrs.Mode == SGLIST_TO_PORT)
  287.             {
  288.                _asm { int 3 }       /* Expecting to go the opposite direction */
  289.             } /* endif */
  290.  
  291.             if ( npACB->ISMFlags & ACBIF_ATA_OPERATION )
  292.             {
  293.                cXferBytes = npACB->npCmdIO->cXferBytesRemain;
  294.                npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  295.                npACB->ISMState = ACBIS_COMPLETE_STATE;
  296.  
  297.             }
  298.             else
  299.             {
  300.                npACB->IORegs[FI_PBYTECTH] = GetRegister( npACB, FI_PBYTECTH );
  301.                npACB->IORegs[FI_PBYTECTL] = GetRegister( npACB, FI_PBYTECTL );
  302.  
  303.                cXferBytes = MAKEUSHORT( npACB->IORegs[FI_PBYTECTL],
  304.                                         npACB->IORegs[FI_PBYTECTH]);
  305.             }
  306.  
  307.             if (cXferBytes & 1)
  308.             {
  309.                cXferBytes++;
  310.             }
  311.             /*
  312.             ┌──────────────────────────────────────────────────────────────────┐
  313.             │ If overrun, determine amount of extra bytes to transfer, and set │
  314.             │ IOSGPtrs count to get only the number of bytes we are expecting  │
  315.             └──────────────────────────────────────────────────────────────────┘
  316.             */
  317.  
  318.             if ( cXferBytes > npACB->npCmdIO->cXferBytesRemain )
  319.             {
  320.                cExtraBytes = cXferBytes - npACB->npCmdIO->cXferBytesRemain;
  321.                cXferBytes = npACB->npCmdIO->cXferBytesRemain;
  322.             }
  323.  
  324.             npACB->npCmdIO->IOSGPtrs.numTotalBytes = cXferBytes;
  325.  
  326.             /*
  327.             ┌────────────────────────────────────────────────────────┐
  328.             │ Start the interrupt timer if this is an ATAPI transfer │
  329.             └────────────────────────────────────────────────────────┘
  330.             */
  331.  
  332.             if ( !(npACB->ISMFlags & ACBIF_ATA_OPERATION) )
  333.             {
  334.                DISABLE
  335.                if ( npACB->ISMFlags & ACBIF_INTERRUPT )
  336.                {
  337.                   INT3
  338.                }
  339.                npACB->ISMFlags |= (ACBIF_WAITSTATE | ACBIF_INTERRUPT);
  340.  
  341.                if ( ADD_StartTimerMS((PULONG) &npACB->IRQTimeOutHandle,
  342.                                      (ULONG)  npACB->IRQTimeOut,
  343.                                      (PFN)    IRQTimeOutHandler,
  344.                                      (PVOID)  npACB,
  345.                                      (ULONG)  0                      ) )
  346.                {
  347.                   _asm { int 3 }
  348.                } /* endif */
  349.             }
  350.  
  351.             /*
  352.             ┌─────────────────────────────────────────┐
  353.             │ Device will prepare for next interrupt  │
  354.             │ after last byte is transfered to host   │
  355.             └─────────────────────────────────────────┘
  356.             */
  357.  
  358.             ENABLE
  359.             ADD_XferIOW( &npACB->npCmdIO->IOSGPtrs );
  360.  
  361.             /*
  362.             ┌───────────────────────────────────────────────────┐
  363.             │ if extra bytes remain, put them in the byte bucket│
  364.             └───────────────────────────────────────────────────┘
  365.             */
  366.  
  367.             while ( cExtraBytes )
  368.             {
  369.                inwp( Port , ByteBucket );
  370.                cExtraBytes-=2;
  371.             } /* endwhile */
  372.  
  373.  
  374.             /*
  375.             ┌─────────────────────────────────────┐
  376.             │ Adjust counts to show last transfer │
  377.             └─────────────────────────────────────┘
  378.             */
  379.             npACB->npCmdIO->cXferBytesComplete += cXferBytes;
  380.             npACB->npCmdIO->cXferBytesRemain   -= cXferBytes;
  381.  
  382.             /*
  383.             ┌───────────────────────────────────────────────────────────────┐
  384.             │ If an odd byte count was requested, and we have finished the  │
  385.             │ even portion of the transfer, get the last byte and put it in │
  386.             │ the S/G list.                                                 │
  387.             └───────────────────────────────────────────────────────────────┘
  388.             */
  389.             if ( !(npACB->npCmdIO->cXferBytesRemain) &&
  390.                                       ( npACB->ISMFlags & ACBIF_ODD_BYTE_XFER) )
  391.             {
  392.                inwp(Port, OddWord);
  393.                PutByteInSGList ( npACB, OddWord );
  394.  
  395.                npACB->npCmdIO->cXferBytesComplete++;
  396.             } /* endif */
  397.             break;
  398.  
  399.          case IR_XFER_TO_DEVICE :
  400.             if (npACB->npCmdIO->IOSGPtrs.Mode == PORT_TO_SGLIST)
  401.             {
  402.                DISABLE
  403.                _asm { int 3 }       /* Expecting to go the opposite direction */
  404.                ENABLE
  405.             } /* endif */
  406.  
  407.             npACB->IORegs[FI_PBYTECTH] = GetRegister( npACB, FI_PBYTECTH );
  408.             npACB->IORegs[FI_PBYTECTL] = GetRegister( npACB, FI_PBYTECTL );
  409.  
  410.             cXferBytes = MAKEUSHORT( npACB->IORegs[FI_PBYTECTL],
  411.                                      npACB->IORegs[FI_PBYTECTH]);
  412.  
  413.             /*
  414.             ┌──────────────────────────────────────────────────────────────────┐
  415.             │ If underrun, set IOSGPtrs count to send only the number of bytes │
  416.             │ the device is expecting.  Set up cExtraBytes to fill remaining   │
  417.             │ bytes with 0's                                                   │
  418.             └──────────────────────────────────────────────────────────────────┘
  419.             */
  420.  
  421.             if ( cXferBytes > npACB->npCmdIO->cXferBytesRemain )
  422.             {
  423.                cExtraBytes = cXferBytes - npACB->npCmdIO->cXferBytesRemain;
  424.                cXferBytes = npACB->npCmdIO->cXferBytesRemain;
  425.             }
  426.  
  427.             npACB->npCmdIO->IOSGPtrs.numTotalBytes = cXferBytes;
  428.  
  429.             /*
  430.             ┌───────────────────────────┐
  431.             │ Start the interrupt timer │
  432.             └───────────────────────────┘
  433.             */
  434.  
  435.             DISABLE
  436.                if ( npACB->ISMFlags & ACBIF_INTERRUPT )
  437.                {
  438.                   INT3
  439.                }
  440.             npACB->ISMFlags |= (ACBIF_WAITSTATE | ACBIF_INTERRUPT);
  441.             if ( ADD_StartTimerMS((PULONG) &npACB->IRQTimeOutHandle,
  442.                                   (ULONG)  npACB->IRQTimeOut,
  443.                                   (PFN)    IRQTimeOutHandler,
  444.                                   (PVOID)  npACB,
  445.                                   (ULONG)  0                      ) )
  446.             {
  447.                _asm { int 3 }
  448.             } /* endif */
  449.  
  450.             /*
  451.             ┌──────────────────────────────────────────┐
  452.             │ Device will prepare for next interrupt   │
  453.             │ after last byte is transfered from host  │
  454.             └──────────────────────────────────────────┘
  455.             */
  456.  
  457.             ENABLE
  458.             ADD_XferIOW( &npACB->npCmdIO->IOSGPtrs );
  459.  
  460.             /*
  461.             ┌───────────────────────────────────────────────────┐
  462.             │ if device expected more, give it zeros            │
  463.             └───────────────────────────────────────────────────┘
  464.             */
  465.  
  466.             Port = npACB->npCmdIO->IOSGPtrs.iPortAddress;
  467.  
  468.             while ( cExtraBytes )
  469.             {
  470.                outwp( Port , 0 );
  471.                cExtraBytes-=2;
  472.             } /* endwhile */
  473.  
  474.             npACB->npCmdIO->cXferBytesComplete += cXferBytes;
  475.             npACB->npCmdIO->cXferBytesRemain   -= cXferBytes;
  476.  
  477.             break;
  478.  
  479.          case IR_COMPLETE :
  480.  
  481.             /* if an error, get the error register */
  482.  
  483.             if (Status & FX_ERROR )
  484.             {
  485.                npACB->IORegs[FI_PERROR] = GetRegister( npACB, FI_PERROR );
  486.                npACB->OSMReqFlags |= ACBR_SENSE_DATA;
  487.             }
  488.             else if ( !(npACB->ISMFlags & ACBIF_ATA_OPERATION) &&
  489.                        (npACB->npCmdIO->IOSGPtrs.Mode == PORT_TO_SGLIST))
  490.             {
  491.                /*
  492.                ┌───────────────────────────────────────────────────────────┐
  493.                │ if the device did not give us as many bytes as we asked   │
  494.                │ for fill the remaining portion of the SG List with 0's.   │
  495.                └───────────────────────────────────────────────────────────┘
  496.                */
  497.                while ( npACB->npCmdIO->cXferBytesRemain )
  498.                {
  499.                   if (npACB->npCmdIO->IOSGPtrs.SGOffset ==
  500.                      npACB->npCmdIO->IOSGPtrs.pSGList
  501.                               [npACB->npCmdIO->IOSGPtrs.iSGList].XferBufLen)
  502.                   {
  503.                      npACB->npCmdIO->IOSGPtrs.SGOffset = 0;
  504.                      npACB->npCmdIO->IOSGPtrs.iSGList++;
  505.                   }
  506.  
  507.                   PutByteinSGList ( npACB, 0 );
  508.                   npACB->npCmdIO->cXferBytesComplete++;
  509.                   npACB->npCmdIO->cXferBytesRemain--;
  510.                } /* endwhile */
  511.             } /* end else */
  512.  
  513.  
  514.             npACB->ISMState  = ACBIS_COMPLETE_STATE;
  515.             break;
  516.  
  517.          default :
  518.  
  519. //            INT3
  520.  
  521.             npACB->ISMState = ACBIS_COMPLETE_STATE;
  522.             break;
  523.  
  524.       } /* endswitch */
  525.  
  526.    }
  527.    else
  528.    {
  529.       /*
  530.       ┌────────────────────────┐
  531.       │ An Interrupt Timed Out │
  532.       └────────────────────────┘
  533.       */
  534.       npACB->ISMState = ACBIS_COMPLETE_STATE;
  535.       npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  536.       npACB->OSMReqFlags |= ACBR_RESET;
  537.    } /* endif */
  538.  
  539. } /* InterruptState */
  540.  
  541. /*
  542. ╔═══════════════════════════════════════╗
  543. ║                                       ║
  544. ║  PutByteInSGList                      ║
  545. ║                                       ║
  546. ║  Puts the next byte from the port     ║
  547. ║  address in the next SGList location  ║
  548. ║                                       ║
  549. ╚═══════════════════════════════════════╝
  550. */
  551. VOID NEAR PutByteInSGList ( NPACB npACB, USHORT Data )
  552. {
  553.    PSCATGATENTRY pSGE;    /* Current S/G List Entry          */
  554.    ULONG         ppDst;   /* Physical Address of Destination */
  555.    PBYTE         pDst;    /* Virtual Address of Destination  */
  556.    USHORT        ModeFlag;
  557.  
  558.    pSGE   = &npACB->npCmdIO->IOSGPtrs.pSGList[npACB->npCmdIO->IOSGPtrs.iSGList];
  559.                                         /* Point to the current entry */
  560.    ppDst  = pSGE->ppXferBuf + npACB->npCmdIO->IOSGPtrs.SGOffset;
  561.                                         /* Offset in current entry */
  562.  
  563.    if ( DevHelp_PhysToVirt( (ULONG)   ppDst,
  564.                              (USHORT)  1,
  565.                              (PVOID)   &pDst,
  566.                              (PUSHORT) &ModeFlag  ) )
  567.    {
  568.       _asm { int 3 }
  569.    }
  570.  
  571.    *pDst = (UCHAR) (Data >> 8); /* Store the Byte   */
  572. }
  573.  
  574. /*
  575. ╔═══════════════════════════════════════╗
  576. ║                                       ║
  577. ║  WriteATAPIPkt                        ║
  578. ║                                       ║
  579. ║  Write ATAPI command packet to data   ║
  580. ║  register                             ║
  581. ║                                       ║
  582. ╚═══════════════════════════════════════╝
  583. */
  584. VOID NEAR WriteATAPIPkt ( NPACB npACB )
  585. {
  586.    USHORT Port,i;
  587.    USHORT Data;
  588.  
  589.    Port = npACB->IOPorts[FI_PDATA];
  590.  
  591.    if ( !BSY_CLR_DRQ_SET_WAIT( npACB ) )                             /*V@93531*/
  592.              /* Max Poll wait time exceeded */                       /*V@93531*/
  593.    {                                                                 /*V@93531*/
  594.       npACB->ISMState = ACBIS_COMPLETE_STATE;                        /*V@93531*/
  595.       npACB->OSMReqFlags |= ACBR_RESET;  /* Set OSM for reset */     /*V@93531*/
  596.    }                                                                 /*V@93531*/
  597.    else
  598.    {
  599.       /*
  600.       ┌───────────────────────────┐
  601.       │ Start the interrupt timer │
  602.       └───────────────────────────┘
  603.       */
  604.       DISABLE
  605.       if ( npACB->ISMFlags & ACBIF_INTERRUPT )
  606.       {
  607.          INT3
  608.       }
  609.       npACB->ISMFlags |= (ACBIF_WAITSTATE | ACBIF_INTERRUPT);
  610.       npACB->ISMState = ACBIS_INTERRUPT_STATE;
  611.  
  612.       if ( ADD_StartTimerMS((PULONG) &npACB->IRQTimeOutHandle,
  613.                             (ULONG)  npACB->IRQTimeOut,
  614.                             (PFN)    IRQTimeOutHandler,
  615.                             (PVOID)  npACB,
  616.                             (ULONG)  0                      ) )
  617.       {
  618.          _asm { int 3 }
  619.       } /* endif */
  620.  
  621.       i=0;
  622.       do
  623.       {
  624.          Data = MAKEUSHORT(npACB->npCmdIO->ATAPIPkt[i],
  625.                            npACB->npCmdIO->ATAPIPkt[i+1]);  /*  MAKEUSHORT (h,l)  */
  626.          i+=2;
  627.          outwp( Port, Data );
  628.          IODelay ();
  629.       } while ( i < npACB->npUCB->CmdPacketLength);
  630.  
  631.       ENABLE
  632.  
  633.    }
  634.  
  635. } /* WriteATAPIPkt */
  636.  
  637. /*
  638. ╔════════════════════════════════════╗
  639. ║                                    ║
  640. ║  StartATAPICmd                     ║
  641. ║                                    ║
  642. ║  Write an ATAPI CMD and Paramters  ║
  643. ║                                    ║
  644. ╚════════════════════════════════════╝
  645. */
  646. VOID NEAR StartATAPICmd ( NPACB npACB )
  647. {
  648.    USHORT Port;
  649.    USHORT Data;
  650.    USHORT Status;
  651.    USHORT i;
  652.    USHORT IOMask;
  653.    USHORT Flags;
  654.    USHORT cBytes;
  655.  
  656.    /* Set Drive Select Register */
  657.    npACB->IORegs[FI_PDRVSLCT] =
  658.            DEFAULT_ATAPI_DRV_SLCT_REG | ((npACB->UnitId == 0) ? UNIT0 : UNIT1 );
  659.  
  660.    IOMask = FM_PATAPI_CMD;              /* Registers mask for ATAPI Cmd pkt */
  661.    Flags  = npACB->ISMFlags;
  662.  
  663.    /* Set Feature Register Data ( DMA OFF ) */
  664.    npACB->IORegs[FI_PFEATURE] = DEFAULT_ATAPI_FEATURE_REG & ~DMA_ON;
  665.  
  666.    cBytes = npACB->npCmdIO->cXferBytesRemain;
  667.    if ( cBytes > MAX_XFER_BYTES_PER_INTERRUPT )
  668.       cBytes = MAX_XFER_BYTES_PER_INTERRUPT;
  669.  
  670.    /* Set Byte Count registers (Low and High order) */
  671.    npACB->IORegs[FI_PBYTECTH] = cBytes >> 8;
  672.    npACB->IORegs[FI_PBYTECTL] = cBytes & LOW_BYTE_MASK;
  673.  
  674.    /*
  675.    ┌───────────────────────────────────────────────────────────────────────────┐
  676.    │ The LBA bit of the ATAPI Drive Select Register is a reserved bit starting │
  677.    │ in revision 1.2, and therefore must be set to 0.  However, in the earlier │
  678.    │ specs, the LBA bit must be 1.                                             │
  679.    └───────────────────────────────────────────────────────────────────────────┘
  680.    */
  681.  
  682.    if ( npACB->npUCB->Capabilities & UCBC_SPEC_REV_17B)
  683.    {
  684.       npACB->IORegs[FI_PDRVSLCT] |= REV_17B_SET_LBA;
  685.    } /* endif */
  686.  
  687.    /* Set Command Register with ATAPI Command */
  688.    npACB->IORegs[FI_PCMD] = FX_PKTCMD;
  689.  
  690.    if ( npACB->npUCB->Capabilities & UCBC_INTERRUPT_DRQ )
  691.    {
  692.       DISABLE
  693.       if (npACB->ISMFlags & ACBIF_INTERRUPT)
  694.       {
  695.          INT3
  696.       }
  697.       npACB->ISMFlags |= (ACBIF_WAITSTATE | ACBIF_INTERRUPT);
  698.       npACB->ISMState = ACBIS_INTERRUPT_STATE;
  699.  
  700.       /*
  701.       ┌───────────────────────────┐
  702.       │ Start the interrupt timer │
  703.       └───────────────────────────┘
  704.       */
  705.  
  706.       if ( ADD_StartTimerMS((PULONG) &npACB->IRQTimeOutHandle,
  707.                             (ULONG)  npACB->IRQTimeOut,
  708.                             (PFN)    IRQTimeOutHandler,
  709.                             (PVOID)  npACB,
  710.                             (ULONG)  0                      ) )
  711.       {
  712.          _asm { int 3 }
  713.       } /* endif */
  714.       ENABLE
  715.    }
  716.    else
  717.    {
  718.       npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  719.       npACB->ISMState = ACBIS_WRITE_ATAPI_PACKET_STATE;
  720.    }
  721.  
  722.    /*
  723.    ┌──────────────────────────┐
  724.    │ Write selected registers │
  725.    └──────────────────────────┘
  726.    */
  727.    for ( i = FI_PFEATURE; IOMask; i++ )
  728.    {
  729.      IOMask >>= 1;
  730.  
  731.      if ( IOMask & 0x0001 )
  732.      {
  733.        Port = npACB->IOPorts[i];
  734.        Data = npACB->IORegs[i];
  735.        outp( Port, Data);
  736.        IODelay();
  737.      }
  738.    }
  739.  
  740. } /* StartATAPICmd */
  741.  
  742. /*
  743. ╔════════════════════════════════════╗
  744. ║                                    ║
  745. ║  StartATACmd                       ║
  746. ║                                    ║
  747. ║  Write an ATA CMD and Paramters    ║
  748. ║                                    ║
  749. ╚════════════════════════════════════╝
  750. */
  751. VOID NEAR StartATACmd ( NPACB npACB )
  752. {
  753.  
  754.    USHORT Port;
  755.    USHORT Data;
  756.    USHORT Status;
  757.    USHORT i;
  758.    USHORT IOMask;
  759.    USHORT Flags;
  760.  
  761.    IOMask = FM_PATA_CMD;              /* Registers mask for ATA Commands */
  762.  
  763.    Flags  = npACB->ISMFlags;
  764.  
  765.    /* Set Drive Select Register */
  766.    npACB->IORegs[FI_PDRVSLCT] =
  767.            DEFAULT_ATAPI_DRV_SLCT_REG | ((npACB->UnitId == 0) ? UNIT0 : UNIT1 );
  768.  
  769.    /* Set Command Register with ATA Command */
  770.    if ( npACB->npUCB->ReqFlags & UCBR_IDENTIFY )
  771.    {
  772.       npACB->IORegs[FI_PCMD] = FX_IDENTIFYDRIVE;
  773.  
  774.       DISABLE
  775.       if (npACB->ISMFlags & ACBIF_INTERRUPT)
  776.       {
  777.          INT3
  778.       }
  779.       npACB->ISMFlags |= (ACBIF_INTERRUPT | ACBIF_WAITSTATE);
  780.       npACB->ISMState = ACBIS_INTERRUPT_STATE;
  781.  
  782.       /*
  783.       ┌───────────────────────────┐
  784.       │ Start the interrupt timer │
  785.       └───────────────────────────┘
  786.       */
  787.  
  788.       if ( ADD_StartTimerMS((PULONG) &npACB->IRQTimeOutHandle,
  789.                             (ULONG)  npACB->IRQTimeOut,
  790.                             (PFN)    IRQTimeOutHandler,
  791.                             (PVOID)  npACB,
  792.                             (ULONG)  0                      ) )
  793.       {
  794.          _asm { int 3 }
  795.       } /* endif */
  796.       ENABLE
  797.  
  798.    }
  799.  
  800.    else if ( npACB->npUCB->ReqFlags & UCBR_RESET )
  801.    {
  802.       npACB->IORegs[FI_PCMD] = FX_SOFTRESET;
  803.       npACB->ISMState = ACBIS_COMPLETE_STATE;
  804.       npACB->ISMFlags &= ~ACBIF_WAITSTATE;
  805.    }
  806.  
  807.    else
  808.    {
  809.       INT3
  810.    }
  811.  
  812.  
  813.    /*
  814.    ┌──────────────────────────┐
  815.    │ Write selected registers │
  816.    └──────────────────────────┘
  817.    */
  818.    for ( i = FI_PFEATURE; IOMask; i++ )
  819.    {
  820.      IOMask >>= 1;
  821.  
  822.      if ( IOMask & 0x0001 )
  823.      {
  824.        Port = npACB->IOPorts[i];
  825.        Data = npACB->IORegs[i];
  826.        outp( Port, Data);
  827.        IODelay();
  828.      }
  829.    }
  830.  
  831. }
  832.  
  833. /*
  834. ╔═══════════════════════════════════════╗
  835. ║                                       ║
  836. ║  InitializeISM                        ║
  837. ║                                       ║
  838. ║  Initializes state and flag variables ║
  839. ║                                       ║
  840. ╚═══════════════════════════════════════╝
  841. */
  842. VOID NEAR InitializeISM ( NPACB npACB )
  843. {
  844.      UCHAR                  Opcode;
  845.      struct CDB_ModeSense_10  NEAR *pModeSenseCmd; /* in order to fix 1.7B drives */
  846.      struct CDB_PlayAudio_MSF NEAR *pPlayAudioMSFCmd;
  847.  
  848.    if ( !( npACB->ISMFlags & ACBIF_ATA_OPERATION ) )
  849.    {
  850.       /*
  851.       ┌────────────────────────────┐
  852.       │ set opcode dependent flags │
  853.       └────────────────────────────┘
  854.       */
  855.  
  856.       Opcode = npACB->npCmdIO->ATAPIPkt[0];
  857.  
  858.       switch( Opcode )
  859.       {
  860.          /* Immediate Commands - complete after returning status */
  861.  
  862.          case ATAPI_AUDIO_SCAN :
  863.          case SCSI_PLAY_AUDIO_10 :
  864.          case SCSI_PLAY_AUDIO_12 :
  865.          case SCSI_PLAY_MSF :
  866.          case SCSI_PLAY_TRACK_REL :
  867.          case SCSI_PLAY_TRACK_REL_12 :
  868.          case SCSI_SEEK_10 :
  869.  
  870.          /* Completion Status Only */
  871.  
  872.          case SCSI_START_STOP_UNIT :
  873.          case SCSI_PAUSE_RESUME :
  874.          case SCSI_LOCK_UNLOCK :
  875.          case SCSI_REZERO_UNIT :
  876.          case ATAPI_SET_CDROM_SPEED :
  877.          case ATAPI_STOP_PLAYSCAN :
  878.          case SCSI_TEST_UNIT_READY :
  879.  
  880.             npACB->ISMFlags |= (ACBIF_COMPLETION_STATUS_ONLY | ACBIF_WAITSTATE);
  881.             break;
  882.  
  883.          /* Single IO */
  884.          case SCSI_INQUIRY :
  885.          case SCSI_READ_CAPACITY :
  886.          case SCSI_MODE_SENSE_10 :
  887.          case SCSI_READ_HEADER :
  888.          case SCSI_READ_SUB_CHAN :
  889.          case SCSI_READ_TOC :
  890.          case SCSI_REQUEST_SENSE :
  891.  
  892.             npACB->ISMFlags |= (ACBIF_SINGLEIO | ACBIF_WAITSTATE);
  893.             break;
  894.  
  895.          /* Block IO */
  896.          case SCSI_READ_10 :
  897.          case SCSI_READ_12 :
  898.          case ATAPI_READ_CD :
  899.          case ATAPI_READ_CD_MSF :
  900.  
  901.             npACB->ISMFlags |= (ACBIF_MULTIPLEIO | ACBIF_WAITSTATE);
  902.             break;
  903.  
  904.          case SCSI_MODE_SELECT_10 :
  905.             npACB->ISMFlags |= (ACBIF_MULTIPLEIO | ACBIF_WAITSTATE);
  906.             /*
  907.             ┌───────────────────────────────────┐
  908.             │ change default transfer direction │
  909.             └───────────────────────────────────┘
  910.             */
  911.             npACB->npCmdIO->IOSGPtrs.Mode = SGLIST_TO_PORT;
  912.  
  913.             break;
  914.  
  915.          default :
  916.             if ( !(npACB->ISMFlags & ACBIF_ATA_OPERATION) )
  917.             {
  918.                npACB->ISMFlags |=  ACBIF_WAITSTATE;
  919.                break;
  920.             }
  921.       } /* endswitch */
  922.  
  923.       /*
  924.       ┌───────────────────────────────────────────────┐
  925.       │ If drive is only revision 1.7B compatible,    │
  926.       │ change the opcodes to the 1.7B spec's opcodes │
  927.       │ and fix the inconsistancies in the data       │
  928.       └───────────────────────────────────────────────┘
  929.       */
  930.       if ( npACB->npUCB->Capabilities & UCBC_SPEC_REV_17B)
  931.       {
  932.          switch (Opcode)
  933.          {
  934.          case ATAPI_AUDIO_SCAN :
  935.             npACB->npCmdIO->ATAPIPkt[0] = REV_17B_ATAPI_AUDIO_SCAN;
  936.             break;
  937.  
  938.          case ATAPI_SET_CDROM_SPEED :
  939.             npACB->npCmdIO->ATAPIPkt[0] = REV_17B_ATAPI_SET_CDROM_SPEED;
  940.             break;
  941.  
  942.          case ATAPI_READ_CD :
  943.             npACB->npCmdIO->ATAPIPkt[0] = REV_17B_ATAPI_READ_CD;
  944.             break;
  945.  
  946.          case ATAPI_READ_CD_MSF :
  947.             npACB->npCmdIO->ATAPIPkt[0] = REV_17B_ATAPI_READ_CD_MSF;
  948.             break;
  949.  
  950.          case SCSI_PLAY_MSF :
  951.             pPlayAudioMSFCmd =
  952.                      (struct CDB_PlayAudio_MSF NEAR *)npACB->npCmdIO->ATAPIPkt;
  953.             /* silly 1.7B drives want this data in BCD */
  954.             pPlayAudioMSFCmd->starting_M = x2BCD(pPlayAudioMSFCmd->starting_M);
  955.             pPlayAudioMSFCmd->starting_S = x2BCD(pPlayAudioMSFCmd->starting_S);
  956.             pPlayAudioMSFCmd->starting_F = x2BCD(pPlayAudioMSFCmd->starting_F);
  957.             pPlayAudioMSFCmd->ending_M   = x2BCD(pPlayAudioMSFCmd->ending_M);
  958.             pPlayAudioMSFCmd->ending_S   = x2BCD(pPlayAudioMSFCmd->ending_S);
  959.             pPlayAudioMSFCmd->ending_F   = x2BCD(pPlayAudioMSFCmd->ending_F);
  960.             break;
  961.  
  962.          case SCSI_MODE_SENSE_10 :
  963.             pModeSenseCmd =
  964.                       (struct CDB_ModeSense_10  NEAR *)npACB->npCmdIO->ATAPIPkt;
  965.             if (pModeSenseCmd->page_code == PAGE_CAPABILITIES)
  966.             {
  967.                pModeSenseCmd->page_code = REV_17B_PAGE_CAPABILITIES;
  968.             }
  969.  
  970.          default :
  971.             break;
  972.          } /* endswitch */
  973.       } /* endif */
  974.    }
  975.    /*
  976.    ┌────────────────────┐
  977.    │ Odd Byte Transfers │
  978.    └────────────────────┘
  979.    */
  980.    if ( npACB->npCmdIO->IOSGPtrs.numTotalBytes & 1 )  /* Is this an odd byte transfer? */
  981.    {
  982.       if (npACB->npCmdIO->IOSGPtrs.Mode == PORT_TO_SGLIST)
  983.       {
  984.          npACB->npCmdIO->IOSGPtrs.numTotalBytes -= 1; /* Must be even transfer Amount */
  985.          npACB->ISMFlags |= ACBIF_ODD_BYTE_XFER;
  986.       }
  987.       else
  988.       {
  989.          npACB->npCmdIO->IOSGPtrs.numTotalBytes += 1; /* Must be even transfer Amount */
  990.       } /* endif */
  991.    } /* endif */
  992. }
  993.  
  994. /*
  995. ╔════════════════════════════════════╗
  996. ║                                    ║
  997. ║  IRQTimeOutHandler                 ║
  998. ║                                    ║
  999. ║  Times out the interrupt           ║
  1000. ║                                    ║
  1001. ╚════════════════════════════════════╝
  1002. */
  1003. VOID FAR IRQTimeOutHandler( ULONG TimerHandle, ULONG Parm1, ULONG Parm2 )
  1004. {
  1005.    NPACB         npACB;
  1006.  
  1007.    DISABLE
  1008.    ADD_CancelTimer( TimerHandle );
  1009.  
  1010.    npACB = (NPACB) Parm1;
  1011.  
  1012.    npACB->IRQTimeOutHandle = 0;
  1013.    npACB->ISMFlags &= ~ACBIF_INTERRUPT;
  1014.  
  1015.    npACB->TimerFlags |= ACBT_INTERRUPT; /* Tell interrupt state we timedout */
  1016.  
  1017.    if ( npACB->ISMState == ACBIS_INTERRUPT_STATE )
  1018.    {
  1019.       ENABLE
  1020.       StartISM( npACB );
  1021.    }
  1022.    else
  1023.       ENABLE
  1024. }
  1025.  
  1026. /*
  1027. ╔════════════════════════════════════╗
  1028. ║                                    ║
  1029. ║  AdapterIRQ0                       ║
  1030. ║                                    ║
  1031. ║  Routes received IRQs for Adapter  ║
  1032. ║  0 to generic handler              ║
  1033. ║                                    ║
  1034. ╚════════════════════════════════════╝
  1035. */
  1036. USHORT FAR _loadds AdapterIRQ0()
  1037. {
  1038.  
  1039.    if ( ACBPtrs[0].npACB->ResourceFlags & ACBRF_SHARED )             /*V@93531*/
  1040.       return( AdptInterrupt( ACBPtrs[0].npACB ) );                   /*V@93531*/
  1041.    else                                                              /*V@93531*/
  1042.       return( AdptInterrupt( ACBPtrs[0].npACB ) >> 1 );              /*V@93531*/
  1043.       /* Set carry flag interrupt is unclaimed */                    /*V@93531*/
  1044. }
  1045.  
  1046. /*
  1047. ╔════════════════════════════════════╗
  1048. ║                                    ║
  1049. ║  AdapterIRQ1                       ║
  1050. ║                                    ║
  1051. ║  Routes received IRQs for Adapter  ║
  1052. ║  1 to generic handler              ║
  1053. ║                                    ║
  1054. ╚════════════════════════════════════╝
  1055. */
  1056. USHORT FAR _loadds AdapterIRQ1()
  1057. {
  1058.  
  1059.    if ( ACBPtrs[1].npACB->ResourceFlags & ACBRF_SHARED )             /*V@93531*/
  1060.       return( AdptInterrupt( ACBPtrs[1].npACB ) );                   /*V@93531*/
  1061.    else                                                              /*V@93531*/
  1062.       return( AdptInterrupt( ACBPtrs[1].npACB ) >> 1 );              /*V@93531*/
  1063.       /* Set carry flag if interrupt is unclaimed */                 /*V@93531*/
  1064. }
  1065.  
  1066. /*
  1067. ╔════════════════════════════════════╗
  1068. ║                                    ║
  1069. ║  AdapterIRQ2                       ║
  1070. ║                                    ║
  1071. ║  Routes received IRQs for Adapter  ║
  1072. ║  2 to generic handler              ║
  1073. ║                                    ║
  1074. ╚════════════════════════════════════╝
  1075. */
  1076. USHORT FAR _loadds AdapterIRQ2()
  1077. {
  1078.    if ( ACBPtrs[2].npACB->ResourceFlags & ACBRF_SHARED )             /*V@93531*/
  1079.       return( AdptInterrupt( ACBPtrs[2].npACB ) );                   /*V@93531*/
  1080.    else                                                              /*V@93531*/
  1081.       return( AdptInterrupt( ACBPtrs[2].npACB ) >> 1 );              /*V@93531*/
  1082.       /* Set carry flag interrupt is unclaimed */                    /*V@93531*/
  1083. }
  1084.  
  1085. /*
  1086. ╔════════════════════════════════════╗
  1087. ║                                    ║
  1088. ║  AdapterIRQ3                       ║
  1089. ║                                    ║
  1090. ║  Routes received IRQs for Adapter  ║
  1091. ║  3 to generic handler              ║
  1092. ║                                    ║
  1093. ╚════════════════════════════════════╝
  1094. */
  1095. USHORT FAR _loadds AdapterIRQ3()
  1096. {
  1097.    if ( ACBPtrs[3].npACB->ResourceFlags & ACBRF_SHARED )             /*V@93531*/
  1098.       return( AdptInterrupt( ACBPtrs[3].npACB ) );                   /*V@93531*/
  1099.    else                                                              /*V@93531*/
  1100.       return( AdptInterrupt( ACBPtrs[3].npACB ) >> 1 );              /*V@93531*/
  1101.       /* Set carry flag interrupt is unclaimed */                    /*V@93531*/
  1102. }
  1103.  
  1104. /*
  1105. ╔══════════════════════════════════════╗
  1106. ║                                      ║
  1107. ║  AdptInterrupt                       ║
  1108. ║                                      ║
  1109. ║  Determines if IRQ should be claimed ║
  1110. ║  and sets state flags accordingly    ║
  1111. ║                                      ║
  1112. ╚══════════════════════════════════════╝
  1113. */
  1114. USHORT NEAR AdptInterrupt( NPACB npACB )
  1115. {
  1116.    USHORT     Claimed = 0;
  1117.  
  1118.    if ( npACB )
  1119.    {
  1120.       DISABLE
  1121.  
  1122.       Claimed = 1;
  1123.  
  1124.       /*
  1125.       ┌─────────────────────────────────────────────────────────┐
  1126.       │ Read the controller status register to clear interrupt  │
  1127.       │ in case hardware is setup for level triggered operation │
  1128.       └─────────────────────────────────────────────────────────┘
  1129.       */
  1130.       GetRegister( npACB, FI_PSTATUS );
  1131.  
  1132.       if ( npACB->ISMFlags & ACBIF_INTERRUPT )
  1133.       {
  1134.  
  1135.          npACB->ISMFlags &= ~ACBIF_INTERRUPT;
  1136.  
  1137.          if ( npACB->IRQTimeOutHandle )
  1138.          {
  1139.             ADD_CancelTimer( npACB->IRQTimeOutHandle );
  1140.             npACB->IRQTimeOutHandle = 0;
  1141.          }
  1142.          else
  1143.          {
  1144.             _asm { int 3 }
  1145.          }
  1146.  
  1147.          DevHelp_EOI( npACB->IRQLevel );
  1148.  
  1149.          ENABLE
  1150.          StartISM( npACB );
  1151.       }
  1152.       else
  1153.       {
  1154.          npACB->SpuriousIRQ++;
  1155.  
  1156.          DevHelp_EOI( npACB->IRQLevel );
  1157.       }
  1158.    }
  1159.  
  1160.    return( ~Claimed );
  1161. } /* AdptInterrupt */
  1162.  
  1163. /*
  1164. ╔═════════════════════════════════════════════╗
  1165. ║                                             ║
  1166. ║  GetRegister                                ║
  1167. ║                                             ║
  1168. ║  Get the error data from the error register ║
  1169. ║                                             ║
  1170. ╚═════════════════════════════════════════════╝
  1171. */
  1172. USHORT NEAR GetRegister ( NPACB npACB, USHORT Register )
  1173. {
  1174.    USHORT Port;
  1175.    USHORT Data;
  1176.  
  1177.    Port = npACB->IOPorts[Register];
  1178.    inp ( Port, Data );
  1179.    return ( Data );
  1180.  
  1181. } /* GetRegister */
  1182.