/*static char *SCCSID = "@(#)subq3.c    6.2 91/06/13";*/
/****************************************************************************/
/*                                                                          */
/*                       IBM/Microsoft Confidential                         */
/*                                                                          */
/*                 Copyright (c) IBM Corporation  1987, 1990                */
/*                 Copyright (c) Microsoft Corp.  1987, 1990                */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/

#include        <dos.h>
#include        <doscalls.h>
#include        <drt.h>
#include        <error.h>
#include        <error2.h>
#if defined(MMIOPH)
#include        <infoseg.h>
#include        <perfhook.h>
#endif
#include        <ipcqueue.h>

        struct STATDATA statseg = {0,0,0,0,0,0,0};  /* data used in all routines */
/*MDLL  int    _acrtused = 0;  /* nullify c initialization for dyna link */

/********************** START OF SPECIFICATIONS **********************/
/*                                                                   */
/* SOURCE FILE NAME: subq3.c                                         */
/*                                                                   */
/* DESCRIPTIVE NAME: Common Subroutines for IPC Queues which are     */
/*                   the least frequently used                       */
/*                                                                   */
/* COPYRIGHT: (TOP MODULE ONLY)                                      */
/*                                                                   */
/* STATUS: RELEASE 1 LEVEL 0                                         */
/*                                                                   */
/* FUNCTION:                                                         */
/*                                                                   */
/* NOTES:                                                            */
/*    DEPENDENCIES:                                                  */
/*    RESTRICTIONS:                                                  */
/*    PATCH LABEL: (TOP MODULE ONLY)                                 */
/*                                                                   */
/* ENTRY POINTS:                                                     */
/*             L_Remove                                              */
/*             dynainit                                              */
/*             El_Delete                                             */
/*                                                                   */
/* INTERNAL REFERENCES:                                              */
/*    ROUTINES:                                                      */
/*                                                                   */
/* EXTERNAL REFERENCES:                                              */
/*             DOSSUBFREE:FAR                                        */
/*             Q_Delete:near                                         */
/*             DOSSUBSET:FAR                                         */
/*                                                                   */
/*********************** END OF SPECIFICATIONS ***********************/

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    L_Remove                                     */
/*                                                                  */
/* DESCRIPTIVE NAME:   L_Remove                                     */
/*                                                                  */
/* FUNCTION:   Deletes links, and if appropriate, delete affected   */
/*             queues.                                              */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        L_Remove                                     */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*             DD       addr of link to delete                      */
/*             DD       addr of previous link                       */
/*             DW       queue handle of linked queue                */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'SYS ERROR'                                          */
/*                                                                  */
/* EFFECTS:    Deletes link, and if needed, deletes queue           */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DOSSUBFREE:FAR                                       */
/*             Q_Delete:near                                        */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      L_Remove:                                                   */
/*                                                                  */
/*      set error               'NO ERROR'                          */
/*      initialize exitlist action variables                        */
/*      set exitlist action flag = ACT_DEL_LNK                      */
/*      if (static.fst_lnk = offset) then                           */
/*        static.fst_lnk = offset.l_chain                           */
/*      else                                                        */
/*        set back_chn.l_chain = offset.l_chain                     */
/*      endif                                                       */
/*      free memory block located at offset via DosSubFree          */
/*      if (DosSubFree returns in error) then                       */
/*        set error             'SYS ERROR'                         */
/*      endif                                                       */
/*      set exitlist action flag off                                */
/*      if (error) then                                             */
/*        return with error                                         */
/*      endif                                                       */
/*      set offset = static.fst_lnk                                 */
/*      back_chn = NULL                                             */
/*      while (offset != NULL or                                    */
/*             offset.l_hndl != requested queue handle) do          */
/*        back_chn = offset                                         */
/*        offset = offset.l_chain                                   */
/*      endwhile                                                    */
/*      if (offset = NULL) then                                     */
/*        set qu_entry = static.fst_q                               */
/*        back_chn = NULL                                           */
/*        while (qu_entry != NULL and                               */
/*               qu_entry.q_hndl != requested queue handle) do      */
/*          back_chn = qu_entry                                     */
/*          qu_entry = qu_entry.q_chain                             */
/*        endwhile                                                  */
/*        if (qu_entry != NULL) then                                */
/*          set no_links in qu_entry.q_flags                        */
/*        endif                                                     */
/*      endif                                                       */
/*      return                                                      */

unsigned int
L_Remove(loffset,lprev,qhandl)
struct  L_ENTRY far *loffset;
struct  L_ENTRY far *lprev;
register unsigned int    qhandl;
{
        extern  struct  STATDATA        statseg;
        extern  unsigned char   action;
        extern  struct  L_ENTRY far *prev_fst_link;
        extern  struct  L_ENTRY far *lnk1;
        extern  struct  L_ENTRY far *lnk2;
        extern  struct  L_ENTRY far *lnk3;

        struct  L_ENTRY far *lrec;
        struct  L_ENTRY far *lback;
        struct  Q_ENTRY far *qrec;
        struct  Q_ENTRY far *qback;
        register unsigned int rc;

        rc = NO_ERROR;
        prev_fst_link = statseg.fst_link;
        lnk1 = loffset;
        lnk2 = lprev;
        lnk3 = (*loffset).l_chain;
        action = ACT_DEL_LNK;
        if (statseg.fst_link == loffset)
                statseg.fst_link = (*loffset).l_chain;
        else
                (*lprev).l_chain = (*loffset).l_chain;
        if ((DOSSUBFREE(FP_SEG(loffset),FP_OFF(loffset),sizeof(struct L_ENTRY))) != NO_ERROR)
                rc = ERROR_SYS_INTERNAL;
        action = 0;
        if (rc != NO_ERROR)
                return(rc);
        lrec = statseg.fst_link;
        lback = NULL;
        while ((lrec != NULL) && ((*lrec).l_qhndl != qhandl))
        {
                lback = lrec;
                lrec = (*lrec).l_chain;
        }
        if (lrec == NULL)
        {
                qrec = statseg.fst_q;
                qback = NULL;
                while ((qrec != NULL) && ((*qrec).q_hndl != qhandl))
                {
                        qback = qrec;
                        qrec = (*qrec).q_chain;
                }
                if (qrec != NULL)
                        (*qrec).q_flags &= ~Q_LINKS;
        }
        return(NO_ERROR);
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    DynaInit                                     */
/*                                                                  */
/* DESCRIPTIVE NAME:   Initialization                               */
/*                                                                  */
/* FUNCTION:   Prepares the Queue Package for use                   */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        dynainit                                     */
/*    LINKAGE:         far  at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX != 0                                              */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX == 0                                              */
/*                                                                  */
/* EFFECTS:                                                         */
/*              Initializes First Queue Segment, Static Data        */
/*              sets global info seg pointer                        */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DOSSUBSET:FAR                                        */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      dynainit:                                                   */
/*                                                                  */
/*      initialize First Queue Segment via DosSubSet                */
/*      if (DosSubSet returns in error) then                        */
/*        set error code          'SYS ERROR'                       */
/*      else                                                        */
/*        initialize queue variables                                */
/*      endif                                                       */
/*      return                                                      */

        unsigned char   initq = NULL;
        struct  InfoSegGDT far  *globptr = NULL;

unsigned int far
DYNAINIT()
{
        extern  struct  STATDATA        statseg;
        extern  struct  Q_INST  far     *ISEG;
        extern  int QSEG1;
        extern  unsigned char   initq;

        unsigned int    GSeg,LSeg;
        PUSHALL_DS();
        if ((DOSSUBSET(QSEG1,((unsigned) 1),QSEGSIZ)) != NO_ERROR)
        {
                return(POPALL(0));      /* zero on dyna. init means error */
        }
        else
        {
/*              krnldbug();     */
                DOSGETINFOSEG((unsigned far *) &GSeg,(unsigned far *) &LSeg);
                PUT_SEG(globptr,GSeg);
                statseg.seg_size = QSEGSIZ;
                initq = S_INIT;
                statseg.flag = S_INIT;
                statseg.nu_hnd = NULL;
                statseg.fst_q = NULL;
                statseg.fst_link = NULL;
                return(POPALL(0xffff));   /* non zero means ok */
        }
}

/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    El_Delete                                    */
/*                                                                  */
/* DESCRIPTIVE NAME:   El_Delete                                    */
/*                                                                  */
/* FUNCTION:   Delete all elements associated with a queue.         */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        El_Delete                                    */
/*    LINKAGE:         near at pl 2                                 */
/*                                                                  */
/* INPUT:                                                           */
/*             DD      offset of queue entry                        */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*             AX = 0                                               */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*             AX != 0                                              */
/*             'SYS ERROR'                                          */
/*                                                                  */
/* EFFECTS:    Deletes all elements associated with a queue.        */
/*             Adjusts the queue structure.                         */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*             DOSSUBFREE:FAR                                       */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

/*      El_Delete:                                                  */
/*                                                                  */
/*      initialize error                'NO ERROR'                  */
/*      if (queue contains elements) the                            */
/*        lst = last pointer                                        */
/*        que1 = qoffset                                            */
/*        while (qoffset.q_fst != lst && no error)                  */
/*          initialize exitlist variables                           */
/*          set exitlist action flag = ACT_DEL_FST_EMT              */
/*          update element chain                                    */
/*          decrement element count                                 */
/*          delete memory block via DosSubFree                      */
/*          if (DosSubFree returns in error) then                   */
/*            set error code      'SYS ERROR'                       */
/*          endif                                                   */
/*          set exitlist action flag off                            */
/*        endwhile                                                  */
/*        if (no error) then                                        */
/*          set exitlist action variables                           */
/*          set exitlist action flag = ACT_DEL_ONLY_EMT             */
/*          update queue structure                                  */
/*          delete memory block via DosSubFree                      */
/*          if (DosSubFree returns in error) then                   */
/*            set error code      'SYS ERROR'                       */
/*          endif                                                   */
/*          set exitlist action flag off                            */
/*      else                                                        */
/*          update queue structure                                  */
/*      endif                                                       */
/*      return                                                      */

unsigned int
El_Delete(qoffset)
struct  Q_ENTRY far *qoffset;
{
        extern  unsigned char   action;
        extern  unsigned count;
        extern  struct  Q_ENTRY far *que1;
        extern  struct  E_ENTRY far *emt1;
        extern  struct  E_ENTRY far *emt3;

        struct  E_ENTRY far     *lst;
        register unsigned int   rc;


        rc = NO_ERROR;
        if ((*qoffset).q_fst != NULL)
        {
                lst = (*qoffset).q_lst;
                que1 = qoffset;
                while (((*qoffset).q_fst != lst) && (rc == NO_ERROR))
                {
                        count = (*qoffset).q_cnt;
                        emt1 = (*qoffset).q_fst;
                        emt3 = (*emt1).e_next;
                        action = ACT_DEL_FST_EMT;
                        (*qoffset).q_fst = emt3;
                        (*emt3).e_prev = NULL;
                        (*qoffset).q_cnt--;
                        if ((DOSSUBFREE((FP_SEG(emt1)),(FP_OFF(emt1)),sizeof(struct E_ENTRY))) != NO_ERROR)
                                rc = ERROR_SYS_INTERNAL;
                        action = 0;
                }
                if (rc == NO_ERROR)
                {
                        emt1 = (*qoffset).q_fst;
                        action = ACT_DEL_ONLY_EMT;
                        (*qoffset).q_fst = NULL;
                        (*qoffset).q_lst = NULL;
                        (*qoffset).q_cnt = NULL;
                        if ((DOSSUBFREE((FP_SEG(emt1)),(FP_OFF(emt1)),sizeof(struct E_ENTRY))) != NO_ERROR)
                                rc = ERROR_SYS_INTERNAL;
                        action = 0;
                }
        }
        else
        {
                (*qoffset).q_lst = NULL;
                (*qoffset).q_cnt = NULL;
        }
        return(rc);
}

#if defined(MMIOPH)
/********************** START OF SPECIFICATIONS *********************/
/*                                                                  */
/* SUBROUTINE NAME:    Queues_Sys_Trace                             */
/*                                                                  */
/* DESCRIPTIVE NAME:   Queues System Trace                          */
/*                                                                  */
/* FUNCTION:   Writes RAS Trace information to appropriate place    */
/*                                                                  */
/* NOTES:                                                           */
/*                                                                  */
/* ENTRY POINT:        queues_sys_trace                             */
/*    LINKAGE:         ?                                            */
/*                                                                  */
/* INPUT:                                                           */
/*                                                                  */
/* EXIT-NORMAL:                                                     */
/*                                                                  */
/* EXIT-ERROR:                                                      */
/*                                                                  */
/* EFFECTS:                                                         */
/*                                                                  */
/* INTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/* EXTERNAL REFERENCES:                                             */
/*    ROUTINES:                                                     */
/*                                                                  */
/*********************** END OF SPECIFICATIONS **********************/

void queues_sys_trace(que_major_code,que_data_len,que_minor_code,que_data)
unsigned que_major_code;
unsigned int que_data_len;
unsigned que_minor_code;
char far *que_data;
{
  extern  struct  InfoSegGDT far  *globptr;
  struct Dekko_Addr far *base_addr;
  if (TEST_TRACING((*globptr).mec_table,que_major_code)) {
     FP_SEG(base_addr) = (*globptr).MMIOBase;
     FP_OFF(base_addr) = 0;
     (*base_addr).majmin_code = ((que_major_code << 8) + que_minor_code);
     for (;que_data_len > 1 ;que_data_len -= 2)
        (*base_addr).perf_data = *((unsigned far *)que_data)++;
     if (que_data_len == 1) {
        (*base_addr).perf_data = *que_data;
        } /* endif */
  }
return;
}
#endif
