d8cf55d7b3e4b389efffa05d11b21509a01eec1f
[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.30.2.1 2006/12/12 14:56:38 martinea 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 extern OpenFiles_T *pDev;
82
83 void SCSI_OS_Version(void)
84 {
85 #ifndef lint
86    static char rcsid[] = "$Id: scsi-linux.c,v 1.30.2.1 2006/12/12 14:56:38 martinea Exp $";
87    DebugPrint(DEBUG_ERROR, SECTION_INFO, "scsi-os-layer: %s\n",rcsid);
88 #endif
89 }
90
91 int SCSI_CloseDevice(int DeviceFD)
92 {
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   int DeviceFD;
118   int i;
119   int timeout;
120   struct stat pstat;
121   char *buffer = NULL ;           /* Will contain the device name after checking */
122   int openmode = O_RDONLY;
123
124   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### START SCSI_OpenDevice\n");
125   if (pDev[ip].inqdone == 0)
126     {
127       pDev[ip].inqdone = 1;
128       if (strncmp("/dev/sg", pDev[ip].dev, 7) != 0) /* Check if no sg device for an link .... */
129         {
130           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : checking if %s is a sg device\n", pDev[ip].dev);
131           if (lstat(pDev[ip].dev, &pstat) != -1)
132             {
133               if (S_ISLNK(pstat.st_mode) == 1)
134                 {
135                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : is a link, checking destination\n");
136                   if ((buffer = (char *)malloc(513)) == NULL)
137                     {
138                       DebugPrint(DEBUG_ERROR, SECTION_SCSI,"SCSI_OpenDevice : malloc failed\n");
139                       return(0);
140                     }
141                   memset(buffer, 0, 513);
142                   if (( i = readlink(pDev[ip].dev, buffer, 512)) == -1)
143                     {
144                       if (errno == ENAMETOOLONG )
145                         {
146                         } else {
147                           pDev[ip].SCSI = 0;
148                         }
149                     }
150                   if ( i >= 7)
151                     {
152                       if (strncmp("/dev/sg", buffer, 7) == 0)
153                         {
154                           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : link points to %s\n", buffer) ;
155                           pDev[ip].flags = 1;
156                         }
157                     }
158                 } else {/* S_ISLNK(pstat.st_mode) == 1 */
159                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"No link %s\n", pDev[ip].dev) ;
160                   buffer = stralloc(pDev[ip].dev);
161                 }
162             } else {/* lstat(DeviceName, &pstat) != -1 */ 
163               DebugPrint(DEBUG_ERROR, SECTION_SCSI,"can't stat device %s\n", pDev[ip].dev);
164               return(0);
165             }
166         } else {
167           buffer = stralloc(pDev[ip].dev);
168           pDev[ip].flags = 1;
169         }
170       
171       if (pDev[ip].flags == 1)
172         {
173           openmode = O_RDWR;
174         }
175       
176       DebugPrint(DEBUG_INFO, SECTION_SCSI,"Try to open %s\n", buffer);
177       if ((DeviceFD = open(buffer, openmode)) >= 0)
178         {
179           pDev[ip].avail = 1;
180           pDev[ip].devopen = 1;
181           pDev[ip].fd = DeviceFD;
182         } else {
183           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice open failed\n");
184           amfree(buffer);
185           return(0);
186         }
187       
188       DebugPrint(DEBUG_INFO, SECTION_SCSI,"done\n");
189       if ( pDev[ip].flags == 1)
190         {
191           pDev[ip].SCSI = 1;
192         }
193       
194       pDev[ip].dev = buffer;
195       if (pDev[ip].SCSI == 1)
196         {
197           DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : use SG interface\n");
198           if ((timeout = ioctl(pDev[ip].fd, SG_GET_TIMEOUT)) > 0) 
199             {
200               DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : current timeout %d\n", timeout);
201               timeout = 60000;
202               if (ioctl(pDev[ip].fd, SG_SET_TIMEOUT, &timeout) == 0)
203                 {
204                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : timeout set to %d\n", timeout);
205                 }
206             }
207           pDev[ip].inquiry = (SCSIInquiry_T *)malloc(INQUIRY_SIZE);
208           if (SCSI_Inquiry(ip, pDev[ip].inquiry, (u_char)INQUIRY_SIZE) == 0)
209             {
210               if (pDev[ip].inquiry->type == TYPE_TAPE || pDev[ip].inquiry->type == TYPE_CHANGER)
211                 {
212                   for (i=0;i < 16;i++)
213                     pDev[ip].ident[i] = pDev[ip].inquiry->prod_ident[i];
214                   for (i=15; i >= 0 && !isalnum(pDev[ip].ident[i]); i--)
215                     {
216                       pDev[ip].ident[i] = '\0';
217                     }
218                   pDev[ip].SCSI = 1;
219
220                   if (pDev[ip].inquiry->type == TYPE_TAPE)
221                   {
222                           pDev[ip].type = stralloc("tape");
223                   }
224
225                   if (pDev[ip].inquiry->type == TYPE_CHANGER)
226                   {
227                           pDev[ip].type = stralloc("changer");
228                   }
229
230                   PrintInquiry(pDev[ip].inquiry);
231                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice (1)\n");
232                   return(1);
233                 } else {
234                   close(DeviceFD);
235                   amfree(pDev[ip].inquiry);
236                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice (0)\n");
237                   return(0);
238                 }
239             } else {
240               pDev[ip].SCSI = 0;
241               pDev[ip].devopen = 0;
242               close(DeviceFD);
243               amfree(pDev[ip].inquiry);
244               pDev[ip].inquiry = NULL;
245               DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice (1)\n");
246               return(1);
247             }
248         } else /* if (pDev[ip].SCSI == 1) */ {  
249           DebugPrint(DEBUG_INFO, SECTION_SCSI,"Device not capable for SCSI commands\n");
250           pDev[ip].SCSI = 0;
251           pDev[ip].devopen = 0;
252           close(DeviceFD);
253           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice (1)\n");
254           return(1);
255         }
256     } else { /* if (pDev[ip].inqdone == 0) */
257       if (pDev[ip].flags == 1)
258         {
259           openmode = O_RDWR;
260         } else {
261           openmode = O_RDONLY;
262         }
263       if ((DeviceFD = open(pDev[ip].dev, openmode)) >= 0)
264         {
265           pDev[ip].devopen = 1;
266           pDev[ip].fd = DeviceFD;
267           if (pDev[ip].flags == 1)
268             {
269               if ((timeout = ioctl(pDev[ip].fd, SG_GET_TIMEOUT)) > 0) 
270                 {
271                   DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : current timeout %d\n", timeout);
272                   timeout = 60000;
273                   if (ioctl(pDev[ip].fd, SG_SET_TIMEOUT, &timeout) == 0)
274                     {
275                       DebugPrint(DEBUG_INFO, SECTION_SCSI,"SCSI_OpenDevice : timeout set to %d\n", timeout);
276                     }
277                 }
278             }
279           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice (1)\n");
280           return(1);
281         } else {
282           DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice open failed\n");
283           return(0);
284         }
285     }
286   DebugPrint(DEBUG_INFO, SECTION_SCSI,"##### STOP SCSI_OpenDevice should not happen !!\n");
287   return(0);
288 }
289
290 #define SCSI_OFF SIZEOF(struct sg_header)
291 int SCSI_ExecuteCommand(int DeviceFD,
292                         Direction_T Direction,
293                         CDB_T CDB,
294                         size_t CDB_Length,
295                         void *DataBuffer,
296                         size_t DataBufferLength,
297                         RequestSense_T *pRequestSense,
298                         size_t RequestSenseLength)
299 {
300   struct sg_header *psg_header;
301   char *buffer;
302   size_t osize = 0;
303   ssize_t status;
304
305   /* Basic sanity checks */
306   assert(CDB_Length <= UCHAR_MAX);
307   assert(RequestSenseLength <= UCHAR_MAX);
308
309   /* Clear buffer for cases where sense is not returned */
310   memset(pRequestSense, 0, RequestSenseLength);
311
312   if (pDev[DeviceFD].avail == 0)
313     {
314       return(-1);
315     }
316
317   if (pDev[DeviceFD].devopen == 0)
318       if (SCSI_OpenDevice(DeviceFD) == 0)
319           return(-1);
320   
321   if (SCSI_OFF + CDB_Length + DataBufferLength > 4096) 
322     {
323       SCSI_CloseDevice(DeviceFD);
324       return(-1);
325     }
326
327   buffer = (char *)malloc(SCSI_OFF + CDB_Length + DataBufferLength);
328   if (buffer == NULL)
329     {
330       dbprintf(("SCSI_ExecuteCommand memory allocation failure.\n"));
331       SCSI_CloseDevice(DeviceFD);
332       return(-1);
333     }
334   memset(buffer, 0, SCSI_OFF + CDB_Length + DataBufferLength);
335   memcpy(buffer + SCSI_OFF, CDB, CDB_Length);
336   
337   psg_header = (struct sg_header *)buffer;
338   if (CDB_Length >= 12)
339     {
340       psg_header->twelve_byte = 1;
341     } else {
342       psg_header->twelve_byte = 0;
343     }
344   psg_header->result = 0;
345   psg_header->reply_len = (int)(SCSI_OFF + DataBufferLength);
346   
347   switch (Direction)
348     {
349     case Input:
350       osize = 0;
351       break;
352     case Output:
353       osize = DataBufferLength;
354       break;
355     }
356   
357   DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
358   
359   status = write(pDev[DeviceFD].fd, buffer, SCSI_OFF + CDB_Length + osize);
360   if ( (status < (ssize_t)0) ||
361        (status != (ssize_t)(SCSI_OFF + CDB_Length + osize)) ||
362        (psg_header->result != 0)) 
363     {
364       dbprintf(("SCSI_ExecuteCommand error send \n"));
365       SCSI_CloseDevice(DeviceFD);
366       amfree(buffer);
367       return(SCSI_ERROR);
368     }
369   
370   memset(buffer, 0, SCSI_OFF + DataBufferLength);
371   status = read(pDev[DeviceFD].fd, buffer, SCSI_OFF + DataBufferLength);
372   memset(pRequestSense, 0, RequestSenseLength);
373   memcpy(pRequestSense, psg_header->sense_buffer, 16);
374   
375   if ( (status < 0) ||
376        (status != (ssize_t)(SCSI_OFF + DataBufferLength)) || 
377        (psg_header->result != 0)) 
378     { 
379       dbprintf(("SCSI_ExecuteCommand error read \n"));
380       dbprintf(("Status %zd (%lu) %2X\n", status, SCSI_OFF + DataBufferLength,psg_header->result ));
381       SCSI_CloseDevice(DeviceFD);
382       amfree(buffer);
383       return(SCSI_ERROR);
384     }
385
386   if (DataBufferLength)
387     {
388        memcpy(DataBuffer, buffer + SCSI_OFF, DataBufferLength);
389     }
390
391   SCSI_CloseDevice(DeviceFD);
392   amfree(buffer);
393   return(SCSI_OK);
394 }
395
396 #else
397
398 static inline int min(int x, int y)
399 {
400   return (x < y ? x : y);
401 }
402
403
404 static inline int max(int x, int y)
405 {
406   return (x > y ? x : y);
407 }
408
409 int SCSI_OpenDevice(int ip)
410 {
411   int DeviceFD;
412   int i;
413
414   if (pDev[ip].inqdone == 0)
415     {
416       pDev[ip].inqdone = 1;
417       if ((DeviceFD = open(pDev[ip].dev, O_RDWR)) >= 0)
418         {
419           pDev[ip].avail = 1;
420           pDev[ip].fd = DeviceFD;
421           pDev[ip].SCSI = 0;
422           pDev[ip].inquiry = (SCSIInquiry_T *)malloc(INQUIRY_SIZE);
423           dbprintf(("SCSI_OpenDevice : use ioctl interface\n"));
424           if (SCSI_Inquiry(ip, pDev[ip].inquiry, (u_char)INQUIRY_SIZE) == 0)
425             {
426               if (pDev[ip].inquiry->type == TYPE_TAPE || pDev[ip].inquiry->type == TYPE_CHANGER)
427                 {
428                   for (i=0;i < 16 && pDev[ip].inquiry->prod_ident[i] != ' ';i++)
429                     pDev[ip].ident[i] = pDev[ip].inquiry->prod_ident[i];
430                   pDev[ip].ident[i] = '\0';
431                   pDev[ip].SCSI = 1;
432                   PrintInquiry(pDev[ip].inquiry);
433                   return(1);
434                 } else {
435                   amfree(pDev[ip].inquiry);
436                   close(DeviceFD);
437                   return(0);
438                 }
439             } else {
440               close(DeviceFD);
441               amfree(pDev[ip].inquiry);
442               pDev[ip].inquiry = NULL;
443               return(1);
444             }
445         }
446       return(1); 
447     } else {
448       if ((DeviceFD = open(pDev[ip].dev, O_RDWR)) >= 0)
449         {
450           pDev[ip].fd = DeviceFD;
451           pDev[ip].devopen = 1;
452           return(1);
453         } else {
454           pDev[ip].devopen = 0;
455           return(0);
456         }
457     }
458 }
459
460 int SCSI_ExecuteCommand(int DeviceFD,
461                         Direction_T Direction,
462                         CDB_T CDB,
463                         int CDB_Length,
464                         void *DataBuffer,
465                         int DataBufferLength,
466                         RequestSense_T *pRequestSense,
467                         int RequestSenseLength)
468 {
469   unsigned char *Command;
470   int Zero = 0, Result;
471  
472   if (pDev[DeviceFD].avail == 0)
473     {
474       return(SCSI_ERROR);
475     }
476
477   if (pDev[DeviceFD].devopen == 0)
478     {
479       if (SCSI_OpenDevice(DeviceFD) == 0)
480           return(-1);
481     }
482
483   memset(pRequestSense, 0, RequestSenseLength);
484   switch (Direction)
485     {
486     case Input:
487       Command = (unsigned char *)
488         malloc(8 + max(DataBufferLength, RequestSenseLength));
489       memcpy(&Command[0], &Zero, 4);
490       memcpy(&Command[4], &DataBufferLength, 4);
491       memcpy(&Command[8], CDB, CDB_Length);
492       break;
493     case Output:
494       Command = (unsigned char *)
495         malloc(8 + max(CDB_Length + DataBufferLength, RequestSenseLength));
496       memcpy(&Command[0], &DataBufferLength, 4);
497       memcpy(&Command[4], &Zero, 4);
498       memcpy(&Command[8], CDB, CDB_Length);
499       memcpy(&Command[8 + CDB_Length], DataBuffer, DataBufferLength);
500       break;
501     }
502   
503   DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
504   
505   Result = ioctl(pDev[DeviceFD].fd, SCSI_IOCTL_SEND_COMMAND, Command);
506   if (Result != 0)
507     memcpy(pRequestSense, &Command[8], RequestSenseLength);
508   else if (Direction == Input)
509     memcpy(DataBuffer, &Command[8], DataBufferLength);
510   amfree(Command);
511   SCSI_CloseDevice(DeviceFD);
512
513   switch(Result)
514     {
515       case 0:
516         return(SCSI_OK);
517         break;
518     default:
519       return(SCSI_SENSE);
520       break;
521     }
522 }
523 #endif
524
525 /*
526  * Send the command to the device with the
527  * ioctl interface
528  */
529 int Tape_Ioctl( int DeviceFD, int command)
530 {
531   struct mtop mtop;
532   int ret = 0;
533
534   if (pDev[DeviceFD].devopen == 0)
535     {
536       if (SCSI_OpenDevice(DeviceFD) == 0)
537           return(-1);
538     }
539
540   switch (command)
541     {
542     case IOCTL_EJECT:
543       mtop.mt_op = MTOFFL;
544       mtop.mt_count = 1;
545       break;
546      default:
547       break;
548     }
549
550   if (ioctl(pDev[DeviceFD].fd , MTIOCTOP, &mtop) != 0)
551     {
552       dbprintf(("Tape_Ioctl error ioctl %s\n",strerror(errno)));
553       SCSI_CloseDevice(DeviceFD);
554       return(-1);
555     }
556
557   SCSI_CloseDevice(DeviceFD);
558   return(ret);  
559 }
560
561 int Tape_Status( int DeviceFD)
562 {
563   struct mtget mtget;
564   int ret = 0;
565
566   memset(&mtget, 0, SIZEOF(mtget));
567   if (pDev[DeviceFD].devopen == 0)
568     {
569       if (SCSI_OpenDevice(DeviceFD) == 0)
570           return(-1);
571     }
572
573   if (ioctl(pDev[DeviceFD].fd , MTIOCGET, &mtget) != 0)
574   {
575      DebugPrint(DEBUG_ERROR, SECTION_TAPE,"Tape_Status error ioctl %s\n",
576                 strerror(errno));
577      SCSI_CloseDevice(DeviceFD);
578      return(-1);
579   }
580
581   DebugPrint(DEBUG_INFO, SECTION_TAPE,"ioctl -> mtget.mt_gstat %lX\n",mtget.mt_gstat);
582   if (GMT_ONLINE(mtget.mt_gstat))
583     {
584       ret = TAPE_ONLINE;
585     }
586   
587   if (GMT_BOT(mtget.mt_gstat))
588     {
589       ret = ret | TAPE_BOT;
590     }
591   
592   if (GMT_EOT(mtget.mt_gstat))
593     {
594       ret = ret | TAPE_EOT;
595     }
596   
597   if (GMT_WR_PROT(mtget.mt_gstat))
598     {
599       ret = ret | TAPE_WR_PROT;
600     }
601   
602   if (GMT_DR_OPEN(mtget.mt_gstat))
603     {
604       ret = ret | TAPE_NOT_LOADED;
605     }
606   
607   SCSI_CloseDevice(DeviceFD);
608   return(ret); 
609 }
610
611 /*
612  * This functions scan all /dev/sg* devices
613  * It opens the device an print the result of the inquiry 
614  *
615  */
616 int ScanBus(int print)
617 {
618   DIR *dir;
619   struct dirent *dirent;
620   int count = 0;
621
622   if ((dir = opendir("/dev/")) == NULL)
623     {
624       dbprintf(("/dev/ error: %s", strerror(errno)));
625       return 0;
626     }
627
628   while ((dirent = readdir(dir)) != NULL)
629     {
630       if (strstr(dirent->d_name, "sg") != NULL)
631       {
632         pDev[count].dev = malloc(10);
633         pDev[count].inqdone = 0;
634         snprintf(pDev[count].dev, SIZEOF(pDev[count].dev),
635             "/dev/%s", dirent->d_name);
636         if (OpenDevice(count,pDev[count].dev, "Scan", NULL ))
637           {
638             SCSI_CloseDevice(count);
639             pDev[count].inqdone = 0;
640             
641             if (print)
642               {
643                 printf("name /dev/%s ", dirent->d_name);
644                 
645                 switch (pDev[count].inquiry->type)
646                   {
647                   case TYPE_DISK:
648                     printf("Disk");
649                     break;
650                   case TYPE_TAPE:
651                     printf("Tape");
652                     break;
653                   case TYPE_PRINTER:
654                     printf("Printer");
655                     break;
656                   case TYPE_PROCESSOR:
657                     printf("Processor");
658                     break;
659                   case TYPE_WORM:
660                     printf("Worm");
661                     break;
662                   case TYPE_CDROM:
663                     printf("Cdrom");
664                     break;
665                   case TYPE_SCANNER:
666                     printf("Scanner");
667                     break;
668                   case TYPE_OPTICAL:
669                     printf("Optical");
670                     break;
671                   case TYPE_CHANGER:
672                     printf("Changer");
673                     break;
674                   case TYPE_COMM:
675                     printf("Comm");
676                     break;
677                   default:
678                     printf("unknown %d",pDev[count].inquiry->type);
679                     break;
680                   }
681                 printf("\n");
682               }
683             count++;
684             printf("Count %d\n",count);
685           } else {
686             amfree(pDev[count].dev);
687             pDev[count].dev=NULL;
688           }
689       }
690     }
691   return 0;
692 }
693 #endif
694 /*
695  * Local variables:
696  * indent-tabs-mode: nil
697  * c-file-style: gnu
698  * End:
699  */