Le HOWTO Linux de la programmation SCSI <author>Heiko Eißfeldt <tt/heiko@colossus.escape.de/ <date>v1.4, 14 Juin 1995 version française Bernard Choppy bernard.choppy@alias.fdn.fr <abstract> Ce document traite de la programmation de l'interface SCSI générique de Linux. </abstract> <!-- \catcode`\_=12 --> <toc> <sect>Introduction <p> Ce document est un guide d'installation et de programmation de l'interface générique SCSI de Linux. Il traite des prérequis du noyau, des mappings de périphériques, et de l'interaction de base avec ces derniers. Quelques exemples simples de programmation sont inclus. Il est nécessaire d'avoir une connaissance générale du jeu de commandes SCSI~; pour plus d'informations sur le standard SCSI et ce qui le concerne, se reporter à l'annexe de ce document. Note~: la version texte simple de ce document ne dispose pas de la référence croisée (indiquée par ``''). <sect>Qu'est-ce que l'interface SCSI générique~? <p> L'interface générique SCSI a été implémentée pour fournir un accès général à des matériels (éventuellement exotiques) au standard SCSI. Il a été développé par Lawrence Foard (<tt> entropy@world.std.com</tt>) et sponsorisé par Killy Corporation (voir les commentaires de <tt> drivers/scsi/sg.h</tt>). L'interface permet la manipulation de pilotes spéciaux depuis des applications au niveau utilisateur (i.e. en-dehors du noyau). Ainsi, le développement de pilotes au niveau noyau, plus risqué et plus difficile à déverminer, n'est pas nécessaire. Néammoins, si l'on ne programme pas correctement le pilote, il est possible de bloquer le bus SCSI, le pilote ou le noyau. C'est pourquoi il est important de programmer correctement le pilote générique et de commencer par sauvegarder tous les fichiers pour éviter toute perte de données. Une autre précaution utile est de faire un <tt>sync</tt> avant de lancer vos programmes pour garantir l'écriture du contenu de tous les tampons sur le disque, limitant ainsi la perte de données en cas de blocage système. Un autre avantage du pilote générique est que, aussi longtemps que l'interface elle-même ne change pas, toutes les applications restent indépendantes des nouveaux développements du noyau. En comparaison, d'autres pilotes de bas niveau doivent être synchronisés avec d'autres modifications internes du noyau. Typiquement, le pilote générique est utilisé pour communiquer avec les nouveaux équipements SCSI qui imposent l'écriture d'applications spécifiques au niveau utilisateur pour tirer avantage de leurs fonctionnalités (par exemple les numériseurs, imprimantes, juke-boxes de CD-ROM). L'interface générique permet à celles-ci d'être développées rapidement. <sect>Que faut-il pour l'utiliser~? <p> <sect1>Configuration du noyau <p> Il vous faut un contrôleur SCSI reconnu, évidemment. De plus, votre noyau doit être compilé avec le support du contrôleur en plus du support générique. La configuration du noyau Linux (par <tt/make config/ sous /usr/src/linux) doit avoir une allure de ce genre~: <tscreen><verb> ... * * 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 * ... </verb></tscreen> Si vous en disposez, les modules peuvent évidemment remplacer avantageusement ces supports. <sect1>Fichiers de périphériques <p> Le pilote générique utilise ses propres fichiers de périphériques, distincts de ceux utilisés par les autres pilotes SCSI. Ceux-ci peuvent être générés à l'aide du script <tt/MAKEDEV/, qu'on trouve habituellement dans le répertoire <tt>/dev</tt>. <tt/MAKEDEV sg/ produit les fichiers suivants~: <tscreen><verb> 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 | | numéros majeur, mineur </verb></tscreen> On trouve aussi des périphériques de type raw pour l'accès séquentiel. Sur certains système, ces périphériques peuvent s'appeler <tt>/dev/{sg0,sg1,...}</tt>, en fonction de votre installation. Vous devrez donc adapter les exemples qui suivent en conséquence. <sect1>Mapping de périphériques <p> Ces périphériques sont mappés dynamiquement sur les id/LUN (LUN~= Logical UNit, unité logique) de votre bus SCSI. Le mapping alloue consécutivement les périphériques selon les LUN de chacun sur chaque bus SCSI trouvés, à partir des LUN/id/bus inférieurs. Il commence par le premier contrôleur SCSI et continue sans interruption avec tous les autres contrôleurs. Cette étape est actuellement réalisée lors de l'initialisation du pilote SCSI. Par exemple, si vous avez trois périphériques SCSI configurés avec les id 1, 3 et 5 sur le premier bus SCSI (chacun avec un LUN), alors le mapping qui suit sera réalisé~: <tscreen><verb> /dev/sga -> SCSI id 1 /dev/sgb -> SCSI id 3 /dev/sgc -> SCSI id 5 </verb></tscreen> Maintenant, si vous ajoutez un nouveau périphérique d'id 4, le mapping (après la prochaine scrutation du bus) sera~: <tscreen><verb> /dev/sga -> SCSI id 1 /dev/sgb -> SCSI id 3 /dev/sgc -> SCSI id 4 /dev/sgd -> SCSI id 5 </verb></tscreen> Notez la modification pour l'id 5 -- le périphérique correspondant n'est plus mappé sur <tt>/dev/sgc</tt> mais sur <tt>/dev/sgd</tt>. <sect2> Re-scruter les périphériques <p> Pour forcer une scrutation, un pilote modularisé peut être supprimé et réinséré. Il scrute le bus à nouveau lors de l'initialisation. Mais pour pouvoir supprimer le pilote, aucun de ses périphériques ne doit être utilisé à cet instant. Lors de l'ajout de nouveaux périphériques, gardez à l'esprit que le nombre d'entrées disponibles pour ceux-ci est limité. La mémoire a été allouée lors du lancement de la machine et dispose d'espace pour seulement deux nouveaux périphériques. La scrutation de tous les LUN des bus SCSI n'est pas recommandée. Il y a trop de périphériques (bogués) qui peuvent bloquer le bus SCSI lorsqu'on les appelle avec une valeur de LUN différente de zéro (0). Le noyau maintient une table interne de périphériques connus pour ce défaut, pour lesquels il ne scrute que le LUN~0. Les nouveaux noyaux scrutent ainsi par défaut (seulement la LUN~0). <sect>Guide du programmeur <!-- FIXME: I don't want a section number here --> <p> Les sections qui suivent s'adressent aux programmeurs désireux d'utiliser l'interface générique SCSI dans leurs propres applications. Un exemple sera donné qui montre comment accéder à un périphérique SCSI à l'aide des commandes INQUIRY et TESTUNITREADY. Lors de l'utilisation de ces exemples de code, prenez garde à ce qui suit~: <itemize> <item>l'interface générique SCSI a été étendue dans la version 1.1.68 du noyau. Les exemples nécessitent au moins cette version. En revanche, évitez d'utiliser les noyaux de 1.1.77 à 1.1.89 qui disposent d'une interface générique SCSI défectueuse. <item>la constante DEVICE de la section d'en-tête qui décrit le périphérique accédé doit être positionnée en fonction de vos périphériques disponibles (voir la section <ref id="sec-header">. </itemize> <sect>Vue d'ensemble de la programmation des périphériques <p> Le fichier d'en-tête <tt>drivers/scsi/sg.h</tt> dans l'arborescence des sources Linux contient une description de l'interface (ce qui suit est fondé sur la version 1.1.68 du noyau)~: <tscreen><verb> struct sg_header { int pack_len; /* longueur du paquet entrant <4096 (y compris en-tete) */ int reply_len; /* longueur maxi de reponse attendue <4096 */ int pack_id; /* numero id du paquet */ int result; /* 0==ok, sinon voir les codes errno */ unsigned int twelve_byte:1; /* Force la longueur a 12 pour les commandes des groupes 6 &ero 7 */ unsigned int other_flags:31; /* pour usage futur */ unsigned char sense_buffer[16]; /* utilise seulement en lecture */ /* la commande suit puis les donnees de la commande */ }; </verb></tscreen> Cette structure décrit comment une commande SCSI doit être traitée et disposer d'espace pour le résultat de son exécution. Les composants individuels de la structure seront abordés plus loin à la section <ref id="sec-header">. La méthode générale pour échanger des données avec le pilote générique est la suivante~: pour envoyer une commande à un périphérique générique ouvert, il faut effectuer un <tt/write()/ d'un bloc composé de trois parties~: <tscreen><verb> struct sg_header commande SCSI donnees en sortie </verb></tscreen> Pour obtenir le résultat d'une commande, il faut effectuer un <tt/read()/ d'un bloc composé des trois parties (similaires)~: <tscreen><verb> struct sg_header donnees en entree </verb></tscreen> Il s'agit d'une vue générale du processus. Les sections qui suivent décrivent chaque étape en détail. NOTE~: jusqu'à de récentes versions du noyau, il reste nécessaire de bloquer le signal SIGINT entre les appels correspondants de <tt/write()/ et de <tt/read()/ (i.e. par <tt/sigprocmask()/). Un return après la partie <tt/write()/ sans le <tt/read()/ suivant pour lire les résultats va bloquer les accès suivants. Ce blocage de signal n'a pas encore été inclus dans le code exemple. Evitez donc d'envoyer un SIGINT (par ^C, par exemple) lors du test de ceux-ci. <sect>Ouverture de périphérique <p> Un périphérique générique doit être ouvert préalablement à l'accès à celui-ci pour la lecture et l'écriture~: <tscreen><verb> int fd = open (device_name, O_RDWR); </verb></tscreen> (Ce qui précède s'applique même pour les matériels en lecture seule comme les lecteurs de CD-ROM). Il faut exécuter un <tt/write/ pour envoyer la commande et un <tt/read/ pour en lire le résultat. En cas d'erreur, le code de retour est négatif (se reporter à la section <ref id="sec-errorhandling"> pour la liste complète des codes). <sect>La structure d'en-tête <p> <label id="sec-header"> La structure d'en-tête <tt/struct sg_header/ est utilisée comme couche de contrôle entre l'application et le pilote noyau. Abordons maintenant le détail de ses composants. <descrip> <tag/int pack_len/ définit la taille de bloc en écriture. Cette valeur est définie dans le noyau pour une utilisation interne. <tag/int reply_len/ définit la taille de bloc acceptée en réponse. Cette valeur est définie du côté application. <tag/int pack_id/ ce champ facilite l'appariement des réponses aux requêtes. L'application peut fournir un identifiant unique à chaque requête. Supposons que vous ayez écrit un certain nombre de commandes (mettons quatre) pour un périphérique. Celles-ci peuvent fonctionner en parallèle, l'une d'entre elles étant la plus rapide. Lors de la lecture des réponses par quatre <sq>read</sq>, celles-ci ne sont pas forcément dans l'ordre des requêtes. Pour identifier la réponse correcte pour une requête, on peut utiliser le champ <tt/pack_id/. Habituellement, cette valeur est incrémentée après chaque requête (et boucle éventuellement). Le nombre maximum de requêtes émises simultanément est limité par le noyau à SG_MAX_QUEUE (en général, quatre). <tag/int result/ c'est la valeur du résultat d'un appel à <tt/write/ ou à <tt/read/. Elle est définie par le pilote générique (noyau). Ces codes sont définis dans <tt/errno.h/ (0 indique un résultat correct). <tag/unsigned int twelve_byte:1/ ce champ n'est nécessaire que lors de l'utilisation de commandes spécifiques non standard (dans la plage 0xc0 à 0xff). Lorsque la longueur de ces commandes est de 12 octets au lieu de 10, il faut positionner ce champ à 1 avant l'appel à <tt/write/. D'autres longueurs de commandes ne peuvent être utilisées. Ce champ est positionné par l'application. <tag/unsigned char sense_buffer[16]/ Ce tampon est positionné après l'exécution d'une commande (après un appel à <tt/read()/) et contient le code de <sq>sensation</sq> SCSI (NdT.~: dans le reste du document, on utilisera simplement la formule <sq>tampon SCSI</sq>). Certains résultats de commandes doivent être lus à cet emplacement (par exemple pour <tt/TESTUNITREADY/). Il ne contient habituellement que des octets nuls. La valeur de ce champ est positionnée par le pilote générique (noyau). </descrip> L'exemple de fonction qui suit s'interface directement avec le pilote générique du noyau. Il définit la structure d'en-tête, envoie la commande par <tt/write/, lit le résultat par <tt/read/ et effectue un certain contrôle d'erreur (limité). Les données du tampon SCSI sont disponibles dans le tampon de sortie (sauf si un pointeur nul a été fourni, auquel cas elles se trouvent dans le tampon d'émission). Nous l'utiliserons dans les exemples qui suivent. Note~: positionnez la valeur de <tt/DEVICE/ à celle qui correspond à votre matériel. <tscreen><verb> #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 <linux/../../drivers/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 avec 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; /* safety checks */ 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'entete 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; #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]); } /* 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 */ } </verb></tscreen> Bien que cela puisse sembler quelque peu complexe au premier abord, une grande partie du code est dédiée aux contrôle et détection d'erreurs (ce qui est utile même après la fin de l'exécution du code). <tt/handle_SCSI_cmd/ présente une forme généralisée pour tous les types de commandes SCSI, qui correspondent à l'une des catégories qui suivent~: <tscreen><verb> 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 donnes, pas de sortie| selection de mode, ecriture entree et sortie de donnees | detection de mode </verb></tscreen> <sect>Exemple de commande de requête <p> L'une des commandes SCSI de base est <tt/INQUIRY/, utilisée pour identifier les type et constructeur du périphérique. Voici la définition issue de la spécification SCSI-2 (se reporter au standard SCSI-2 pour les détails). <tscreen><verb> Table 44: Commande INQUIRY +=====-========-========-========-========-========-========-========-========+ | Bit| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |Octet| | | | | | | | | |=====+=======================================================================| | 0 | Code operation (12h) | |-----+-----------------------------------------------------------------------| | 1 |Numero logique d'unite LUN| Reserve | EVPD | |-----+-----------------------------------------------------------------------| | 2 | Code page | |-----+-----------------------------------------------------------------------| | 3 | Reserve | |-----+-----------------------------------------------------------------------| | 4 | Taille d'allocation | |-----+-----------------------------------------------------------------------| | 5 | Controle | +=============================================================================+ </verb></tscreen> Les données en sortie ont l'allure suivante~: <tscreen><verb> 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 | | +=============================================================================+ </verb></tscreen> L'exemple qui suit utilise la fonction de bas niveau <tt/handle_SCSI_cmd/ pour effectuer la commande SCSI INQUIRY. Tout d'abord, nous ajoutons le bloc de commande à l'en-tête générique, puis appelons <tt/handle_SCSI_cmd/. Notez que l'argument taille de tampon en sortie de l'appel <tt/handle_SCSI_cmd/ exclut la taille de l'en-tête générique. Après l'exécution de la commande, le tampon de sortie contient les informations demandées, sauf erreur. <tscreen><verb> #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 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); } </verb></tscreen> L'exemple ci-dessus suit cette structure. La fonction Inquiry recopie son bloc de commande après l'en-tête générique (donné par <tt/SCSI_OFF/). Les données en entrée sont absentes de cette commande. <tt/handle_SCSI_cmd/ définit la structure d'en-tête. Nous pouvons maintenant implémenter la fonction <tt/main/ qui complète ce programme d'exemple fonctionnel. <tscreen><verb> 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 ); } </verb></tscreen> Tout d'abord, nous ouvrons le périphérique, contrôlons l'absence d'erreur, puis appelons la fonction de haut niveau. Ensuite, nous affichons des résultats sous une forme lisible, dont le constructeur, le produit et la version. Note~: Il y a plus d'informations dans le résultat de <sq>Inquiry</sq> que ce que fournit ce programme. Il vous est loisible d'étendre celui-ci au type de périphérique, version ANSI, etc. Le type de périphérique a une importance particulière, puisqu'il détermine les jeux de commandes obligatoires et facultatives pour celui-ci. Si vous ne souhaitez pas le programmer vous-même, Eric Youngdale a réalisé le programme scsiinfo, qui fournit à peu près toute information disponible sur les périphériques SCSI. Cherchez à tsx-11.mit.edu dans pub/Linux/ALPHA/scsi (NdT~: on trouvera ce programme sur les sites miroirs français, comme ftp.ibp.fr, à un emplacement similaire). <sect>Le <sq>tampon SCSI</sq> <p> <label id="sec-sensebuff"> Les commandes qui ne renvoient pas de données peuvent fournir des informations d'état à l'aide du tampon SCSI (qui fait partie intégrante de la structure d'en-tête). Les données d'état sont disponibles lorsque la commande précédente s'est terminée avec un état <sq>CHECK CONDITION</sq>. Dans ce cas, le noyau rapatrie automatiquement les données d'état à l'aide d'une commande <sq>REQUEST SENSE</sq>. Sa structure est la suivante~: <tscreen><verb> +=====-========-========-========-========-========-========-========-========+ | 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 | Field Replaceable Unit Code | |-----+-----------------------------------------------------------------------| | 15 | SKSV | | |- - -+------------ Specifique clef d'etat ---| | 17 | | |-----+-----------------------------------------------------------------------| | 18 | | |- - -+--- Octets supplementaires d'etat ---| | n | | +=============================================================================+ </verb></tscreen> Note~: les champs les plus utiles sont la clef d'état (cf. section <ref id="sec-sensekeys">), code d'état additionnel et qualificateur de code d'état additionnel (cf. section <ref id="sec-sensecodes">). Les deux derniers sont utilisé en combinaison l'un avec l'autre. <sect>Exemple d'utilisation du tampon SCSI <p> Nous allons utiliser ici la commande <sq>TEST UNIT READY</sq> pour contrôler si un support est chargé dans notre périphérique. Les déclarations d'en-tête et la fonction <tt/handle_SCSI_cmd/ de l'exemple de <sq>Inquiry</sq> seront aussi nécessaires. <tscreen><verb> 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 | +=============================================================================+ </verb></tscreen> Voici la fonction qui l'implémente~: <tscreen><verb> #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 ) { /* request READY status */ 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; } </verb></tscreen> Nous pouvons réaliser le contrôle à l'aide de cette fonction <tt/main/~: <tscreen><verb> 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 est decharge\n"); } else { printf("le support est charge\n"); } } </verb></tscreen> Le fichier <tt/generic_demo.c/ en annexe contient les deux exemples. <sect>Fonctions ioctl <p> <label id="sec-ioctl"> Deux fonctions ioctl sont disponibles~: <itemize> <item> <tt/ioctl(fd, SG_SET_TIMEOUT, &Timeout);/ définit la valeur du timeout à <tt/Timeout/ * 10 millisecondes. <tt/Timeout/ doit être déclaré comme int. <item> <tt/ioctl(fd, SG_GET_TIMEOUT, &Timeout);/ lit la valeur du timeout en cours. <tt/Timeout/ doit être déclaré comme int. </itemize> <sect>Valeurs par défaut du pilote <p> <label id="sec-Defaults"> <sect1>Tailles de transfert <p> <label id="sec-length"> Actuellement (au moins jusqu'au noyau version 1.1.68), les tailles d'entrée et de sortie doivent être inférieures ou égales à 4~096 octets, sauf si le noyau a été compilé avec <tt/SG_BIG_BUFF/ défini, auquel cas elles ne sont plus limitées qu'à <tt/SG_BIG_BUFF/ (soit 32768) octets. Ces tailles sont données incluant l'en-tête générique ainsi que le bloc de commande en entrée. <sect1>Timeout et valeurs de réessais <p> La valeur du timeout par défaut est d'une minute (<tt/Timeout/~= 6~000). Elle peut être modifiée à l'aide d'un appel à ioctl (cf. section <ref id="sec-ioctl">). Le nombre de réessais par défaut est un. <sect>Comment obtenir les spécifications SCSI~? <p> Il existe des standards appelés SCSI-1, SCSI-2 et SCSI-3. Les standards assurent à peu de choses près la compatibilité ascendante. Le standard SCSI-1 est (d'après l'auteur) en grande partie obsolète, et SCSI-2 est celui qui est le plus largement utilisé. SCSI-3 est très jeune et très cher. Ces jeux de commandes standardisés spécifient des commandes obligatoires et facultatives pour les constructeurs de matériels SCSI et doivent être préférées aux extensions spécifiques non standard et pour lesquelles l'information est plus difficile à obtenir. Evidemment, il n'y a parfois aucune alternative à ces extensions. Des copies électroniques sont disponibles par FTP anonyme depuis~: <itemize> <item>ftp.cs.tulane.edu:pub/scsi <item>ncrinfo.ncr.com:/pub/standards <item>ftp.cs.uni-sb.de:/pub/misc/doc/scsi </itemize> (J'ai eu mes spécifications SCSI dans le CD-ROM Linux d'Yggdrasil dans le répertoire /usr/doc/scsi-2 et /usr/doc/scsi-1). La FAQ SCSI liste aussi les sources d'information imprimée suivantes~: Les spécifications SCSI~- disponible depuis~: <tscreen><verb> 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 a 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 obtenu de 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 de 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 </verb></tscreen> <sect>Sources d'information en relation <p> <sect1>HOWTOs et FAQs <p> Le <bf/SCSI-HOWTO/ Linux de Drew Eckhardt (NdT~: disponible en version française) traite de tous les contrôleurs SCSI reconnus ainsi que des questions spécifiques aux périphériques. De nombreuses techniques de dépannages sont fournies. Il est disponible sur sunsite.unc.edu dans /pub/Linux/docs/LDP et ses sites miroirs. Les questions générales concernant SCSI trouvent leur réponse dans la FAQ SCSI depuis le forum Usenet comp.periphs.scsi (disponible sur tsc-11 dans /pub/linux/ALPHA/scsi et ses sites miroirs). <sect1>Mailing list <p> Il existe une <bf/mailing list/ (NdT~: intraduisible, n'est-il pas~?) qui traite des rapports de bogues et questions sur le développement SCSI sous Linux. Pour la rejoindre, envoyez un courrier à <tt/majordomo@vger.rutgers.edu/ avec la ligne <tt/subscribe linux-scsi/ dans le corps du message. Les messages doivent être envoyés à <tt/linux-scsi@vger.rutgers.edu/. Un texte d'aide peut être demandé par envoi de la ligne de message <sq>help</sq> à <tt/majordomo@vger.rutgers.edu/. <sect1>Exemples de code <p> <descrip> <tag>sunsite.unc.edu: apps/graphics/hpscanpbm-0.3a.tar.gz</tag> Ce paquetage pilote un digitaliseur HP scanjet à l'aide de l'interface générique. <tag>tsx-11.mit.edu: BETA/cdrom/private/mkisofs/cdwrite-1.3.tar.gz</tag> Le paquetage cdwrite utilise l'interface générique pour écrire une image de CD sur un graveur. <tag>sunsite.unc.edu: apps/sound/cds/cdda2wav*.src.tar.gz</tag> Un composant pour mes propres applications, qui copie des pistes audio de CD sous forme de fichiers wav. </descrip> <sect>Autres choses utiles <p> Des choses qui pourraient devenir pratiques. Je n'ai aucune idée de la présence de version plus récentes ou meilleures ici ou là. Toute information bienvenue. <sect1>Aides à l'écriture de pilotes de périphériques <p> Ces documents peuvent être trouvés sur le serveur ftp de sunsite.unc.edu et ses miroirs. <descrip> <tag>/pub/Linux/docs/kernel/kernel-hackers-guide</tag> Le guide des stakhanovistes du noyau LDP (NdT~: Projet de Documentation Linux). Il est peut-être un peu ancien, mais traite les points les plus fondamentaux. <tag>/pub/Linux/docs/kernel/drivers.doc.z</tag> Ce document traite de l'écriture de pilotes caractères. <tag>/pub/Linux/docs/kernel/tutorial.doc.z</tag> Tutoriel sur l'écriture d'un pilote de périphérique caractère avec le code. <tag>/pub/Linux/docs/kernel/scsi.paper.tar.gz</tag> Un document Latex décrivant comment écrire un pilote SCSI. <tag>/pub/Linux/docs/hardware/DEVICES</tag> Une liste des numéros majeurs et mineurs utilisés par Linux. </descrip> <sect1>Utilitaires <p> <descrip> <tag>tsx-11.mit.edu: ALPHA/scsi/scsiinfo*.tar.gz</tag> Programme d'interrogation d'un périphérique SCSI pour obtenir ses paramètres d'utilisation, listes de défauts, etc. Une interface X nécessitant Tk/Tcl/wish est disponible. Avec cette dernière, vous pouvez facilement modifier la configuration du lecteur. <tag>tsx-11.mit.edu: ALPHA/kdebug</tag> Une extension gdb pour le déverminage du noyau. </descrip> <sect>Autres interfaces d'accès à SCSI <p> Dans Linux, on peut accéder différemment à SCSI via des appels ioctl SCSI_IOCTL_SEND_COMMAND qui nécessitent des privilèges root. Les paquetages <sq>scsiinfos</sq> ainsi que <sq>cdda2wav</sq> les utilisent. D'autres interfaces similaires sont utilisées dans le monde Unix, mais ne sont pas disponibles pour Linux~: <enum> <item>CAM (Common Access Method) développée par Future Domain et d'autres constructeurs SCSI. Linux dispose maintenant d'un petit support pour un système CAM SCSI (essentiellement pour bouter depuis un disque dur). CAM supporte même le mode <sq>target</sq>, qui permet de déguiser un ordinateur en périphérique SCSI (c.à.d. réaliser un petit réseau SCSI). <item>ASPI (Advanced SCSI Programming Interface) developpée par Adaptec. C'est le standard de facto pour les machines MS-DOS. <!-- AIDEZ-MOI à en savoir plus sur les interfaces qui suivent <item> ??? est disponible sur NeXTStep. <item> DSLIB est disponible sur Silicon Graphics. <item> SCSI... est disponible sur les machines SUN. <item> SCO Unix a aussi quelque chose. <item> HPUX utilise des ioctl. --> </enum> D'autres interfaces applicatives existent aussi chez SCO(TM), NeXT(TM), Silicon Graphics(TM) et SUN(TM). <sect>Commentaires finaux <p> L'interface générique SCSI jette un pont sur le fossé entre les applications utilisateur et les périphériques spécifiques. Mais plutôt que de charger de nombreux programmes avec des jeux similaires de fonctions de bas niveau, il serait plus souhaitable de disposer d'une bibliothèque partagée avec un jeu généralisé de fonctions de bas niveau pour un usage particulier. Le but principal est de disposer de couches d'interfaces indépendantes. Une bonne conception doit séparer une application en routines de bas niveau et indépendantes du matériel. Celles-ci peuvent être placées dans une bibliothèque partagée et rendues disponibles pour toutes les applications. Ainsi, les interfaces standardisées doivent être suivies autant que possible avant d'en réaliser de nouvelles. Vous devriez maintenant en savoir plus que moi sur l'interface générique SCSI de Linux. Vous pouvez donc commencer à développer de puissantes applications pour le plus grand bénéfice de la communauté Linux... <sect>Remerciements <p> Un grand merci à Jeff Tranter pour ses corrections et améliorations considérables de ce texte, ainsi qu'à Carlos Puchol pour ses commentaires utiles. L'aide de Drew Eckhardt et Eric Youngdale sur mes premières questions (idiotes) sur l'utilisation de cette interface a été appréciée. <appendix> <sect>Annexe <p> <sect>Traitement d'erreurs <p> <label id="sec-errorhandling"> Les fonctions <tt/open/, <tt/ioctl/, <tt/write/ et <tt/read/ peuvent renvoyer des erreurs. Dans ce cas, leur valeur de retour est -1 et la variable globale errno est positionnée sur le numéro d'erreur (négatif). Les valeurs de errno sont définies dans <tt>/usr/include/errno.h</tt>. Les valeurs négatives possibles sont les suivantes~: <tscreen><verb> 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 blocant, | | 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 | -EWOULDBLOCK | le peripherique bloque. Essayez plus tard. write | -EIO | taille trop petite (plus petite que cette de l'en- | | tete generique). Attention : il n'y a actuellement | | aucun controle de debordement. | -EWOULDBLOCK | 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). | -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. supra). </verb></tscreen> Pour la lecture et l'écriture, des valeurs de retour positivent indiquent comme d'habitude la quantité d'octets transférés. Cette valeur doit correspondre à celle demandée. <sect1>décodage de l'état d'erreur <p> <label id="sec-stat-decoding"> En plus, une information détaillée est fournie par <tt/hd_status/ du noyau et par <tt>sense_buffer</tt> du périphérique (cf. section <ref id="sec-sensebuff">), les deux utilisant la structure d'en-tête générique. Le sens de <tt/hd_status/ peut être trouvé dans <tt>drivers/scsi/scsi.h</tt>~; cet <tt/unsigned int/ est composé de différentes parties~: <tscreen><verb> lsb | ... | ... | msb =======|===========|===========|============ status | sense key | host code | driver byte </verb></tscreen> Les macros qui suivent de <tt>drivers/scsi/scsi.h</tt> peuvent être utilisées pour en séparer les champs~: <tscreen><verb> 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 </verb></tscreen> <sect1>Codes d'état <p> <label id="sec-statuscodes"> Les codes d'état de périphérique qui suivent (issus de <tt>drivers/scsi/scsi.h</tt>) doivent être utilisés avec la macro <tt/status_byte/ (cf. section <ref id="sec-stat-decoding">)~: <tscreen><verb> Value | Symbol ======|===================== 0x00 | GOOD 0x01 | CHECK_CONDITION 0x02 | CONDITION_GOOD 0x04 | BUSY 0x08 | INTERMEDIATE_GOOD 0x0a | INTERMEDIATE_C_GOOD 0x0c | RESERVATION_CONFLICT </verb></tscreen> On constate que ces valeurs symboliques ont subi un <bf/shift droit/. Lorsque l'état est CHECK_CONDITION, les données du buffer SCSI sont valides (contrôlez en particulier le code d'état additionnel et le qualificateur de code d'état additionnel). Les valeurs qui suivent concernent les spécifications SCSI-2~: <tscreen><verb> 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 | +================================================================+ </verb></tscreen> La définition des codes de l'octet d'état sont données ci-dessous~: <descrip> <tag/GOOD./ Cet état indique que la cible a correctement exécuté la commande. <tag/CHECK CONDITION./ Cet état indique qu'une condition de contention s'est produite (cf. 6.6). <tag/CONDITION MET./ Cet état, ou INTERMEDIATE-CONDITION MET est renvoyé lorsque les conditions de l'opération demandée sont satisfaites (cf. commandes SEARCH DATA et PRE-FETCH). <tag/BUSY./ Cet état indique que la cible est occupée. Il peut être renvoyé lorsque la cible ne peut accepter de commande depuis un initiateur inacceptable par ailleurs (i.e. conflit d'absence de réservation). L'action de reprise recommandée est une nouvelle tentative ultérieure. <tag/INTERMEDIATE./ Cet état, ou INTERMEDIATE-CONDITION MET doit être renvoyée après chaque commande réussie d'une série de commandes liées (sauf pour la dernière), sauf si celle-ci se termine par un CHECK CONDITION, RESERVATION CONFLICT, ou COMMAND TERMINATED. Si ni INTERMEDIATE ni INTERMEDIATE-CONDITION MET n'est renvoyé, la série de commandes se termine, ainsi que le processus d'entrées/sorties. <tag/INTERMEDIATE-CONDITION MET./ Cet état est la vombinaison de CONDITION MET et de INTERMEDIATE. <tag/RESERVATION CONFLICT./ Cet état doit être renvoyé lorsqu'un initiateur tente d'accéder à une unité logique ou à un extension à l'intérieur d'une unité logique réservée avec un type de réservation en conflit pour un autre périphérique SCSI (cf. commandes RESERVE et RESERVE UNIT). L'action de reprise recommandée est une nouvelle tentative ultérieure. <tag/COMMAND TERMINATED./ Cet état doit être renvoyé lorsque la cible termine le processus d'entrées/sorties après réception d'un message TERMINATE I/O PROCESS (cf. 5.6.22). Cet état indique aussi qu'une condition de contention s'est produite (cf. 6.6). <tag/QUEUE FULL./ Cet état doit être implémenté si la file d'attente marquée (tagged queuing) l'est aussi. Il est renvoyé lors de la réception 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'entrée/sortie n'est alors pas placé dans la file de commandes. </descrip> <sect1>Clefs du buffer SCSI <p> <label id="sec-sensekeys"> Les clefs résultantes peuvent être rapatriées à l'aide de la macro <tt/msg_byte/ (cf. section <ref id="sec-stat-decoding">). Les symboles du noyau qui suivent sont prédéfinis dans <tt>drivers/scsi/scsi.h</tt>)~: <tscreen><verb> Value | Symbol ======|================ 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 </verb></tscreen> Une liste extraite de la doc SCSI-2 suit (issue de la section 7.2.14.3)~: <tscreen><verb> 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 | | | données 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, destionation 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. | +=============================================================================+ </verb></tscreen> <sect1>Codes hôte <p> <label id="sec-hostcodes"> Les codes hôtes qui suivent sont définis au niveau de <tt>drivers/scsi/scsi.h</tt>. Ils sont positionnés par le pilote du noyau et doivent être utilisés avec la macro <tt/host_byte/ (cf. section <ref id="sec-stat-decoding">)~: <tscreen><verb> 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 </verb></tscreen> <sect1>Codes du pilote <p> <label id="sec-drivercodes"> Le pilote de niveau intermédiaire catégorise l'état renvoyé par le pilote de bas niveau en fonction du buffer SCSI du périphérique. Il suggère certaines actions pouvant être tentées comme un réessai, un abandon ou un changement de topographie. La routine <tt/scsi_done/ de <tt/scsi.c/ effectue un travail très différencié fondé sur <tt/host_byte()/, <tt/status_byte()/, <tt/msg_byte()/ et la suggestion précédente. Ensuite, il positionne l'octet du pilote afin d'indiquer ce qui a été réalisé. L'octet du pilote est en deux parties~: l'état du pilote et la suggestion. Chaque moitié est composée des valeurs suivantes (de <tt/scsi.h/) combinées par un <tt/OR/~: <tscreen><verb> 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 | temine (DID_BAD_TARGET ou DID_ABORT) 0x06 | DRIVER_TIMEOUT | temine avec timeout 0x07 | DRIVER_HARD | temine avec une erreur fatale 0x08 | DRIVER_SENSE | buffer SCSI disponible pour informations </verb></tscreen> <tscreen><verb> Valeur| Symbole | Description de la suggestion ======|================|======================================== 0x10 | SUGGEST_RETRY | reessayer la requete SCSI 0x20 | SUGGEST_ABORT | abandonner la requete 0x30 | SUGGEST_REMAP | remap le bloc (no 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 </verb></tscreen> <sect>Codes et qualificateurs du buffer SCSI additionnels <p> <label id="sec-sensecodes"> Lorsque l'état de la commande SCSI exécutée est CHECK_CONDITION, des données sont disponibles dans le buffer SCSI. Les code et qualificateur additionnels se trrouvent dans ce tampon. Je joins ici deux tables issues des spécifications SCSI-2. La première est triée alphabétiquement, la seconde, numériquement (NdT~: la traduction ayant un tantinet bouleversé l'ordre alphabétique, seul la table triée par numéros a été conservée. Le lecteur pourra se reporter à la version originale en américain pour la liste alphabétique). <sect1>ASC et ASCQ dans l'ordre numérique <p> <tscreen><verb> 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 - Scanneur 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 | +=============================================================================+ </verb></tscreen> <tscreen><verb> 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 - Scanneur 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 recuperes 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 &ero 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 | +=============================================================================+ </verb></tscreen> <tscreen><verb> 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 - Scanneur 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 | +=============================================================================+ </verb></tscreen> <tscreen><verb> 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 - Scanneur 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 | +=============================================================================+ </verb></tscreen> <tscreen><verb> 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 - Scanneur 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 | +=============================================================================+ </verb></tscreen> <tscreen><verb> 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 - Scanneur 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 | +=============================================================================+ </verb></tscreen> <sect>Référence rapide des commandes SCSI <p> La table 365 est une liste ordonnée numériquement des codes opération des commandes. <tscreen><verb> 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 - Scanneur 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 | +=============================================================================+ </verb></tscreen> <tscreen><verb> 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 - Scanneur ou numeriseur | | . . .O - memoire Optique | | . . . M - changeur de Media | | . . . C - peripherique de Communications | | . . . . | | OP DTLPWRSOMC 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 | +=============================================================================+ </verb></tscreen> <tscreen><verb> 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 - Scanneur 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 | +=============================================================================+ </verb></tscreen> <tscreen><verb> 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 - Scanneur 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 donnes de defauts (12) | | B8 | | B8 O lecture de l'etata d'element | | B9 | | BA | | BB | | BC | | BD | | BE | | BF | +=============================================================================+ </verb></tscreen> <sect>Programmes d'exemple <p> Voici le programme exemple en C qui demande le constructeur et le modèle et indique si un medium est chargé dans le périphérique. <tscreen><verb> #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 <linux/../../drivers/scsi/sg.h> #define DEVICE "/dev/sgc" #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 */ /* process a complete scsi cmd. Use the generic scsi interface. */ 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; /* safety checks */ 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; #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 /* expedition 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 */ /* retrieve result */ 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, "lecture (generique) :\n Buffer 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]); 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 ) { /* request READY status */ 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"); } } </verb></tscreen> </article>