Imported Upstream version 2.5.1
[debian/amanda] / changer-src / scsi-solaris.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-solaris.c,v 1.26 2006/05/25 01:47:10 johnfranks Exp $
28  *
29  * Interface to execute SCSI commands on an Sun Workstation
30  *
31  * Copyright (c) Thomas Hepper th@ant.han.de
32  */
33
34
35 #include <amanda.h>
36
37 #ifdef HAVE_SOLARIS_LIKE_SCSI
38 /*
39 #ifdef HAVE_STDIO_H
40 */
41 #include <stdio.h>
42 /*
43 #endif
44 */
45 #ifdef HAVE_SYS_TYPES_H
46 #include <sys/types.h>
47 #endif
48 #ifdef HAVE_SYS_STAT_H
49 #include <sys/stat.h>
50 #endif
51 #ifdef HAVE_FCNTL_H
52 #include <fcntl.h>
53 #endif
54
55 #include <sys/scsi/impl/uscsi.h>
56
57 #include <scsi-defs.h>
58 #include <sys/mtio.h>
59
60 void SCSI_OS_Version()
61 {
62 #ifndef lint
63    static char rcsid[] = "$Id: scsi-solaris.c,v 1.26 2006/05/25 01:47:10 johnfranks Exp $";
64    DebugPrint(DEBUG_INFO, SECTION_INFO, "scsi-os-layer: %s\n",rcsid);
65 #endif
66 }
67
68 int SCSI_OpenDevice(int ip)
69 {
70   int DeviceFD;
71   int i;
72   extern OpenFiles_T *pDev;
73
74   if (pDev[ip].inqdone == 0)
75     {
76       pDev[ip].inqdone = 1;
77       if ((DeviceFD = open(pDev[ip].dev, O_RDWR| O_NONBLOCK)) >= 0)
78         {
79           pDev[ip].avail = 1;
80           pDev[ip].fd = DeviceFD;
81           pDev[ip].SCSI = 0;
82           pDev[ip].devopen = 1;
83           pDev[ip].inquiry = (SCSIInquiry_T *)malloc(INQUIRY_SIZE);
84           
85           if (SCSI_Inquiry(ip, pDev[ip].inquiry, (unsigned char)INQUIRY_SIZE) == 0)
86             {
87               if (pDev[ip].inquiry->type == TYPE_TAPE || pDev[ip].inquiry->type == TYPE_CHANGER)
88                 {
89                   for (i=0;i < 16;i++)
90                     pDev[ip].ident[i] = pDev[ip].inquiry->prod_ident[i];
91                   for (i=15; i >= 0 && !isalnum((int)pDev[ip].ident[i]) ; i--)
92                     {
93                       pDev[ip].ident[i] = '\0';
94                     }
95                   pDev[ip].SCSI = 1;
96
97                   if (pDev[ip].inquiry->type == TYPE_TAPE)
98                   {
99                           pDev[ip].type = stralloc("tape");
100                   }
101
102                   if (pDev[ip].inquiry->type == TYPE_CHANGER)
103                   {
104                           pDev[ip].type = stralloc("changer");
105                   }
106
107                   PrintInquiry(pDev[ip].inquiry);
108                   return(1);
109                 } else {
110                   close(DeviceFD);
111                   free(pDev[ip].inquiry);
112                   return(0);
113                 }
114             }
115             free(pDev[ip].inquiry);
116             pDev[ip].inquiry = NULL;
117             return(1);
118         } else {
119           dbprintf(("SCSI_OpenDevice %s failed\n", pDev[ip].dev));
120           return(0);
121         }
122     } else {
123       if ((DeviceFD = open(pDev[ip].dev, O_RDWR| O_NDELAY)) >= 0)
124         {
125           pDev[ip].fd = DeviceFD;
126           pDev[ip].devopen = 1;
127           return(1);
128         }
129     }
130   return(0); 
131 }
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
145 int SCSI_ExecuteCommand(int DeviceFD,
146                         Direction_T Direction,
147                         CDB_T CDB,
148                         size_t CDB_Length,
149                         void *DataBuffer,
150                         size_t DataBufferLength,
151                         RequestSense_T *RequestSense,
152                         size_t RequestSenseLength)
153 {
154   extern OpenFiles_T *pDev;
155   extern FILE * debug_file;
156   int ret = 0;
157   int retries = 1;
158   extern int errno;
159   struct uscsi_cmd Command;
160   static int depth = 0;
161
162   /* Basic sanity checks */
163   assert(CDB_Length <= UCHAR_MAX);
164   assert(RequestSenseLength <= UCHAR_MAX);
165
166   /* Clear buffer for cases where sense is not returned */
167   memset(RequestSense, 0, RequestSenseLength);
168
169   if (pDev[DeviceFD].avail == 0)
170     {
171       return(SCSI_ERROR);
172     }
173   
174   if (depth++ > 2)
175   {
176      --depth;
177      SCSI_CloseDevice(DeviceFD);
178      return SCSI_ERROR;
179   }
180   memset(&Command, 0, SIZEOF(struct uscsi_cmd));
181   memset(RequestSense, 0, RequestSenseLength);
182   switch (Direction)
183     {
184     case Input:
185       if (DataBufferLength > 0)
186         memset(DataBuffer, 0, DataBufferLength);
187
188       /* Command.uscsi_flags =  USCSI_READ | USCSI_RQENABLE;    */
189       Command.uscsi_flags = USCSI_DIAGNOSE | USCSI_ISOLATE
190         | USCSI_READ | USCSI_RQENABLE;
191       break;
192     case Output:
193       /* Command.uscsi_flags =  USCSI_WRITE | USCSI_RQENABLE;   */
194       Command.uscsi_flags = USCSI_DIAGNOSE | USCSI_ISOLATE
195         | USCSI_WRITE | USCSI_RQENABLE;
196       break;
197     }
198   /* Set timeout to 5 minutes. */
199   Command.uscsi_timeout = 300;
200   Command.uscsi_cdb = (caddr_t) CDB;
201   Command.uscsi_cdblen = (u_char)CDB_Length;
202
203   if (DataBufferLength > 0)
204     {  
205       Command.uscsi_bufaddr = DataBuffer;
206       Command.uscsi_buflen = DataBufferLength;
207     } else {
208 /*
209  * If there is no data buffer force the direction to write, read with
210  * a null buffer will fail (errno 22)
211  */
212       Command.uscsi_flags = USCSI_DIAGNOSE | USCSI_ISOLATE
213         | USCSI_WRITE | USCSI_RQENABLE;
214    }
215
216   Command.uscsi_rqbuf = (caddr_t)RequestSense;
217   Command.uscsi_rqlen = (u_char)RequestSenseLength;
218   DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
219   while (retries > 0)
220   {
221     if (pDev[DeviceFD].devopen == 0)
222       if (SCSI_OpenDevice(DeviceFD) == 0)
223         {
224           sleep(1);
225           continue;
226         }
227
228     if ((ret = ioctl(pDev[DeviceFD].fd, USCSICMD, &Command)) >= 0)
229     {
230       ret = Command.uscsi_status;
231       break;
232     }
233     dbprintf(("ioctl on %d failed, errno %s, ret %d\n",
234               pDev[DeviceFD].fd, strerror(errno), ret));
235 #if 0
236     RequestSense(DeviceFD, &pExtendedRequestSense, 0);
237 #endif
238     DecodeSense(RequestSense, "SCSI_ExecuteCommand:", debug_file);
239     retries--;
240   }
241   --depth;
242   SCSI_CloseDevice(DeviceFD);
243
244   DebugPrint(DEBUG_INFO, SECTION_SCSI,"ioctl ret (%d)\n",ret);
245   return(SCSI_OK);
246 }
247
248 /*
249  * Send the command to the device with the
250  * ioctl interface
251  */
252 int Tape_Ioctl( int DeviceFD, int command)
253 {
254   extern OpenFiles_T *pDev;
255   struct mtop mtop;
256   int ret = 0;
257
258   if (pDev[DeviceFD].devopen == 0)
259       if (SCSI_OpenDevice(DeviceFD) == 0)
260           return(-1);
261
262   switch (command)
263     {
264     case IOCTL_EJECT:
265       mtop.mt_op = MTOFFL;
266       mtop.mt_count = 1;
267       break;
268      default:
269       break;
270     }
271
272   if (ioctl(pDev[DeviceFD].fd , MTIOCTOP, &mtop) != 0)
273     {
274       dbprintf(("Tape_Ioctl error ioctl %s\n", strerror(errno)));
275       SCSI_CloseDevice(DeviceFD);
276       return(-1);
277     }
278
279   SCSI_CloseDevice(DeviceFD);
280   return(ret);  
281 }
282
283 int Tape_Status( int DeviceFD)
284 {
285   extern OpenFiles_T *pDev;
286   struct mtget mtget;
287   int ret = -1;
288
289   memset(&mtget, 0, SIZEOF(mtget));
290   if (pDev[DeviceFD].devopen == 0)
291       if (SCSI_OpenDevice(DeviceFD) == 0)
292           return(-1);
293   
294   if (ioctl(pDev[DeviceFD].fd , MTIOCGET, &mtget) != 0)
295     {
296       dbprintf(("Tape_Status error ioctl %s\n", strerror(errno)));
297       SCSI_CloseDevice(DeviceFD);
298       return(-1);
299     }
300
301   /*
302    * I have no idea what is the meaning of the bits in mt_erreg
303    * I assume that nothing set is tape loaded
304    * 0x2 is no tape online
305    */
306
307   DebugPrint(DEBUG_INFO, SECTION_TAPE, "ioctl result for mt_dsreg (%d)\n", mtget.mt_dsreg);
308   DebugPrint(DEBUG_INFO, SECTION_TAPE, "ioctl result for mt_erreg (%d)\n", mtget.mt_erreg);
309
310   if (mtget.mt_erreg == 0)
311     {
312       ret = ret | TAPE_ONLINE;
313     }
314
315   if (mtget.mt_erreg & 0x2)
316     {
317       ret = ret | TAPE_NOT_LOADED;
318     }
319
320   SCSI_CloseDevice(DeviceFD);
321
322   return(ret); 
323 }
324
325 int ScanBus(int print)
326 {
327         (void)print;    /* Quiet unused parameter warning */
328         return(-1);
329 }
330
331 #endif
332 /*
333  * Local variables:
334  * indent-tabs-mode: nil
335  * c-file-style: gnu
336  * End:
337  */