a152b2411f344ba15e82d3794ea80d0658090996
[debian/amanda] / changer-src / scsi-bsd.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-bsd.c,v 1.1.2.10.4.2.2.4 2003/06/05 20:44:23 martinea Exp $
28  *
29  * Interface to execute SCSI commands on an BSD System (FreeBSD)
30  *
31  * Copyright (c) Thomes Hepper th@ant.han.de
32  */
33
34
35 #include <amanda.h>
36
37 #ifdef HAVE_BSD_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/scsiio.h>
57 #include <sys/mtio.h>
58
59 #include <scsi-defs.h>
60
61 void SCSI_OS_Version()
62 {
63 #ifndef lint
64    static char rcsid[] = "$Id: scsi-bsd.c,v 1.1.2.10.4.2.2.4 2003/06/05 20:44:23 martinea Exp $";
65    DebugPrint(DEBUG_INFO, SECTION_INFO, "scsi-os-layer: %s\n",rcsid);
66 #endif
67 }
68
69
70 /*
71  * Check if the device is already open,
72  * if no open it and save it in the list 
73  * of open files.
74  * 
75  * Return:
76  * 0  -> device not opened
77  * 1  -> sucess , device open
78  * -1 -> fatal error
79  */
80 int SCSI_OpenDevice(int ip)
81 {
82   extern OpenFiles_T *pDev;
83   int i;
84   char * DeviceName;
85
86
87   /*
88    * If the SCSI inquiry was not done lets try to get
89    * some infos about the device
90    */
91   if (pDev[ip].inqdone == 0) {
92     pDev[ip].inqdone = 1;                                                     /* Set it to 1, so the inq is done */
93     pDev[ip].SCSI = 0;                                                        /* This will only be set if the inquiry works */
94     pDev[ip].inquiry = (SCSIInquiry_T *)malloc(INQUIRY_SIZE);
95     
96     if (( pDev[ip].fd = open(pDev[ip].dev, O_RDWR)) > 0)                      /* We need the device in read/write mode */
97       {
98         pDev[ip].devopen = 1;                                                 /* The device is open for use */
99         pDev[ip].avail = 1;                                                   /* And it is available, it could be opened */
100         if (SCSI_Inquiry(ip, pDev[ip].inquiry, INQUIRY_SIZE) == 0)            /* Lets try to get the result of an SCSI inquiry */
101           {
102             if (pDev[ip].inquiry->type == TYPE_TAPE || pDev[ip].inquiry->type == TYPE_CHANGER)  /* If it worked and we got an type of */
103                                                                                                 /* either tape or changer continue */
104               {
105                 for (i=0;i < 16 ;i++)                                         /* Copy the product ident to the pDev struct */
106                   pDev[ip].ident[i] = pDev[ip].inquiry->prod_ident[i];
107                 for (i=15; i >= 0 && !isalnum(pDev[ip].ident[i]); i--)        /* And terminate it with an \0, remove all white space */
108                   {
109                     pDev[ip].ident[i] = '\0';
110                   }
111                 pDev[ip].SCSI = 1;                                            /* OK, its an SCSI device ... */
112
113                   if (pDev[ip].inquiry->type == TYPE_TAPE)
114                   {
115                           pDev[ip].type = stralloc("tape");
116                   }
117
118                   if (pDev[ip].inquiry->type == TYPE_CHANGER)
119                   {
120                           pDev[ip].type = stralloc("changer");
121                   }
122
123                 PrintInquiry(pDev[ip].inquiry);                               /* Some debug output */
124                 return(1);                                                    /* All done */
125               } else {
126                 free(pDev[ip].inquiry);                                       /* The SCSI was ok, but not an TAPE/CHANGER device ... */
127                 pDev[ip].devopen = 0;
128                 pDev[ip].avail = 0;
129                 close(pDev[ip].fd); 
130                 return(0);                                                    /*Might be an ChgExit is better */
131               }
132           } else { /* if SCSI_Inquiry */                                      /* The inquiry failed */
133             free(pDev[ip].inquiry);                                           /* free the allocated memory */
134             pDev[ip].inquiry = NULL;
135             return(1);                                                        /* Its not an SCSI device, but can be used for read/write */
136           }
137       }  /* open() */
138     return(0);                                                                /* Open failed .... */
139   } else { /* pDev[ip].inqdone */                                             /* OK this is the way we go if the device */
140     if (( pDev[ip].fd = open(pDev[ip].dev, O_RDWR)) > 0)                      /* was opened successfull before */
141       {
142         pDev[ip].devopen = 1;
143         return(1);
144       } 
145   }
146   return(0);                                                                 /* Default, return device not available */
147 }
148
149 /*
150  * Close the device 
151  * abd set the flags in the device struct 
152  *
153  */
154 int SCSI_CloseDevice(int DeviceFD)
155 {
156   int ret;
157   extern OpenFiles_T *pDev;
158   
159   ret = close(pDev[DeviceFD].fd) ;
160   pDev[DeviceFD].devopen = 0;
161   return(ret);
162 }
163
164 int SCSI_ExecuteCommand(int DeviceFD,
165                         Direction_T Direction,
166                         CDB_T CDB,
167                         int CDB_Length,
168                         void *DataBuffer,
169                         int DataBufferLength,
170                         char *pRequestSense,
171                         int RequestSenseLength)
172 {
173   extern OpenFiles_T *pDev;
174   ExtendedRequestSense_T ExtendedRequestSense;
175   scsireq_t ds;
176   int Zero = 0, Result;
177   int retries = 5;
178   extern int errno;
179   
180   if (pDev[DeviceFD].avail == 0)
181     {
182       return(SCSI_ERROR);
183     }
184
185   memset(&ds, 0, sizeof(scsireq_t));
186   memset(pRequestSense, 0, RequestSenseLength);
187   memset(&ExtendedRequestSense, 0 , sizeof(ExtendedRequestSense_T)); 
188   
189   ds.flags = SCCMD_ESCAPE; 
190   /* Timeout */
191   ds.timeout = 120000;
192   /* Set the cmd */
193   memcpy(ds.cmd, CDB, CDB_Length);
194   ds.cmdlen = CDB_Length;
195   /* Data buffer for results */
196   if (DataBufferLength > 0)
197     {
198       ds.databuf = (caddr_t)DataBuffer;
199       ds.datalen = DataBufferLength;
200     }
201   /* Sense Buffer */
202   /*
203     ds.sense = (u_char)pRequestSense;
204   */
205   ds.senselen = RequestSenseLength;
206     
207   switch (Direction) 
208     {
209     case Input:
210       ds.flags = ds.flags | SCCMD_READ;
211       break;
212     case Output:
213       ds.flags = ds.flags | SCCMD_WRITE;
214       break;
215     }
216     
217   while (--retries > 0) {
218     
219     if (pDev[DeviceFD].devopen == 0)
220       {
221         SCSI_OpenDevice(DeviceFD);
222       }
223     Result = ioctl(pDev[DeviceFD].fd, SCIOCCOMMAND, &ds);
224     SCSI_CloseDevice(DeviceFD);
225    
226     memcpy(pRequestSense, ds.sense, RequestSenseLength);
227     if (Result < 0)
228       {
229         dbprintf(("errno : %d\n",errno));
230         return (SCSI_ERROR);
231       }
232     dbprintf(("SCSI_ExecuteCommand(BSD) %02X STATUS(%02X) \n", CDB[0], ds.retsts));
233     switch (ds.retsts)
234       {
235       case SCCMD_BUSY:                /*  BUSY */
236         break;
237       case SCCMD_OK:                /*  GOOD */
238         return(SCSI_OK);
239         break;
240       case SCCMD_SENSE:               /*  CHECK CONDITION */
241         return(SCSI_SENSE);
242         break;
243       default:
244         continue;
245       }
246   }   
247   return(SCSI_SENSE);
248 }
249
250 /*
251  * Send the command to the device with the
252  * ioctl interface
253  */
254 int Tape_Ioctl( int DeviceFD, int command)
255 {
256   extern OpenFiles_T *pDev;
257   struct mtop mtop;
258   int ret = 0;
259
260   if (pDev[DeviceFD].devopen == 0)
261     {
262       SCSI_OpenDevice(DeviceFD);
263     }
264
265   switch (command)
266     {
267     case IOCTL_EJECT:
268       mtop.mt_op = MTOFFL;
269       mtop.mt_count = 1;
270       break;
271     default:
272       break;
273     }
274
275   if (ioctl(pDev[DeviceFD].fd , MTIOCTOP, &mtop) != 0)
276     {
277       dbprintf(("Tape_Ioctl error ioctl %d\n",errno));
278       SCSI_CloseDevice(DeviceFD);
279       return(-1);
280     }
281
282   SCSI_CloseDevice(DeviceFD);
283   return(ret);  
284 }
285
286 int Tape_Status( int DeviceFD)
287 {
288 /* 
289   Not yet
290 */
291   return(-1);
292 }
293
294 int ScanBus(int print)
295 {
296 /*
297   Not yet
298 */
299   return(-1);
300 }
301
302 #endif
303 /*
304  * Local variables:
305  * indent-tabs-mode: nil
306  * c-file-style: gnu
307  * End:
308  */