c20003fc733d153db79d1d097a5b05a675609796
[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.25 2005/10/15 13:20:47 martinea 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.25 2005/10/15 13:20:47 martinea 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, 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             } else {
115               free(pDev[ip].inquiry);
116               pDev[ip].inquiry = NULL;
117               return(1);
118             }
119           return(1);
120         } else {
121           dbprintf(("SCSI_OpenDevice %s failed\n", pDev[ip].dev));
122           return(0);
123         }
124     } else {
125       if ((DeviceFD = open(pDev[ip].dev, O_RDWR| O_NDELAY)) >= 0)
126         {
127           pDev[ip].fd = DeviceFD;
128           pDev[ip].devopen = 1;
129           return(1);
130         }
131     }
132   return(0); 
133 }
134
135
136 int SCSI_CloseDevice(int DeviceFD)
137 {
138   int ret;
139   extern OpenFiles_T *pDev;
140
141   ret = close(pDev[DeviceFD].fd);
142   pDev[DeviceFD].devopen = 0;
143   return(ret);
144 }
145
146
147 int SCSI_ExecuteCommand(int DeviceFD,
148                         Direction_T Direction,
149                         CDB_T CDB,
150                         int CDB_Length,
151                         void *DataBuffer,
152                         int DataBufferLength,
153                         char *pRequestSense,
154                         int RequestSenseLength)
155 {
156   extern OpenFiles_T *pDev;
157   extern FILE * debug_file;
158   int ret = 0;
159   int retries = 1;
160   extern int errno;
161   struct uscsi_cmd Command;
162 #if 0
163   ExtendedRequestSense_T pExtendedRequestSense;
164 #endif
165   static int depth = 0;
166
167   if (pDev[DeviceFD].avail == 0)
168     {
169       return(SCSI_ERROR);
170     }
171   
172   if (depth++ > 2)
173   {
174      --depth;
175      SCSI_CloseDevice(DeviceFD);
176      return SCSI_ERROR;
177   }
178   memset(&Command, 0, sizeof(struct uscsi_cmd));
179   memset(pRequestSense, 0, RequestSenseLength);
180   switch (Direction)
181     {
182     case Input:
183       if (DataBufferLength > 0)
184         memset(DataBuffer, 0, DataBufferLength);
185
186       /* Command.uscsi_flags =  USCSI_READ | USCSI_RQENABLE;    */
187       Command.uscsi_flags = USCSI_DIAGNOSE | USCSI_ISOLATE
188         | USCSI_READ | USCSI_RQENABLE;
189       break;
190     case Output:
191       /* Command.uscsi_flags =  USCSI_WRITE | USCSI_RQENABLE;   */
192       Command.uscsi_flags = USCSI_DIAGNOSE | USCSI_ISOLATE
193         | USCSI_WRITE | USCSI_RQENABLE;
194       break;
195     }
196   /* Set timeout to 5 minutes. */
197   Command.uscsi_timeout = 300;
198   Command.uscsi_cdb = (caddr_t) CDB;
199   Command.uscsi_cdblen = CDB_Length;
200
201   if (DataBufferLength > 0)
202     {  
203       Command.uscsi_bufaddr = DataBuffer;
204       Command.uscsi_buflen = DataBufferLength;
205     } else {
206 /*
207  * If there is no data buffer force the direction to write, read with
208  * a null buffer will fail (errno 22)
209  */
210       Command.uscsi_flags = USCSI_DIAGNOSE | USCSI_ISOLATE
211         | USCSI_WRITE | USCSI_RQENABLE;
212    }
213
214   Command.uscsi_rqbuf = (caddr_t) pRequestSense;
215   Command.uscsi_rqlen = RequestSenseLength;
216   DecodeSCSI(CDB, "SCSI_ExecuteCommand : ");
217   while (retries > 0)
218   {
219     if (pDev[DeviceFD].devopen == 0)
220       if (SCSI_OpenDevice(DeviceFD) == 0)
221         {
222           sleep(1);
223           continue;
224         }
225
226     if ((ret = ioctl(pDev[DeviceFD].fd, USCSICMD, &Command)) >= 0)
227     {
228       ret = Command.uscsi_status;
229       break;
230     }
231     dbprintf(("ioctl on %d failed, errno %d, ret %d\n",pDev[DeviceFD].fd, errno, ret));
232 #if 0
233     RequestSense(DeviceFD, &pExtendedRequestSense, 0);
234 #endif
235     DecodeSense((RequestSense_T *)pRequestSense,
236                 "SCSI_ExecuteCommand:", debug_file);
237     retries--;
238   }
239   --depth;
240   SCSI_CloseDevice(DeviceFD);
241
242   switch (ret)
243     {
244     default:
245       DebugPrint(DEBUG_INFO, SECTION_SCSI,"ioctl ret (%d)\n",ret);
246       return(SCSI_OK);
247       break;
248     }
249 }
250
251 /*
252  * Send the command to the device with the
253  * ioctl interface
254  */
255 int Tape_Ioctl( int DeviceFD, int command)
256 {
257   extern OpenFiles_T *pDev;
258   struct mtop mtop;
259   int ret = 0;
260
261   if (pDev[DeviceFD].devopen == 0)
262       if (SCSI_OpenDevice(DeviceFD) == 0)
263           return(-1);
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   extern OpenFiles_T *pDev;
289   struct mtget mtget;
290   int ret = -1;
291
292   if (pDev[DeviceFD].devopen == 0)
293       if (SCSI_OpenDevice(DeviceFD) == 0)
294           return(-1);
295   
296   if (ioctl(pDev[DeviceFD].fd , MTIOCGET, &mtget) != 0)
297     {
298       dbprintf(("Tape_Status error ioctl %d\n",errno));
299       SCSI_CloseDevice(DeviceFD);
300       return(-1);
301     }
302
303   /*
304    * I have no idea what is the meaning of the bits in mt_erreg
305    * I assume that nothing set is tape loaded
306    * 0x2 is no tape online
307    */
308
309   DebugPrint(DEBUG_INFO, SECTION_TAPE, "ioctl result for mt_dsreg (%d)\n", mtget.mt_dsreg);
310   DebugPrint(DEBUG_INFO, SECTION_TAPE, "ioctl result for mt_erreg (%d)\n", mtget.mt_erreg);
311
312   if (mtget.mt_erreg == 0)
313     {
314       ret = ret | TAPE_ONLINE;
315     }
316
317   if (mtget.mt_erreg & 0x2)
318     {
319       ret = ret | TAPE_NOT_LOADED;
320     }
321
322   SCSI_CloseDevice(DeviceFD);
323
324   return(ret); 
325 }
326
327 int ScanBus(int print)
328 {
329         return(-1);
330 }
331
332 #endif
333 /*
334  * Local variables:
335  * indent-tabs-mode: nil
336  * c-file-style: gnu
337  * End:
338  */