Le HOWTO Linux de la programmation SCSI
 Heiko  Eissfeldt [email protected] (version francaise
 : Thierry Danis [email protected], le  26  Janvier  1998,
 largement  basee  sur la traduction de la version v1.4 faite
 par Bernard Choppy [email protected]).
 v1.5, 7 Juin 1996

 Ce document traite de la programmation de l'interface  SCSI  generique
 de Linux.

 11..  LLeess nnoouuvveeaauutteess

 Les  interfaces  des  nouveaux  noyaux  ont un peu change. Le chapitre
 'rescrutation des peripheriques' est concerne par ces changements.  Il
 est  maintenant possible d'ajouter et d'enlever des peripheriques SCSI
 a chaud et a la volee.

 A  partir  de  la  version  1.3.98,  certains   fichiers   d'inclusion
 importants ont ete deplaces ou decoupes (sg.h and scsi.h).

 Quelques bugs idiots ont ete remplaces par d'autres.

 22..  IInnttrroodduuccttiioonn

 Ce  document  est  un  guide  d'installation  et  de  programmation de
 l'interface generique SCSI de Linux.

 Il traite des prerequis du noyau, de l'organisation des peripheriques,
 et  de  l'interaction  de  base  avec  ces derniers. Quelques exemples
 simples de programmation en C sont inclus. Pour de plus amples details
 sur  la  norme  SCSI  et  les  informations associees, reportez-vous a
 l'annexe de ce document.

 Note : la version texte simple  de  ce  document  ne  dispose  pas  de
 references croisees (indiquees par ``'').

 33..  QQuu''eesstt--ccee qquuee ll''iinntteerrffaaccee SSCCSSII ggeenneerriiqquuee ??

 L'interface generique SCSI a ete faite pour fournir un acces general a
 des  peripheriques  SCSI  (eventuellement  exotiques).  Elle   a   ete
 developpee  par Lawrence Foard ( [email protected]) et sponsorisee
 par   Killy   Corporation   (voir   les   commentaires   du    fichier
 drivers/scsi/sg.h).

 Cette interface permet a des programmes applicatifs (c'est-a-dire hors
 du noyau) d'acceder aux fonctionnalites de certains peripheriques.  Le
 developpement  de  pilotes dans le noyau, plus risques et difficiles a
 mettre au point, n'est ainsi plus necessaire.

 Neanmoins, si le peripherique n'est pas correctement programme, il est
 possible  de  bloquer  le  bus  SCSI,  le  pilote,  ou le noyau. C'est
 pourquoi  il  est  important  de  programmer  correctement  le  pilote
 generique,  et  de  commencer  par  sauvegarder tous les fichiers afin
 d'eviter une perte de donnees. Une autre precaution utile est de faire
 un  sync  avant  de  lancer vos programmes pour garantir l'ecriture de
 tous les tampons sur le disque ; cela limitera la perte de donnees  en
 cas de blocage du systeme.

 Un  autre  avantage  du  pilote generique est que, aussi longtemps que
 l'interface elle-meme ne change pas, toutes les  applications  restent
 independantes  des  nouveaux  developpements du noyau. En comparaison,
 les pilotes de bas niveau  du  noyau  doivent  suivre  les  evolutions
 internes de celui-ci.

 Typiquement, le pilote generique est utilise pour communiquer avec les
 nouveaux  equipements  SCSI  qui  exigent  l'ecriture   d'applications
 utilisateur  specifiques  pour  tirer avantage de leurs fonctionalites
 (par exemple les scanners, les imprimantes, le juke-boxes  de  CDROM).
 L'interface   generique   permet   un   developpement  rapide  de  ces
 applications.

 44..  QQuuee ffaauutt--iill ppoouurr ll''uuttiilliisseerr ??

 44..11..  CCoonnffiigguurraattiioonn dduu nnooyyaauu

 Il vous faut evidemment un adapteur SCSI reconnu. De plus, votre noyau
 doit  etre  compile  avec  le  support du pilote generique, en plus de
 celui pour votre adapteur.  La configuration du noyau Linux (par  make
 config sous /usr/src/linux) doit ressembler a :

       ...
      *
      * SCSI support
      *
      SCSI support? (CONFIG_SCSI) [n] y
      *
      * SCSI support type (disk, tape, CDrom)
      *
       ...
      Scsi generic support (CONFIG_CHR_DEV_SG) [n] y
      *
      * SCSI low-level drivers
      *
       ...

 Si  le  noyau  est modulable, vous pouvez tout aussi bien utiliser les
 modules.

 44..22..  FFiicchhiieerrss ssppeecciiaauuxx

 Le pilote generique utilise ses propres fichiers speciaux. Ils peuvent
 etre  crees par le script MAKEDEV, que l'on trouve habituellement dans
 le repertoire /dev. La commande MAKEDEV sg cree les fichiers  suivants
 :

      crw-------   1 root     system    21,   0 Aug 20 20:09 /dev/sga
      crw-------   1 root     system    21,   1 Aug 20 20:09 /dev/sgb
      crw-------   1 root     system    21,   2 Aug 20 20:09 /dev/sgc
      crw-------   1 root     system    21,   3 Aug 20 20:09 /dev/sgd
      crw-------   1 root     system    21,   4 Aug 20 20:09 /dev/sge
      crw-------   1 root     system    21,   5 Aug 20 20:09 /dev/sgf
      crw-------   1 root     system    21,   6 Aug 20 20:09 /dev/sgg
      crw-------   1 root     system    21,   7 Aug 20 20:09 /dev/sgh
                                         |    |
                             numeros majeur, mineur

 Notez  que  ces  fichiers  sont  des  fichiers  en mode caractere pour
 permettre les acces  directs.  Sur  certains  systemes,  ces  fichiers
 peuvent   s'appeler   /dev/{sg0,sg1,...},   en   fonction   de   votre
 installation. Vous devrez donc adapter les  exemples  qui  suivant  en
 consequence.

 44..33..  OOrrggaanniissaattiioonn ddeess ppeerriipphheerriiqquueess

 Les  fichiers  speciaux  sont affectes dynamiquement aux ID/LUN (LUN :
 Unite logique) du bus SCSI.  Les  peripheriques  sont  consecutivement
 alloues  selon les unites logiques de chaque peripherique detecte lors
 de la scrutation du bus, les plus petits LUN/ID/BUS etant  alloues  en
 premier.  Le noyau commence par le premier controleur SCSI et continue
 sans interruption avec tous les  autres  adapteurs.  Cette  etape  est
 actuellement realisee lors de l'initialisation du pilote SCSI.

 Par exemple, si vous avez trois peripheriques SCSI configures avec les
 ID 1, 3 et 5 sur le premier bus SCSI  (chacun  avec  une  seule  unite
 logique), l'affectation sera la suivante :

      /dev/sga -> SCSI id 1
      /dev/sgb -> SCSI id 3
      /dev/sgc -> SCSI id 5

 Si vous ajoutez maintenant un nouveau peripherique d'identificateur 4,
 l'organisation apres la prochaine scrutation du bus sera :

      /dev/sga -> SCSI id 1
      /dev/sgb -> SCSI id 3
      /dev/sgc -> SCSI id 4
      /dev/sgd -> SCSI id 5

 Notez  le  changement  pour  l'identificateur  5  -  le   peripherique
 correspondant n'est plus affecte a /dev/sgc, mais a /dev/sgd.

 Les noyaux plus recents permettent de changer cet ordre.

 44..33..11..  IInnsseerrttiioonn eett rreettrraaiitt ddyynnaammiiqquueess ddee ppeerriipphheerriiqquueess SSCCSSII

 Dans les noyaux recents avec un systeme de fichier /proc monte, il est
 possible de retirer et d'ajouter un peripherique libre (non-busy) a la
 volee.

 Pour enlever un peripherique SCSI :

      echo "scsi remove-single-device a b c d" > /proc/scsi/scsi

 De la meme maniere, ajouter un peripherique SCSI se fera par :

      echo "scsi add-single-device a b c d" > /proc/scsi/scsi

 Ici, a, b, c et d sont definis de la facon suivante :

            a == identificateur de l'adapteur (le premier a l'id 0)
            b == canal SCSI sur l'adapteur (le premier a le numero 0)
            c == ID
            d == LUN (la premiere ayant le numero 0)

 Ainsi,  si  nous  desirons  intervertir  l'affectation  des   fichiers
 /dev/sgc et /dev/sgd de l'exemple precedent, nous pouvons faire :

      echo "scsi remove-single-device 0 0 4 0" > /proc/scsi/scsi
      echo "scsi remove-single-device 0 0 5 0" > /proc/scsi/scsi
      echo "scsi add-single-device 0 0 5 0" > /proc/scsi/scsi
      echo "scsi add-single-device 0 0 4 0" > /proc/scsi/scsi

 puisque  les  peripheriques  generiques  sont  alloues dans leur ordre
 d'insertion.

 Si vous voulez ajouter de nouveaux  peripheriques  sur  le  bus  SCSI,
 gardez  a l'esprit qu'un nombre limite d'entrees supplementaires a ete
 attribue. La memoire a ete allouee au demarrage, et il n'y a de  place
 que pour 2 entrees supplementaires.

 55..  LLee gguuiiddee dduu pprrooggrraammmmeeuurr

 Les   sections  qui  suivent  s'adressent  aux  programmeurs  desireux
 d'utiliser l'interface generique SCSI dans leurs propres applications.
 Nous  allons  donner un exemple permettant d'acceder a un peripherique
 SCSI par le biais des commandes INQUIRY et TESTUNITREADY.

 Lors de l'utilisation de ces exemples, prenez garde a ce qui suit :

 +o  l'emplacement des fichiers d'inclusion sg.h et scsi.h  a  change  a
    partir  du  noyau  1.3.98.  Ces  fichiers  se trouvent maintenant a
    /usr/src/linux/include/scsi,  qui  devrait  etre   un   lien   vers
    /usr/include/scsi. Dans les versions precedentes, ils se trouvaient
    dans /usr/src/linux/drivers/scsi. Nous supposerons  dans  la  suite
    que vous utilisez un de ces noyaux recents.

 +o  l'interface  generique SCSI a ete etendue dans la version 1.1.68 du
    noyau.  Les  exemples  necessitent  au  moins  cette  version.   En
    revanche,  evitez  d'utiliser  les  noyaux  de  1.1.77 a 1.1.89 qui
    disposent d'une interface generique SCSI defectueuse.

 +o  la constante DEVICE de la section qui decrit le peripherique accede
    doit  etre positionnee en fonction de vos peripheriques disponibles
    (reportez-vous au chapitre ``La structure d'en-tete'').

 66..  VVuuee dd''eennsseemmbbllee ddee llaa pprrooggrraammmmaattiioonn ddeess ppeerriipphheerriiqquueess

 Le fichier d'inclusion include/scsi/sg.h contient une  description  de
 l'interface (celle du noyau 1.3.98) :

      struct sg_header
       {
                              /*
                               * longueur du paquet entrant (y compris en-tete)
                               */
        int pack_len;
                              /*
                               * taille max de la reponse attendue
                               */
        int reply_len;
                              /*
                               * numero d'id du paquet
                               */
        int pack_id;
                              /*
                               * 0 == ok,
                               * pour les autres, voir les codes pour errno
                               */
        int result;
                              /*
                               * Force la longueur a 12 pour les commandes des
                               * groupes 6 & 7
                               */
        unsigned int twelve_byte:1;
                              /*
                               * pour utilisation future
                               */
        unsigned int other_flags:31;
                              /*
                               * uniquement utilise lors des lectures
                               */
        unsigned char sense_buffer[16];
                              /*
                               * la commande suit puis les donnees de la
                               * commande
                               * .............
                               */

 Cette  structure decrit comment une commande SCSI doit etre traitee et
 disposer de place pour le resultat de son  execution.  Les  composants
 individuels de la structure seront abordes plus loin a la section ``La
 structure d'en-tete''.

 La methode generale pour echanger des donnees avec le pilote generique
 est  la  suivante  :  pour  envoyer  une  commande  a  un peripherique
 generique ouvert, il faut ecrire (write()) un bloc compose  des  trois
 parties suivantes :

                                   struct sg_header
                                     commande SCSI
                           donnees envoyees avec la commande

 Pour obtenir le resultat d'une commande, il faut lire (read()) un bloc
 composes des parties suivantes (similaires a l'ecriture) :

                                   struct sg_header
                                   donnees en entree

 Il s'agit d'une vue generale de la procedure. Les sections qui suivent
 decrivent chaque etape en detail.

 NOTE  :  jusqu'a de recentes versions du noyau, il etait necessaire de
 bloquer le signal  SIGINT  entre  les  appels  write()  et  le  read()
 correspondant  (par  exemple,  par  sigprocmask()). Un retour apres la
 partie ecriture sans lecture pour recuperer les resultats  va  bloquer
 les  acces  suivants.  Le  blocage du signal n'a pas encore ete inclus
 dans le code des exemples. Evitez donc d'envoyer un  SIGINT  (par  ^C,
 par exemple) lors du test de ceux-ci.

 77..  OOuuvveerrttuurree dduu ppeerriipphheerriiqquuee

 Un peripherique generique doit etre ouvert avant tout acces en lecture
 ou en ecriture :

              int fd = open(nom_du_peripherique, O_RDWR);

 (ce qui precede s'applique aussi pour les materiels en  lecture  seule
 comme les lecteurs de CDROM).

 Il  faut executer un write pour envoyer la commande et un read pour en
 lire le resultat. En cas d'erreur, le code de retour est  negatif  (se
 reporter  a la section ``Traitement d'erreurs'' pour la liste complete
 des codes de retour).

 88..  LLaa ssttrruuccttuurree dd''eenn--tteettee

 La structure d'en-tete struct sg_header est utilisee comme  couche  de
 controle   entre  l'application  et  le  pilote  du  noyau.   Abordons
 maintenant le detail de ses composants.

    iinntt ppaacckk__lleenn
       definit la taille du bloc envoye au  pilote.  Cette  valeur  est
       definie dans le noyau pour une utilisation interne.

    iinntt rreeppllyy__lleenn
       definit  la  taille du bloc accepte en reponse. Cette valeur est
       definie du cote application.

    iinntt ppaacckk__iidd
       Ce champ  facilite  l'appariement  des  reponses  aux  requetes.
       L'application  peut  fournir  un  identifiant  unique  a  chaque
       requete. Supposons que vous ayez  ecrit  un  certain  nombre  de
       commandes  (disons  4)  pour  un peripherique. Celles-ci peuvent
       fonctionner en parallele, l'une  d'entre  elles  etant  la  plus
       rapide.  Lors  de  la  lecture  des  reponses par quatre "read",
       celles-ci ne sont pas forcement dans l'ordre des requetes.  Pour
       identifier  la  reponse  correcte  pour  une  requete,  on  peut
       utiliser le champ  pack_id.  Habituellement,  cette  valeur  est
       incrementee  apres chaque requete (et boucle eventuellement). Le
       nombre maximum de requetes emises simultanement est  limite  par
       le noyau a SG_MAX_QUEUE (en general, quatre).

    iinntt rreessuulltt
       C'est  la  valeur du resultat d'un appel a read ou a write. Elle
       est (parfois) definie par la le pilote generique (partie noyau).
       Il est plus prudent de le positionner a 9 avant l'appel a write.
       Ces codes sont declares dans le fichier errno.h  (0  indique  un
       resultat correct).

    uunnssiiggnneedd iinntt ttwweellvvee__bbyyttee::11
       Ce champ n'est necessaire que lors de l'utilisation de commandes
       specifiques non standard (dans la plage 0xc0 a 0xff). Lorsque la
       longueur  de  ces  commandes  est de 12 octets au lieu de 10, il
       faut positionner ce champ a 1 avant l'appel  a  write.  D'autres
       longueurs  de  commandes ne peuvent etre utilisees. Ce champ est
       positionne par l'application.

    uunnssiiggnneedd cchhaarr sseennssee__bbuuffffeerr[[1166]]
       Ce tampon est positionne apres l'execution d'une commande (apres
       un appel a read()) et contient le code de "sensation" SCSI (SCSI
       send code. NdT. :  dans  le  reste  du  document,  on  utilisera
       simplement  la  formule  "tampon  SCSI").  Certains resultats de
       commandes doivent etre lus a cet emplacement (par  exemple  pour
       TESTUNITREADY).  Il  ne  contient  habituellement que des octets
       nuls. La valeur de  ce  champ  est  positionnee  par  le  pilote
       generique (partie noyau).

 L'exemple  de fonction qui suit s'interface directement avec le pilote
 generique du noyau. Il  definit  la  structure  d'en-tete,  envoie  la
 commande  par  write,  lit  le resultat par read et effectue un nombre
 (limite) de controles d'erreurs.  Les  donnees  du  tampon  SCSI  sont
 disponibles  dans  le  tampon de sortie (sauf si un pointeur nul a ete
 fourni, auquel cas elles se trouvent dans le  tampon  d'entree).  Nous
 l'utiliserons dans les exemples qui suivent.

 Note  : positionnez la valeur de DEVICE a celle qui correspond a votre
 materiel.

 #define DEVICE "/dev/sgc"

 /* Programme d'exemple utilisant l'interface SCSI generique */
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <scsi/sg.h>

 #define SCSI_OFF sizeof(struct sg_header)
 static  unsigned char cmd[SCSI_OFF + 18];       /* tampon de commande SCSI */
 int     fd;                                     /*
                                                  * descripteur de peripherique/
                                                  * fichier SCSI
                                                  */
 /* traite une commande SCSI complete. Utilise l'interface generique */
 static int handle_SCSI_cmd(unsigned cmd_len,     /* longueur de commande  */
                            unsigned in_size,     /* taille data en entree */
                            unsigned char *i_buff,/* tampon d'entree       *//
                            unsigned out_size,    /* taille data en sortie */
                            unsigned char *o_buff /* tampon de sortie      */
                            )
 {
     int status = 0;
     struct sg_header *sg_hd;

     /* verifications de securite */
     if (!cmd_len) return -1;            /* necessite que cmd_len != 0 */
     if (!i_buff) return -1;             /* necessite que i_buff != 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;          /* pas de tampon de sortie, pas de */
                                         /* taille                          */

     /* construction de l'en-tete generique de peripherique */
     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; /* non indispensable */
     sg_hd->pack_id;     /* inutilise */
     sg_hd->other_flags; /* inutilise */
 #endif

     /* envoi de la commande */
     status = write( fd, i_buff, SCSI_OFF + cmd_len + in_size );
     if ( status < 0 || status != SCSI_OFF + cmd_len + in_size ||
                        sg_hd->result ) {
         /* condition d'erreur */
         fprintf( stderr, "write(generic) resultat = 0x%x cmd = 0x%x\n",
                     sg_hd->result, i_buff[SCSI_OFF] );
         perror("");
         return status;
     }

     if (!o_buff) o_buff = i_buff; /* controle du pointeur du tampon */
     /* recuperation du resultat */
     status = read( fd, o_buff, SCSI_OFF + out_size);
     if ( status < 0 || status != SCSI_OFF + out_size || sg_hd->result ) {
         /* condition d'erreur */
         fprintf( stderr, "read(generic) statut = 0x%x, resultat = 0x%x, "
                          "cmd = 0x%x\n",
                          status, sg_hd->result, o_buff[SCSI_OFF] );
         fprintf( stderr, "read(generic) tampon SCSI "
                 "%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 < 0)
             perror("");
     }
     /* A-t-on ce qu'on attendait ? */
     if (status == SCSI_OFF + out_size) status = 0; /* on a tout */

     return status;  /* 0 indique que tout est bon */
 }

 Bien que cela puisse sembler quelque peu complexe  au  premier  abord,
 une  grande  partie  du  code  est  dediee  aux  controle et detection
 d'erreurs (ce qui est utile meme  une  fois  que  le  code  fonctionne
 correctement).

 Handle_SCSI_cmd  presente une forme generalisee pour tous les types de
 commandes SCSI, qui correspondent a l'une des categories qui suivent :

           Mode de donnees            |    Exemple de commande
      =============================================================
      ni entree ni sortie de donnees  |     test d'unite prete
      pas d'entree, sortie de donnees |      requete, lecture
      entree de donnees, pas de sortie| selection de mode, ecriture
        entree et sortie de donnees   |     detection de mode

 99..  EExxeemmppllee ddee ccoommmmaannddee ddee rreeqquueettee

 L'une des commandes SCSI de base est INQUIRY, utilisee pour identifier
 les type et constructeur du peripherique. Voici la definition issue de
 la  specification  SCSI-2  (se  reporter  au  standard SCSI-2 pour les
 details).

                             Table 44: Commande INQUIRY
 +=====-========-========-========-========-========-========-========-========+
 |  Bit|   7    |   6    |   5    |   4    |   3    |   2    |   1    |   0    |
 |Octet|        |        |        |        |        |        |        |        |
 |=====+=======================================================================|
 | 0   |                           Code operation (12h)                        |
 |-----+-----------------------------------------------------------------------|
 | 1   |Numero d'unite logique    |                  Reserve          |  EVPD  |
 |-----+-----------------------------------------------------------------------|
 | 2   |                           Code page                                   |
 |-----+-----------------------------------------------------------------------|
 | 3   |                           Reserve                                     |
 |-----+-----------------------------------------------------------------------|
 | 4   |                           Taille d'allocation                         |
 |-----+-----------------------------------------------------------------------|
 | 5   |                           Controle                                    |
 +=============================================================================+

 Les donnees en sortie ont l'allure suivante :

                    Table 45: Format standard de donnees INQUIRY
 +=====-========-========-========-========-========-========-========-========+
 |  Bit|   7    |   6    |   5    |   4    |   3    |   2    |   1    |   0    |
 |Octet|        |        |        |        |        |        |        |        |
 |=====+==========================+============================================|
 | 0   | Qualificateur de periph. |           Type de peripherique             |
 |-----+-----------------------------------------------------------------------|
 | 1   |  RMB   |                  Modificateur de type de peripherique        |
 |-----+-----------------------------------------------------------------------|
 | 2   |   Version ISO   |       Version ECMA       |  Version approuvee ANSI  |
 |-----+-----------------+-----------------------------------------------------|
 | 3   |  AENC  | TrmIOP |     Reserve     |   Format de donnees en reponse    |
 |-----+-----------------------------------------------------------------------|
 | 4   |                    Longueur additionnelle (n-4)                       |
 |-----+-----------------------------------------------------------------------|
 | 5   |                           Reserve                                     |
 |-----+-----------------------------------------------------------------------|
 | 6   |                           Reserve                                     |
 |-----+-----------------------------------------------------------------------|
 | 7   | RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserve | CmdQue | SftRe  |
 |-----+-----------------------------------------------------------------------|
 | 8   | (MSB)                                                                 |
 |- - -+---                      Identification de constructeur             ---|
 | 15  |                                                                 (LSB) |
 |-----+-----------------------------------------------------------------------|
 | 16  | (MSB)                                                                 |
 |- - -+---                      Identification de produit                  ---|
 | 31  |                                                                 (LSB) |
 |-----+-----------------------------------------------------------------------|
 | 32  | (MSB)                                                                 |
 |- - -+---                      Niveau de revision du produit              ---|
 | 35  |                                                                 (LSB) |
 |-----+-----------------------------------------------------------------------|
 | 36  |                                                                       |
 |- - -+---                      Specifique constructeur                    ---|
 | 55  |                                                                       |
 |-----+-----------------------------------------------------------------------|
 | 56  |                                                                       |
 |- - -+---                        Reserve                                  ---|
 | 95  |                                                                       |
 |=====+=======================================================================|
 |     |                       Parametres specifiques constructeur             |
 |=====+=======================================================================|
 | 96  |                                                                       |
 |- - -+---                      Specifique constructeur                    ---|
 | n   |                                                                       |
 +=============================================================================+

 L'exemple qui suit utilise la fonction de bas  niveau  handle_SCSI_cmd
 pour effectuer la commande SCSI INQUIRY.

 Tout d'abord, nous ajoutons le bloc de commande a l'en-tete generique,
 puis appelons handle_SCSI_cmd. Notez que l'argument taille  de  tampon
 en  sortie  de  l'appel  handle_SCSI_cmd exclut la taille de l'en-tete
 generique. Apres l'execution de  la  commande,  le  tampon  de  sortie
 contient les informations, sauf si une erreur s'est produite.

 #define INQUIRY_CMD     0x12
 #define INQUIRY_CMDLEN  6
 #define INQUIRY_REPLY_LEN 96
 #define INQUIRY_VENDOR  8       /* decalage vers le nom du constructeur */

 /* recherche du constructeur et du modele */
 static unsigned char *Inquiry ( void )
 {
   unsigned char Inqbuffer[ SCSI_OFF + INQUIRY_REPLY_LEN ];
   unsigned char cmdblk [ INQUIRY_CMDLEN ] =
       { INQUIRY_CMD,  /* commande                 */
                   0,  /* lun/reserve              */
                   0,  /* code de page             */
                   0,  /* reserve                  */
   INQUIRY_REPLY_LEN,  /* longueur allocation      */
                   0 };/* reserve / drapeau / lien */

   memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) );

   /*
    * +------------------+
    * | struct sg_header | <- commande
    * +------------------+
    * | copie de cmdblk  | <- commande + SCSI_OFF
    * +------------------+
    */

   if (handle_SCSI_cmd(sizeof(cmdblk), 0, cmd,
                       sizeof(Inqbuffer) - SCSI_OFF, Inqbuffer )) {
       fprintf( stderr, "La requete a echoue\n" );
       exit(2);
   }
   return (Inqbuffer + SCSI_OFF);
 }

 L'exemple  ci-dessus suit cette structure. La fonction Inquiry recopie
 son bloc de commande apres l'en-tete generique (donne  par  SCSI_OFF).
 Les donnees en entree sont absentes de cette commande. handle_SCSI_cmd
 definit la structure d'en-tete. Nous pouvons maintenant implementer la
 fonction main qui complete ce programme d'exemple fonctionnel.

      void main( void )
      {
        fd = open(DEVICE, O_RDWR);
        if (fd < 0) {
          fprintf( stderr, "Il faut les permissions lecture/ecriture pour "DEVICE".\n" );
          exit(1);
        }

        /* affiche certains champs du resultat de Inquiry() */
        printf( "%s\n", Inquiry() + INQUIRY_VENDOR );
      }

 Tout  d'abord,  nous  ouvrons  le  peripherique,  controlons l'absence
 d'erreur, puis appelons la fonction  de  haut  niveau.  Ensuite,  nous
 affichons  des resultats sous une forme lisible, dont le constructeur,
 le produit et la version.

 Note : il y a plus d'informations dans le resultat de "Inquiry" que ce
 que  fournit ce petit programme. Il vous est loisible d'etendre celui-
 ci au type de peripherique, version ANSI, etc. Le type de peripherique
 a  une  importance  particuliere,  puisqu'il  determine  les  jeux  de
 commandes obligatoires et  facultatives  pour  celui-ci.  Si  vous  ne
 souhaitez  pas  le  programmer  vous-meme, Eric Youngdale a realise le
 programme  scsiinfo,  qui  fournit  a  peu  pres   toute   information
 disponible pour un peripherique SCSI. Cherchez sur tsx-11.mit.edu dans
 pub/Linux/ALPHA/scsi (NdT : on trouvera ce  programme  sur  les  sites
 miroirs francais, comme ftp.ibp.fr, a un emplacement similaire).

 1100..  LLee ""ttaammppoonn SSCCSSII""

 Les  commandes  qui  ne  renvoient  pas de donnees peuvent fournir des
 informations  d'etat  a  l'aide  du  tampon  SCSI  (qui  fait   partie
 integrante  de  la  structure  d'en-tete).  Les  donnees  d'etat  sont
 disponibles lorsque la commande  precedente  s'est  terminee  avec  un
 statut   "CHECK   CONDITION".   Dans   ce   cas,   le  noyau  rapatrie
 automatiquement les donnees d'etat a l'aide  d'une  commande  "REQUEST
 SENSE". Sa structure est la suivante :

      +=====-========-========-========-========-========-========-========-========+
      |  Bit|   7    |   6    |   5    |   4    |   3    |   2    |   1    |   0    |
      |Octet|        |        |        |        |        |        |        |        |
      |=====+========+==============================================================|
      | 0   | Valide |                  Code d'erreur (70h ou 71h)                  |
      |-----+-----------------------------------------------------------------------|
      | 1   |                           Numero de segment                           |
      |-----+-----------------------------------------------------------------------|
      | 2   |Filemark|  EOM   |  ILI   |Reserve |         Clef d'etat               |
      |-----+-----------------------------------------------------------------------|
      | 3   | (MSB)                                                                 |
      |- - -+---                        Information                              ---|
      | 6   |                                                                 (LSB) |
      |-----+-----------------------------------------------------------------------|
      | 7   |                           Longueur additionnelle d'etat (n-7)         |
      |-----+-----------------------------------------------------------------------|
      | 8   | (MSB)                                                                 |
      |- - -+---                        Information specifique de la commande    ---|
      | 11  |                                                                 (LSB) |
      |-----+-----------------------------------------------------------------------|
      | 12  |                           Code d'etat additionnel                     |
      |-----+-----------------------------------------------------------------------|
      | 13  |                           Qualificateur de code d'etat additionnel    |
      |-----+-----------------------------------------------------------------------|
      | 14  |                           Code d'unite de champ remplacable           |
      |-----+-----------------------------------------------------------------------|
      | 15  |  SKSV  |                                                              |
      |- - -+------------               Specifique clef d'etat                   ---|
      | 17  |                                                                       |
      |-----+-----------------------------------------------------------------------|
      | 18  |                                                                       |
      |- - -+---                        Octets supplementaires d'etat            ---|
      | n   |                                                                       |
      +=============================================================================+

 Note  :  les  champs  les plus utiles sont la clef d'etat (cf. section
 ``Clefs  du  buffer  SCSI''),  le  code  d'etat  additionnel   et   le
 qualificateur  de  code  d'etat  additionnel  (cf.  section ``Codes et
 qualificateurs du buffer SCSI additionnels''). Les deux derniers  sont
 utilises en combinaison l'un avec l'autre.

 1111..  EExxeemmppllee dd''uuttiilliissaattiioonn dduu ttaammppoonn SSCCSSII

 Nous  allons utiliser ici la commande "TEST UNIT READY" pour controler
 si un support est charge dans  notre  peripherique.  Les  declarations
 d'en-tete  et  la  fonction  handle_SCSI_cmd de l'exemple de "Inquiry"
 seront aussi necessaires.

                              Table 73: Commande TEST UNIT READY
      +=====-========-========-========-========-========-========-========-========+
      |  Bit|   7    |   6    |   5    |   4    |   3    |   2    |   1    |   0    |
      |Octet|        |        |        |        |        |        |        |        |
      |=====+=======================================================================|
      | 0   |                           Code operation (00h)                        |
      |-----+-----------------------------------------------------------------------|
      | 1   |Numero d'unite logique LUN|                  Reserve                   |
      |-----+-----------------------------------------------------------------------|
      | 2   |                           Reserve                                     |
      |-----+-----------------------------------------------------------------------|
      | 3   |                           Reserve                                     |
      |-----+-----------------------------------------------------------------------|
      | 4   |                           Reserve                                     |
      |-----+-----------------------------------------------------------------------|
      | 5   |                           Controle                                    |
      +=============================================================================+

 Voici la fonction qui l'implemente :

 #define TESTUNITREADY_CMD 0
 #define TESTUNITREADY_CMDLEN 6

 #define ADD_SENSECODE 12
 #define ADD_SC_QUALIFIER 13
 #define NO_MEDIA_SC 0x3a
 #define NO_MEDIA_SCQ 0x00

 int TestForMedium ( void )
 {
   /* demande le statut READY */
   static unsigned char cmdblk [TESTUNITREADY_CMDLEN] = {
       TESTUNITREADY_CMD, /* commande */
                       0, /* lun/reserve */
                       0, /* reserve */
                       0, /* reserve */
                       0, /* reserve */
                       0};/* controle */

   memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) );

   /*
    * +------------------+
    * | struct sg_header | <- commande
    * +------------------+
    * | copie de cmdblk  | <- commande + SCSI_OFF
    * +------------------+
    */

   if (handle_SCSI_cmd(sizeof(cmdblk), 0, cmd,
                             0, NULL)) {
       fprintf (stderr, "Unite non prete\n");
       exit(2);
   }

   return
    *(((struct sg_header*)cmd)->sense_buffer +ADD_SENSECODE) !=
                                                         NO_MEDIA_SC ||
    *(((struct sg_header*)cmd)->sense_buffer +ADD_SC_QUALIFIER) !=
                                                         NO_MEDIA_SCQ;
 }

 Nous pouvons maintenant realiser le controle a l'aide de  la  fonction
 main :

 void main( void )
 {
   fd = open(DEVICE, O_RDWR);
   if (fd < 0) {
     fprintf( stderr, "Il faut les permissions lecture/ecriture pour "DEVICE".\n"
  );
     exit(1);
   }

   /* on regarde si le support est charge */

   if (!TestForMedium()) {
     printf("le support n'est pas charge\n");
   } else {
     printf("le support est charge\n");
   }
 }

 Le fichier generic_demo.c en annexe contient les deux exemples.

 1122..  FFoonnccttiioonnss iiooccttll

 Deux fonctions ioctl sont disponibles :

 +o  ioctl(fd, SG_SET_TIMEOUT, &Timeout); definit la valeur du timeout a
    Timeout * 10 millisecondes.  Timeout  doit  etre  declare  en  tant
    qu'entier (int).

 +o  ioctl(fd,  SG_GET_TIMEOUT,  &Timeout);  lit la valeur du timeout en
    cours. Timeout doit etre declare en tant qu'entier (int).

 1133..  VVaalleeuurrss ppaarr ddeeffaauutt dduu ppiilloottee

 1133..11..  TTaaiilllleess ddee ttrraannssffeerrtt

 Actuellement (au moins jusqu'au noyau  version  1.1.68),  les  tailles
 d'entree  et  de  sortie  doivent  etre  inferieures  ou egales a 4096
 octets, sauf si le noyau a ete compile avec la  constante  SG_BIG_BUFF
 definie,  auquel  cas  elles sont limitees  a SG_BIG_BUFF (soit 32768)
 octets. Les tailles donnees comprennent l'en-tete generique ainsi  que
 le bloc de commande fourni en entree.  SG_BIG_BUFF peut etre augmentee
 sans probleme jusqu'a (131072 - 512). Pour en beneficier, vous  devrez
 bien evidemment regenerer un nouveau noyau et redemarrer avec.

 1133..22..  TTiimmeeoouutt eett vvaalleeuurrss ddee rreeeessssaaiiss

 La  valeur  du  timeout par defaut est d'une minute (Timeout = 6 000).
 Elle peut etre modifiee a l'aide  d'un  appel  a  ioctl  (cf.  section
 ``Fonctions ioctl'').  Le nombre de reessais par defaut est un.

 1144..  CCoommmmeenntt oobbtteenniirr lleess ssppeecciiffiiccaattiioonnss SSCCSSII ??

 Il  existe  des  normes  appelees SCSI-1, SCSI-2 et SCSI-3. Les normes
 assurent a peu de choses pres la compatibilite ascendante.

 Le standard SCSI-1 est (d'apres l'auteur) en grande  partie  obsolete,
 et SCSI-2 est celui qui est le plus largement utilise. SCSI-3 est tres
 jeune et tres cher. Ces jeux de commandes normalises  definissent  des
 commandes  obligatoires  et  facultatives  pour  les  constructeurs de
 materiels SCSI et doivent etre preferees  aux  extensions  specifiques
 non  normalisees et pour lesquelles l'information est plus difficile a
 obtenir. Evidemment,  il  n'y  a  parfois  aucune  alternative  a  ces
 extensions proprietaires.

 Des copies electroniques sont disponibles par FTP anonyme depuis :

 +o  ftp.cs.tulane.edu:pub/scsi

 +o  ftp.symbios.com:/pub/standards

 +o  ftp.cs.uni-sb.de:/pub/misc/doc/scsi

 (J'ai  eu  mes  specifications  SCSI dans le CD-ROM Linux d'Yggdrasil,
 dans le repertoires /usr/doc/scsi-2 et /usr/doc/scsi-1).

 La FAQ SCSI liste aussi les sources d'information imprimee suivantes :

 Les specifications SCSI - disponible depuis :

            Global Engineering Documents
            15 Inverness Way East
            Englewood Co  80112-5704
            (800) 854-7179
              SCSI-1: X3.131-1986
              SCSI-2: X3.131-199x
              SCSI-3 X3T9.2/91-010R4 Working Draft

      (Global Engineering Documentation in Irvine, CA (714)261-1455??)

      SCSI-1: Doc \# X3.131-1986 from ANSI, 1430 Broadway, NY, NY 10018

      IN-DEPTH EXPLORATION OF SCSI peut etre trouve chez
      Solution Technology, Attn: SCSI Publications, POB 104, Boulder Creek,
      CA 95006, (408)338-4285, FAX (408)338-4374

      THE SCSI ENCYLOPEDIA et SCSI BENCH REFERENCE peuvent etre obtenus chez
      ENDL Publishing, 14426 Black Walnut Ct., Saratoga, CA 95090,
      (408)867-6642, FAX (408)867-2115

      SCSI: UNDERSTANDING THE SMALL COMPUTER SYSTEM INTERFACE est publie chez
      Prentice-Hall, ISBN 0-13-796855-8

 1155..  DD''aauuttrreess ssoouurrcceess dd''iinnffoorrmmaattiioonn

 1155..11..  HHOOWWTTOOss eett FFAAQQss

 Le  SSCCSSII--HHOOWWTTOO  Linux  de  Drew  Eckhardt (NdT : disponible en version
 francaise) traite de tous les controleurs SCSI reconnus ainsi que  des
 questions  specifiques  aux  peripheriques.  De nombreux aides pour le
 depannage sont fournies. Il est disponible  sur  sunsite.unc.edu  dans
 /pub/Linux/docs/LDP et sur ses sites miroirs.

 Les questions generales concernant le SCSI ont une reponse dans la FAQ
 SCSI du groupe de news comp.periphs.scsi (disponible sur  tsx-11  dans
 /pub/linux/ALPHA/scsi et sur les sites miroirs).

 1155..22..  LLaa lliissttee ddee mmeessssaaggeerriiee

 Il  existe une lliissttee ddee mmeessssaaggeerriiee qui traite des rapports d'anomalies
 et questions sur le developpement SCSI sous Linux. Pour la  rejoindre,
 envoyez   un  courrier  a  [email protected]  avec  la  ligne
 subscribe linux-scsi dans le corps du message.  Les  messages  doivent
 etre  envoyes a [email protected]. Un texte d'aide peut etre
 demande   par   envoi   de   la   ligne   de    message    "help"    a
 [email protected].

 1155..33..  EExxeemmpplleess ddee ccooddee

    ssuunnssiittee..uunncc..eedduu:: aappppss//ggrraapphhiiccss//hhppssccaannppbbmm--00..33aa..ttaarr..ggzz
       Ce  paquetage gere un scanner HP scanjet a l'aide de l'interface
       generique.

    ttssxx--1111..mmiitt..eedduu:: BBEETTAA//ccddrroomm//pprriivvaattee//mmkkiissooffss//ccddwwrriittee--11..33..ttaarr..ggzz
       Le paquetage cdwrite utilise l'interface generique  pour  ecrire
       une image de CD sur un graveur.

    ssuunnssiittee..uunncc..eedduu:: aappppss//ssoouunndd//ccddss//ccddddaa22wwaavv**..ssrrcc..ttaarr..ggzz
       Un composant pour mes propres applications, qui copie des pistes
       audio de CD sous forme de fichiers wav.

 1166..  AAuuttrreess cchhoosseess uuttiilleess

 Des choses qui pourraient devenir pratiques. Je n'ai aucune idee de la
 presence  de  versions  plus  recentes  ou meilleures ici ou la. Toute
 information est la bienvenue.

 1166..11..  AAiiddeess aa ll''eeccrriittuurree ddee ppiillootteess ddee ppeerriipphheerriiqquueess

 Ces  documents  peuvent  etre  trouves   sur   le   serveur   ftp   de
 sunsite.unc.edu et sur ses miroirs.

    //ppuubb//LLiinnuuxx//ddooccss//kkeerrnneell//kkeerrnneell--hhaacckkeerrss--gguuiiddee
       Le  guide  des  stakhanovistes  du  noyau  LDP  (NdT : Projet de
       Documentation Linux). Il  est  peut-etre  un  peu  ancien,  mais
       traite les points les plus fondamentaux.

    //ppuubb//LLiinnuuxx//ddooccss//kkeerrnneell//ddrriivveerrss..ddoocc..zz
       Ce document traite de l'ecriture de pilotes caracteres.

    //ppuubb//LLiinnuuxx//ddooccss//kkeerrnneell//ttuuttoorriiaall..ddoocc..zz
       Tutoriel  sur  l'ecriture  d'un pilote de peripherique caractere
       avec le code.

    //ppuubb//LLiinnuuxx//ddooccss//kkeerrnneell//ssccssii..ppaappeerr..ttaarr..ggzz
       Un document Latex decrivant comment ecrire un pilote SCSI.

    //ppuubb//LLiinnuuxx//ddooccss//hhaarrddwwaarree//DDEEVVIICCEESS
       Une liste des numeros majeurs et mineurs utilises par Linux.

 1166..22..  UUttiilliittaaiirreess

    ttssxx--1111..mmiitt..eedduu:: AALLPPHHAA//ssccssii//ssccssiiiinnffoo**..ttaarr..ggzz
       Programme d'interrogation d'un peripherique  SCSI  pour  obtenir
       ses  parametres  d'utilisation,  listes  de  defauts,  etc.  Une
       interface X necessitant Tk/Tcl/wish est disponible.  Avec  cette
       derniere,  vous  pouvez  facilement modifier la configuration du
       lecteur.

    ttssxx--1111..mmiitt..eedduu:: AALLPPHHAA//kkddeebbuugg
       Une extension a pour le deverminage du noyau.

 1177..  AAuuttrreess iinntteerrffaacceess dd''aacccceess aauu SSCCSSII

 Sous Linux, on peut acceder differemment au SCSI via des appels  ioctl
 SCSI_IOCTL_SEND_COMMAND  qui  necessitent  des  privileges  root.  Les
 paquetages "scsiinfos" ainsi que "cdda2wav" les utilisent.

 D'autres interfaces similaires sont utilisees dans le monde Unix, mais
 ne sont pas disponibles pour Linux :

 1. CAM (Common Access Method) developpee par Future Domain et d'autres
    constructeurs SCSI. Linux dispose  maintenant  d'un  petit  support
    pour  un  systeme  CAM  SCSI (essentiellement pour bouter depuis un
    disque dur).  CAM supporte meme le mode  "target",  qui  permet  de
    deguiser  un  ordinateur  en  peripherique SCSI (c.a.d. realiser un
    petit reseau SCSI).

 2. ASPI (Advanced SCSI Programming Interface) developpee par  Adaptec.
    C'est le standard de facto pour les machines MS-DOS.

 3. ??? est disponible sur NeXTStep.

 4. DSLIB est disponible sur Silicon Graphics.

 5. SCSI... est disponible sur les machines SUN.

 6. SCO Unix a aussi quelque chose.

 7. HPUX utilise des ioctl.  -->

 D'autres   interfaces   applicatives   existent  aussi  chez  SCO(TM),
 NeXT(TM), Silicon Graphics(TM) et SUN(TM).

 1188..  CCoommmmeennttaaiirreess ffiinnaallss

 L'interface generique SCSI jette  un  pont  sur  le  fosse  entre  les
 applications utilisateur et les peripheriques specifiques. Mais plutot
 que de charger de nombreux programmes  avec  des  jeux  similaires  de
 fonctions  de bas niveau, il serait plus souhaitable de disposer d'une
 bibliotheque partagee avec un  jeu  generalise  de  fonctions  de  bas
 niveau  pour un usage particulier. Le but principal est de disposer de
 couches d'interfaces independantes. Une bonne conception doit  separer
 une  application  en  routines  de  bas  niveau  et  independantes  du
 materiel.  Celles-ci  peuvent  etre  placees  dans  une   bibliotheque
 partagee  et  rendues disponibles pour toutes les applications. Ainsi,
 les interfaces standardisees doivent etre suivies autant que  possible
 avant d'en realiser de nouvelles.

 Vous  devriez  maintenant  en  savoir  plus  que  moi  sur l'interface
 generique SCSI de Linux. Vous pouvez donc commencer  a  developper  de
 puissantes  applications  pour le plus grand benefice de la communaute
 Linux...

 1199..  RReemmeerrcciieemmeennttss

 Un grand merci a Jeff Tranter pour ses  corrections  et  ameliorations
 considerables   de  ce  texte,  ainsi  qu'a  Carlos  Puchol  pour  ses
 commentaires utiles.  L'aide de Drew Eckhardt et  Eric  Youngdale  sur
 mes premieres questions (idiotes) sur l'utilisation de cette interface
 a ete appreciee.

 TT..  AAnnnneexxee

 UU..  TTrraaiitteemmeenntt dd''eerrrreeuurrss

 Les fonctions open, ioctl, write et read peuvent renvoyer des erreurs.
 Dans ce cas, leur valeur de retour est -1 et la variable globale errno
 est positionnee au numero d'erreur (negatif).  Les  valeurs  de  errno
 sont   definies  dans  /usr/include/errno.h.   Les  valeurs  negatives
 possibles sont les suivantes :

      Fonction | Erreur       | Description
      =========|==============|==================================================
      open     |  ENXIO       | peripherique invalide
               |  EACCES      | l'acces n'est pas en lecture/ecriture (O_RDWR)
               |  EBUSY       | le peripherique est accede en mode non bloquant,
               |              | mais il est occupe actuellement
               |  ERESTARTSYS | erreur interne. Essayez de la rendre reproductible
               |              | et informez-en le canal SCSI (pour les details sur
               |              | le rapport de bogue, se reporter au SCSI-HOWTO de
               |              | Drew Eckhardts).
      ioctl    |  ENXIO       | peripherique invalide
      read     |  EAGAIN      | le peripherique bloque. Essayez plus tard.
               |  ERESTARTSYS | erreur interne. Essayez de la rendre reproductible
               |              | et informez-en le canal SCSI (pour les details sur
               |              | le rapport de bogue, se reporter au SCSI-HOWTO de
               |              | Drew Eckhardts).
      write    |  EIO         | taille trop petite (plus petite que cette de l'en-
               |              | tete generique). Attention : il n'y a actuellement
               |              | aucun controle de debordement.
               |  EAGAIN      | le peripherique bloque. Essayez plus tard.
               |  ENOMEM      | la memoire necessaire pour cette requete ne peut
               |              | etre allouee. Essayez plus tard sauf si vous depas-
               |              | sez la taille maximale de transfert (cf. ci-dessus).
      select   |              | sans description
      close    |              | sans description

 Pour la lecture  et  l'ecriture,  des  valeurs  de  retour  positivent
 indiquent  comme  d'habitude  la  quantite  d'octets transferes. Cette
 valeur doit correspondre a celle demandee.

 UU..11..  DDeeccooddaaggee ddee ll''eettaatt dd''eerrrreeuurr

 En plus, une information detaillee est fournie par hd_status du  noyau
 et   par  sense_buffer  du  peripherique  (cf.  section  ref  id="sec-
 sensebuff" name="Le tampon SCSI">), les deux  utilisant  la  structure
 d'en-tete generique.

 Les   differents   sens   de   hd_status  peuvent  etre  trouves  dans
 drivers/scsi/scsi.h. Cet  unsigned  int  est  compose  de  differentes
 parties :

   lsb  |    ...    |    ...    | msb
 =======|===========|===========|============
 status | sense key | host code | driver byte

 Les  macros  de  drivers/scsi/scsi.h  sont  disponibles, mais elles ne
 peuvent  malheureusement  pas  etre  facilement  utilisees   a   cause
 d'interdependances tordues entre fichiers d'en-tete. Il faudrait faire
 une passe sur ces fichiers pour clarifier les choses.

              Macro          | Description
      =======================|=================================================
      status_byte(hd_status) | Etat du peripherique. cf. section Codes d'etat
      msg_byte(hd_status)    | du peripherique. cf. section buffer SCSI
      host_byte(hd_status)   | du noyau. cf. section codes hote
      driver_byte(hd_status) | du noyau. cf. section codes intermediaires

 UU..22..  CCooddeess dd''eettaatt

 Les   codes   d'etat   de   peripherique   qui   suivent   (issus   de
 drivers/scsi/scsi.h) sont disponibles :

      Valeur | Symbole
      =======|=====================
      0x00   | GOOD
      0x01   | CHECK_CONDITION
      0x02   | CONDITION_GOOD
      0x04   | BUSY
      0x08   | INTERMEDIATE_GOOD
      0x0a   | INTERMEDIATE_C_GOOD
      0x0c   | RESERVATION_CONFLICT

 On  constate  que  ces valeurs symboliques ont subi un ddeeccaallaaggee ddrrooiitt.
 Lorsque l'etat indique CHECK_CONDITION, les  donnees  du  buffer  SCSI
 sont  valides  (controlez en particulier le code d'etat additionnel et
 le qualificateur de code d'etat additionnel).

 Les valeurs qui suivent concernent les specifications SCSI-2 :

                   Table 27 : Code de l'octet d'etat
 +=================================-==============================+
 |      Bits de l'octet d'etat     |  Etat                        |
 |  7   6   5   4   3   2   1   0  |                              |
 |---------------------------------+------------------------------|
 |  R   R   0   0   0   0   0   R  |  GOOD                        |
 |  R   R   0   0   0   0   1   R  |  CHECK CONDITION             |
 |  R   R   0   0   0   1   0   R  |  CONDITION MET               |
 |  R   R   0   0   1   0   0   R  |  BUSY                        |
 |  R   R   0   1   0   0   0   R  |  INTERMEDIATE                |
 |  R   R   0   1   0   1   0   R  |  INTERMEDIATE-CONDITION MET  |
 |  R   R   0   1   1   0   0   R  |  RESERVATION CONFLICT        |
 |  R   R   1   0   0   0   1   R  |  COMMAND TERMINATED          |
 |  R   R   1   0   1   0   0   R  |  QUEUE FULL                  |
 |                                 |                              |
 |       Tous autres codes         |  Reserve                     |
 |----------------------------------------------------------------|
 |       R = Bit reserve                                          |
 +================================================================+

 La definition des codes de l'octet d'etat sont donnees ci-dessous :

    GGOOOODD..
       Cet  etat  indique  que  la  cible  a  correctement  execute  la
       commande.

    CCHHEECCKK CCOONNDDIITTIIOONN..
       Cet  etat  indique qu'une condition de contention s'est produite
       (cf. 6.6).

    CCOONNDDIITTIIOONN MMEETT..
       Cet etat, ou INTERMEDIATE-CONDITION MET est renvoye lorsque  les
       conditions   de   l'operation  demandee  sont  satisfaites  (cf.
       commandes SEARCH DATA et PRE-FETCH).

    BBUUSSYY..
       Cet etat indique que la cible est occupee. Il peut etre  renvoye
       lorsque  la  cible  ne  peut  accepter  de  commande  depuis  un
       initiateur inacceptable par ailleurs (i.e. conflit d'absence  de
       reservation).  L'action  de reprise recommandee est une nouvelle
       tentative ulterieure.

    IINNTTEERRMMEEDDIIAATTEE..
       Cet etat, ou INTERMEDIATE-CONDITION MET doit etre renvoyee apres
       chaque  commande  reussie  d'une  serie de commandes liees (sauf
       pour la derniere), sauf si celle-ci  se  termine  par  un  CHECK
       CONDITION,  RESERVATION  CONFLICT,  ou COMMAND TERMINATED. Si ni
       INTERMEDIATE ni INTERMEDIATE-CONDITION  MET  n'est  renvoye,  la
       serie   de   commandes   se  termine,  ainsi  que  le  processus
       d'entrees/sorties.

    IINNTTEERRMMEEDDIIAATTEE--CCOONNDDIITTIIOONN MMEETT..
       Cet etat est la combinaison de CONDITION MET et de INTERMEDIATE.

    RREESSEERRVVAATTIIOONN CCOONNFFLLIICCTT..
       Cet  etat doit etre renvoye lorsqu'un initiateur tente d'acceder
       a une unite logique ou a un extension a l'interieur d'une  unite
       logique  reservee avec un type de reservation en conflit pour un
       autre peripherique SCSI (cf. commandes RESERVE et RESERVE UNIT).
       L'action  de  reprise  recommandee  est  une  nouvelle tentative
       ulterieure.

    CCOOMMMMAANNDD TTEERRMMIINNAATTEEDD..
       Cet etat doit etre renvoye lorsque la cible termine le processus
       d'entrees/sorties  apres  reception  d'un  message TERMINATE I/O
       PROCESS (cf. 5.6.22). Cet etat indique aussi qu'une condition de
       contention s'est produite (cf. 6.6).

    QQUUEEUUEE FFUULLLL..
       Cet  etat  doit  etre  implemente  si  la file d'attente marquee
       (tagged  queuing)  l'est  aussi.  Il  est  renvoye  lors  de  la
       reception  d'un  message SIMPLE QUEUE TAG, ORDERED QUEUE TAG, ou
       HEAD OF QUEUE TAG et que la file de  commandes  est  pleine.  Le
       processus  d'entree/sortie n'est alors pas place dans la file de
       commandes.

 UU..33..  CClleeffss dduu bbuuffffeerr SSCCSSII

 Les clefs resultantes peuvent etre rapatriees a  l'aide  de  la  macro
 msg_byte  (cf. section ``Decodage de l'etat d'erreur'').  Les symboles
 du noyau qui suivent sont predefinis dans drivers/scsi/scsi.h :

      Valeur | Symbole
      =======|================
      0x00   | NO_SENSE
      0x01   | RECOVERED_ERROR
      0x02   | NOT_READY
      0x03   | MEDIUM_ERROR
      0x04   | HARDWARE_ERROR
      0x05   | ILLEGAL_REQUEST
      0x06   | UNIT_ATTENTION
      0x07   | DATA_PROTECT
      0x08   | BLANK_CHECK
      0x0a   | COPY_ABORTED
      0x0b   | ABORTED_COMMAND
      0x0d   | VOLUME_OVERFLOW
      0x0e   | MISCOMPARE

 Une liste extraite  de  la  doc  SCSI-2  suit  (issue  de  la  section
 7.2.14.3) :

         Table 69: Description des clefs (0h-7h) du buffer SCSI
 +========-====================================================================+
 |  Clef  |  Description                                                       |
 |--------+--------------------------------------------------------------------|
 |   0h   |  NO SENSE.  Indique qu'aucune information specifique n'est         |
 |        |  disponible pour l'unite logique designee. C'est le cas pour les   |
 |        |  commandes reussies ou celles dont l'etat est CHECK CONDITION ou   |
 |        |  COMMAND TERMINATED a cause de l'un des bits filemark, EOM ou ILI. |
 |--------+--------------------------------------------------------------------|
 |   1h   |  RECOVERED ERROR.  Indique que la reussite de la derniere commande |
 |        |  fut conditionnee par une action de reparation effectuee par la    |
 |        |  cible. Les octets additionnels peuvent fournir des details, ainsi |
 |        |  que le champ information. Lorsque plusieurs erreurs reparees se   |
 |        |  produisent durant une commande, le choix de celle indiquee        |
 |        |  (premiere, derniere, plus severe, etc.) depend du peripherique.   |
 |--------+--------------------------------------------------------------------|
 |   2h   |  NOT READY.  Indique que l'unite logique est inaccessible. Une     |
 |        |  intervention manuelle peut etre necessaire.                       |
 |--------+--------------------------------------------------------------------|
 |   3h   |  MEDIUM ERROR.  Indique la fin d'une commande sur une erreur non-  |
 |        |  recuperable, causee probablement par un defaut du support ou une  |
 |        |  erreur de donnees. Cette clef peut aussi etre renvoyee si la      |
 |        |  cible ne peut faire la distinction entre un defaut du support et  |
 |        |  un defaut specifique du materiel (clef 4h).                       |
 |--------+--------------------------------------------------------------------|
 |   4h   |  HARDWARE ERROR.  Indique que la cible a detecte une erreur mate-  |
 |        |  rielle irrecuperable (defaut du controleur, du peripherique, er-  |
 |        |  reur de parite, etc.) lors de l'execution de la commande ou d'un  |
 |        |  auto-test.                                                        |
 |--------+--------------------------------------------------------------------|
 |   5h   |  ILLEGAL REQUEST.  Indique qu'un parametre illegal a ete detecte   |
 |        |  dans le bloc de description de commande ou dans les parametres    |
 |        |  additionnels (pour certaines commandes : FORMAT UNIT, SEARCH DATA,|
 |        |  etc.). Si la cible detecte un parametre incorrect, il doit termi- |
 |        |  ner celle-ci sans modifier le contenu du support. Si le parametre |
 |        |  incorrect se trouve dans les parametres additionnels, la cible    |
 |        |  peut avoir deja modifie le support. Cette clef est aussi renvoyee |
 |        |  lors de la reception d'un message IDENTIFY invalide (5.6.7).      |
 |--------+--------------------------------------------------------------------|
 |   6h   |  UNIT ATTENTION.  Indique que le support amovible a pu etre change |
 |        |  ou que la cible a ete reinitialisee. Cf. 6.9 pour d'autres infor- |
 |        |  mation sur cette condition.                                       |
 |--------+--------------------------------------------------------------------|
 |   7h   |  DATA PROTECT.  Indique qu'une commande de lecture ou d'ecriture a |
 |        |  ete tentee sur un bloc protege contre cette operation. Celle-ci   |
 |        |  n'est pas effectuee.                                              |
 +=============================================================================+

         Table 70: Description des clefs (8h-Fh) du buffer SCSI
 +========-====================================================================+
 |  Clef  |  Description                                                       |
 |--------+--------------------------------------------------------------------|
 |   8h   |  BLANK CHECK.  Indique qu'un peripherique a ecriture unique ou     |
 |        |  sequentiel a trouve un support vierge ou une indication de fin de |
 |        |  donnees de formatage lors de la lecture, ou qu'un support non     |
 |        |  vierge a ecriture seule a ete trouve pendant l'ecriture.          |
 |--------+--------------------------------------------------------------------|
 |   9h   |  Vendor Specific.  Cette clef est disponible pour indiquer des     |
 |        |  cas particuliers specifiques du constructeur.                     |
 |--------+--------------------------------------------------------------------|
 |   Ah   |  COPY ABORTED.  Indique qu'une commande COPY, COMPARE ou COPY AND  |
 |        |  VERIFY a echoue a cause d'une condition d'erreur sur le periphe-  |
 |        |  rique source, destination ou les deux (cf. 7.2.3.2 pour plus de   |
 |        |  details).                                                         |
 |--------+--------------------------------------------------------------------|
 |   Bh   |  ABORTED COMMAND.  Indique que la cible a abandonne la commande.   |
 |        |  L'initiateur peut eventuellement corriger le probleme par une     |
 |        |  nouvelle tentative.                                               |
 |--------+--------------------------------------------------------------------|
 |   Ch   |  EQUAL.  Indique qu'une commande SEARCH DATA a satisfait une con-  |
 |        |  dition d'egalite.                                                 |
 |--------+--------------------------------------------------------------------|
 |   Dh   |  VOLUME OVERFLOW.  Indique qu'un peripherique a memoire-tampon a   |
 |        |  atteint la fin de partition et que des donnees non ecrites sur le |
 |        |  support peuvent rester dans le tampon. Une (ou plusieurs) commande|
 |        |  RECOVER BUFFER DATA peut etre tentee pour lire les donnees non    |
 |        |  ecrites depuis le tampon.                                         |
 |--------+--------------------------------------------------------------------|
 |   Eh   |  MISCOMPARE.  Indique que les donnees source ne correspondent pas  |
 |        |  a celles lues sur le support.                                     |
 |--------+--------------------------------------------------------------------|
 |   Fh   |  RESERVE.                                                          |
 +=============================================================================+

 UU..44..  CCooddeess hhoottee

 Les   codes   hotes   qui   suivent   sont   definis   au   niveau  de
 drivers/scsi/scsi.h. Ils sont positionnes par le pilote  du  noyau  et
 doivent  etre utilises avec la macro host_byte (cf. section ``Decodage
 de l'etat d'erreur'') :

      Valeur | Symbole        | Description
      =======|================|========================================
      0x00   | DID_OK         | Pas d'erreur
      0x01   | DID_NO_CONNECT | Connexion impossible avant le timeout
      0x02   | DID_BUS_BUSY   | BUS occupe durant la periode de timeout
      0x03   | DID_TIME_OUT   | Timeout atteint pour une autre raison
      0x04   | DID_BAD_TARGET | Mauvaise cible
      0x05   | DID_ABORT      | Arret effectue pour une autre raison
      0x06   | DID_PARITY     | Erreur de parite
      0x07   | DID_ERROR      | Erreur interne
      0x08   | DID_RESET      | Reinitialise par quelqu'un
      0x09   | DID_BAD_INTR   | Interruption inattendue recue

 UU..55..  CCooddeess dduu ppiilloottee

 Le pilote de niveau intermediaire categorise  l'etat  renvoye  par  le
 pilote  de  bas  niveau en fonction du buffer SCSI du peripherique. Il
 suggere certaines actions pouvant etre tentees comme  un  reessai,  un
 abandon  ou  un  changement  de  topographie.  La routine scsi_done de
 scsi.c effectue un travail tres  differencie  fonde  sur  host_byte(),
 status_byte(),  msg_byte()  et  la  suggestion precedente. Ensuite, il
 positionne l'octet du pilote afin d'indiquer ce  qui  a  ete  realise.
 L'octet  du  pilote  est  en  deux  parties  :  l'etat du pilote et la
 suggestion. Chaque moitie  est  composee  des  valeurs  suivantes  (de
 scsi.h) combinees par un OR :

 Valeur | Symbole        | Description ou etat du pilote
 =======|================|========================================
 0x00   | DRIVER_OK      | pas d'erreur
 0x01   | DRIVER_BUSY    | inutilise
 0x02   | DRIVER_SOFT    | inutilise
 0x03   | DRIVER_MEDIA   | inutilise
 0x04   | DRIVER_ERROR   | erreur interne du pilote
 0x05   | DRIVER_INVALID | termine (DID_BAD_TARGET ou DID_ABORT)
 0x06   | DRIVER_TIMEOUT | termine avec timeout
 0x07   | DRIVER_HARD    | termine avec une erreur fatale
 0x08   | DRIVER_SENSE   | buffer SCSI disponible pour informations

      Valeur | Symbole        | Description de la suggestion
      =======|================|========================================
      0x10   | SUGGEST_RETRY  | reessayer la requete SCSI
      0x20   | SUGGEST_ABORT  | abandonner la requete
      0x30   | SUGGEST_REMAP  | remape le bloc (non encore implemente)
      0x40   | SUGGEST_DIE    | laisser le noyau tomber en "panic"
      0x80   | SUGGEST_SENSE  | lire le buffer SCSI du peripherique
      0xff   | SUGGEST_IS_OK  | rien a faire

 VV..  CCooddeess eett qquuaalliiffiiccaatteeuurrss dduu bbuuffffeerr SSCCSSII aaddddiittiioonnnneellss

 Lorsque  l'etat  de la commande SCSI executee est CHECK_CONDITION, des
 donnees  sont  disponibles  dans  le  buffer   SCSI.   Les   code   et
 qualificateur additionnels se trouvent dans ce tampon.

 Je joins ici deux tables issues des specifications SCSI-2. La premiere
 est triee  alphabetiquement,  la  seconde,  numeriquement  (NdT  :  la
 traduction ayant un tantinet bouleverse l'ordre alphabetique, seule la
 table triee par numeros a ete conservee. Le lecteur pourra se reporter
 a la version originale en americain pour la liste alphabetique).

 VV..11..  AASSCC eett AASSCCQQ ddaannss ll''oorrddrree nnuummeerriiqquuee

 La  table  qui  suit  fournit  une  liste  de  descriptions  avec  les
 peripheriques auxquels elles s'appliquent.

                        Table 364 : Assignements ASC et ASCQ

 +=============================================================================+
 |           D - peripherique a acces Direct (Disque)                          |
 |           .T - peripherique a acces sequenTiel (bande magneTique)           |
 |           . I - Imprimante                                                  |
 |           .  P - Processeur                                                 |
 |           .  .W -WORM (CD-ROM inscriptible une fois)                        |
 |           .  . R - CD-ROM (lecture seule)                                   |
 |           .  .  S - Scanner ou numeriseur                                   |
 |           .  .  .O - memoire Optique                                        |
 |           .  .  . M - changeur de Media                                     |
 |           .  .  .  C - peripherique de Communications                       |
 |           .  .  .  .                                                        |
 | ASC ASCQ  DTIPWRSOMC  DESCRIPTION                                           |
 | --- ----              ----------------------------------------------------- |
 |  00  00   DTIPWRSOMC  pas d'information additionnelle                       |
 |  00  01    T          marque de fichier detectee                            |
 |  00  02    T    S     fin de partition/medium detectee                      |
 |  00  03    T          marque de jeu detectee                                |
 |  00  04    T    S     debut de partition/medium detecte                     |
 |  00  05    T    S     fin de donnees detectee                               |
 |  00  06   DTIPWRSOMC  fin du processus d'E/S                                |
 |  00  11   R           lecture audio en cours                                |
 |  00  12   R           lecture audio suspendue                               |
 |  00  13   R           lecture audio terminee avec succes                    |
 |  00  14   R           lecture audio stoppee pour cause d'erreur             |
 |  00  15   R           pas d'etat audio en cours a retourner                 |
 |  01  00   DW  O       pas de signal d'index/de secteur                      |
 |  02  00   D   WR OM   deplacement incomplet                                 |
 |  03  00   DTI W SO    echec d'ecriture sur le peripherique                  |
 |  03  01    T          pas d'ecriture en cours                               |
 |  03  02    T          trop d'erreurs d'ecriture                             |
 |  04  00   DTIPWRSOMC  unite logique non prete, cause inconnue               |
 |  04  01   DTIPWRSOMC  unite logique en preparation                          |
 |  04  02   DTIPWRSOMC  unite logique non prete, commande d'init necessaire   |
 |  04  03   DTIPWRSOMC  unite logique non prete, intervention manuelle necess.|
 |  04  04   DTI    O    unite logique non prete, formatage en cours           |
 |  05  00   DTI WRSOMC  l'unite logique ne repond pas a la selection          |
 |  06  00   D   WR OM   pas de position de reference trouvee                  |
 |  07  00   DTI WRSOM   selection de plusieurs peripheriques                  |
 |  08  00   DTI WRSOMC  echec de communication avec l'unite logique           |
 |  08  01   DTI WRSOMC  timeout de communication avec l'unite logique         |
 |  08  02   DTI WRSOMC  erreur de parite en communication avec l'unite logique|
 |  09  00   DT  WR O    erreur de suivi de piste                              |
 |  09  01       WR O    defaillance du servo de suivi de piste                |
 |  09  02       WR O    defaillance du servo de focalisation                  |
 |  09  03       WR O    defaillance du servo de SPINDLE                       |
 +=============================================================================+

 Table 364 : (suite)
 +=============================================================================+
 |           D - peripherique a acces Direct (Disque)                          |
 |           .T - peripherique a acces sequenTiel (bande magneTique)           |
 |           . I - Imprimante                                                  |
 |           .  P - Processeur                                                 |
 |           .  .W -WORM (CD-ROM inscriptible une fois)                        |
 |           .  . R - CD-ROM (lecture seule)                                   |
 |           .  .  S - Scanner ou numeriseur                                   |
 |           .  .  .O - memoire Optique                                        |
 |           .  .  . M - changeur de Media                                     |
 |           .  .  .  C - peripherique de Communications                       |
 |           .  .  .  .                                                        |
 | ASC ASCQ  DTIPWRSOMC  DESCRIPTION                                           |
 | --- ----              ----------------------------------------------------- |
 |  0A  00   DTIPWRSOMC  debordement de la trace d'erreur                      |
 |  0B  00                                                                     |
 |  0C  00    T     S    erreur d'ecriture                                     |
 |  0C  01   D   W  O    erreud d'ecriture corrigee par auto-reallocation      |
 |  0C  02   D   W  O    erreur d'ecriture - auto-reallocation impossible      |
 |  0D  00                                                                     |
 |  0E  00                                                                     |
 |  0F  00                                                                     |
 |  10  00   D   W  O    erreur ID, CRC ou ECC                                 |
 |  11  00   DT  WRSO    erreur de lecture irrecuperable                       |
 |  11  01   DT  W SO    nombre d'essais atteint                               |
 |  11  02   DT  W SO    erreur trop longue a corriger                         |
 |  11  03   DT  W SO    erreurs de lecture multiples                          |
 |  11  04   D   W  O    erreur de lecture - auto-reallocation impossible      |
 |  11  05       WR O    erreur irrecuperable L-EC                             |
 |  11  06       WR O    erreur irrecuperable CIRC                             |
 |  11  07       W  O    erreur de resynchronisation de donnees                |
 |  11  08    T          lecture de bloc incomplete                            |
 |  11  09    T          pas de breche trouvee                                 |
 |  11  0A   DT     O    erreur mal corrigee                                   |
 |  11  0B   D   W  O    erreur de lecture - reassignement recommande          |
 |  11  0C   D   W  O    erreur de lecture - reecriture recommandee            |
 |  12  00   D   W  O    marque d'adresse introuvable pour le champ ID         |
 |  13  00   D   W  O    marque d'adresse introuvable pour le champ donnees    |
 |  14  00   DTI WRSO    identite enregistree introuvable                      |
 |  14  01   DT  WR O    enregistrement introuvable                            |
 |  14  02    T          marque de fichier ou de jeu introuvable               |
 |  14  03    T          fin de donnees introuvable                            |
 |  14  04    T          erreur de sequence de bloc                            |
 |  15  00   DTI WRSOM   erreur de positionnement aleatoire                    |
 |  15  01   DTI WRSOM   erreur de positionnement mecanique                    |
 |  15  02   DT  WR O    erreur de positionnement detectee par la lecture      |
 |  16  00   DW     O    erreur de marque de synchronisation de donnees        |
 |  17  00   DT  WRSO    donnees recuperees sans correction d'erreur           |
 |  17  01   DT  WRSO    donnees recuperees apres plusieurs essais             |
 |  17  02   DT  WR O    donnees recuperees avec un decalage de tete positif   |
 |  17  03   DT  WR O    donnees recuperees avec un decalage de tete negatif   |
 |  17  04       WR O    donnees recuperees avec plusieurs essais et/ou CIRC   |
 |  17  05   D   WR O    donnees recuperees sur l'ID de secteur precedent      |
 |  17  06   D   W  O    donnees recuperees sans ECC - donnees auto-reallouees |
 |  17  07   D   W  O    donnees recuperees sans ECC - reassignement recommande|
 |  17  08   D   W  O    donnees recuperees sans ECC - reecriture recommandee  |
 |  18  00   DT  WR O    donnees recuperees avec correction d'erreur           |
 |  18  01   D   WR O    donnees recuperees avec correction & plusieurs essais |
 |  18  02   D   WR O    donnees recuperees - donnees auto-reallouees          |
 |  18  03        R      donnees recuperees avec CIRC                          |
 |  18  04        R      donnees recuperees avec LEC                           |
 |  18  05   D   WR O    donnees recuperees - reassignement recommande         |
 |  18  06   D   WR O    donnees recuperees - reecriture recommandee           |
 +=============================================================================+

      Table 364 : (suite)
      +=============================================================================+
      |           D - peripherique a acces Direct (Disque)                          |
      |           .T - peripherique a acces sequenTiel (bande magneTique)           |
      |           . I - Imprimante                                                  |
      |           .  P - Processeur                                                 |
      |           .  .W -WORM (CD-ROM inscriptible une fois)                        |
      |           .  . R - CD-ROM (lecture seule)                                   |
      |           .  .  S - Scanner ou numeriseur                                   |
      |           .  .  .O - memoire Optique                                        |
      |           .  .  . M - changeur de Media                                     |
      |           .  .  .  C - peripherique de Communications                       |
      |           .  .  .  .                                                        |
      | ASC ASCQ  DTIPWRSOMC  DESCRIPTION                                           |
      | --- ----              ----------------------------------------------------- |
      |  19  00   D      O    erreur de liste de defauts                            |
      |  19  01   D      O    liste de defauts indisponible                         |
      |  19  02   D      O    erreur de liste de defauts en liste primaire          |
      |  19  03   D      O    erreur de liste de defauts en liste secondaire (grown)|
      |  1A  00   DTIPWRSOMC  erreur de taille de la liste de defauts               |
      |  1B  00   DTIPWRSOMC  erreur de transfert de donnees synchrone              |
      |  1C  00   D      O    liste de defauts introuvable                          |
      |  1C  01   D      O    liste de defauts primaire introuvable                 |
      |  1C  02   D      O    liste de defauts secondaire (grown) introuvable       |
      |  1D  00   D   W  O    erreur de comparaison durant la verification          |
      |  1E  00   D   W  O    ID recupere avec ECC                                  |
      |  1F  00                                                                     |
      |  20  00   DTIPWRSOMC  code d'operation de commande incorrect                |
      |  21  00   DT  WR OM   adresse du bloc logique hors limites                  |
      |  21  01           M   adresse d'element incorrecte                          |
      |  22  00   D           fonction illegale (seulement 20 00, 24 00 ou 26 00)   |
      |  23  00                                                                     |
      |  24  00   DTIPWRSOMC  champ incorrect en CDB                                |
      |  25  00   DTIPWRSOMC  unite logique non supportee                           |
      |  26  00   DTIPWRSOMC  champ incorrect en liste de parametres                |
      |  26  01   DTIPWRSOMC  parametre non supporte                                |
      |  26  02   DTIPWRSOMC  valeur de parametre incorrecte                        |
      |  26  03   DTIPWRSOMC  parametres de seuil non supportes                     |
      |  27  00   DT  W  O    protection en ecriture                                |
      |  28  00   DTIPWRSOMC  transition non-pret/pret (changement de medium ?)     |
      |  28  01           M   acces a un element import ou export                   |
      |  29  00   DTIPWRSOMC  allumage, reinit. ou reinit. du bus a eu lieu         |
      |  2A  00   DTI WRSOMC  parametres changes                                    |
      |  2A  01   DTI WRSOMC  parametres de mode changes                            |
      |  2A  02   DTI WRSOMC  parametres de trace changes                           |
      |  2B  00   DTIPWRSO C  copie impossible : deconnexion du host impossible     |
      |  2C  00   DTIPWRSOMC  erreur de sequence de commandes                       |
      |  2C  01         S     trop de fenetres specifiees                           |
      |  2C  02         S     combinaison de fenetres incorrecte specifiee          |
      |  2D  00    T          erreur d'ecriture en ecrasement de donnees            |
      |  2E  00                                                                     |
      |  2F  00   DTIPWRSOMC  commandes annulees par un autre initiateur            |
      |  30  00   DT  WR OM   medium incompatible present                           |
      |  30  01   DT  WR O    medium illisible - format inconnu                     |
      |  30  02   DT  WR O    medium illisible - format incompatible                |
      |  30  03   DT          cartouche de nettoyage presente                       |
      |  31  00   DT  W  O    format du medium endommage                            |
      |  31  01   D I    O    echec de la commande de format                        |
      |  32  00   D   W  O    plus d'emplacement de defaut disponible               |
      |  32  01   D   W  O    echec de mise a jour de la liste de defauts           |
      |  33  00    T          erreur de longueur de bande                           |
      |  34  00                                                                     |
      |  35  00                                                                     |
      |  36  00     I         manque d'encre, de ruban ou de toner                  |
      +=============================================================================+

      Table 364 : (suite)
      +=============================================================================+
      |           D - peripherique a acces Direct (Disque)                          |
      |           .T - peripherique a acces sequenTiel (bande magneTique)           |
      |           . I - Imprimante                                                  |
      |           .  P - Processeur                                                 |
      |           .  .W -WORM (CD-ROM inscriptible une fois)                        |
      |           .  . R - CD-ROM (lecture seule)                                   |
      |           .  .  S - Scanner ou numeriseur                                   |
      |           .  .  .O - memoire Optique                                        |
      |           .  .  . M - changeur de Media                                     |
      |           .  .  .  C - peripherique de Communications                       |
      |           .  .  .  .                                                        |
      | ASC ASCQ  DTIPWRSOMC  DESCRIPTION                                           |
      | --- ----              ----------------------------------------------------- |
      |  37  00   DTI WRSOMC  parametre arrondi                                     |
      |  38  00                                                                     |
      |  39  00   DTI WRSOMC  sauvegarde de parametres non supportee                |
      |  3A  00   DTI WRSOM   pas de medium                                         |
      |  3B  00    TI         erreur de positionnement sequentiel                   |
      |  3B  01    T          erreur de positionnement de la bande au debut         |
      |  3B  02    T          erreur de positionnement de la bande a la fin         |
      |  3B  03     I         bande ou feuille-a-feuille non pret                   |
      |  3B  04     I         erreur de SLEW (NdT : !?)                             |
      |  3B  05     I         bourrage papier                                       |
      |  3B  06     I         haut de page non detecte                              |
      |  3B  07     I         bas  de page non detecte                              |
      |  3B  08    T          erreur de repositionnement                            |
      |  3B  09         S     lecture apres la fin du medium                        |
      |  3B  0A         S     lecture avant le debut du medium                      |
      |  3B  0B         S     position apres la fin du medium                       |
      |  3B  0C         S     position avant le debut du medium                     |
      |  3B  0D           M   emplacement de destination occupe                     |
      |  3B  0E           M   emplacement d'origine vide                            |
      |  3C  00                                                                     |
      |  3D  00   DTIPWRSOMC  bits incorrects dans le message d'identification      |
      |  3E  00   DTIPWRSOMC  auto-configuration de l'unite non encore realisee     |
      |  3F  00   DTIPWRSOMC  les conditions de fonctionnement ont change           |
      |  3F  01   DTIPWRSOMC  le micro-code a ete change                            |
      |  3F  02   DTIPWRSOMC  definition de fonctionnement modifiee                 |
      |  3F  03   DTIPWRSOMC  les donnees de requete ont change                     |
      |  40  00   D           defaillance RAM (40nn obligatoire)                    |
      |  40  NN   DTIPWRSOMC  echec de diagnostic du composant nn (80h-FFh)         |
      |  41  00   D           echec du chemin de donnees (40nn obligatoire)         |
      |  42  00   D           echec d'alllumage ou d'auto-test (40nn obligatoire)   |
      |  43  00   DTIPWRSOMC  erreur de message                                     |
      |  44  00   DTIPWRSOMC  defaillance de cible interne                          |
      |  45  00   DTIPWRSOMC  echec de selection ou de reselection                  |
      |  46  00   DTIPWRSOMC  echec de la reinitialisation logicielle               |
      |  47  00   DTIPWRSOMC  erreur de parite SCSI                                 |
      |  48  00   DTIPWRSOMC  reception de message d'erreur detecte par initiateur  |
      |  49  00   DTIPWRSOMC  erreur message incorrect                              |
      |  4A  00   DTIPWRSOMC  erreur de phase de commande                           |
      |  4B  00   DTIPWRSOMC  erreur de phase de donnees                            |
      |  4C  00   DTIPWRSOMC  echec de l'auto-configuration de l'unite logique      |
      |  4D  00                                                                     |
      |  4E  00   DTIPWRSOMC  commandes en recouvrement                             |
      |  4F  00                                                                     |
      |  50  00    T          erreur d'ecriture en ajout                            |
      |  50  01    T          erreur de positionnement en ajout                     |
      |  50  02    T          erreur de positionnement par rapport au timing        |
      |  51  00    T     O    erreur d'effacement                                   |
      |  52  00    T          defaut de cartouche                                   |
      +=============================================================================+

      Table 364 : (suite)
      +=============================================================================+
      |           D - peripherique a acces Direct (Disque)                          |
      |           .T - peripherique a acces sequenTiel (bande magneTique)           |
      |           . I - Imprimante                                                  |
      |           .  P - Processeur                                                 |
      |           .  .W -WORM (CD-ROM inscriptible une fois)                        |
      |           .  . R - CD-ROM (lecture seule)                                   |
      |           .  .  S - Scanner ou numeriseur                                   |
      |           .  .  .O - memoire Optique                                        |
      |           .  .  . M - changeur de Media                                     |
      |           .  .  .  C - peripherique de Communications                       |
      |           .  .  .  .                                                        |
      | ASC ASCQ  DTIPWRSOMC  DESCRIPTION                                           |
      | --- ----              ----------------------------------------------------- |
      |  53  00   DTI WRSOM   echec de chargement ou d'ejection du medium           |
      |  53  01    T          echec de dechargement de la bande                     |
      |  53  02   DT  WR OM   peripherique protege contre le changement de medium   |
      |  54  00      P        defaillance de l'interface host-SCSI                  |
      |  55  00      P        defaut de ressources systeme                          |
      |  56  00                                                                     |
      |  57  00        R      impossible de recuperer la table du contenu           |
      |  58  00          O    la generation n'existe pas                            |
      |  59  00          O    lecture de bloc mis a jour                            |
      |  5A  00   DTIPWRSOM   requete operateur ou demande de changement d'etat     |
      |  5A  01   DT  WR OM   requete operateur d'extraction du medium              |
      |  5A  02   DT  W  O    l'operateur a selectionne la protection en ecriture   |
      |  5A  03   DT  W  O    l'operateur a selectionne l'autorisation d'ecriture   |
      |  5B  00   DTIPWRSOM   exception de trace                                    |
      |  5B  01   DTIPWRSOM   condition de seuil remplie                            |
      |  5B  02   DTIPWRSOM   compteur de trace au maximum                          |
      |  5B  03   DTIPWRSOM   plus de code pour la liste de trace                   |
      |  5C  00   D      O    changement d'etat RPL                                 |
      |  5C  01   D      O    SPINDLES synchronisees                                |
      |  5C  02   D      O    SPINDLES non synchronisees                            |
      |  5D  00                                                                     |
      |  5E  00                                                                     |
      |  5F  00                                                                     |
      |  60  00         S     defaillance de la lampe                               |
      |  61  00         S     erreur d'acquisition video                            |
      |  61  01         S     impossible de capturer la video                       |
      |  61  02         S     hors de la zone focalisee                             |
      |  62  00         S     erreur de positionnement de la tete de digitalisation |
      |  63  00        R      fin de zone utilisateur sur cette piste               |
      |  64  00        R      mode illegal pour cette piste                         |
      |  65  00                                                                     |
      |  66  00                                                                     |
      |  67  00                                                                     |
      |  68  00                                                                     |
      |  69  00                                                                     |
      |  6A  00                                                                     |
      |  6B  00                                                                     |
      |  6C  00                                                                     |
      |  6D  00                                                                     |
      |  6E  00                                                                     |
      |  6F  00                                                                     |
      +=============================================================================+

 Table 364 : (fin)
 +=============================================================================+
 |           D - peripherique a acces Direct (Disque)                          |
 |           .T - peripherique a acces sequenTiel (bande magneTique)           |
 |           . I - Imprimante                                                  |
 |           .  P - Processeur                                                 |
 |           .  .W -WORM (CD-ROM inscriptible une fois)                        |
 |           .  . R - CD-ROM (lecture seule)                                   |
 |           .  .  S - Scanner ou numeriseur                                   |
 |           .  .  .O - memoire Optique                                        |
 |           .  .  . M - changeur de Media                                     |
 |           .  .  .  C - peripherique de Communications                       |
 |           .  .  .  .                                                        |
 | ASC ASCQ  DTIPWRSOMC  DESCRIPTION                                           |
 | --- ----              ----------------------------------------------------- |
 |  70  00                                                                     |
 |  71  00                                                                     |
 |  72  00                                                                     |
 |  73  00                                                                     |
 |  74  00                                                                     |
 |  75  00                                                                     |
 |  76  00                                                                     |
 |  77  00                                                                     |
 |  78  00                                                                     |
 |  79  00                                                                     |
 |  7A  00                                                                     |
 |  7B  00                                                                     |
 |  7C  00                                                                     |
 |  7D  00                                                                     |
 |  7E  00                                                                     |
 |  7F  00                                                                     |
 |                                                                             |
 |  80  xxh \                                                                  |
 |   jusqu'a >  specifique constructeur                                        |
 |  FF  xxh /                                                                  |
 |                                                                             |
 |  xxh 80 \                                                                   |
 |  jusqu'a >  qualification du standard ASC specifique constructeur           |
 |  xxh FF /                                                                   |
 |              TOUS LES CODES VIDES OU NON MONTRES SONT RESERVES              |
 +=============================================================================+

 WW..  RReeffeerreennccee rraappiiddee ddeess ccoommmmaannddeess SSCCSSII

 La table 365 est une liste ordonnee numeriquement des codes  operation
 des commandes.

                         Table 365 : Codes operations SCSI-2

 +=============================================================================+
 |           D - peripherique a acces Direct               Clef de colonne     |
 |           .T - peripherique a acces sequenTiel          N = Necessaire      |
 |           . I - Imprimante                              O = Optionnel       |
 |           .  P - Processeur                             C = Constructeur    |
 |           .  .W -WORM (CD-ROM inscriptible une fois)    R = Reserve         |
 |           .  . R - CD-ROM (lecture seule)                                   |
 |           .  .  S - Scanner ou numeriseur                                   |
 |           .  .  .O - memoire Optique                                        |
 |           .  .  . M - changeur de Media                                     |
 |           .  .  .  C - peripherique de Communications                       |
 |           .  .  .  .                                                        |
 |        OP DTIPWRSOMC Description                                            |
 |----------+----------+-------------------------------------------------------|
 |        00 NNNNNNNNNN test d'unite prete                                     |
 |        01  N         rembobinage                                            |
 |        01 O C OO OO  remise a zero de l'unite                               |
 |        02 CCCCCC  C                                                         |
 |        03 NNNNNNNNNN requete de buffer SCSI                                 |
 |        04   O        formatage                                              |
 |        04 N      O   formatage de l'unite                                   |
 |        05 CNCCCC  C  lecture des limites de bloc                            |
 |        06 CCCCCC  C                                                         |
 |        07         O  initialisation de l'etat d'un element                  |
 |        07 OCC O  OC  reassignation de blocs                                 |
 |        08          N lecture de message (06)                                |
 |        08 ONC OO OC  lecture (06)                                           |
 |        08    O       reception                                              |
 |        09 CCCCCC  C                                                         |
 |        0A   N        impression                                             |
 |        0A          N emission de message (06)                               |
 |        0A    N       emission (06)                                          |
 |        0A ON  O  OC  ecriture (06)                                          |
 |        0B O   OO OC  deplacement (06)                                       |
 |        0B   O        SLEW et impression                                     |
 |        0C CCCCCC  C                                                         |
 |        0D CCCCCC  C                                                         |
 |        0E CCCCCC  C                                                         |
 |        0F COCCCC  C  lecture inversee                                       |
 |        10   O O      synchronisation du tampon                              |
 |        10 CN CCC     ecriture de marques de fichiers                        |
 |        11 CNCCCC     espace                                                 |
 |        12 NNNNNNNNNN requete                                                |
 |        13 COCCCC     verification (06)                                      |
 |        14 COOCCC     recuperation des donnees bufferisees                   |
 |        15 ONO OOOOOO selection de mode (06)                                 |
 |        16 N   NN NO  reservation                                            |
 |        16  NN   N    reservation d'unite                                    |
 |        17 N   NN NO  liberation                                             |
 |        17  NN   N    liberation d'unite                                     |
 |        18 OOOOOOOO   copie                                                  |
 |        19 CNCCCC     effacement                                             |
 |        1A ONO OOOOOO lecture du buffer SCSI (06)                            |
 |        1B  O         chargement dechargement                                |
 |        1B       O    digitalisation                                         |
 |        1B   O        arret d'impression                                     |
 |        1B O   OO O   arret demarrage de l'unite                             |
 +=============================================================================+

 Table 365 : (suite)
 +=============================================================================+
 |           D - peripherique a acces Direct               Clef de colonne     |
 |           .T - peripherique a acces sequenTiel          N = Necessaire      |
 |           . I - Imprimante                              O = Optionnel       |
 |           .  P - Processeur                             C = Constructeur    |
 |           .  .W -WORM (CD-ROM inscriptible une fois)    R = Reserve         |
 |           .  . R - CD-ROM (lecture seule)                                   |
 |           .  .  S - Scanner ou numeriseur                                   |
 |           .  .  .O - memoire Optique                                        |
 |           .  .  . M - changeur de Media                                     |
 |           .  .  .  C - peripherique de Communications                       |
 |           .  .  .  .                                                        |
 |        OP DTIPWRSOMC Description                                            |
 |----------+----------+-------------------------------------------------------|
 |        1C OOOOOOOOOO reception des resultats du diagnostic                  |
 |        1D NNNNNNNNNN emission de diagnostic                                 |
 |        1E OO  OO OO  protection contre l'enlevement du medium               |
 |        1F                                                                   |
 |        20 C   CC C                                                          |
 |        21 C   CC C                                                          |
 |        22 C   CC C                                                          |
 |        23 C   CC C                                                          |
 |        24 C   CCN    definition de fenetre                                  |
 |        25       O    lecture de fenetre                                     |
 |        25 N   N  N   lecture de capacite                                    |
 |        25      N     lecture de capacite de cd-rom                          |
 |        26 C   CC                                                            |
 |        27 C   CC                                                            |
 |        28          O lecture de message (10)                                |
 |        28 N   NNNN   lecture (10)                                           |
 |        29 C   CC O   lecture de generation                                  |
 |        2A          O emission de message (10)                               |
 |        2A       O    emission (10)                                          |
 |        2A N   N  N   ecriture (10)                                          |
 |        2B  O         localisation                                           |
 |        2B         O  positionnement sur element                             |
 |        2B O   OO O   deplacement (10)                                       |
 |        2C C      O   effacement (10)                                        |
 |        2D C   O  O   lecture de bloc mis a jour                             |
 |        2E O   O  O   lecture et verification (10)                           |
 |        2F O   OO O   verification (10)                                      |
 |        30 O   OO O   lecture de donnee haute (10)                           |
 |        31       O    position d'objet                                       |
 |        31 O   OO O   recherche de donnee egale (10)                         |
 |        32 O   OO O   recherche de donnee basse (10)                         |
 |        33 O   OO O   definition de limites (10)                             |
 |        34       O    lecture de l'etat du tampon de donnees                 |
 |        34 O   OO O   pre-lecture                                            |
 |        34  O         lecture de position                                    |
 |        35 O   OO O   synchronisation du cache                               |
 |        36 O   OO O   verrouillage/deverrouillage du cache                   |
 |        37 O      O   lecture de donnees defectueuses (10)                   |
 |        38     O  O   digitalisation du medium                               |
 |        39 OOOOOOOO   comparaison                                            |
 |        3A OOOOOOOO   copie et verification                                  |
 |        3B OOOOOOOOOO ecriture de tampon                                     |
 |        3C OOOOOOOOOO lecture de tampon                                      |
 |        3D     O  O   mise a jour de bloc                                    |
 |        3E O   OO O   lecture longue                                         |
 |        3F O   O  O   ecriture longue                                        |
 +=============================================================================+

      Table 365 : (suite)
      +=============================================================================+
      |           D - peripherique a acces Direct               Clef de colonne     |
      |           .T - peripherique a acces sequenTiel          N = Necessaire      |
      |           . I - Imprimante                              O = Optionnel       |
      |           .  P - Processeur                             C = Constructeur    |
      |           .  .W -WORM (CD-ROM inscriptible une fois)    R = Reserve         |
      |           .  . R - CD-ROM (lecture seule)                                   |
      |           .  .  S - Scanner ou numeriseur                                   |
      |           .  .  .O - memoire Optique                                        |
      |           .  .  . M - changeur de Media                                     |
      |           .  .  .  C - peripherique de Communications                       |
      |           .  .  .  .                                                        |
      |        OP DTIPWRSOMC Description                                            |
      |----------+----------+-------------------------------------------------------|
      |        40 OOOOOOOOOO changement de definition                               |
      |        41 O          ecriture identique                                     |
      |        42      O     lecture de sous-canal                                  |
      |        43      O     lecture du TOC                                         |
      |        44      O     lecture d'en-tete                                      |
      |        45      O     lecture audio (10)                                     |
      |        46                                                                   |
      |        47      O     lecture audio MSF                                      |
      |        48      O     lecture d'index de piste audio                         |
      |        49      O     lecture de piste relative (10)                         |
      |        4A                                                                   |
      |        4B      O     reprise de pause                                       |
      |        4C OOOOOOOOOO trace de selection                                     |
      |        4D OOOOOOOOOO trace du buffer SCSI                                   |
      |        4E                                                                   |
      |        4F                                                                   |
      |        50                                                                   |
      |        51                                                                   |
      |        52                                                                   |
      |        53                                                                   |
      |        54                                                                   |
      |        55 OOO OOOOOO mode de selection (10)                                 |
      |        56                                                                   |
      |        57                                                                   |
      |        58                                                                   |
      |        59                                                                   |
      |        5A OOO OOOOOO mode du buffer SCSI (10)                               |
      |        5B                                                                   |
      |        5C                                                                   |
      |        5D                                                                   |
      |        5E                                                                   |
      |        5F                                                                   |
      +=============================================================================+

 Table 365 : (fin)
 +=============================================================================+
 |           D - peripherique a acces Direct               Clef de colonne     |
 |           .T - peripherique a acces sequenTiel          N = Necessaire      |
 |           . I - Imprimante                              O = Optionnel       |
 |           .  P - Processeur                             C = Constructeur    |
 |           .  .W -WORM (CD-ROM inscriptible une fois)    R = Reserve         |
 |           .  . R - CD-ROM (lecture seule)                                   |
 |           .  .  S - Scanner ou numeriseur                                   |
 |           .  .  .O - memoire Optique                                        |
 |           .  .  . M - changeur de Media                                     |
 |           .  .  .  C - peripherique de Communications                       |
 |           .  .  .  .                                                        |
 |        OP DTLPWRSOMC Description                                            |
 |----------+----------+-------------------------------------------------------|
 |        A0                                                                   |
 |        A1                                                                   |
 |        A2                                                                   |
 |        A3                                                                   |
 |        A4                                                                   |
 |        A5         N  deplacement de medium                                  |
 |        A5      O     lecture audio (12)                                     |
 |        A6         O  changement de medium                                   |
 |        A7                                                                   |
 |        A8          O lecture de message (12)                                |
 |        A8     OO O   lecture (12)                                           |
 |        A9      O     lecture de piste relative (12)                         |
 |        AA          O emission de message (12)                               |
 |        AA     O  O   ecriture (12)                                          |
 |        AB                                                                   |
 |        AC        O   effacement (12)                                        |
 |        AD                                                                   |
 |        AE     O  O   ecriture et verification (12)                          |
 |        AF     OO O   verification (12)                                      |
 |        B0     OO O   recherche de donnee haute (12)                         |
 |        B1     OO O   recherche de donnee egale (12)                         |
 |        B2     OO O   recherche de donnee basse (12)                         |
 |        B3     OO O   definition des limites (12)                            |
 |        B4                                                                   |
 |        B5                                                                   |
 |        B5         O  demande d'adresse d'element volume                     |
 |        B6                                                                   |
 |        B6         O  emission de TAG de volume                              |
 |        B7        O   lecture des donnees de defauts (12)                    |
 |        B8                                                                   |
 |        B8         O  lecture de l'etat d'element                            |
 |        B9                                                                   |
 |        BA                                                                   |
 |        BB                                                                   |
 |        BC                                                                   |
 |        BD                                                                   |
 |        BE                                                                   |
 |        BF                                                                   |
 +=============================================================================+

 XX..  PPrrooggrraammmmeess dd''eexxeemmppllee

 Voici  le  programme  exemple  en  C qui demande le constructeur et le
 modele et indique si un medium est charge dans le peripherique.

 #define DEVICE "/dev/sgc"
 /* Programme de demonstration de l'interface SCSI generique */
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <scsi/sg.h>

 #define SCSI_OFF sizeof(struct sg_header)
 static unsigned char cmd[SCSI_OFF + 18];        /* tampon de commandes SCSI */
 int     fd;                          /* descripteur de periph./fichier SCSI */

 /* traite une commande SCSI complete. Utilise l'interface SCSI generique */

 static int handle_scsi_cmd(unsigned cmd_len,         /* longueur */
                            unsigned in_size,         /* taille data IN */
                            unsigned char *i_buff,    /* tampon IN */
                            unsigned out_size,        /* taille data OUT */
                            unsigned char *o_buff     /* tampon OUT */
                            )
 {
     int status = 0;
     struct sg_header *sg_hd;

     /* quelques controles de routine */
     if (!cmd_len) return -1;            /* cmd_len doit etre != 0 */
     if (!i_buff) return -1;             /* tampon IN doit etre != 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;

     /* construction de l'en-tete du pilote generique */
     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; /* pas indispensable */
     sg_hd->pack_id;     /* inutilise */
     sg_hd->other_flags; /* inutilise */
 #endif

     /* envoi de la commande */
     status = write( fd, i_buff, SCSI_OFF + cmd_len + in_size );
     if ( status < 0 || status != SCSI_OFF + cmd_len + in_size ||
                        sg_hd->result ) {
         /* une erreur s'est produite */
         fprintf( stderr, "ecriture (generique) resultat = 0x%x cmd = 0x%x\n",
                     sg_hd->result, i_buff[SCSI_OFF] );
         perror("");
         return status;
     }

     if (!o_buff) o_buff = i_buff;       /* controle du pointeur du tampon */

     /* recuperation du resultat */
     status = read( fd, o_buff, SCSI_OFF + out_size);
     if ( status < 0 || status != SCSI_OFF + out_size || sg_hd->result ) {
         /* une erreur s'est produite */
         fprintf( stderr, "lecture (generique) resultat = 0x%x cmd = 0x%x\n",
                 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 < 0)
             perror("");
     }
     /* Voyons si nous avons ce que nous attendions */
     if (status == SCSI_OFF + out_size) status = 0; /* on a tout */

     return status;  /* 0 indique que tout est OK */
 }

 #define INQUIRY_CMD     0x12
 #define INQUIRY_CMDLEN  6
 #define INQUIRY_REPLY_LEN 96
 #define INQUIRY_VENDOR  8    /* Decalage sur le constructeur dans la reponse */

 /* On demande le constructeur et le modele */
 static unsigned char *Inquiry ( void )
 {
   unsigned char Inqbuffer[ SCSI_OFF + INQUIRY_REPLY_LEN ];
   unsigned char cmdblk [ INQUIRY_CMDLEN ] =
       { INQUIRY_CMD,  /* commande */
                   0,  /* lun/reserve */
                   0,  /* code page */
                   0,  /* reserve */
   INQUIRY_REPLY_LEN,  /* longueur d'allocation */
                   0 };/* reserve/drapeau/lien */

   memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) );

   /*
    * +------------------+
    * | struct sg_header | <- cmd
    * +------------------+
    * | copie de cmdblk  | <- cmd + SCSI_OFF
    * +------------------+
    */

   if (handle_scsi_cmd(sizeof(cmdblk), 0, cmd,
                       sizeof(Inqbuffer) - SCSI_OFF, Inqbuffer )) {
       fprintf( stderr, "Echec de la demande\n" );
       exit(2);
   }
   return (Inqbuffer + SCSI_OFF);
 }

 #define TESTUNITREADY_CMD 0
 #define TESTUNITREADY_CMDLEN 6

 #define ADD_SENSECODE 12
 #define ADD_SC_QUALIFIER 13
 #define NO_MEDIA_SC 0x3a
 #define NO_MEDIA_SCQ 0x00
 int TestForMedium ( void )
 {
   /* demande de l'etat READY */
   static unsigned char cmdblk [TESTUNITREADY_CMDLEN] = {
       TESTUNITREADY_CMD, /* commande */
                       0, /* lun/reserve */
                       0, /* reserve */
                       0, /* reserve */
                       0, /* reserve */
                       0};/* reserve */

   memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) );

   /*
    * +------------------+
    * | struct sg_header | <- cmd
    * +------------------+
    * | copie de cmdblk  | <- cmd + SCSI_OFF
    * +------------------+
    */

   if (handle_scsi_cmd(sizeof(cmdblk), 0, cmd,
                             0, NULL)) {
       fprintf (stderr, "Echec du test d'unite prete\n");
       exit(2);
   }

   return
    *(((struct sg_header*)cmd)->sense_buffer +ADD_SENSECODE) !=
                                                         NO_MEDIA_SC ||
    *(((struct sg_header*)cmd)->sense_buffer +ADD_SC_QUALIFIER) !=
                                                         NO_MEDIA_SCQ;
 }

 void main( void )
 {
   fd = open(DEVICE, O_RDWR);
   if (fd < 0) {
     fprintf( stderr, "Il faut les droits lecture/ecriture sur "DEVICE".\n" );
     exit(1);
   }

   /* on ecrit quelques champs du resultat de la requete */
   printf( "%s\n", Inquiry() + INQUIRY_VENDOR );

   /* on regarde si le medium est charge */
   if (!TestForMedium()) {
     printf("pas de medium charge\n");
   } else {
     printf("un medium est present\n");
   }
 }