/****************************************************************************
 *
 *    Beschreibung  : Dies ist ein Beispiel fr die Programmierung von
 *                    PlugIns fr GEMAR.
 *                    Wenn ein Fehler bei einem SCSI-Aufruf auftritt, der
 *                    Check Condition meldet, holt GEMAR die Request
 *                    Sense Daten vom Gert, um die Fehlermeldung
 *                    zusammenzustellen.
 *                    Falls ein PlugIn mit dem Namen REQSENSE.PLG
 *                    existiert, wird dieses geladen und mit einem
 *                    Zeiger auf die Request-Sense Daten aufgerufen.
 *                    Das PlugIn kann dann eine differenzierte Fehlermel-
 *                    dung zusammenstellen und eine Zeiger darauf
 *                    liefern.
 *
 * $Source: /dev/e/hm2/user/gemar/plugin\RCS\REQSENSE.C,v $
 *
 * $Revision: 1.2 $
 *
 * $Author: S_Engel $
 *
 * $Date: 1995/10/21 17:09:14 $
 *
 * $State: Exp $
 *
 *****************************************************************************
 * History:
 *
 * $Log: REQSENSE.C,v $
 * Revision 1.2  1995/10/21  17:09:14  S_Engel
 * Bugfix: Auswertung der Fehlerbits in Sensekey falsch.
 *
 * Revision 1.1  1995/01/01  20:03:26  S_Engel
 * Initial revision
 *
 *
 *
 ****************************************************************************/



/* die blichen Header-Dateien --------------- */
int errno;
long _FilSysV;

#include <portab.h>
#include <tos.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

char Msg[100];

typedef struct head
{
  int valid     : 1; 
  int ErrorCode : 7;
} HEADBITS;

typedef struct key
{
  int FM       : 1;
  int EOM      : 1;
  int ILI      : 1;
  int reserved : 1;
  Key          : 4;
} KEY;

typedef struct reqsense
{
  char HeadBits;    /* eigentlich HEADBITS, aber Bitfield mindestens 16 Bit */
  char SegmentNo;
  char SenseKey;    /* eigentlich KEY, aber... */
  char InfoByte1;
  char InfoByte2;
  char InfoByte3;
  char InfoByte4;
  char AddLength;
  unsigned long  CmdSpecific;
  char AS;
  char ASQ;
} REQSENSE;


typedef struct tcall
{
  int   num;
  long  Call;
} TCALL;


char NoSense[]          = "Kein Fehler?";
char ReqSenseError[]    = "Fehler bei Request Sense!";
char UnknownError[]     = "Unbekannter Fehler";
char FileMark[]         = "Filemark";
char EndOfMedia[]       = "Bandende";
char IllegalLength[]    = "IllegalLength";
char RecoveredError[]   = "Korrigierter Lesefehler";
char NotReady[]         = "Nicht bereit";
char MediumError[]      = "Medium-Fehler";
char HardwareError[]    = "Hardware-Fehler";
char IllegalRequest[]   = "Illegaler Befehl";
char UnitAttention[]    = "Unit Attention";
char DataProtect[]      = "Schreibschutz";
char BlankCheck[]       = "Keine Daten auf dem Band";
char CopyAborted[]      = "Abbruch von 'Copy'";
char AbortedCommand[]   = "Abgebrocheneds Kommando";
char Equal[]            = "Equal";
char VolumeOverflow[]   = "Volume Overflow/Bandende";
char Miscompare[]       = "Miscompare";



/* vom Programm bergebene Parameter */
typedef struct
  {
    int Version;    
    void *private;
    int ApplId;
    int VDIHandle;
    char *PlugPath;
    int (*Alert) (int defbutt, char *msg);
  } PLUGPARMS;


PLUGPARMS *PlugParms;

/* Rcggabestruktur */
TCALL CallTab;

/* Funktionen -------------------------------- */

long cdecl CallProc (REQSENSE *SenseData);


/***********************************************/
/* Initialisierung des Moduls:                 */
/***********************************************/
long cdecl init(PLUGPARMS *parms)
{
  if (((long)parms == 0)             /* Keine Parameter? -> Urks     */
     || (parms->Version < 0x0000))   /* Minimalversion der Parameter */
  {
    return 0;
  }

  /* Parameterzeiger merken */
  PlugParms = parms;

  CallTab.num = 1;
  CallTab.Call = (long)CallProc;
  
  /* Adresse der Aufrufstruktur zurckgeben */
  return((long)&CallTab);
}  


/***********************************************/
/* Text fr AS und ASQ aus REQSENSE.DAT lesen  */
/***********************************************/
void GetAS(char buffer[], int AS, int ASQ)
{
  
  char fname[512], msg[120];
  int count, as, asq; 
  FILE *file;

  /* Kopie des Pfades */
  strcpy(fname, PlugParms->PlugPath);
  
  /* Pfad abtrennen */
  for (count = (int) strlen(fname); 
       (count >= 0) && (fname[count] != 92);
        --count)
    {
      fname[count] = 0;  
    }

  strcat(fname, "REQSENSE.DAT");
  file = fopen(fname, "r"); 

  if (file == NULL)
    {
      strcpy(buffer, "REQSENSE.PLG: ");
      strcat(buffer, fname);
      strcat(buffer, " not found");
      return;
    }
 
  while (1)
  {
    if (fscanf(file, "%x %x %[#-z ]", &as, &asq, msg) == 0) 
      {
        /* Ende der Datei -> AS und ASQ an bereits existierende Meldung anhngen */
        sprintf(msg, ": AS: $%02x, ASQ: $%02x", AS, ASQ);
        strcat (buffer, msg);
        break;
      }
    if ((AS == as) && ((ASQ == asq) || (asq == 0xFF)))
    {
      strcpy(buffer, msg);

      /* qualifier mit FF soll in Text einkopiert werden */
      if (asq == 0xFF)
        {
          sprintf(buffer, msg, ASQ);
        }
      break;        
    }
  }
  fclose(file);   /* Datei schlieen */
}   /* GetAS */


/***********************************************/
/* die eigentliche Plug-Prozedur               */
/***********************************************/
long cdecl CallProc(REQSENSE *SenseData)
{
  if ((long) SenseData != -1)      /* beim Deinit-Call nichts machen */
    {
      if ((((int) SenseData->HeadBits & 0x7f) != 0x70)
           && (((int) SenseData->HeadBits & 0x7f) != 0x71))
      {
        strcpy (Msg, "Was'n das'n?");
      }
      else
      {
        switch (SenseData->SenseKey & 0x0F)
        {
/* Es kann sein, da der SenseKey 0 ist, aber in den beren Bits etwas markiert ist.
          case 0x00: strcpy(Msg, NoSense); 
                     break;
 */ 
          case 0x01: strcpy(Msg, RecoveredError);
                     break;
          case 0x02: strcpy(Msg, NotReady);
                     break;
          case 0x03: strcpy(Msg, MediumError);
                     break;
          case 0x04: strcpy(Msg, HardwareError);
                     break;
          case 0x05: strcpy(Msg, IllegalRequest);
                     break;
          case 0x06: strcpy(Msg, UnitAttention);
                     break;
          case 0x07: strcpy(Msg, DataProtect);
                     break;
          case 0x08: strcpy(Msg, BlankCheck);
                     break;
      /* |09H : RETURN VendorUnique; */
          case 0x0A: strcpy(Msg, CopyAborted);
                     break;
          case 0x0B: strcpy(Msg, AbortedCommand);
                     break;
          case 0x0C: strcpy(Msg, Equal);
                     break;
          case 0x0D: strcpy(Msg, VolumeOverflow);
                     break;
          case 0x0E: strcpy(Msg, Miscompare);
                     break;
          
          default:   if (SenseData->SenseKey & 0x80)
                     {
                       strcpy(Msg, FileMark);
                     } 
                     else
                     {
                       if (SenseData->SenseKey & 0x40)
                       {
                         strcpy(Msg, EndOfMedia);
                       }
                       else
                       {
                         if (SenseData->SenseKey & 0x20)
                         {
                           strcpy(Msg, IllegalLength);
                         }
                         else
                         {
                           sprintf(Msg, " Code : $%x Key : $%x", 
                                   SenseData->HeadBits, SenseData->SenseKey);
                         }
                       }
                     }
        }
      }
      
      /* und den Additional Sense-Code, wenn er gemeldet ist */
      if (SenseData->AS != 0)
      {
        GetAS(Msg, SenseData->AS, SenseData->ASQ);
      }
       return (long)&Msg;
    }
  else
    {
      return 0;
    }
}     /* CallProc */
