                     Systemglobaler SCSI-Treiber

                               SCSIDRV

                             Release 1.00

                                 von

                            Steffen Engel
                            Krppelstr. 2
                         D-38100 Braunschweig

                     MausNet: Steffen Engel @ SZ2



Inhaltsverzeichnis
==================

 1 Vorwort

 2 Einleitung
   2.1 Strukturen
   2.2 Nomenklatur

 3 Funktionen
   3.1 In
   3.2 Out
   3.3 InquireSCSI
   3.4 InquireBus
   3.5 CheckDev
   3.6 RescanBus
   3.7 Open
   3.8 Close
   3.9 Error
   3.10 Install
   3.11 Deinstall
   3.12 GetCmd
   3.13 SendData
   3.14 GetData
   3.15 SendStatus
   3.16 SendMsg
   3.17 GetMsg
   3.18 ReqData

 4 Virtuelles RAM

 5 Tips

 6 Treiberinstallation



1 Vorwort
=========

Diese Dokumentation ist nicht kurz, sie ist aber wichtig. Ich
empfehle, den Text auszudrucken, da er dann wesentlich
bersichtlicher ist.

Wesentlich ist der Teil zum Absetzen von SCSI-Kommandos und zur
Abfrage der vorhandenen Busse. Der Teil zur Installation von
Targetroutinen ist nur fr spezielle Flle ntig. Die dazugehrigen
Funktionen mssen vom Treiber auch nicht bereitgestellt werden. Die
Existenz der Strukturen und des Treibers lassen also keine
Rckschlsse auf die Mglichkeit zur Installation von Target-Routinen
oder Disconnect zu.

Wer einen Treiber benutzen oder selbst schreiben mchte, hier sind be-
sonders die Autoren von Festplattentreibern gefragt, sollte als
erstes die Funktionen zur Benutzung und Abfrage der SCSI-
Schnittstellen beachten. Eine eventuelle Untersttzung der Target-
Routinen kann spter folgen.

Als Beispiele kann man sich die beiligenden Programme und Quelltexte
ansehen.



2 Einleitung
============

Fr den Atari fehlen seit jeher systemglobale SCSI-Routinen.
Dummerweise mu daher jeder, der SCSI-Gerte programmieren will,
eigene SCSI-Routinen schreiben, was mit jedem neuen Rechner von vorne
los geht.

Desweiteren ist es sinnvoll, mit den echten SCSI-Ports (wie bei TT,
Falcon oder der Medusa) auch als Target auftreten zu knnen.

Dazu kommen alternative SCSI-Ports, wie sie durch Zusatzkarten in ST,
TT oder der Medusa eingesetzt werden.

Besonders wichtig sind Emulatoren (zB MagiCMac, STonX) oder
alternative Rechner (Clones), an deren SCSI-Ports man ja nicht
herankommt, wenn man die Hardware nicht kennt.

Daher dieser Entwurf zur Installation eines globalen SCSI-Handlers.
Potentiell kann der Handler bereits im Betriebssystem installiert
werden, womit Plattentreiber auch auf die alternativen SCSI-Ports
zugreifen knnen, ohne Kenntnis von der Implementierung der Hardware
zu haben.

Daraus ergibt sich die folgende Vorgehensweise fr alle SCSI
nutzenden Programme:

    Bei Existenz des SCSI-Cookies sollen die darin zur Verfgung
     gestellten Funktionen verwendet werden.

    Existiert der Cookie nicht, sollten, soweit vorhanden, eigene
     Routinen verwendet werden.

     Bei Programmen, die nur auf den hier verwendeten Routinen
     aufsetzen und keine eigenen Routinen on board haben, mu dement-
     sprechend mit einer Fehlermeldung abgebrochen werden.

Auch Plattentreiber sollten dies so machen, denn es knnen SCSI-
Treiber rersetfest oder im ROM eingebunden werden, die dann vom
Plattentreiber benutzt werden sollten.

Sollte der Cookie nicht installiert sein, so ist es sinnvoll, wenn
Plattentreiber diesen installieren, um ihre eigenen Routinen global
zur Verfgung zu stellen.

Erwnschter Leistungsumfang des SCSI-Treibers:

    Fhigkeit zu krummen Transferzahlen auf ACSI (Stichwort DMA-fifo-
     Loch)

    Class 1 Komandos auf ACSI (per ALIA-Technik, Linked-Cmd oder ICD-
     Technik)

    FRB-Transfers (ACSI) sind Aufgabe des Treibers


2.1 Strukturen
--------------

  XBRA      : SCSI

  Vektoren  : Falcon : MFP-Interrupt 7, Vektor 7 (normal VR $40 -> $11C)
              TT     : TT-MFP-Interrupt 15, Vektor 7 (normal VR $50 -> $17C)

Aufbau des SCSI-Cookies:

Name des Cookie: SCSI Wert des Cookie: Zeiger auf die Struktur
tScsiCall (Typen siehe SCSIDEFS.H, SCSIDEFS.D)


2.2 Nomenklatur
---------------

 BYTE:     8 Bit (unsigned char)

 UWORD:    16 Bit ganzzahlig positiv (unsigned word)

 ULONG:    32 Bit ganzzahlig positiv (unsigned long)

 WORD:     16 Bit ganzzahlig (word)

 LONG:     32 Bit ganzzahlig (long)

 BOOLEAN:  WORD TRUE : 1 FALSE : 0

benutzte Register in den Routinen: D0-D2, A0-A1 (PureC-Konvention)

Parameterbergabe: auf dem Stack (cdecl) ( NEIN!! nichts anderes!!! )



3 Funktionen
============


3.1 In
------

Sendet ein SCSI-Kommando und empfngt die kommenden Daten.

Als Parameter wird ein Zeiger auf eine SCSI-Kommandostruktur
bergeben, in der alle ntigen Informationen ber den gewnschten
Zugriff enthalten sind.

  LONG  cdecl (*In)           (tpSCSICmd  Parms);

  typedef struct
  {
    tHandle Handle;                     /* Handle fr Bus und Gert             */
    BYTE  *Cmd;                         /* Zeiger auf CmdBlock                  */
    UWORD CmdLen;                       /* Lnge des Cmd-Block
    void  *Buffer;                      /* Datenpuffer                          */
    ULONG TransferLen;                  /* bertragungslnge                    */
    BYTE  *SenseBuffer;                 /* Puffer fr ReqSense (18 Bytes)       */
    ULONG Timeout;                      /* Timeout in 1/200 sec                 */
    UWORD Flags;                        /* Bitvektor fr Ablaufwnsche          */
      #define Disconnect 0x10           /* versuche disconnect                  */

  }tSCSICmd;
  typedef tSCSICmd *tpSCSICmd;

 Handle:       Das Handle des angesprochenen Gertes

 Cmd:          Zeiger auf den zu bertragenden Kommandoblock.

 CmdLen:       Lnge des Kommandoblockes  (Die Kommandolnge ist
               eigentlich fr einen SCSI-Treiber nicht ntig. Da ACSI
               jedoch nicht targetgesteuert ablaufen kann, einige
               Plattentreiber dieses Feature auch auf den echten SCSI-
               Ports nicht verwenden und zuknftige Gertetreiber fr
               Clones (Mac/Gemulator/STOnX) evtl. diesen Wert
               ebenfalls bentigen, mu er immer angegeben werden.)

 Buffer:       Zeiger auf den Transferpuffer

 TransferLen:  Anzahl der zu bertragenden Bytes.

 SenseBuffer:  Puffer fr Request Sense Daten.

               Wird automatisch gefllt, wenn das Gert Check
               Condition meldet.

 Timeout:      Maximale Wartezeit fr die Ausfhrung des Kommandos in
               1/200 sec.

 Flags:        Bitvektor mit Zusatzinformationen/aufforderungen

Bemerkung: die Lnge des Kommandoblockes ist eigentlich nur fr ACSI
ntig, oder fr Treiber, die nicht vom Target gesteuert werden. Daher
mu sie immer korrekt bergeben werden  ( Laut SCSI-Norm steuert das
angesprochene Target die Bus-Phasen. Das heit, das Target fordert
solange Kommando-Bytes an, bis es die Anzahl der zu dem Kommando
gehrenden Bytes erhalten hat.

Daher ist es fr die SCSI-Routinen nicht ntig, zu wissen, wie lang
das Kommando ist.

Bei ACSI kann die Busphase nicht abgefragt werden, daher mu die Kom-
mandolnge immer genannt werden. )

Ergebnis:

  NOSCSIERROR      0L /* Kein Fehler                                   */
  SELECTERROR     -1L /* Fehler beim Selektieren                       */
  STATUSERROR     -2L /* Default-Fehler                                */
  PHASEERROR      -3L /* ungltige Phase                               */
  BSYERROR        -4L /* BSY verloren                                  */
  BUSERROR        -5L /* Busfehler bei DMA-bertragung                 */
  TRANSERROR      -6L /* Fehler beim DMA-Transfer (nichts bertragen)  */
  FREEERROR       -7L /* Bus wird nicht mehr freigegeben               */
  TIMEOUTERROR    -8L /* Timeout                                       */
  DATATOOLONG     -9L /* Daten fr ACSI-Softtransfer zu lang           */
  LINKERROR      -10L /* Fehler beim Senden des Linked-Command (ACSI)  */
  TIMEOUTARBIT   -11L /* Timeout bei der Arbitrierung                  */
  PENDINGERROR   -12L /* auf diesem handle ist ein Fehler vermerkt     */
  PARITIYERROR   -13L /* Transfer verursachte Parity-Fehler            */

  Wert grer Null: Statusbyte des SCSI-Gertes, bei Status 2 (Check Condition)
  befinden sich die RequestSense-Daten im Sensebuffer.


BEISPIEL:

Aufruf von Inquiry

WORD Inquiry(tHandle handle, char *inqdata)
{
  tScsiCmd ScsiCmd;
  BYTE CmdBlock[6]={0x12,0,0,0,36,0};   /* Kommand 18, 36 Bytes */
  BYTE ReqBuff[18];

  ScsiCmd.Handle      = handle;       /* Gertehandle */
  ScsiCmd.Cmd         = CmdBlock;     /* das Kommando */
  ScsiCmd.CmdLen      = 6;            /* 6-Byte-Kommando */
  ScsiCmd.Buffer      = inqdata;      /* Datenpuffer */
  ScsiCmd.TransLen    = 36;           /* 36 Bytes erwartet */
  ScsiCmd.SenseBuffer = ReqBuff;      /* bei Fehlern dorthin */
  ScsiCmd.Timeout     = 1000;         /* 5 sec */
  ScsiCmd.Flags       = 0;            /* keine Besonderheiten */

  return (ScsiCall->In((tpScsiCmd)&ScsiCmd));
}

ACHTUNG: Bei virtuellem RAM ist selbst auf den Transfer ber ST-RAM
zu achten (s. Abschnitt VIRTUELLES RAM)


3.2 Out
-------

Sendet ein SCSI-Kommando und sendet die Daten. Parameter wie bei In.

  LONG  cdecl (*Out)           (tpSCSICmd  Parms);

  typedef struct
  {
    tHandle Handle;                     /* Handle fr Bus und Gert             */
    BYTE  *Cmd;                         /* Zeiger auf CmdBlock                  */
    UWORD CmdLen;                       /* Lnge des Cmd-Block (fr ACSI ntig) */
    void  *Buffer;                      /* Datenpuffer                          */
    ULONG TransferLen;                  /* bertragungslnge                    */
    BYTE  *SenseBuffer;                 /* Puffer fr ReqSense (18 Bytes)       */
    ULONG Timeout;                      /* Timeout in 1/200 sec                 */
    UWORD Flags;                        /* Bitvektor fr Ablaufwnsche          */
      #define Disconnect 0x10           /* versuche disconnect                  */

  }tSCSICmd;
  typedef tSCSICmd *tpSCSICmd;

ACHTUNG:

Bei virtuellem RAM ist selbst auf den Transfer ber ST-RAM zu achten (s.
Abschnitt VIRTUELLES RAM)


3.3 InquireSCSI
---------------

  LONG  cdecl (*InquireSCSI)  (WORD       what,
                               tBusInfo  *Info);
    #define cInqFirst  0
    #define cInqNext   1


  typedef struct
  {
    tPrivate Private;
     /* fr den Treiber */
    char  BusName[20];
     /* zB 'SCSI', 'ACSI', 'PAK-SCSI' */
    UWORD BusNo;
     /* Nummer, unter der der Bus anzusprechen ist */
    UWORD Features;
        #define cArbit     0x01    /* auf dem Bus wird arbitriert                          */
        #define cAllCmds   0x02    /* hier knnen ale SCSI-Cmds abgesetzt werden           */
        #define cTargCtrl  0x04    /* Das Target steuert den Ablauf (so soll's sein!)      */
        #define cTarget    0x08    /* auf diesem Bus kann man sich als Target installieren */
        #define cCanDisconnect 0x10 /* Disconnect ist mglich                             */
        #define cScatterGather 0x20 /* scatter gather bei virtuellem RAM mglich */
    /* bis zu 16 Features, die der Bus kann, zB Arbit,
     * Full-SCSI (alle SCSI-Cmds im Gegensatz zu ACSI)
     * Target oder Initiator gesteuert
     * kann alle Adressen bedienen (Stichwort: ACSI-Port im TT!)
     * Ein SCSI-Handle ist auch ein Zeiger auf eine Kopie dieser Information!
     */
    ULONG MaxLen;
    /* maximale Transferlnge auf diesem Bus (in Bytes)
     * entspricht zB bei ACSI der Gre des FRB
     */
  }tBusInfo;

Nach vorhandenen Bussen suchen. Man ruft, hnlich zu Fsfirst/Fsnext,
zunchst mit InqFirst in what auf, danach mit InqNext, bis ein
negativer Wert auftritt. Die Reihenfolge der Meldungen (erst Bus 0,
dann 1 dann 2) ist _nicht_ gewhrleistet, es kann auch sein, da erst
Bus 3, dann Bus 2, dann 0, dann 1 gemeldet wird.

Es sind maximal 32 Busse mglich.

Man erhlt Informationen ber den Bus in der Info-Struktur.

Ergebnis:

  = 0   : Ok
  < 0 : Kein weiteres Gert

ACHTUNG: es mu natrlich immer der gleiche Record fr Info genommen
werden, da darin vom Treiber protokolliert wird, welche bereits
gemeldet wurden.

Aufgabe: Fr Konfigurationsdialoge oder auch selbstttige
Konfiguration nach den vorhandenen Bussen suchen.

Dabei sind vorbelegt die Bus-Nummern 0 (ACSI) und 1 (Standard-SCSI:
Falcon, TT, Medusa, MagicMac...)

Es sind dennoch keine Annahmen ber die Anzahl der Gerte oder die
maximale Gerte-Id zulssig. Die vorhandenen Gerte mssen mit
InquireBus erfragt werden.

Beispiel: siehe SRCHDRV.C


3.4 InquireBus
--------------

  LONG  cdecl (*InquireBus)   (WORD       what,
                               WORD       BusNo,
                               tDevInfo  *Dev);

  typedef struct
  {
    BYTE Private[32];
    DLONG SCSIId;
  }tDevInfo;


Einen Bus nach vorhandenen Gerten abfragen. Erster Aufruf mit
cInqFirst, danach mit cInqNext. Liefert 0, bis keine weiteren Ids
mehr berichtet werden.

Ergbenis:

  = 0 : Ok
  < 0 : keine weiteren Gerte

Beispiel: siehe SRCHDRV.C


3.5 CheckDev
------------

  LONG  cdecl (*CheckDev)     (WORD         BusNo,
                               const DLONG *SCSIId,
                               char        *Name,
                               UWORD       *Features);

Wie InquireSCSI, nur da explizit nach einem bestimmten Bus und einer
bestimmten SCSI-ID gefragt wird.

Als Antwort erhlt man den Namen des Busses, sowie die Informationen,
was mit dem genannten Gert mglich ist.

Ergebnis:

  = 0         : Ok
  < 0         : Fehler
   -2 EDRIVNR : Informationen konnten nicht ermittelt werden (zB Kontrolle
                auf ICD-Fhigkeit)
  -15 EUNDEV  : Die Busnummer oder die Gertenummer wird nicht verwaltet
  -36 EACCDN  : Zugriff nicht mglich (zB eigene SCSI-Id auf einem
                arbitrierenden Bus)

Dies ist fr zwei Dinge sinnvoll:

    Ein Programm ldt eine Parameterdatei und kann hiermit
     kontrollieren ob

      - der Bus existiert

      - der Busname verndert ist (bei alternativen Bussen knnen Un-
        terschiede vorhanden sein)

      - das Gert ansprechbar ist

    Fr alternative Hostadapter kontrolliert der Treiber, ob er
     speziell dieses Gert anders ansprechen kann, als auf dem Bus
     blich (zB ICD: voller Kommandosatz auf ACSI auf _diesem_ Gert)


3.6 RescanBus
-------------

LONG  cdecl RescanBus  (WORD       BusNo);

Der Bus soll vom Treiber erneut auf vorhanden Gerte kontrolliert
werden.

Fr Applikationen zwei sinnvolle Anwendungen:

  1. Tool fr Kontrolle auf nachtrglich eingeschaltete Gerte.
     Beispiel: SCSI.CPX

  2. Programm sucht nach einem bestimmten Gert und findet es nicht.
     Einmal RescanBus, danach neue Suche. Beispiel: GEMAR. Wenn kein
     Streamer gefunden wurde, wird nach einem RescanBus noch mal nach
     einem Streamer geschaut.


3.7 Open
--------

  LONG  cdecl (*Open)         (WORD         BusNo,
                               const DLONG *SCSIId,
                               ULONG       *MaxLen);

Ein Handle fr ein Gert holen.

SCSIId ist die SCSI-Id des Gertes, fr das das Handle geliefert
werden soll. Die Variable ist 64 Bit gro, um die Vorgaben von SCSI-3
erfllen zu knnen. Bei den bisher zur Verfgung stehenden Treibern
und Bussen werden nur die unteren 8 Bit (von SCSIId.lo) verwendet.
Der Rest mu 0 sein. Es ist nicht zulssig, irgendwelche anderen
Informationen in der SCSI-Id unterzubringen!

Ergebnis

  > 0    : handle (Zeiger auf Featurevektor)
           In MaxLen ist angegeben, welche maximale Transferlnge mit einem
           Zugriff bertragen werden kann.
  < 0    : Fehler
  ENMHDL : keine Handles mehr frei
  EUNDEV : unbekanntes Gert auf diesen Bus/unbekannter Bus
  EACCDN : unerlaubtes Gert auf diesem Bus (zB eigene SCSI-Id bei Arbitrierung)


3.8 Close
---------

  LONG  cdecl (*Close)        (tHandle    handle);

Handle wieder freigeben

Ergebnis:

  = 0 : Ok
  < 0 : Fehler
EINVHDL : ungltiges Handle


3.9 Error
---------

  LONG  cdecl (*Error)        (tHandle    handle,
                               WORD       rwflag,
                               WORD       ErrNo);
        #define cErrRead   0
        #define cErrWrite  1
          #define cErrMediach  0
          #define cErrReset    1

Fehlerstatus auf dem Gert abfragen/setzen

Hiermit kann man fragen, welche Fehler auf dem Gert in letzter Zeit
aufgetreten sind. Dies ist ntig, da evtl. mehrere Programme mit
diesem Gert arbeiten und damit derjenige, der den Status mit Request
Sense ausliest, der einzige ist, der wei, was passiert ist. Daher
mu jeder, der Request Sense auswertet, einen entsprechenden Fehler
melden, damit dieser fr alle anderen Prozesse mit einem offenen
Hande protokolliert wird.

Gemeldet werden mu alles, was einen Wechselstatus des Gertes
ergibt, also Mediach und Reset. Nur so kann zB der Plattentreiber
einen Mediachange mitbekommen, wenn bei einem Image-Backup das Medium
gewechselt wurde.

rwflag = 0 fragt den Status ab (16 Bit Bitvektor) und lscht ihn fr
dieses handle. rwflag = 1 setzt das Bit ErrNo bei allen auf dieses
Gert geffneten handles.


3.10 Install
------------

Nur fr Targethandling, siehe SCSIDRV2


3.11 Deinstall
--------------

Nur fr Targethandling, siehe SCSIDRV2


3.12 GetCmd
-----------

Nur fr Targethandling, siehe SCSIDRV2


3.13 SendData
-------------

Nur fr Targethandling, siehe SCSIDRV2


3.14 GetData
------------

Nur fr Targethandling, siehe SCSIDRV2


3.15 SendStatus
---------------

Nur fr Targethandling, siehe SCSIDRV2


3.16 SendMsg
------------

Nur fr Targethandling, siehe SCSIDRV2


3.17 GetMsg
-----------

Nur fr Targethandling, siehe SCSIDRV2


3.18 ReqData
------------

Nur fr Targethandling, siehe SCSIDRV2



4 Virtuelles RAM
================

Bei vorhandenem virtuellem RAM ist es dem Treiber leider nicht
mglich, selbstttig die physikalische Adresse des zu
transferierenden Speichers zu ermitteln (die virtuellen Treiber
liefern keinerlei solche Information). Eine eigenstndige
Entscheidung des Treibers, wann die Daten durch einen Puffer im ST-
RAM zu kopieren sind, erscheint auch nicht sinnvoll, da zur
Vermeidung von Deadlocks fr jeden Proze ein eigener Puffer
eingerichtet werden mte. Daher mssen Programme selbstttig davor
sorgen, da der zu transferierende Speicher im ST-RAM liegt, wenn
virtuelles RAM vorliegt (siehe auch SCSILIB.H). Der Transfer fr ACSI-
Zugriffe ber den FRB bzw den XFRB stellt dabei kein Problem da.



5 Tips
======

Wenn ein Programm den Treiber benutzt, sollte es unbedingt auf ein
Gert ein InquireDev absetzen. Dies ist sinnvoll, wenn der Treiber
dadurch feststellen kann, was fr ein Adaptertyp zB auf ACSI liegt.
Meine Routinen checken dabei, ob es sich um einen ALIA handelt, oder
auch um einen ICD-Adapter. Im Falle eines ICD-Adapters ergibt sich
dadurch die Mglichkeit, da der Treiber fr Class-1-Kommandos die
ICD-Technik benutzt.



6 Treiberinstallation
=====================

Dieses Kapitel ist noch nicht fertiggestellt.

Es werden nur wesentliche Stichpunkte genannt, die von Treibern zu
beachten sind.

Wenn bereits ein Treiber installiert ist:

    Treiber drfen bereits existierende Busse nicht ersetzen, es mu
     also zunchst nach Bussen gescannt werden, dann knnen die
     eigenen Busse auf freie Bus-Ids gelegt werden.

     Der Cookieinhalt des vorhergehenden Treibers wird dann gemerkt
     und die eigenen Daten werden in die Struktur des alten Treibers
     geschrieben, die Daten werden also ersetzt.

     Der Cookiewert (der Zeiger im Cookiejar) darf NICHT ersetzt
     werden.

    Tabellen und Variablen mssen beim Treiberstart initialisiert
     werden. Initialisierte Varibalen (DATA-Segement) sind nicht
     zulssig, da ein resetfest geladener Treiber (Stichwort SCSI.RAM
     bei MagiC) dann nicht funktionieren kann.

    die Fehlermeldungen die ein Treiber zu melden hat/melden kann:

        Timeout auf /SEL (/BSY kam nicht)

        ist fr Busphasen vorgesehen, die nicht der SCSI-Norm
        entsprechen. Dies sind die Phasen mit /C/D = 0, /MSG = 1 und
        /I/O = 0 oder = 1

        Das Target hat unkontrolliert den Bus freigegeben (busy loss)

        TT-DMA-Chip)

        wenn Datenphase eingeleitet, aber dann nichts bertragen
        wurde, also als Gertefehler, nicht als SCSI-Fehler zu
        verstehen.

        werden konnte (Busy bleibt stehen)

        SELECTERROR verwenden)

        werden (zB FRB-Gre).

        mit Linked Cmds

        keine Arbitrierung um den Bus mit Erfolg beendet werden
        konnte.

        Fehler gemerkt und nicht abgeholt ist. Der Klient mu mit
        Error(cErrRead) den Fehler abholen, dann wird der Fehler auf
        diesem Handle gelscht.



