This file is indexed.

/usr/share/doc/HOWTO/de-html/DE-SCSI-Programmierung-HOWTO-7.html is in doc-linux-de 2003.10-5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
 <META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.65">
 <TITLE>Das Linux SCSI Programmier HOWTO: Die Kopfstruktur</TITLE>
 <LINK HREF="DE-SCSI-Programmierung-HOWTO-8.html" REL=next>
 <LINK HREF="DE-SCSI-Programmierung-HOWTO-6.html" REL=previous>
 <LINK HREF="DE-SCSI-Programmierung-HOWTO.html#toc7" REL=contents>
</HEAD>
<BODY>
<A HREF="DE-SCSI-Programmierung-HOWTO-8.html"><IMG SRC="next.png" ALT="Weiter"></A>
<A HREF="DE-SCSI-Programmierung-HOWTO-6.html"><IMG SRC="prev.png" ALT="Zurück"></A>
<A HREF="DE-SCSI-Programmierung-HOWTO.html#toc7"><IMG SRC="toc.png" ALT="Inhalt"></A>
<HR>
<H2><A NAME="s7">7.</A> <A HREF="DE-SCSI-Programmierung-HOWTO.html#toc7">Die Kopfstruktur</A></H2>


<P>
<A NAME="sec-header"></A> 
Die Kopfstruktur <CODE>struct sg_header</CODE> dient als &Uuml;bergabeschnittstelle
zwischen Applikation und Kerneltreiber.
Jetzt kommen wir zu den einzelnen Komponenten dieser Struktur.</P>

<P>
<DL>
<DT><B>int pack_len</B><DD>
<P>definiert die Gr&ouml;&szlig;e des an den Treiber gesendeten 
Blocks.
Das Feld wird vom Kernel zur internen Verwaltung gef&uuml;llt.</P>
<DT><B>int reply_len</B><DD>
<P>definiert die Gr&ouml;&szlig;e des erwarteten Antwortblocks.
Das Feld wird von der Applikation bestimmt.</P>

<DT><B>int pack_id</B><DD>
<P>Dieses Feld dient zum Wiederfinden einer Antwort zur 
gestarteten
Anfrage. Die Applikation kann einen neuen ID f&uuml;r jedes Kommando angeben. 
Die
Antworten sind dann den Kommandos zuzuordnen, auch wenn sie in anderer 
Reihenfolge
erscheinen. Bis zu SG_MAX_QUEUE (z.B. 4) parallele Kommandos sind m&ouml;glich.</P>

<DT><B>int result</B><DD>
<P>Der R&uuml;ckgabewert eines  <CODE>read</CODE> oder <CODE>write</CODE> Aufrufs.
Dieses Feld sollte vom Kernel definiert werden (leider nicht immer).
Daher ist es am besten, das Feld vor den <CODE>write</CODE> Aufrufen explizit
auf Null zu setzen. Die Codes sind in <CODE>errno.h</CODE> aufgef&uuml;hrt (0 bedeutet
kein Fehler).</P>

<DT><B>unsigned int twelve_byte:1</B><DD>
<P>Das Feld wird nur bei Nichtstandardbefehlen
(vendor specific Kommandos) im Bereich 0xc0 - 0xff ausgewertet.
Wenn Kommandos aus diesem Bereich eine L&auml;nge von 12 Bytes statt 10 Bytes
(ohne eventuelle Daten) haben,
mu&szlig; dieses Feld vor dem <CODE>write</CODE> Aufruf auf Eins gesetzt werden. Andere
L&auml;ngen werden nicht unterst&uuml;tzt. Dieses Feld wird von der Applikation
gef&uuml;llt.</P>

<DT><B>unsigned char sense_buffer[16]</B><DD>
<P>Dieser Puffer wird nach
Abarbeitung eines Kommandos (<CODE>read()</CODE> Aufruf) vom Kernel gef&uuml;llt und
enth&auml;lt den sogenannten SCSI sense code. 
Manche SCSI Kommandoergebnisse stehen hier (z.B. die des <CODE>TESTUNITREADY</CODE>
Kommandos). Ansonsten enth&auml;lt der Puffer Nullen.</P>
</DL>
</P>


<P>Die folgende Beispielfunktion stellt den Kontakt mit dem Interface her.
Erst wird die Kopfstruktur definiert, dann der Befehl per <CODE>write</CODE>
geschickt, das Ergebnis per <CODE>read</CODE> abgeholt und Fehlerstati gecheckt.
Der Sensepuffer ist im Ausgabepuffer untergebracht, es sei denn ein
NULL-Zeiger wurde angegeben, dann wird der Eingabepuffer verwendet.
Wir werden ihn in einem der Beispiele verwenden.</P>
<P>Hinweis: Setze den Wert f&uuml;r <CODE>DEVICE</CODE> auf einen Deiner 
Ger&auml;tedeskriptoren.</P>

<P>
<BLOCKQUOTE><CODE>
<PRE>
#define DEVICE "/dev/sgc"

/* Beispielprogramm zur Demonstration des generischen SCSI-Interface */
#include &lt;stdio.h>
#include &lt;unistd.h>
#include &lt;string.h>
#include &lt;fcntl.h>
#include &lt;errno.h>
#include &lt;scsi/sg.h>


#define SCSI_OFF sizeof(struct sg_header)
static unsigned char cmd[SCSI_OFF + 18];      /* SCSI Kommandopuffer */
int fd;                               /* SCSI device/file-Deskriptor */

/* einen kompletten SCSI Befehl abarbeiten. Verwende das generische 
SCSI-Interface. */
static int handle_SCSI_cmd(unsigned cmd_len,         /* Kommandol&auml;nge */
                           unsigned in_size,         /* Eingabedatengr&ouml;&szlig;e */
                           unsigned char *i_buff,    /* Eingabepuffer */
                           unsigned out_size,        /* Ausgabedatengr&ouml;&szlig;e */
                           unsigned char *o_buff     /* Ausgabepuffer */
                           )
{
    int status = 0;
    struct sg_header *sg_hd;

    /* Sicherheits&uuml;berpr&uuml;fungen */
    if (!cmd_len) return -1;            /* erfordert cmd_len != 0 */
    if (!i_buff) return -1;             /* erfordert Eingabepuffer != NULL */
#ifdef SG_BIG_BUFF
    if (SCSI_OFF + cmd_len + in_size > SG_BIG_BUFF) return -1;
    if (SCSI_OFF + out_size > SG_BIG_BUFF) return -1;
#else
    if (SCSI_OFF + cmd_len + in_size > 4096) return -1;
    if (SCSI_OFF + out_size > 4096) return -1;
#endif

    if (!o_buff) out_size = 0;      /* kein Ausgabepuffer, keine 
Ausgabegr&ouml;&szlig;e */

    /* Aufbau der generischen SCSI-Device Kopfstruktur */
    sg_hd = (struct sg_header *) i_buff;
    sg_hd->reply_len   = SCSI_OFF + out_size;
    sg_hd->twelve_byte = cmd_len == 12;
    sg_hd->result = 0;
#if     0
    sg_hd->pack_len    = SCSI_OFF + cmd_len + in_size; /* nicht notwendig */
    sg_hd->pack_id;     /* unbenutzt */
    sg_hd->other_flags; /* unbenutzt */
#endif

    /* Befehl schicken */
    status = write( fd, i_buff, SCSI_OFF + cmd_len + in_size );
    if ( status &lt; 0 || status != SCSI_OFF + cmd_len + in_size || 
                       sg_hd->result ) {
        /* ein Fehler ist aufgetreten */
        fprintf( stderr, "write(generic) result = 0x%x cmd = 0x%x\n",
                    sg_hd->result, i_buff[SCSI_OFF] );
        perror("");
        return status;
    }
    
    if (!o_buff) o_buff = i_buff;       /* Pufferpointer checken */
    sg_hd = (struct sg_header *) o_buff;

    /* Ergebnis abholen */
    status = read( fd, o_buff, SCSI_OFF + out_size);
    if ( status &lt; 0 || status != SCSI_OFF + out_size || sg_hd->result ) {
        /* ein Fehler ist aufgetreten */
        fprintf( stderr, "read(generic) status = 0x%x, result = 0x%x, "
                         "cmd = 0x%x\n", 
                         status, sg_hd->result, o_buff[SCSI_OFF] );
        fprintf( stderr, "read(generic) sense "
                "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", 
                sg_hd->sense_buffer[0],         sg_hd->sense_buffer[1],
                sg_hd->sense_buffer[2],         sg_hd->sense_buffer[3],
                sg_hd->sense_buffer[4],         sg_hd->sense_buffer[5],
                sg_hd->sense_buffer[6],         sg_hd->sense_buffer[7],
                sg_hd->sense_buffer[8],         sg_hd->sense_buffer[9],
                sg_hd->sense_buffer[10],        sg_hd->sense_buffer[11],
                sg_hd->sense_buffer[12],        sg_hd->sense_buffer[13],
                sg_hd->sense_buffer[14],        sg_hd->sense_buffer[15]);
        if (status &lt; 0)
            perror("");
    }
    /* Nachsehen, ob wir bekommen haben, was wir wollten */
    if (status == SCSI_OFF + out_size) status = 0; /* alles bekommen */

    return status;  /* 0 bedeutet kein Fehler */
}
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>Auf den ersten Blick mag dies abschreckend wirken, jedoch dient der meiste
Code zur &Uuml;berpr&uuml;fung und zum Melden von Fehlern. Das ist 
n&uuml;tzlich,
selbst wenn der Code fehlerfrei gemacht wurde.</P>
<P><CODE>Handle_SCSI_cmd</CODE> hat eine generalisierte Form f&uuml;r alle Arten von
SCSI Kommandos, was den Transfer von Daten angeht. Es gibt diese Kategorien:</P>

<P>
<BLOCKQUOTE><CODE>
<PRE>
       Datenmodus                     | Beispiel Kommando
=========================================================
weder Eingabe- noch Ausgabe-Daten     | test unit ready
keine Eingabedaten, aber Ausgabedaten | inquiry, read
Eingabedaten, aber keine Ausgabedaten | mode select, write
Eingabedaten und Ausgabedaten         | mode sense
</PRE>
</CODE></BLOCKQUOTE>
</P>


<HR>
<A HREF="DE-SCSI-Programmierung-HOWTO-8.html"><IMG SRC="next.png" ALT="Weiter"></A>
<A HREF="DE-SCSI-Programmierung-HOWTO-6.html"><IMG SRC="prev.png" ALT="Zurück"></A>
<A HREF="DE-SCSI-Programmierung-HOWTO.html#toc7"><IMG SRC="toc.png" ALT="Inhalt"></A>
</BODY>
</HTML>