6557fbc68f72090fbe260354e0e412b377a25c38
[debian/amanda] / changer-src / scsi-linux.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-2000 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: scsi-linux.c,v 1.1.2.18.4.1.2.5 2003/07/05 16:59:01 ant Exp $
28  *
29  * Interface to execute SCSI commands on Linux
30  *
31  * Copyright (c) Thomas Hepper th@ant.han.de
32  */
33
34
35 #include <amanda.h>
36
37 #ifdef HAVE_DMALLOC_H
38 #include <dmalloc.h>
39 #endif
40
41 #ifdef HAVE_LINUX_LIKE_SCSI
42
43 /*
44 #ifdef HAVE_STDIO_H
45 */
46 #include <stdio.h>
47 /*
48 #endif
49 */
50 #ifdef HAVE_SYS_TYPES_H
51 #include <sys/types.h>
52 #endif
53 #ifdef HAVE_SYS_STAT_H
54 #include <sys/stat.h>
55 #endif
56 #ifdef HAVE_FCNTL_H
57 #include <fcntl.h>
58 #endif
59
60 #ifdef HAVE_DIRENT_H
61 #include <dirent.h>
62 #endif
63
64 #include <time.h>
65
66 #ifdef HAVE_SCSI_SCSI_IOCTL_H
67 #include <scsi/scsi_ioctl.h>
68 #endif
69
70 #ifdef HAVE_SCSI_SG_H
71 #include <scsi/sg.h>
72 #define LINUX_SG
73 #endif
74
75 #ifdef HAVE_SYS_MTIO_H
76 #include <sys/mtio.h>
77 #endif
78
79 #include <scsi-defs.h>
80
81
82 void SCSI_OS_Version()
83 {
84 #ifndef lint
85    static char rcsid[] = "$Id: scsi-linux.c,v 1.1.2.18.4.1.2.5 2003/07/05 16:59:01 ant Exp $";
86    DebugPrint(DEBUG_ERROR, SECTION_INFO, "scsi-os-layer: %s\n",rcsid);
87 #endif
88 }
89
90 int SCSI_CloseDevice(int DeviceFD)
91 {
92   extern OpenFiles_T *pDev;
93   int ret = 0;
94   
95   if (pDev[DeviceFD].devopen == 1)
96     {
97       pDev[DeviceFD].devopen = 0;
98       ret = close(pDev[DeviceFD].fd);
99     }
100
101   return(ret);
102 }
103
104 /* Open a device to talk to an scsi device, either per ioctl, or
105  * direct writing....
106  * Return:
107  * 0 -> error
108  * 1 -> OK
109  *
110  * TODO:
111  * Define some readable defs for the falgs which can be set (like in the AIX dreiver)
112  *
113  */
114 #ifdef LINUX_SG
115 int SCSI_OpenDevice(int ip)
116 {
117   extern OpenFiles_T *pDev;
118   int DeviceFD;
119   int i;
120   int timeout;
121   int sg_info = 0;                /* Used to get some infos about the sg interface */
122   int ret = 0;                    /* To store return results from ioctl etc */
123   struct stat pstat;
124   char *buffer = NULL ;           /* Will contain the device name after checking */
125   int openmode = O_RDONLY;
126
127   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_OpenDevice\n");
128   if (pDev[ip].inqdone == 0)
129     {
130       pDev[ip].inqdone = 1;
131       if (strncmp("/dev/sg", pDev[ip].dev, 7) != 0) /* Check if no sg device for an link .... */
132         {
133           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : checking if %s is a sg device\n", pDev[ip].dev);
134           if (lstat(pDev[ip].dev, &pstat) != -1)
135             {
136               if (S_ISLNK(pstat.st_mode) == 1)
137                 {
138                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : is a link, checking destination\n");
139                   if ((buffer = (char *)malloc(512)) == NULL)
140                     {
141                       DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_OpenDevice : malloc failed\n");
142                       return(0);
143                     }
144                   memset(buffer, 0, 512);
145                   if (( i = readlink(pDev[ip].dev, buffer, 512)) == -1)
146                     {
147                       if (errno == ENAMETOOLONG )
148                         {
149                         } else {
150                           pDev[ip].SCSI = 0;
151                         }
152                     }
153                   if ( i >= 7)
154                     {
155                       if (strncmp("/dev/sg", buffer, 7) == 0)
156                         {
157                           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : link points to %s\n", buffer) ;
158                           pDev[ip].flags = 1;
159                         }
160                     }
161                 } else {/* S_ISLNK(pstat.st_mode) == 1 */
162                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"No link %s\n", pDev[ip].dev) ;
163                   buffer = stralloc(pDev[ip].dev);
164                 }
165             } else {/* lstat(DeviceName, &pstat) != -1 */ 
166               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"can't stat device %s\n", pDev[ip].dev);
167               return(0);
168             }
169         } else {
170           buffer = stralloc(pDev[ip].dev);
171           pDev[ip].flags = 1;
172         }
173       
174       if (pDev[ip].flags == 1)
175         {
176           openmode = O_RDWR;
177         }
178       
179       DebugPrint(DEBUG_INFO, SECTION_SCSI,"Try to open %s\n", buffer);
180       if ((DeviceFD = open(buffer, openmode)) > 0)
181         {
182           pDev[ip].avail = 1;
183           pDev[ip].devopen = 1;
184           pDev[ip].fd = DeviceFD;
185         } else {
186           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice open failed\n");
187           return(0);
188         }
189       
190       DebugPrint(DEBUG_INFO, SECTION_SCSI,"done\n");
191       if ( pDev[ip].flags == 1)
192         {
193           pDev[ip].SCSI = 1;
194         }
195       
196       pDev[ip].dev = stralloc(buffer);
197       if (pDev[ip].SCSI == 1)
198         {
199           if ((ret = ioctl(DeviceFD, SG_GET_VERSION_NUM, &sg_info)) == 0)
200             {
201               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : SG_VERSION %d\n",sg_info);  
202             } else {
203               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : SG_VERSION ioctl returned %d\n", ret);
204             }
205
206           if ((ret = ioctl(DeviceFD, SG_GET_RESERVED_SIZE, &sg_info)) == 0)
207             {
208               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : SG_RESERVED_SIZE %d\n",sg_info);  
209             } else {
210               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : SG_RESERVED_SIZE ioctl returned %d\n", ret);
211             }
212
213           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : use SG interface\n");
214           if ((timeout = ioctl(pDev[ip].fd, SG_GET_TIMEOUT)) > 0) 
215             {
216               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : current timeout %d\n", timeout);
217               timeout = 60000;
218               if (ioctl(pDev[ip].fd, SG_SET_TIMEOUT, &timeout) == 0)
219                 {
220                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : timeout set to %d\n", timeout);
221                 }
222             }
223           pDev[ip].inquiry = (SCSIInquiry_T *)malloc(INQUIRY_SIZE);
224           if (SCSI_Inquiry(ip, pDev[ip].inquiry, INQUIRY_SIZE) == 0)
225             {
226               if (pDev[ip].inquiry->type == TYPE_TAPE || pDev[ip].inquiry->type == TYPE_CHANGER)
227                 {
228                   for (i=0;i < 16;i++)
229                     pDev[ip].ident[i] = pDev[ip].inquiry->prod_ident[i];
230                   for (i=15; i >= 0 && !isalnum(pDev[ip].ident[i]); i--)
231                     {
232                       pDev[ip].ident[i] = '\0';
233                     }
234                   pDev[ip].SCSI = 1;
235
236                   if (pDev[ip].inquiry->type == TYPE_TAPE)
237                   {
238                           pDev[ip].type = stralloc("tape");
239                   }
240
241                   if (pDev[ip].inquiry->type == TYPE_CHANGER)
242                   {
243                           pDev[ip].type = stralloc("changer");
244                   }
245
246                   PrintInquiry(pDev[ip].inquiry);
247                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice (1)\n");
248                   return(1);
249                 } else {
250                   close(DeviceFD);
251                   free(pDev[ip].inquiry);
252                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice (0)\n");
253                   return(0);
254                 }
255             } else {
256               pDev[ip].SCSI = 0;
257               pDev[ip].devopen = 0;
258               close(DeviceFD);
259               free(pDev[ip].inquiry);
260               pDev[ip].inquiry = NULL;
261               DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice (1)\n");
262               return(1);
263             }
264         } else /* if (pDev[ip].SCSI == 1) */ {  
265           DebugPrint(DEBUG_INFO, SECTION_SCSI,"Device not capable for SCSI commands\n");
266           pDev[ip].SCSI = 0;
267           pDev[ip].devopen = 0;
268           close(DeviceFD);
269           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice (1)\n");
270           return(1);
271         }
272     } else { /* if (pDev[ip].inqdone == 0) */
273       if (pDev[ip].flags == 1)
274         {
275           openmode = O_RDWR;
276         } else {
277           openmode = O_RDONLY;
278         }
279       if ((DeviceFD = open(pDev[ip].dev, openmode)) > 0)
280         {
281           pDev[ip].devopen = 1;
282           pDev[ip].fd = DeviceFD;
283           if (pDev[ip].flags == 1)
284             {
285               if ((timeout = ioctl(pDev[ip].fd, SG_GET_TIMEOUT)) > 0) 
286                 {
287                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : current timeout %d\n", timeout);
288                   timeout = 60000;
289                   if (ioctl(pDev[ip].fd, SG_SET_TIMEOUT, &timeout) == 0)
290                     {
291                       DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : timeout set to %d\n", timeout);
292                     }
293                 }
294             }
295           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice (1)\n");
296           return(1);
297         } else {
298           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice open failed\n");
299           return(0);
300         }
301     }
302   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice should not happen !!\n");
303   return(0);
304 }
305
306 #define SCSI_OFF sizeof(struct sg_header)
307 int SCSI_ExecuteCommand(int DeviceFD,
308                         Direction_T Direction,
309                         CDB_T CDB,
310                         int CDB_Length,
311                         void *DataBuffer,
312                         int DataBufferLength,
313                         char *pRequestSense,
314                         int RequestSenseLength)
315 {
316   extern OpenFiles_T *pDev;
317   struct sg_header *psg_header;
318   char *buffer;
319   int osize = 0;
320   int status;
321
322   if (pDev[DeviceFD].avail == 0)
323     {
324       return(-1);
325     }
326
327   if (pDev[DeviceFD].devopen == 0)
328     {
329       SCSI_OpenDevice(DeviceFD);
330     }
331   
332 /*   if (SCSI_OFF + CDB_Length + DataBufferLength > 4096)  */
333 /*     { */
334 /*       SCSI_CloseDevice(DeviceFD); */
335 /*       DebugPrint(DEBUG_ERROR, SECTION_SCSI,"##### SCSI_ExecuteCommand error, SCSI_OFF + CDB_Length + DataBufferLength > 4096\n"); */
336 /*       return(-1); */
337 /*     } */
338
339   buffer = (char *)malloc(SCSI_OFF + CDB_Length + DataBufferLength);
340   memset(buffer, 0, SCSI_OFF + CDB_Length + DataBufferLength);
341   memcpy(buffer + SCSI_OFF, CDB, CDB_Length);
342   
343   psg_header = (struct sg_header *)buffer;
344   if (CDB_Length >= 12)
345     {
346       psg_header->twelve_byte = 1;
347     } else {
348       psg_header->twelve_byte = 0;
349     }
350   psg_header->result = 0;
351   psg_header->reply_len = SCSI_OFF + DataBufferLength;
352   
353   switch (Direction)
354     {
355     case Input:
356       osize = 0;
357       break;
358     case Output:
359       osize = DataBufferLength;
360       break;
361     }
362   
363   DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
364   
365   status = write(pDev[DeviceFD].fd, buffer, SCSI_OFF + CDB_Length + osize);
366   if ( status < 0 || status != SCSI_OFF + CDB_Length + osize ||
367        psg_header->result ) 
368     {
369       dbprintf(("SCSI_ExecuteCommand error send \n"));
370       SCSI_CloseDevice(DeviceFD);
371       return(SCSI_ERROR);
372     }
373   
374   memset(buffer, 0, SCSI_OFF + DataBufferLength);
375   status = read(pDev[DeviceFD].fd, buffer, SCSI_OFF + DataBufferLength);
376   memset(pRequestSense, 0, RequestSenseLength);
377   memcpy(pRequestSense, psg_header->sense_buffer, 16);
378   
379   if ( status < 0 || status != SCSI_OFF + DataBufferLength || 
380        psg_header->result ) 
381     { 
382       dbprintf(("SCSI_ExecuteCommand error read \n"));
383       dbprintf(("Status %d (%d) %2X\n", status, SCSI_OFF + DataBufferLength, psg_header->result ));
384       SCSI_CloseDevice(DeviceFD);
385       return(SCSI_ERROR);
386     }
387
388   if (DataBufferLength)
389     {
390        memcpy(DataBuffer, buffer + SCSI_OFF, DataBufferLength);
391     }
392
393   free(buffer);
394   SCSI_CloseDevice(DeviceFD);
395   return(SCSI_OK);
396 }
397
398 #else
399
400 static inline int min(int x, int y)
401 {
402   return (x < y ? x : y);
403 }
404
405
406 static inline int max(int x, int y)
407 {
408   return (x > y ? x : y);
409 }
410
411 int SCSI_OpenDevice(int ip)
412 {
413   extern OpenFiles_T *pDev;
414   int DeviceFD;
415   int i;
416
417   if (pDev[ip].inqdone == 0)
418     {
419       pDev[ip].inqdone = 1;
420       if ((DeviceFD = open(pDev[ip].dev, O_RDWR)) > 0)
421         {
422           pDev[ip].avail = 1;
423           pDev[ip].fd = DeviceFD;
424           pDev[ip].SCSI = 0;
425           pDev[ip].inquiry = (SCSIInquiry_T *)malloc(INQUIRY_SIZE);
426           dbprintf(("SCSI_OpenDevice : use ioctl interface\n"));
427           if (SCSI_Inquiry(ip, pDev[ip].inquiry, INQUIRY_SIZE) == 0)
428             {
429               if (pDev[ip].inquiry->type == TYPE_TAPE || pDev[ip].inquiry->type == TYPE_CHANGER)
430                 {
431                   for (i=0;i < 16 && pDev[ip].inquiry->prod_ident[i] != ' ';i++)
432                     pDev[ip].ident[i] = pDev[ip].inquiry->prod_ident[i];
433                   pDev[ip].ident[i] = '\0';
434                   pDev[ip].SCSI = 1;
435                   PrintInquiry(pDev[ip].inquiry);
436                   return(1);
437                 } else {
438                   free(pDev[ip].inquiry);
439                   close(DeviceFD);
440                   return(0);
441                 }
442             } else {
443               close(DeviceFD);
444               free(pDev[ip].inquiry);
445               pDev[ip].inquiry = NULL;
446               return(1);
447             }
448         }
449       return(1); 
450     } else {
451       if ((DeviceFD = open(pDev[ip].dev, O_RDWR)) > 0)
452         {
453           pDev[ip].fd = DeviceFD;
454           pDev[ip].devopen = 1;
455           return(1);
456         } else {
457           pDev[ip].devopen = 0;
458           return(0);
459         }
460     }
461 }
462
463 int SCSI_ExecuteCommand(int DeviceFD,
464                         Direction_T Direction,
465                         CDB_T CDB,
466                         int CDB_Length,
467                         void *DataBuffer,
468                         int DataBufferLength,
469                         char *pRequestSense,
470                         int RequestSenseLength)
471 {
472   extern OpenFiles_T *pDev;
473   unsigned char *Command;
474   int Zero = 0, Result;
475  
476   if (pDev[DeviceFD].avail == 0)
477     {
478       return(SCSI_ERROR);
479     }
480
481   if (pDev[DeviceFD].devopen == 0)
482     {
483       SCSI_OpenDevice(DeviceFD);
484     }
485
486   memset(pRequestSense, 0, RequestSenseLength);
487   switch (Direction)
488     {
489     case Input:
490       Command = (unsigned char *)
491         malloc(8 + max(DataBufferLength, RequestSenseLength));
492       memcpy(&Command[0], &Zero, 4);
493       memcpy(&Command[4], &DataBufferLength, 4);
494       memcpy(&Command[8], CDB, CDB_Length);
495       break;
496     case Output:
497       Command = (unsigned char *)
498         malloc(8 + max(CDB_Length + DataBufferLength, RequestSenseLength));
499       memcpy(&Command[0], &DataBufferLength, 4);
500       memcpy(&Command[4], &Zero, 4);
501       memcpy(&Command[8], CDB, CDB_Length);
502       memcpy(&Command[8 + CDB_Length], DataBuffer, DataBufferLength);
503       break;
504     }
505   
506   DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
507   
508   Result = ioctl(pDev[DeviceFD].fd, SCSI_IOCTL_SEND_COMMAND, Command);
509   if (Result != 0)
510     memcpy(pRequestSense, &Command[8], RequestSenseLength);
511   else if (Direction == Input)
512     memcpy(DataBuffer, &Command[8], DataBufferLength);
513   free(Command);
514   SCSI_CloseDevice(DeviceFD);
515
516   switch(Result)
517     {
518       case 0:
519         return(SCSI_OK);
520         break;
521     default:
522       return(SCSI_SENSE);
523       break;
524     }
525 }
526 #endif
527
528 /*
529  * Send the command to the device with the
530  * ioctl interface
531  */
532 int Tape_Ioctl( int DeviceFD, int command)
533 {
534   extern OpenFiles_T *pDev;
535   struct mtop mtop;
536   int ret = 0;
537
538   if (pDev[DeviceFD].devopen == 0)
539     {
540       SCSI_OpenDevice(DeviceFD);
541     }
542
543   switch (command)
544     {
545     case IOCTL_EJECT:
546       mtop.mt_op = MTOFFL;
547       mtop.mt_count = 1;
548       break;
549      default:
550       break;
551     }
552
553   if (ioctl(pDev[DeviceFD].fd , MTIOCTOP, &mtop) != 0)
554     {
555       dbprintf(("Tape_Ioctl error ioctl %d\n",errno));
556       SCSI_CloseDevice(DeviceFD);
557       return(-1);
558     }
559
560   SCSI_CloseDevice(DeviceFD);
561   return(ret);  
562 }
563
564 int Tape_Status( int DeviceFD)
565 {
566   extern OpenFiles_T *pDev;
567   struct mtget mtget;
568   int ret = 0;
569
570   if (pDev[DeviceFD].devopen == 0)
571     {
572       SCSI_OpenDevice(DeviceFD);
573     }
574
575   if (ioctl(pDev[DeviceFD].fd , MTIOCGET, &mtget) != 0)
576   {
577      DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Tape_Status error ioctl %d\n",errno);
578      SCSI_CloseDevice(DeviceFD);
579      return(-1);
580   }
581
582   DebugPrint(DEBUG_INFO, SECTION_TAPE,"ioctl -> mtget.mt_gstat %lX\n",mtget.mt_gstat);
583   if (GMT_ONLINE(mtget.mt_gstat))
584     {
585       ret = TAPE_ONLINE;
586     }
587   
588   if (GMT_BOT(mtget.mt_gstat))
589     {
590       ret = ret | TAPE_BOT;
591     }
592   
593   if (GMT_EOT(mtget.mt_gstat))
594     {
595       ret = ret | TAPE_EOT;
596     }
597   
598   if (GMT_WR_PROT(mtget.mt_gstat))
599     {
600       ret = ret | TAPE_WR_PROT;
601     }
602   
603   if (GMT_DR_OPEN(mtget.mt_gstat))
604     {
605       ret = ret | TAPE_NOT_LOADED;
606     }
607   
608   SCSI_CloseDevice(DeviceFD);
609   return(ret); 
610 }
611
612 /*
613  * This functions scan all /dev/sg* devices
614  * It opens the device an print the result of the inquiry 
615  *
616  */
617 int ScanBus(int print)
618 {
619   DIR *dir;
620   struct dirent *dirent;
621   extern OpenFiles_T *pDev;
622   extern int errno;
623   int count = 0;
624
625   dir = opendir("/dev/");
626
627   while ((dirent = readdir(dir)) != NULL)
628     {
629       if (strstr(dirent->d_name, "sg") != NULL)
630       {
631         pDev[count].dev = malloc(10);
632         pDev[count].inqdone = 0;
633         sprintf(pDev[count].dev,"/dev/%s", dirent->d_name);
634         if (OpenDevice(count,pDev[count].dev, "Scan", NULL ))
635           {
636             SCSI_CloseDevice(count);
637             pDev[count].inqdone = 0;
638             
639             if (print)
640               {
641                 printf("name /dev/%s ", dirent->d_name);
642                 
643                 switch (pDev[count].inquiry->type)
644                   {
645                   case TYPE_DISK:
646                     printf("Disk");
647                     break;
648                   case TYPE_TAPE:
649                     printf("Tape");
650                     break;
651                   case TYPE_PRINTER:
652                     printf("Printer");
653                     break;
654                   case TYPE_PROCESSOR:
655                     printf("Processor");
656                     break;
657                   case TYPE_WORM:
658                     printf("Worm");
659                     break;
660                   case TYPE_CDROM:
661                     printf("Cdrom");
662                     break;
663                   case TYPE_SCANNER:
664                     printf("Scanner");
665                     break;
666                   case TYPE_OPTICAL:
667                     printf("Optical");
668                     break;
669                   case TYPE_CHANGER:
670                     printf("Changer");
671                     break;
672                   case TYPE_COMM:
673                     printf("Comm");
674                     break;
675                   default:
676                     printf("unknown %d",pDev[count].inquiry->type);
677                     break;
678                   }
679                 printf("\n");
680               }
681             count++;
682             printf("Count %d\n",count);
683           } else {
684             free(pDev[count].dev);
685             pDev[count].dev=NULL;
686           }
687       }
688     }
689   return 0;
690 }
691 #endif
692 /*
693  * Local variables:
694  * indent-tabs-mode: nil
695  * c-file-style: gnu
696  * End:
697  */