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