b747884d54f7d6d26d8842f9be00505e2a9b91d3
[debian/amanda] / changer-src / scsi-irix.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-irix.c,v 1.22 2005/10/15 13:20:47 martinea Exp $
28  *
29  * Interface to execute SCSI commands on an SGI Workstation
30  *
31  * Copyright (c) Thomas Hepper th@ant.han.de
32  */
33
34
35 #include <amanda.h>
36
37 #ifdef HAVE_IRIX_LIKE_SCSI
38
39 /*
40 #ifdef HAVE_STDIO_H
41 */
42 #include <stdio.h>
43 /*
44 #endif
45 */
46 #ifdef HAVE_SYS_TYPES_H
47 #include <sys/types.h>
48 #endif
49 #ifdef HAVE_SYS_STAT_H
50 #include <sys/stat.h>
51 #endif
52 #ifdef HAVE_FCNTL_H
53 #include <fcntl.h>
54 #endif
55
56 #include <sys/scsi.h>
57 #include <sys/dsreq.h>
58 #include <sys/mtio.h>
59
60 #include <scsi-defs.h>
61
62 void SCSI_OS_Version()
63 {
64 #ifndef lint
65    static char rcsid[] = "$Id: scsi-irix.c,v 1.22 2005/10/15 13:20:47 martinea Exp $";
66    DebugPrint(DEBUG_INFO, SECTION_INFO, "scsi-os-layer: %s\n",rcsid);
67 #endif
68 }
69
70
71 /*
72  */
73 int SCSI_OpenDevice(int ip)
74 {
75   extern OpenFiles_T *pDev;
76   int DeviceFD;
77   int i;
78   
79   if (pDev[ip].inqdone == 0)
80     {
81       if ((DeviceFD = open(pDev[ip].dev, O_RDWR | O_EXCL)) >= 0)
82         {
83           pDev[ip].inqdone = 1;          pDev[ip].SCSI = 0;
84           pDev[ip].avail = 1;
85           pDev[ip].fd = DeviceFD;
86           pDev[ip].inquiry = (SCSIInquiry_T *)malloc(INQUIRY_SIZE);
87           if (SCSI_Inquiry(ip, pDev[ip].inquiry, INQUIRY_SIZE) == 0)
88             {
89               if (pDev[ip].inquiry->type == TYPE_TAPE || pDev[ip].inquiry->type == TYPE_CHANGER)
90                 {
91                   for (i=0;i < 16 ;i++)
92                     pDev[ip].ident[i] = pDev[ip].inquiry->prod_ident[i];
93                   for (i=15; i >= 0 && !isalnum((int)pDev[ip].ident[i]) ; i--)
94                     {
95                       pDev[ip].ident[i] = '\0';
96                     }
97                   pDev[ip].SCSI = 1;
98                   close(DeviceFD);
99
100                   if (pDev[ip].inquiry->type == TYPE_TAPE)
101                   {
102                           pDev[ip].type = stralloc("tape");
103                   }
104
105                   if (pDev[ip].inquiry->type == TYPE_CHANGER)
106                   {
107                           pDev[ip].type = stralloc("changer");
108                   }
109
110                   PrintInquiry(pDev[ip].inquiry);
111                   return(1);
112                 } else { /* ! TYPE_TAPE ! TYPE_CHANGER */
113                   close(DeviceFD);
114                   free(pDev[ip].inquiry);
115                   pDev[ip].inquiry = NULL;
116                   pDev[ip].avail = 0;
117                   return(0);
118                 }
119             } else { /* inquiry failed */
120               close(DeviceFD);
121               free(pDev[ip].inquiry);
122               pDev[ip].inquiry = NULL;
123               pDev[ip].avail = 0;
124               return(0);
125             }
126
127           /*
128            * Open ok, but no SCSI communication available 
129            */
130
131           free(pDev[ip].inquiry);
132           pDev[ip].inquiry = NULL;
133           close(DeviceFD);
134           pDev[ip].avail = 0;
135           return(0);
136         }
137     } else {
138       if ((DeviceFD = open(pDev[ip].dev, O_RDWR | O_EXCL)) >= 0)
139         {
140           pDev[ip].fd = DeviceFD;
141           pDev[ip].devopen = 1;
142           return(1);
143         } else {
144           pDev[ip].devopen = 0;
145           return(0);
146         }
147     }
148   return(0); 
149 }
150
151 int SCSI_CloseDevice(int DeviceFD)
152 {
153   extern OpenFiles_T *pDev;
154   int ret = 0;
155   
156   if (pDev[DeviceFD].devopen == 1)
157     {
158       pDev[DeviceFD].devopen = 0;
159       ret = close(pDev[DeviceFD].fd);
160     }
161
162   return(ret);
163 }
164
165 int SCSI_ExecuteCommand(int DeviceFD,
166                         Direction_T Direction,
167                         CDB_T CDB,
168                         int CDB_Length,
169                         void *DataBuffer,
170                         int DataBufferLength,
171                         char *pRequestSense,
172                         int RequestSenseLength)
173 {
174   extern OpenFiles_T *pDev;
175   ExtendedRequestSense_T ExtendedRequestSense;
176   struct dsreq ds;
177   int Result;
178   int retries = 5;
179   
180   if (pDev[DeviceFD].avail == 0)
181     {
182       return(SCSI_ERROR);
183     }
184   
185   memset(&ds, 0, sizeof(struct dsreq));
186   memset(pRequestSense, 0, RequestSenseLength);
187   memset(&ExtendedRequestSense, 0 , sizeof(ExtendedRequestSense_T)); 
188   
189   ds.ds_flags = DSRQ_SENSE|DSRQ_TRACE|DSRQ_PRINT; 
190   /* Timeout */
191   ds.ds_time = 120000;
192   /* Set the cmd */
193   ds.ds_cmdbuf = (caddr_t)CDB;
194   ds.ds_cmdlen = CDB_Length;
195   /* Data buffer for results */
196   ds.ds_databuf = (caddr_t)DataBuffer;
197   ds.ds_datalen = DataBufferLength;
198   /* Sense Buffer */
199   ds.ds_sensebuf = (caddr_t)pRequestSense;
200   ds.ds_senselen = RequestSenseLength;
201   
202   switch (Direction) 
203     {
204     case Input:
205       ds.ds_flags = ds.ds_flags | DSRQ_READ;
206       break;
207     case Output:
208       ds.ds_flags = ds.ds_flags | DSRQ_WRITE;
209       break;
210     }
211   
212   while (--retries > 0) {
213     if (pDev[DeviceFD].devopen == 0)
214       {
215         if (SCSI_OpenDevice(DeviceFD) == 0)
216           {
217             dbprintf(("SCSI_ExecuteCommand could not open %s: %s\n",
218                       pDev[DeviceFD].dev,
219                       strerror(errno)));
220             sleep(1); /* Give device a little time befor retry */
221             continue;
222           }
223       }
224     Result = ioctl(pDev[DeviceFD].fd, DS_ENTER, &ds);
225     SCSI_CloseDevice(DeviceFD);
226
227     if (Result < 0)
228       {
229         RET(&ds) = DSRT_DEVSCSI;
230         SCSI_CloseDevice(DeviceFD);
231         return (SCSI_ERROR);
232       }
233     DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
234     dbprintf(("\t\t\tSTATUS(%02X) RET(%02X)\n", STATUS(&ds), RET(&ds)));
235     switch (STATUS(&ds))
236       {
237       case ST_BUSY:                /*  BUSY */
238         break;
239       case STA_RESERV:             /*  RESERV CONFLICT */
240         if (retries > 0)
241           sleep(2);
242         continue;
243       case ST_GOOD:                /*  GOOD 0x00 */
244         switch (RET(&ds))
245           {
246           case DSRT_SENSE:
247             return(SCSI_SENSE);
248             break;
249           case DSRT_SHORT:
250             return(SCSI_OK);
251             break;
252           case DSRT_OK:
253           default:
254             return(SCSI_OK);
255           }
256       case ST_CHECK:               /*  CHECK CONDITION 0x02 */ 
257         switch (RET(&ds))
258           {
259           case DSRT_SENSE:
260             return(SCSI_SENSE);
261             break;
262           default:
263             return(SCSI_CHECK);
264             break;
265           }
266         return(SCSI_CHECK);
267         break;
268       case ST_COND_MET:            /*  INTERM/GOOD 0x10 */
269       default:
270         continue;
271       }
272   }     
273   return(SCSI_ERROR);
274 }
275
276 int Tape_Ioctl ( int DeviceFD, int command)
277 {
278   extern OpenFiles_T *pDev;
279   struct mtop mtop;
280   
281   if (pDev[DeviceFD].devopen == 0)
282     {
283       if (SCSI_OpenDevice(DeviceFD) == 0)
284           return(-1);
285     }
286   
287   switch (command)
288     {
289     case IOCTL_EJECT:
290       mtop.mt_op = MTUNLOAD;
291       mtop.mt_count = 1;
292       break;
293     default:
294       break;
295     }
296   
297   ioctl(pDev[DeviceFD].fd, MTIOCTOP, &mtop);
298   SCSI_CloseDevice(DeviceFD);
299   return(0);
300 }
301
302 int Tape_Status( int DeviceFD)
303 {
304   extern OpenFiles_T *pDev;
305   struct mtget mtget;
306   int ret = 0;
307
308   if (pDev[DeviceFD].devopen == 0)
309     {
310       if (SCSI_OpenDevice(DeviceFD) == 0)
311           return(-1);
312     }
313
314   if (ioctl(pDev[DeviceFD].fd , MTIOCGET, &mtget) != 0)
315     {
316       dbprintf(("Tape_Status error ioctl %d\n",errno));
317       SCSI_CloseDevice(DeviceFD);
318       return(-1);
319     }
320   
321   switch(mtget.mt_dposn)
322     {
323     case MT_EOT:
324       ret = ret | TAPE_EOT;
325       break;
326     case MT_BOT:
327       ret = ret | TAPE_BOT;
328       break;
329     case MT_WPROT:
330       ret = ret | TAPE_WR_PROT;
331       break;
332     case MT_ONL:
333       ret = TAPE_ONLINE;
334       break;
335     case MT_EOD:
336       break;
337     case MT_FMK:
338       break;
339     default:
340       break;
341     }
342
343   SCSI_CloseDevice(DeviceFD);
344   return(ret); 
345 }
346
347 int ScanBus(int print)
348 {
349   DIR *dir;
350   struct dirent *dirent;
351   extern OpenFiles_T *pDev;
352   extern int errno;
353   int count = 0;
354
355   if ((dir = opendir("/dev/scsi")) == NULL)
356     {
357       dbprintf(("Can not read /dev/scsi: %s", strerror(errno)));
358       return 0;
359     }
360
361   while ((dirent = readdir(dir)) != NULL)
362     {
363       if (strstr(dirent->d_name, "sc") != NULL)
364       {
365         pDev[count].dev = malloc(10);
366         pDev[count].inqdone = 0;
367         sprintf(pDev[count].dev,"/dev/scsi/%s", dirent->d_name);
368         if (OpenDevice(count,pDev[count].dev, "Scan", NULL ))
369           {
370             SCSI_CloseDevice(count);
371             pDev[count].inqdone = 0;
372             
373             if (print)
374               {
375                 printf("name /dev/scsi/%s ", dirent->d_name);
376                 
377                 switch (pDev[count].inquiry->type)
378                   {
379                   case TYPE_DISK:
380                     printf("Disk");
381                     break;
382                   case TYPE_TAPE:
383                     printf("Tape");
384                     break;
385                   case TYPE_PRINTER:
386                     printf("Printer");
387                     break;
388                   case TYPE_PROCESSOR:
389                     printf("Processor");
390                     break;
391                   case TYPE_WORM:
392                     printf("Worm");
393                     break;
394                   case TYPE_CDROM:
395                     printf("Cdrom");
396                     break;
397                   case TYPE_SCANNER:
398                     printf("Scanner");
399                     break;
400                   case TYPE_OPTICAL:
401                     printf("Optical");
402                     break;
403                   case TYPE_CHANGER:
404                     printf("Changer");
405                     break;
406                   case TYPE_COMM:
407                     printf("Comm");
408                     break;
409                   default:
410                     printf("unknown %d",pDev[count].inquiry->type);
411                     break;
412                   }
413                 printf("\n");
414               }
415             count++;
416             printf("Count %d\n",count);
417           } else {
418             free(pDev[count].dev);
419             pDev[count].dev=NULL;
420           }
421       }
422     }
423   return 0;
424 }
425
426 #endif
427 /*
428  * Local variables:
429  * indent-tabs-mode: nil
430  * c-file-style: gnu
431  * End:
432  */