  Le HOWTO Linux de la programmation SCSI
  Heiko  Eissfeldt heiko@colossus.escape.de (version francaise
  : Thierry Danis thierry.danis@hol.fr, le  26  Janvier  1998,
  largement  basee  sur la traduction de la version v1.4 faite
  par Bernard Choppy choppy@imaginet.fr).
  v1.5, 7 Juin 1996

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

  11..  LLeess nnoouuvveeaauutteess

  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.

  22..  IInnttrroodduuccttiioonn

  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 ``'').

  33..  QQuu''eesstt--ccee qquuee ll''iinntteerrffaaccee SSCCSSII ggeenneerriiqquuee ??

  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 ( entropy@world.std.com) 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.

  44..  QQuuee ffaauutt--iill ppoouurr ll''uuttiilliisseerr ??

  44..11..  CCoonnffiigguurraattiioonn dduu nnooyyaauu

  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.

  44..22..  FFiicchhiieerrss ssppeecciiaauuxx

  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.

  44..33..  OOrrggaanniissaattiioonn ddeess ppeerriipphheerriiqquueess

  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.

  44..33..11..  IInnsseerrttiioonn eett rreettrraaiitt ddyynnaammiiqquueess ddee ppeerriipphheerriiqquueess SSCCSSII

  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.

  55..  LLee gguuiiddee dduu pprrooggrraammmmeeuurr

  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'').

  66..  VVuuee dd''eennsseemmbbllee ddee llaa pprrooggrraammmmaattiioonn ddeess ppeerriipphheerriiqquueess

  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.

  77..  OOuuvveerrttuurree dduu ppeerriipphheerriiqquuee

  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).

  88..  LLaa ssttrruuccttuurree dd''eenn--tteettee

  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.

     iinntt ppaacckk__lleenn
        definit la taille du bloc envoye au  pilote.  Cette  valeur  est
        definie dans le noyau pour une utilisation interne.

     iinntt rreeppllyy__lleenn
        definit  la  taille du bloc accepte en reponse. Cette valeur est
        definie du cote application.

     iinntt ppaacckk__iidd
        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).

     iinntt rreessuulltt
        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).

     uunnssiiggnneedd iinntt ttwweellvvee__bbyyttee::11
        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.

     uunnssiiggnneedd cchhaarr sseennssee__bbuuffffeerr[[1166]]
        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

  99..  EExxeemmppllee ddee ccoommmmaannddee ddee rreeqquueettee

  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).

  1100..  LLee ""ttaammppoonn SSCCSSII""

  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.

  1111..  EExxeemmppllee dd''uuttiilliissaattiioonn dduu ttaammppoonn SSCCSSII

  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.

  1122..  FFoonnccttiioonnss iiooccttll

  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).

  1133..  VVaalleeuurrss ppaarr ddeeffaauutt dduu ppiilloottee

  1133..11..  TTaaiilllleess ddee ttrraannssffeerrtt

  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.

  1133..22..  TTiimmeeoouutt eett vvaalleeuurrss ddee rreeeessssaaiiss

  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.

  1144..  CCoommmmeenntt oobbtteenniirr lleess ssppeecciiffiiccaattiioonnss SSCCSSII ??

  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

  1155..  DD''aauuttrreess ssoouurrcceess dd''iinnffoorrmmaattiioonn

  1155..11..  HHOOWWTTOOss eett FFAAQQss

  Le  SSCCSSII--HHOOWWTTOO  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).

  1155..22..  LLaa lliissttee ddee mmeessssaaggeerriiee

  Il  existe une lliissttee ddee mmeessssaaggeerriiee qui traite des rapports d'anomalies
  et questions sur le developpement SCSI sous Linux. Pour la  rejoindre,
  envoyez   un  courrier  a  majordomo@vger.rutgers.edu  avec  la  ligne
  subscribe linux-scsi dans le corps du message.  Les  messages  doivent
  etre  envoyes a linux-scsi@vger.rutgers.edu. Un texte d'aide peut etre
  demande   par   envoi   de   la   ligne   de    message    "help"    a
  majordomo@vger.rutgers.edu.

  1155..33..  EExxeemmpplleess ddee ccooddee

     ssuunnssiittee..uunncc..eedduu:: aappppss//ggrraapphhiiccss//hhppssccaannppbbmm--00..33aa..ttaarr..ggzz
        Ce  paquetage gere un scanner HP scanjet a l'aide de l'interface
        generique.

     ttssxx--1111..mmiitt..eedduu:: BBEETTAA//ccddrroomm//pprriivvaattee//mmkkiissooffss//ccddwwrriittee--11..33..ttaarr..ggzz
        Le paquetage cdwrite utilise l'interface generique  pour  ecrire
        une image de CD sur un graveur.

     ssuunnssiittee..uunncc..eedduu:: aappppss//ssoouunndd//ccddss//ccddddaa22wwaavv**..ssrrcc..ttaarr..ggzz
        Un composant pour mes propres applications, qui copie des pistes
        audio de CD sous forme de fichiers wav.

  1166..  AAuuttrreess cchhoosseess uuttiilleess

  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.

  1166..11..  AAiiddeess aa ll''eeccrriittuurree ddee ppiillootteess ddee ppeerriipphheerriiqquueess

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

     //ppuubb//LLiinnuuxx//ddooccss//kkeerrnneell//kkeerrnneell--hhaacckkeerrss--gguuiiddee
        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.

     //ppuubb//LLiinnuuxx//ddooccss//kkeerrnneell//ddrriivveerrss..ddoocc..zz
        Ce document traite de l'ecriture de pilotes caracteres.

     //ppuubb//LLiinnuuxx//ddooccss//kkeerrnneell//ttuuttoorriiaall..ddoocc..zz
        Tutoriel  sur  l'ecriture  d'un pilote de peripherique caractere
        avec le code.

     //ppuubb//LLiinnuuxx//ddooccss//kkeerrnneell//ssccssii..ppaappeerr..ttaarr..ggzz
        Un document Latex decrivant comment ecrire un pilote SCSI.

     //ppuubb//LLiinnuuxx//ddooccss//hhaarrddwwaarree//DDEEVVIICCEESS
        Une liste des numeros majeurs et mineurs utilises par Linux.

  1166..22..  UUttiilliittaaiirreess

     ttssxx--1111..mmiitt..eedduu:: AALLPPHHAA//ssccssii//ssccssiiiinnffoo**..ttaarr..ggzz
        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.

     ttssxx--1111..mmiitt..eedduu:: AALLPPHHAA//kkddeebbuugg
        Une extension a pour le deverminage du noyau.

  1177..  AAuuttrreess iinntteerrffaacceess dd''aacccceess aauu SSCCSSII

  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).

  1188..  CCoommmmeennttaaiirreess ffiinnaallss

  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...

  1199..  RReemmeerrcciieemmeennttss

  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.

  TT..  AAnnnneexxee

  UU..  TTrraaiitteemmeenntt dd''eerrrreeuurrss

  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.

  UU..11..  DDeeccooddaaggee ddee ll''eettaatt dd''eerrrreeuurr

  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

  UU..22..  CCooddeess dd''eettaatt

  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 ddeeccaallaaggee ddrrooiitt.
  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 :

     GGOOOODD..
        Cet  etat  indique  que  la  cible  a  correctement  execute  la
        commande.

     CCHHEECCKK CCOONNDDIITTIIOONN..
        Cet  etat  indique qu'une condition de contention s'est produite
        (cf. 6.6).

     CCOONNDDIITTIIOONN MMEETT..
        Cet etat, ou INTERMEDIATE-CONDITION MET est renvoye lorsque  les
        conditions   de   l'operation  demandee  sont  satisfaites  (cf.
        commandes SEARCH DATA et PRE-FETCH).

     BBUUSSYY..
        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.

     IINNTTEERRMMEEDDIIAATTEE..
        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.

     IINNTTEERRMMEEDDIIAATTEE--CCOONNDDIITTIIOONN MMEETT..
        Cet etat est la combinaison de CONDITION MET et de INTERMEDIATE.

     RREESSEERRVVAATTIIOONN CCOONNFFLLIICCTT..
        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.

     CCOOMMMMAANNDD TTEERRMMIINNAATTEEDD..
        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).

     QQUUEEUUEE FFUULLLL..
        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.

  UU..33..  CClleeffss dduu bbuuffffeerr SSCCSSII

  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.                                                          |
  +=============================================================================+

  UU..44..  CCooddeess hhoottee

  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

  UU..55..  CCooddeess dduu ppiilloottee

  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

  VV..  CCooddeess eett qquuaalliiffiiccaatteeuurrss dduu bbuuffffeerr SSCCSSII aaddddiittiioonnnneellss

  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).

  VV..11..  AASSCC eett AASSCCQQ ddaannss ll''oorrddrree nnuummeerriiqquuee

  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              |
  +=============================================================================+

  WW..  RReeffeerreennccee rraappiiddee ddeess ccoommmmaannddeess SSCCSSII

  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                                                                   |
  +=============================================================================+

  XX..  PPrrooggrraammmmeess dd''eexxeemmppllee

  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");
    }
  }

