home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ddkx86v5.zip / DDKX86 / SRC / DEV / DASD / IBM / IBM2SCSI / SCSISUBS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-14  |  48.3 KB  |  1,123 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 = SCSISUBS.C
  15.  *
  16.  * DESCRIPTIVE NAME = IBM2SCSI.ADD - Adapter Driver for IBM SCSI adapters.
  17.  *                    General routines.
  18.  *
  19.  *
  20.  * VERSION = V2.0
  21.  *
  22.  * DATE
  23.  *
  24.  * DESCRIPTION  This file contains general utility routines for the ADD.
  25.  *
  26. */
  27.  
  28. /*----------------------*/
  29. /* System include files */
  30. /*----------------------*/
  31.  
  32. #define INCL_NOBASEAPI
  33. #define INCL_NOPMAPI
  34. #include "os2.h"
  35.  
  36. /*----------------------*/
  37. /* ADD include files    */
  38. /*----------------------*/
  39.  
  40. #include "strat2.h"
  41. #include "dhcalls.h"
  42. #include "iorb.h"
  43. #include "scb.h"
  44. #include "reqpkt.h"
  45. #include "abios.h"
  46. #include "scsi.h"
  47.  
  48. /*----------------------*/
  49. /* Local include files  */
  50. /*----------------------*/
  51.  
  52. #include "mmscb.h"
  53. #include "delivery.h"
  54. #include "scsiadd.h"
  55. #include "scsiextn.h"
  56. #include "scsipro.h"
  57.  
  58.  
  59. /************************************************************************/
  60. /*                                                                      */
  61. /* FindDeviceEntry                                                      */
  62. /*                                                                      */
  63. /*    Find the specified unit handle entry and return a pointer to the  */
  64. /*    device table entry.                                               */
  65. /*                                                                      */
  66. /*    Entry:  FindDeviceEntry(uh)                                       */
  67. /*                                                                      */
  68. /*            uh - unit handle                                          */
  69. /*                                                                      */
  70. /*    Exit:  NULL if entry not found                                    */
  71. /*                                                                      */
  72. /************************************************************************/
  73.  
  74. NPDCB FindDeviceEntry(USHORT uh)
  75.  
  76. {
  77.  
  78.    /*-------------------------------------------------------------*/
  79.    /* Get the device table entry from the unit handle table.  The */
  80.    /* unit handle uh is used as an index into the table.          */
  81.    /*-------------------------------------------------------------*/
  82.  
  83.    if (uh < cDevices) {
  84.       return(*(UnitHandleTbl + uh));
  85.    }
  86.    else {
  87.       return(NULL);
  88.    }
  89. }
  90.  
  91.  
  92. /************************************************************************/
  93. /*                                                                      */
  94. /* BuildSCB                                                             */
  95. /*                                                                      */
  96. /*    Build the specified canned SCB.                                   */
  97. /*                                                                      */
  98. /*    Entry:  BuildSCB(npSCB, type, npDCB, lba, ppBuf, BufLen, BlkCnt,  */
  99. /*                     BlkSize)                                         */
  100. /*                                                                      */
  101. /*            npSCB   - ptr to the SCB to be built                      */
  102. /*            type    - type of SCB to build                            */
  103. /*            npDCB   - ptr to the device control block                 */
  104. /*            lba     - logical block address                           */
  105. /*            ppBuf   - phys ptr to the system buffer address (SG list) */
  106. /*            BufLen  - Buffer length                                   */
  107. /*            BlkCnt  - number of blocks to xfer                        */
  108. /*            BlkSize - block size                                      */
  109. /*                                                                      */
  110. /*    Exit:   good always.                                              */
  111. /*                                                                      */
  112. /************************************************************************/
  113.  
  114. VOID BuildSCB(NPSCB npSCB, USHORT type, NPDCB npDCB, ULONG lba, ULONG ppBuf,
  115.               ULONG BufLen, USHORT BlkCnt, USHORT BlkSize)
  116. {
  117.  
  118.    /*-------------------------------------------------------------*/
  119.    /* Build the SCB using the switch statement.  The SCB built is */
  120.    /* considered a default SCB.  It will, if applicable, have the */
  121.    /* scatter/gather list enabled.  The caller should turn this   */
  122.    /* off if required.  All other fields will be zero'd to insure */
  123.    /* the SCB is fresh.  The chain field will also be disabled as */
  124.    /* a default.                                                  */
  125.    /*-------------------------------------------------------------*/
  126.  
  127.    npSCB->LBA        = lba;
  128.    npSCB->ppXferBuf  = ppBuf;
  129.    npSCB->XferBufLen = BufLen;
  130.    npSCB->ppTSB      = ppData + (USHORT)&npDCB->tsb;
  131.    npSCB->ppNxtSCB   = 0L;
  132.    npSCB->EXT.BLK.BlockCnt   = BlkCnt;
  133.    npSCB->EXT.BLK.BlockSize  = BlkSize;
  134.  
  135.    switch (type) {
  136.  
  137.       case SCB_READ:
  138.          npSCB->Cmd    = SCBREAD;
  139.          npSCB->Enable = SCBEWREAD;
  140.          break;
  141.  
  142.       case SCB_WRITE:
  143.  
  144.          npSCB->Cmd    = SCBWRITE;
  145.          npSCB->Enable = SCBEWWRITE;
  146.          break;
  147.  
  148.       case SCB_READV:
  149.          npSCB->Cmd    = SCBREADV;
  150.          npSCB->Enable = SCBEWREADV;
  151.          break;
  152.  
  153.       case SCB_WRITEV:
  154.          npSCB->Cmd    = SCBWRITEV;
  155.          npSCB->Enable = SCBEWWRITEV;
  156.          break;
  157.  
  158.       case SCB_CMDSENSE:
  159.          npSCB->Cmd    = SCBCMDSENSE;
  160.          npSCB->Enable = SCBEWCMDSENSE;
  161.          break;
  162.  
  163.       case SCB_DEVICECAP:
  164.          npSCB->Cmd    = SCBDEVICECAP;
  165.          npSCB->Enable = SCBEWDEVICECAP;
  166.          break;
  167.  
  168.       case SCB_DEVICEINQ:
  169.          npSCB->Cmd    = SCBDEVICEINQ;
  170.          npSCB->Enable = SCBEWDEVICEINQ;
  171.          break;
  172.  
  173.       case SCB_SENDOTHER:
  174.          npSCB->Cmd    = SCBSENDOTHER;
  175.          npSCB->Enable = SCBEWSENDOTHER;
  176.          break;
  177.  
  178.       default:
  179.          ERRMSG1("Attempt to build invalid SCB type %w\n\r",type);
  180.  
  181.    }
  182. }
  183.  
  184.  
  185. /************************************************************************/
  186. /*                                                                      */
  187. /* AllocSCB                                                             */
  188. /*                                                                      */
  189. /*    Get an SCB for the caller.  An SCB is retrieved from the SCB pool */
  190. /*    free list.  If there are no free SCBs then the reserved SCB in    */
  191. /*    the DCB is allocated.  It is allocated only if the request is in  */
  192. /*    the process of being started.  This eliminates a possible dead    */
  193. /*    lock situation where no SCBs are available.                       */
  194. /*                                                                      */
  195. /*    Entry:  AllocSCB()                                                */
  196. /*                                                                      */
  197. /*            npDCB - Ptr to the DCB                                    */
  198. /*            pIORB - ptr to the IORB                                   */
  199. /*                                                                      */
  200. /*    Exit:   NULL if not found, pointer to an SCBCTRL if found.        */
  201. /*                                                                      */
  202. /************************************************************************/
  203.  
  204. NPSCBH AllocSCB(NPDCB npDCB, PIORB pIORB)
  205.  
  206. {
  207.  
  208.    NPSCBH npSCBH;
  209.  
  210.    SAVEIF();      /* nobody but us messes with the free list for a bit  */
  211.  
  212.    /*---------------------------------------------------------------*/
  213.    /* Try to get an SCB from the free list.  If no more SCBs on the */
  214.    /* free list then try to allocate the DCB reserved SCB.  The SCB */
  215.    /* from the DCB is only allocated if the IORB is in the process  */
  216.    /* of starting.                                                  */
  217.    /*---------------------------------------------------------------*/
  218.  
  219.    if (npSCBH = npSCBFreeList) {       /* asignment intentional !!  */
  220.       npSCBFreeList              = npSCBFreeList->scbctrl.npNextSCBH;
  221.       npSCBH->scbctrl.npNextSCBH = NULL;
  222.       npSCBH->scbctrl.status     = 0;
  223.    }
  224.    else {
  225.       if (!(npDCB->status & UNITSCBBUSY) &&
  226.           (IORBWRKSP(pIORB,Status) & IORBSTARTING ||
  227.           npDCB->state == IDLE)) {
  228.          npSCBH             = &(npDCB->ResSCBH);
  229.          npDCB->status     |= UNITSCBBUSY;
  230.          npSCBH->scbctrl.status = DCBSCB;
  231.       }
  232.       else {
  233.          npSCBH = NULL;
  234.       }
  235.    }
  236.  
  237.    /*--------------------------------------*/
  238.    /* If we found one, then initialize it. */
  239.    /*--------------------------------------*/
  240.  
  241.    if (npSCBH) {
  242.       npSCBH->scb.LBA                 = 0L;
  243.       npSCBH->scb.ppXferBuf           = 0L;
  244.       npSCBH->scb.XferBufLen          = 0L;
  245.       npSCBH->scb.ppNxtSCB            = 0L;
  246.       npSCBH->scb.EXT.BLK.BlockCnt    = 0;
  247.       npSCBH->scb.EXT.BLK.BlockSize   = 0;
  248.       npSCBH->scbctrl.pIORB           = pIORB;
  249.    }
  250.  
  251.    RESTOREIF();
  252.  
  253.    return(npSCBH);
  254.  
  255. }
  256.  
  257.  
  258. /************************************************************************/
  259. /*                                                                      */
  260. /* FreeSCB                                                              */
  261. /*                                                                      */
  262. /*    Put the SCB(s) back on the free list.  The ptr passed is a ptr    */
  263. /*    to a SCB control structure.  The number of SCBs in the list       */
  264. /*    is also given.  The DCB reserved SCB can also be in the list.     */
  265. /*                                                                      */
  266. /*    Entry:  FreeSCB(cSCBs, SCBList, npDCB)                            */
  267. /*                                                                      */
  268. /*            cSCBs   - number of SCBs to free in a linked list.        */
  269. /*                    - 0 indicates all.                                */
  270. /*            SCBList - ptr to first SCBControl header                  */
  271. /*            npDCB   - ptr to device control block                     */
  272. /*                                                                      */
  273. /*    Exit:   returns a ptr to the remainder of the pool list if only   */
  274. /*            the first entry is returned.  NULL if only 1 item in the  */
  275. /*            list or the whole list is freed.                          */
  276. /*                                                                      */
  277. /*    Notes:  Only 64K entries can be returned with cSCBs = 0 on input  */
  278. /*            This should more than handle any case.                    */
  279. /*                                                                      */
  280. /************************************************************************/
  281.  
  282. NPSCBH FreeSCB(USHORT cSCBs, NPSCBH npSCBListH, NPDCB npDCB)
  283.  
  284. {
  285.  
  286.    NPSCBH npSCBH, nextSCBH;
  287.  
  288.    SAVEIF();                   /* save the interrupt flag and disable  */
  289.  
  290.    npSCBH = npSCBListH;
  291.  
  292.    do {
  293.       if (!(npSCBH->scbctrl.status & DCBSCB)) {
  294.  
  295.          nextSCBH                   = npSCBH->scbctrl.npNextSCBH;
  296.          npSCBH->scbctrl.npNextSCBH = npSCBFreeList;
  297.          npSCBFreeList              = npSCBH;
  298.          npSCBH                     = nextSCBH;
  299.       }
  300.       else {
  301.          npDCB->status                    &= ~UNITSCBBUSY;
  302.          npSCBH                            = npSCBH->scbctrl.npNextSCBH;
  303.          npDCB->ResSCBH.scbctrl.npNextSCBH = NULL;
  304.       }
  305.    } while (npSCBH && --cSCBs);
  306.  
  307.    RESTOREIF();                /* restore the interrupt flag  */
  308.  
  309.    return(npSCBH);
  310.  
  311. }
  312.  
  313.  
  314. /************************************************************************/
  315. /*                                                                      */
  316. /* QueueIORB                                                            */
  317. /*                                                                      */
  318. /*    This routine will place the IORB on the waiting queue for the     */
  319. /*    device.  The location option indicates if the IORB is to be       */
  320. /*    queued at the end or the front.  The end of the queue is found by */
  321. /*    walking the chain until the IORB_CHAIN field is not set.  This    */
  322. /*    will indicate the end of the chain.                               */
  323. /*                                                                      */
  324. /*    Entry:  QueueIORB(pIORB, npDCB, loc)                              */
  325. /*                                                                      */
  326. /*            pIORB - ptr to IORB to queue                              */
  327. /*            npDCB - ptr to device control block                       */
  328. /*            loc   - front or back of the queue                        */
  329. /*                                                                      */
  330. /*    Exit:   normal always                                             */
  331. /*                                                                      */
  332. /*    Note:   This routine can be called at interrupt time.             */
  333. /*                                                                      */
  334. /************************************************************************/
  335.  
  336. VOID QueueIORB(PIORB pIORB, NPDCB npDCB, USHORT loc)
  337.  
  338. {
  339.  
  340.    PIORB pCurIORB;
  341.  
  342.    SAVEIF();                           /* nobody else in here           */
  343.    TRACE(TR_QUEUED, pIORB);            /* insert a queued trace record  */
  344.  
  345.    /*--------------------------------------------------------------*/
  346.    /* If the location is the back of the queue then find the end   */
  347.    /* of the queue and link this IORB to last one.  If there is no */
  348.    /* queue yet then this IORB becomes the queue.                  */
  349.    /*--------------------------------------------------------------*/
  350.  
  351.    if (loc == BACK) {
  352.       if (!npDCB->pWorkQ) {                            /* no work queued  */
  353.          npDCB->pWorkQ = pIORB;
  354.       }
  355.       else {                                           /* work is queued  */
  356.          pCurIORB = npDCB->pWorkQ;
  357.          while (pCurIORB->RequestControl & IORB_CHAIN) {
  358.             pCurIORB = pCurIORB->pNxtIORB;
  359.          }
  360.          pCurIORB->pNxtIORB = pIORB;
  361.          pCurIORB->RequestControl |= IORB_CHAIN;
  362.       }
  363.    }
  364.  
  365.    /*--------------------------------------------------------------*/
  366.    /* Otherwise the location is the front.  Make this IORB the 1st */
  367.    /* IORB in the chain.                                           */
  368.    /*--------------------------------------------------------------*/
  369.  
  370.    else {
  371.       if (npDCB->pWorkQ) {                        /* work already queued */
  372.          pIORB->RequestControl |= IORB_CHAIN;
  373.          pIORB->pNxtIORB = npDCB->pWorkQ;
  374.          npDCB->pWorkQ = pIORB;
  375.       }
  376.       else {
  377.          npDCB->pWorkQ = pIORB;
  378.          pIORB->RequestControl &= ~IORB_CHAIN;
  379.       }
  380.    }
  381.  
  382.    RESTOREIF();
  383. }
  384.  
  385. /************************************************************************/
  386. /*                                                                      */
  387. /* DeQueueIORB                                                          */
  388. /*                                                                      */
  389. /*    This routine dequeues the first element in the IORB work queue.   */
  390. /*    It will return NULL if the work queue is empty.                   */
  391. /*                                                                      */
  392. /*    Entry:  DeQueueIORB(npDCB)                                        */
  393. /*                                                                      */
  394. /*            npDCB - ptr to device control block                       */
  395. /*                                                                      */
  396. /*    Exit:   PIORB = IORB if present, NULL otherwise                   */
  397. /*                                                                      */
  398. /*    Note:   This routine can be called at interrupt time.             */
  399. /*                                                                      */
  400. /************************************************************************/
  401.  
  402. PIORB DeQueueIORB(NPDCB npDCB)
  403.  
  404. {
  405.  
  406.    PIORB pIORB;
  407.  
  408.    /*---------------------------------------------------------------*/
  409.    /* Turn ints off and peel the first IORB from the queue.  If no  */
  410.    /* IORBs in the queue then return NULL.                          */
  411.    /*---------------------------------------------------------------*/
  412.  
  413.    SAVEIF();
  414.  
  415.    if (pIORB = npDCB->pWorkQ) {                 /* assignment intentional !! */
  416.       npDCB->pWorkQ          = pIORB->pNxtIORB;
  417.       pIORB->pNxtIORB        = NULL;
  418.       pIORB->RequestControl &= ~IORB_CHAIN;
  419.       TRACE(TR_DEQUEUED, pIORB);
  420.    }
  421.  
  422.    RESTOREIF();
  423.    return(pIORB);
  424. }
  425.  
  426.  
  427. /*************************************************************************/
  428. /*                                                                       */
  429. /* StartIORB                                                             */
  430. /*                                                                       */
  431. /*    This routine starts the passed IORB chain.  The ABIOS RB in the    */
  432. /*    device table entry is set-up to point to the first SCB in hanging  */
  433. /*    off the IORB.  If an SCB chain is being sent somebody else must    */
  434. /*    set up that chain properly.  This routine assumes the device is    */
  435. /*    is not busy.                                                       */
  436. /*                                                                       */
  437. /*    Since the device is not busy, when called at task time we know     */
  438. /*    that there can be nothing queued.  Since nothing is queued, if the */
  439. /*    request completes immediately we don't have to go look for more    */
  440. /*    work to start.  For this reason the caller is responsible for      */
  441. /*    starting more work if there is work queued.                        */
  442. /*                                                                       */
  443. /*                                                                       */
  444. /*       Entry:  StartIORB(pIORB, npDCB, start, complt, error)           */
  445. /*                                                                       */
  446. /*               pIORB  - ptr to the IORB group to start                 */
  447. /*               npDCB  - ptr to the DCB of the device                   */
  448. /*                                                                       */
  449. /*       Exit:   Returns:                                                */
  450. /*                  COMPLETE - Request was started and it completed.     */
  451. /*                  ERROR    - Request completed with error.             */
  452. /*                                                                       */
  453. /*       Note:   This routine can be called at interrupt time.           */
  454. /*                                                                       */
  455. /*                                                                       */
  456. /*************************************************************************/
  457.  
  458. VOID StartIORB(PIORB pIORB, NPDCB npDCB)
  459.  
  460. {
  461.  
  462.    USHORT cmd;
  463.    ULONG  ppSCB, to_cmd;
  464.  
  465.    /*------------------------------------------------------------*/
  466.    /* Assume the request is going to start OK.  Set the IORB to  */
  467.    /* show that the IORB is starting.  Set the active IORB in    */
  468.    /* the DCB, and set the device state.                         */
  469.    /*------------------------------------------------------------*/
  470.  
  471.    IORBWRKSP(pIORB,Status) |= IORBSTARTING;
  472.    npDCB->pActiveIORB = pIORB;
  473.    npDCB->state = WAITONINT;
  474.  
  475.    /*-------------------------------------------------------------------*/
  476.    /* Before sending the SCB out, see if any adjustments in the adapter */
  477.    /* global command timeout is required.  We try to use the adapter    */
  478.    /* value, but it is only good upto 128 minutes.  Some I/Os take upto */
  479.    /* 4 hours (tape erase and retension).  This section of code will    */
  480.    /* adjust the adapter global timeout upto the maximum value as req-  */
  481.    /* uired by the command.  If the timeout specified for the IORB is   */
  482.    /* greater than the max adapter value then the adapter timeout is    */
  483.    /* disabled and the software timeout is used.  Once disabled it will */
  484.    /* never be reset.  In general the timeout value is only adjusted    */
  485.    /* upwards.  It is never lowered.  If the t/o value is adjusted with */
  486.    /* an I/O then we exit here w/o starting the actual I/O.  The int    */
  487.    /* handler will call us back later to start it.                      */
  488.    /*-------------------------------------------------------------------*/
  489.  
  490.    if (!(npDCB->status & UNITTODISABLED)) {        /* only if not disabled */
  491.       if (pIORB->Timeout > npDCB->Timeout) {
  492.          if (pIORB->Timeout > MAX_TIMEOUT) {
  493.             npDCB->status |= UNITTODISABLED;
  494.             to_cmd = SCB_FEATURE;
  495.          }
  496.          else {
  497.             to_cmd = SCB_FEATURE + (pIORB->Timeout << 16);   /* REN 91694 */
  498.          }
  499.  
  500.          if (!StartLocateModeSCB(npDCB->ai, to_cmd,
  501.                             CMD_IMMEDIATE+(USHORT)npDCB->ldn)) {
  502.             npDCB->Timeout = pIORB->Timeout;
  503.             npDCB->state = WAITONSETTIMEOUT;
  504.          }
  505.  
  506.          STI();
  507.          return ;
  508.       }
  509.    }
  510.    else {                                      /* no adapter op required  */
  511.       if (pIORB->Timeout > npDCB->Timeout) {
  512.          npDCB->Timeout = pIORB->Timeout;
  513.       }
  514.    }
  515.  
  516.    /*----------------------------------------------------------------*/
  517.    /* Now for any adapter that has only 1 device attached turn the   */
  518.    /* No Disconnect bit in the SCB enable word on.  This will in-    */
  519.    /* crease performance.
  520.    /*----------------------------------------------------------------*/
  521.  
  522.    if (ACBTbl[npDCB->ai].cDev == 1) {
  523.       IORBWRKSP(pIORB,npSCBH)->scb.Cmd |= SCBCfND;
  524.    }
  525.  
  526.    /*----------------------------------------------------------------*/
  527.    /* Determine the command to send to the adapter.  Send the SCB to */
  528.    /* the adapter.  If there is an error then the adapter is reset   */
  529.    /* by the start routine.  The start routine leaves INTs off.      */
  530.    /*----------------------------------------------------------------*/
  531.  
  532.    cmd = ((IORBWRKSP(pIORB,Status) & IORBSCBLONG) ? CMD_LONGSCB : CMD_NORMSCB);
  533.    if (IORBWRKSP(pIORB,Status) & IORBPASSTHRUSCB) {
  534.       ppSCB = ((PIORB_ADAPTER_PASSTHRU)pIORB)->ppSCB;
  535.    }
  536.    else {
  537.       ppSCB = IORBWRKSP(pIORB,npSCBH)->scbctrl.ppSCB;
  538.    }
  539.  
  540.    TRACE(TR_STARTED, pIORB);
  541.  
  542.    if (!StartLocateModeSCB(npDCB->ai, ppSCB, cmd+(USHORT)npDCB->ldn)) {
  543.       STARTTIMEOUT(npDCB->ai, npDCB->Timeout+30);
  544.       LED_ON(npDCB);
  545.    }
  546.  
  547.    STI();   /* StartLocateModeSCB leaves ints off  */
  548.    return;
  549.  
  550. }
  551.  
  552.  
  553. /*************************************************************************/
  554. /*                                                                       */
  555. /* FinishIORB                                                            */
  556. /*                                                                       */
  557. /*    This routine actually does the finish up processing on the IORB.   */
  558. /*    The caller must free any attached SCBs before calling.             */
  559. /*                                                                       */
  560. /*       1.  If the ADD work space status indicates that a call out is   */
  561. /*           needed then it is done.  The return code is ignored here    */
  562. /*           because it is assumed, by the caller, at this point that    */
  563. /*           the request can do no more work.                            */
  564. /*                                                                       */
  565. /*       2.  The done bit in the IORB is set and the call back is done.  */
  566. /*                                                                       */
  567. /*       Entry:  FinishIORB(pIORB, npDCB)                                */
  568. /*                                                                       */
  569. /*               pIORB  - ptr to the IORB                                */
  570. /*               npDCB  - ptr to the DCB of the device                   */
  571. /*                                                                       */
  572. /*       Exit:   returns                                                 */
  573. /*                                                                       */
  574. /*       Note:   This routine can be called at interrupt time.           */
  575. /*                                                                       */
  576. /*               The IORB is considered invalid after the callback is    */
  577. /*               done.                                                   */
  578. /*                                                                       */
  579. /*************************************************************************/
  580.  
  581. USHORT FinishIORB(PIORB pIORB, NPDCB npDCB)
  582.  
  583. {
  584.  
  585.    USHORT rc;
  586.  
  587.    rc = COMPLETE;  /* assume that we will be done (in case no callout done) */
  588.  
  589.    /*----------------------------------------------------------------------*/
  590.    /* First free any SCBs that were allocated for non move mode devices.   */
  591.    /*----------------------------------------------------------------------*/
  592.  
  593.    if (npDCB) {
  594.       if (!(ACBTbl[npDCB->ai].status & MOVEMODE)) {
  595.          if (IORBWRKSP(pIORB,cSCBs)) {
  596.             FreeSCB(IORBWRKSP(pIORB,cSCBs),IORBWRKSP(pIORB,npSCBH),npDCB);
  597.          }
  598.       }
  599.    }
  600.  
  601.    /*----------------------------------------------------------------------*/
  602.    /* Set the error indicator if there was an error.  The set our int flag */
  603.    /* so that we know it is OK to use the reserved SCB for this device if  */
  604.    /* another stage is required.                                           */
  605.    /*----------------------------------------------------------------------*/
  606.  
  607.    pIORB->Status |= (pIORB->ErrorCode) ? IORB_ERROR : 0;
  608.    IORBWRKSP(pIORB,Status) |= IORBINTERRUPT;
  609.  
  610.    /*----------------------------------------------------------------------*/
  611.    /* Now do our local callout if needed.  The call out is done only if    */
  612.    /* there was no error or if the call out on error bit is set, or there  */
  613.    /* is a recovered error.                                                */
  614.    /*----------------------------------------------------------------------*/
  615.  
  616.    if ( (IORBWRKSP(pIORB,Status) & IORBCALLOUT)              &&
  617.          ( !(pIORB->ErrorCode)                            ||
  618.            (pIORB->Status & IORB_RECOV_ERROR)             ||
  619.            (IORBWRKSP(pIORB,Status) & IORBCALLOUTERR))) {
  620.  
  621.       rc = (*IORBWRKSP(pIORB,npfnCallOut))(pIORB, npDCB);
  622.    }
  623.  
  624.    /*----------------------------------------------------------------------*/
  625.    /* If the callout returned COMPLETE (or rc is default value) and the    */
  626.    /* IORB has the async callback bit set then make the call back.         */
  627.    /*----------------------------------------------------------------------*/
  628.  
  629.    if (rc == COMPLETE) {
  630.       pIORB->Status |= IORB_DONE;
  631.  
  632.       TRACE(TR_FINISHED, pIORB);
  633.       if (pIORB->RequestControl & IORB_ASYNC_POST) {
  634.          *(pIORB->NotifyAddress)(pIORB);
  635.       }
  636.    }
  637.    return(rc);
  638. }
  639.  
  640.  
  641. /*************************************************************************/
  642. /*                                                                       */
  643. /* ValidIORBCommand                                                      */
  644. /*                                                                       */
  645. /*    Determine if the IORB is valid.  This call validates the IORB cmd  */
  646. /*    itself, the state of the device, and the state of the adapter.     */
  647. /*                                                                       */
  648. /*       Entry:  ValidIORBCommand(pIORB)                                 */
  649. /*                                                                       */
  650. /*               pIORB - pointer to the IORB.                            */
  651. /*                                                                       */
  652. /*       Exit:  Returns the DCB ptr if valid, or NULL if not required.   */
  653. /*              If on return the IORB error code is not 0 then there     */
  654. /*              was an error.                                            */
  655. /*                                                                       */
  656. /*************************************************************************/
  657.  
  658. NPDCB ValidIORBCommand(PIORB pIORB)
  659.  
  660. {
  661.  
  662.    USHORT cc;                 /* command code  */
  663.    NPDCB npDCB;
  664.  
  665.    cc = pIORB->CommandCode;
  666.    npDCB = NULL;
  667.  
  668.    if (cc <= MAX_IOCC_COMMAND &&
  669.        pIORB->CommandModifier <= IORBCallTbl[cc].maxcm) {
  670.  
  671.       if (IORBCallTbl[cc].control & NEEDDCB) {
  672.          if ((npDCB = FindDeviceEntry(pIORB->UnitHandle)) != NULL) {
  673.  
  674.             if (npDCB->UnitInfo.UnitFlags & UF_DEFECTIVE) {
  675.                pIORB->ErrorCode = IOERR_DEVICE_DIAGFAIL;
  676.                return(NULL);
  677.             }
  678.  
  679.             if (ACBTbl[npDCB->ai].status & ADAPTERDEFECTIVE) {
  680.                pIORB->ErrorCode = IOERR_ADAPTER_DIAGFAIL;
  681.                return(NULL);
  682.             }
  683.  
  684.             if (ACBTbl[npDCB->ai].status & RESETINPROGRESS ||
  685.                 npDCB->status & UNITDEVCTRL) {
  686.                pIORB->ErrorCode = IOERR_DEVICE_BUSY;
  687.                return(NULL);
  688.             }
  689.          }
  690.          else {
  691.             ERRMSG1("IORB unable to find specified DCB for unit %w\n\r",
  692.                    pIORB->UnitHandle);
  693.             pIORB->ErrorCode = IOERR_CMD_SYNTAX;
  694.             return(NULL);
  695.          }
  696.       }
  697.  
  698.       if (IORBCallTbl[cc].control & NEEDALLOC) {
  699.          if (!(npDCB->status & UNITALLOCATED)) {
  700.             pIORB->ErrorCode = IOERR_UNIT_NOT_ALLOCATED;
  701.             return(NULL);
  702.          }
  703.       }
  704.  
  705.    }
  706.  
  707.    else {
  708.       pIORB->ErrorCode = IOERR_CMD_NOT_SUPPORTED;
  709.       return(NULL);
  710.    }
  711.  
  712.    return(npDCB);
  713.  
  714. }
  715.  
  716. /*************************************************************************/
  717. /*                                                                       */
  718. /* CountSGBlocks                                                         */
  719. /*                                                                       */
  720. /*    Determine the number of blocks in the SG list.                     */
  721. /*                                                                       */
  722. /*       Entry:  CountSGBlocks(pSGList, cSGEntries, BlkSize)             */
  723. /*                                                                       */
  724. /*               pSGList - ptr to the SG list                            */
  725. /*               cSGEntries - number of entries                          */
  726. /*               BlkSize - block size                                    */
  727. /*                                                                       */
  728. /*       Exit: USHORT - number of blocks                                 */
  729. /*                                                                       */
  730. /*       Notes: This routine can be called at interrupt time.            */
  731. /*                                                                       */
  732. /*************************************************************************/
  733.  
  734. USHORT CountSGBlocks(PSCATGATENTRY pSGList, USHORT cSGEntries, USHORT BlkSize)
  735.  
  736. {
  737.  
  738.    USHORT i;
  739.    ULONG  ByteCount;
  740.  
  741.    ByteCount = 0;
  742.  
  743.    for (i=0; i<cSGEntries; i++) {
  744.       ByteCount += (pSGList+i)->XferBufLen;
  745.    }
  746.  
  747.    return((USHORT)(ByteCount/BlkSize));
  748.  
  749. }
  750.  
  751.  
  752. /*************************************************************************/
  753. /*                                                                       */
  754. /* InitIORBWorkSpace                                                     */
  755. /*                                                                       */
  756. /*    This routine initializes the IORB ADD work space.                  */
  757. /*                                                                       */
  758. /*       Entry:  InitIORBWorkSpace(pIORB)                                */
  759. /*                                                                       */
  760. /*               pIORB  - ptr to the IORB.                               */
  761. /*                                                                       */
  762. /*       Exit:  good always.                                             */
  763. /*                                                                       */
  764. /*************************************************************************/
  765.  
  766.  
  767. VOID InitIORBWorkSpace(PIORB pIORB)
  768.  
  769. {
  770.  
  771.    USHORT i;
  772.  
  773.    for (i=0; i< ADD_WORKSPACE_SIZE; i++) {
  774.       pIORB->ADDWorkSpace[i]=0;
  775.    }
  776.    IORBWRKSP(pIORB,Status) |= IORBLAST;
  777.    IORBWRKSP(pIORB,cRetries) = RetryCount;
  778.  
  779. }
  780.  
  781.  
  782. /*************************************************************************/
  783. /*                                                                       */
  784. /* GetNextWork                                                           */
  785. /*                                                                       */
  786. /*    This routine builds the next unit of work for the device.  It      */
  787. /*    removes IORBs from the waiting queue and goups them together to    */
  788. /*    form a SCB chain for the device.  If an IORB is marked as one that */
  789. /*    cannot be grouped with others then it is returned as a separate    */
  790. /*    piece of work.  See below.                                         */
  791. /*                                                                       */
  792. /*       Entry:  GetNextWork(npDCB)                                      */
  793. /*                                                                       */
  794. /*               npDCB  - ptr to the DCB.                                */
  795. /*                                                                       */
  796. /*       Exit:  pIORB  if work ready.                                    */
  797. /*              NULL   if no work waiting.                               */
  798. /*                                                                       */
  799. /*************************************************************************/
  800.  
  801. PIORB GetNextWork(NPDCB npDCB)
  802.  
  803. {
  804.  
  805.    PIORB pCurIORB,                 /* current IORB we are working on         */
  806.          pHeadIORB,                /* head of entire group/chain being built.*/
  807.          pLastIORB;                /* last IORB in current group/chain       */
  808.  
  809.    NPSCBH npSCBH;                  /* scb ptr                                */
  810.  
  811.    USHORT i, j, rc;
  812.  
  813.    pHeadIORB = pLastIORB = NULL;
  814.  
  815.    /*-------------------------------------------------*/
  816.    /* Build an IORB/SCB chain of upto size GroupSize. */
  817.    /*-------------------------------------------------*/
  818.  
  819.    for (i=0; i<GroupSize; i++) {
  820.  
  821.       if (!(pCurIORB = DeQueueIORB(npDCB))) {
  822.          break;
  823.       }
  824.  
  825.       if (!pHeadIORB) pHeadIORB = pLastIORB = pCurIORB;
  826.  
  827.       /*---------------------------------------------------------------*/
  828.       /* First mark the IORB as starting.  Next check the status of    */
  829.       /* the IORB to see if it was setup completely (all resources     */
  830.       /* allocated).  If so then continue.  If not then make the reqd  */
  831.       /* callout (which should be a setup routine).  On retrurn if     */
  832.       /* the return code is NORESOURCE then this IORB is not ready to  */
  833.       /* be started, so requeue it (at the front) and break out of the */
  834.       /* loop now.  If the return code is INCOMPLETE, then the IORB    */
  835.       /* has had some resources allocated to it is OK to start it.  A  */
  836.       /* subsequent interrupt will try again to allocated more re-     */
  837.       /* sources.  For this case it is OK to put the IORB on the chain */
  838.       /* but it must be the last one, so set the loop var to the term- */
  839.       /* inating value.                                                */
  840.       /*---------------------------------------------------------------*/
  841.  
  842.       IORBWRKSP(pCurIORB,Status) |= IORBSTARTING;   /* set started bit  */
  843.  
  844.       if (IORBWRKSP(pCurIORB,Status) & IORBINCOMPLT) {
  845.          if (IORBWRKSP(pCurIORB,Status) & IORBCALLOUT) {
  846.             rc = (*IORBWRKSP(pCurIORB,npfnCallOut))(pCurIORB,npDCB);
  847.             if (rc == NORESOURCE) {
  848.                INFMSG1("GetNextWork - callout returned no resource (%p)\n\r",
  849.                        pCurIORB);
  850.                QueueIORB(pCurIORB, npDCB, FRONT);
  851.                break;                               /* break out now  */
  852.             }
  853.             else if (rc == INCOMPLETE) {
  854.                i = GroupSize;
  855.             }
  856.          }
  857.          else {
  858.             ERRMSG1("Incomplete IORB found w/o callout address (%p)\n\r",
  859.                     pCurIORB);
  860.          }
  861.       }
  862.  
  863.       /*-------------------------------------------------------------------*/
  864.       /* Now see it the IORB can be grouped with others.  If it is OK then */
  865.       /* continue.  If not then see if a chain has already been started.   */
  866.       /* If so then requeue this IORB to the front of the queue and break. */
  867.       /* If not then just break.  (out of the loop)                        */
  868.       /*-------------------------------------------------------------------*/
  869.  
  870.       if (IORBWRKSP(pCurIORB,Status) & IORBNOGROUP) {
  871.          if (pCurIORB != pHeadIORB) {
  872.             QueueIORB(pCurIORB, npDCB, FRONT);
  873.          }
  874.          break;
  875.       }
  876.  
  877.       /*-------------------------------------------------------------------*/
  878.       /* If we get here we know that the IORB is ready to be chained into  */
  879.       /* the group.  A chain has been started if the current IORB is != to */
  880.       /* the last IORB.  To put the IORB on the chain, the 1st SCB in the  */
  881.       /* current IORB is linked to the last SCB on the current chain.  If  */
  882.       /* no chain has been started then initialize the chain.              */
  883.       /*-------------------------------------------------------------------*/
  884.  
  885.       if (pCurIORB != pLastIORB) {
  886.  
  887.          IORBWRKSP(pLastIORB,Status) &= ~IORBLAST;
  888.          pLastIORB->pNxtIORB = pCurIORB;
  889.          pLastIORB->RequestControl |= IORB_CHAIN;
  890.  
  891.          npSCBH = IORBWRKSP(pLastIORB,npSCBH);
  892.          for (j=0; j<IORBWRKSP(pLastIORB,cSCBs)-1; j++) {
  893.             npSCBH = npSCBH->scbctrl.npNextSCBH;
  894.          }
  895.  
  896.          npSCBH->scbctrl.npNextSCBH = IORBWRKSP(pCurIORB,npSCBH);
  897.  
  898.          npSCBH->scb.ppNxtSCB =
  899.             IORBWRKSP(pCurIORB,npSCBH)->scbctrl.ppSCB;
  900.  
  901.          npSCBH->scb.Enable |= SCBEfCC;
  902.  
  903.       }
  904.       pLastIORB = pCurIORB;
  905.  
  906.       if (IORBWRKSP(pCurIORB,Status) & IORBINCOMPLT) {
  907.          break;
  908.       }
  909.    }
  910.  
  911.    return(pHeadIORB);     /* return the head pointer  */
  912. }
  913.  
  914.  
  915.  
  916. /*************************************************************************/
  917. /*                                                                       */
  918. /* Trace                                                                 */
  919. /*                                                                       */
  920. /*    This routine inserts the info in the trace buffer.                 */
  921. /*                                                                       */
  922. /*       Entry:  Trace(event, pIORB)                                     */
  923. /*                                                                       */
  924. /*               event - event to put in buffer.                         */
  925. /*                                                                       */
  926. /*************************************************************************/
  927.  
  928. VOID Trace(USHORT event, PIORB pIORB)
  929.  
  930. {
  931.  
  932.    USHORT temp;             /* DO NOT REMOVE !!   */
  933.  
  934.  
  935.    SAVEIF();
  936.  
  937.    TraceIndex = (TraceIndex == MAXTRACE-1) ? 0 : ++TraceIndex;
  938.  
  939.    (TraceBuf+TraceIndex)->event  = event;
  940.    (TraceBuf+TraceIndex)->unit   = pIORB->UnitHandle;
  941.    (TraceBuf+TraceIndex)->pIORB  = pIORB;
  942.    (TraceBuf+TraceIndex)->cm     = (UCHAR)pIORB->CommandModifier;
  943.    (TraceBuf+TraceIndex)->cc     = (UCHAR)pIORB->CommandCode;
  944.    (TraceBuf+TraceIndex)->status = pIORB->Status;
  945.    (TraceBuf+TraceIndex)->ec     = pIORB->ErrorCode;
  946.    (TraceBuf+TraceIndex)->npSCBH = IORBWRKSP(pIORB,npSCBH);
  947.  
  948.    RESTOREIF();
  949.  
  950. }
  951.  
  952. /*************************************************************************/
  953. /*                                                                       */
  954. /* VirtToPhys                                                            */
  955. /*                                                                       */
  956. /*    This routine converts a virtual address to a physical address.  It */
  957. /*    will work at interrupt time.                                       */
  958. /*                                                                       */
  959. /*       Entry:  VirtToPhys(VirtAddr)                                    */
  960. /*                                                                       */
  961. /*               VirtAddr - virtual address to be converted              */
  962. /*                                                                       */
  963. /*       Exit:  returns ULONG physical address.                          */
  964. /*                                                                       */
  965. /*************************************************************************/
  966.  
  967. ULONG VirtToPhys (PBYTE VirtAddr)
  968.  
  969. {
  970.  
  971.    USHORT rc;
  972.    SCATGATENTRY ScatGatEntry;
  973.    ULONG VirtLinAddr, ScatLinAddr, PageListCount;
  974.  
  975.    DevHelp_VirtToLin(SELECTOROF(VirtAddr), (ULONG)(OFFSETOF(VirtAddr)),
  976.                      (PLIN)&VirtLinAddr);
  977.  
  978.    DevHelp_VirtToLin((USHORT)(((ULONG)((PVOID)&ScatGatEntry)) >> 16),
  979.                      (ULONG)((USHORT)((PVOID)&ScatGatEntry)),
  980.                      (PLIN)&ScatLinAddr);
  981.  
  982.    DevHelp_LinToPageList(VirtLinAddr, 1, ScatLinAddr, (PULONG)&PageListCount);
  983.  
  984.    return(ScatGatEntry.ppXferBuf);
  985.  
  986. }
  987.  
  988.  
  989. /*************************************************************************/
  990. /*                                                                       */
  991. /* CompleteIORBChain                                                     */
  992. /*                                                                       */
  993. /*    This routine loops through an IORB chain completing the IORBs as   */
  994. /*    needed.  It will stop at the IORB which caused an error if         */
  995. /*    requested.                                                         */
  996. /*                                                                       */
  997. /*       Entry:  CompleteIORBChain(npDCB, pHeadIORB, pLastIORB)          */
  998. /*                                                                       */
  999. /*               npDCB     - DCB for device                              */
  1000. /*               pHeadIORB - IORB at the head of the chain               */
  1001. /*               pLastIORB - last IORB.  This IORB will NOT be processed.*/
  1002. /*                           use NULL for entire chain.                  */
  1003. /*               ec        - error code (0 to ignore)                    */
  1004. /*                                                                       */
  1005. /*       Exit:   pIORB - ptr to an IORB                                  */
  1006. /*                                                                       */
  1007. /*               if pLastIORB == NULL then                               */
  1008. /*                  pIORB = NULL if all IORBs where completed            */
  1009. /*                        = IORB that needs to be started (may not have  */
  1010. /*                          been setup completely)                       */
  1011. /*                                                                       */
  1012. /*               if pLastIORB <> NULL                                    */
  1013. /*                  pIORB = the error IORB if found                      */
  1014. /*                        = NULL if not found (error condition)          */
  1015. /*                                                                       */
  1016. /*************************************************************************/
  1017.  
  1018. PIORB CompleteIORBChain(NPDCB npDCB, PIORB pHeadIORB, PIORB pLastIORB,
  1019.                         USHORT ec)
  1020.  
  1021. {
  1022.    PIORB pCurIORB, pNextIORB;
  1023.    BOOL  done;
  1024.    USHORT rc;
  1025.  
  1026.    done = FALSE;
  1027.    pCurIORB = pHeadIORB;
  1028.  
  1029.    /*------------------------------------------------------------------*/
  1030.    /* Follow the chain of IORBs finishing them until pLastIORB is      */
  1031.    /* reached.  An IORB is finished if it is not incomplete or an      */
  1032.    /* error code was specified.  If an error code is passed in then    */
  1033.    /* the IORB error code is set.  In all cases the IORB pointed to by */
  1034.    /* pLastIORB is not finished and is passed back.  A value of NULL   */
  1035.    /* for pLastIORB will complete an entire chain.  The recovered      */
  1036.    /* error bit is set if the IORB already has an error code and no    */
  1037.    /* error code was passed in.                                        */
  1038.    /*------------------------------------------------------------------*/
  1039.  
  1040.    while (!done && pCurIORB) {
  1041.  
  1042.       pNextIORB = pCurIORB->pNxtIORB;
  1043.  
  1044.       if (!(IORBWRKSP(pCurIORB,Status) & IORBINCOMPLT) || ec) {
  1045.  
  1046.          if (pCurIORB != pLastIORB) {
  1047.  
  1048.             if (ec) {
  1049.                pCurIORB->ErrorCode = ec;
  1050.             }
  1051.             else if (pCurIORB->ErrorCode) {
  1052.                pCurIORB->Status |= IORB_RECOV_ERROR;
  1053.             }
  1054.  
  1055.             rc = FinishIORB(pCurIORB, npDCB);                         /*@V95775*/
  1056.             if (rc != COMPLETE) {                                     /*@V95775*/
  1057.                break;                     /* get out now and go finish */
  1058.             }                                                         /*@V95775*/
  1059.             else {
  1060.                pCurIORB = pNextIORB;
  1061.             }
  1062.          }
  1063.       }
  1064.       else {
  1065.          IORBWRKSP(pCurIORB,Status) |= IORBINTERRUPT;
  1066.          (*IORBWRKSP(pCurIORB,npfnCallOut))(pCurIORB, npDCB);
  1067.  
  1068.          #ifdef DEBUG
  1069.             if (!(IORBWRKSP(pCurIORB,Status) & IORBLAST)) {
  1070.                ERRMSG1("Incomplete IORB not last %p\n\r",pCurIORB);
  1071.             }
  1072.          #endif
  1073.       }
  1074.  
  1075.       if (pCurIORB == pLastIORB) {
  1076.          done = TRUE;
  1077.       }
  1078.    }
  1079.  
  1080.    return(pCurIORB);
  1081.  
  1082. }
  1083.  
  1084. /*************************************************************************/
  1085. /*                                                                       */
  1086. /* StartLocateModeSCB                                                    */
  1087. /*                                                                       */
  1088. /*    This routine will start the requested SCB.  It calls the assembler */
  1089. /*    routine to start it.  Upon return if there is an error then a      */
  1090. /*    reset will be done.  This keeps the reset on start code in one     */
  1091. /*    place.  Other parts of the code may call the assembler routine     */
  1092. /*    directly and do somethin different on an error if needed.  This is */
  1093. /*    mainly during intialization where we are not setup to do a reset.  */
  1094. /*                                                                       */
  1095. /*    If the actual start of the SCB fails, bsr never goes non busy,     */
  1096. /*    then we do a reset.                                                */
  1097. /*                                                                       */
  1098. /*       Entry:  StartLocateModeSCB(IOAddr, ppSCB, ldn, flag)            */
  1099. /*                                                                       */
  1100. /*               ai     - adapter index                                  */
  1101. /*               ppSCB  - phys ptr to the SCB (chain)                    */
  1102. /*               cmd    - command to the attention register of the card. */
  1103. /*                                                                       */
  1104. /*       Exit:   <> 0 if some error, 0 if none, ints disabled if IORB    */
  1105. /*               was started.                                            */
  1106. /*                                                                       */
  1107. /*************************************************************************/
  1108.  
  1109. USHORT StartLocateModeSCB(USHORT ai, ULONG ppSCB, USHORT cmd)
  1110.  
  1111. {
  1112.  
  1113.    USHORT ec = 0;
  1114.  
  1115.    if (_StartIO(ACBTbl[ai].baseIO, ppSCB, cmd)) {
  1116.       ResetAdapter(ai);
  1117.       ec = ERROR;
  1118.    }
  1119.  
  1120.    return(ec);
  1121.  
  1122. }
  1123.