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