Merge branch 'upstream'
[debian/amanda] / changer-src / scsi-chio.c
1 /*
2  *      $Id: scsi-chio.c,v 1.14 2006/05/25 01:47:07 johnfranks Exp $
3  *
4  *      scsi-chio.c -- library routines to handle the changer
5  *                      support for chio based systems
6  *
7  *      Author: Eric Schnoebelen, eric@cirr.com
8  *      based on work by: Larry Pyeatt,  pyeatt@cs.colostate.edu 
9  *      Copyright: 1997, 1998 Eric Schnoebelen
10  *
11  *      Patch: Michael Enkelis, michaele@mxim.com)
12  */
13
14 #include "config.h"
15 #include "amanda.h"
16 #include "scsi-defs.h"
17
18 #if (defined(HAVE_CHIO_H) || defined(HAVE_SYS_CHIO_H)) \
19     && !defined(HAVE_CAMLIB_H)
20
21 #include <sys/types.h>
22 #include <sys/ioctl.h>
23 #include <sys/mtio.h>
24
25 /* This include comes with Gerd Knor's SCSI media changer driver.
26  * If you are porting to another system, this is the file that defines
27  * ioctl calls for the changer.  You will have to track it down yourself
28  * and possibly change all the ioctl() calls in this program.  
29  */
30
31 #if defined(HAVE_LINUX_CHIO_H)
32 #  include <linux/chio.h>
33 #else
34 # if defined(HAVE_CHIO_H)
35 #   include <chio.h>
36 # else /* HAVE_SYS_CHIO_H must be defined */
37 #   include <sys/chio.h>
38 # endif /* HAVE_CHIO_H */
39 #endif  /* HAVE_LINUX_CHIO_H */
40
41 char *modname = "@(#)" __FILE__ 
42                 ": SCSI support library for the chio(2) interface @(#)";
43
44 /*
45  * cache the general changer information, for faster access elsewhere
46  */
47 static struct changer_params changer_info;
48 static int changer_info_init = 0;
49 int GetCurrentSlot(int fd, int drive);
50 int GetDeviceStatus (char *tapedev);
51 int OpenDevice (char *tapedev);
52 int CloseDevice (char *device, int DeviceFD);
53 int Tape_Ready1 ( char *tapedev , int wait);
54 int isempty(int fd, int slot);
55 int find_empty(int fd, int start, int count);
56 int get_clean_state(char *tapedev);
57 int get_slot_count(int fd);
58 int get_drive_count(int fd);
59 int eject_tape(char *tapedev);
60 int drive_loaded(int fd, int drivenum);
61 int unload(int fd, int drive, int slot);
62 int load(int fd, int drive, int slot);
63
64 static int get_changer_info(int fd)
65 {
66 int rc = 0;
67
68     if ( !changer_info_init ) {
69         rc = ioctl(fd, CHIOGPARAMS, &changer_info);
70         changer_info_init++;
71     }
72     return (rc);
73 }
74
75 /* Get the number of the first free slot
76  * return > 0 number of empty slot
77  * return = 0 no slot free
78  * return < 0 error
79  */
80 int GetCurrentSlot(int fd, int drive)
81 {
82     struct changer_element_status  ces;
83     int slot;
84     int i, rc;
85
86     (void)drive;
87
88     get_changer_info(fd);
89
90     ces.ces_type = CHET_ST;
91     ces.ces_data = malloc(changer_info.cp_nslots);
92
93     rc = ioctl(fd, CHIOGSTATUS, &ces);
94     if (rc) {
95         dbprintf(_("changer status query failed: 0x%x %s\n"), rc, strerror(errno));
96         return -1;
97     }
98     for (slot = 0; slot < changer_info.cp_nslots; slot++)
99     {
100         i = ces.ces_data[slot] & CESTATUS_FULL;
101         dbprintf(_("\tGetCurrentSlot slot %d = %d\n"), slot, i);
102         if (!i)
103             return(slot);
104     }
105     return -1;
106 }
107
108 int get_clean_state(char *tapedev)
109 {
110 int rc;
111 #if defined(BUILTIN)
112     rc = 0;
113 #else
114 #define GMT_CLN(x)      ((x) & 0x00008000)
115     rc = ( GMT_CLN(GetDeviceStatus(tapedev)) );
116 #endif  /* BUILTIN */
117     return rc;
118 }
119
120 int eject_tape(char *tapedev)
121 /* This function ejects the tape from the drive */
122 {
123 int mtfd;
124 struct mtop mt_com;
125
126     if ( (mtfd = OpenDevice(tapedev) ) < 0) {
127         dbprintf(_("eject_tape : failed\n"));
128         perror(tapedev);
129         exit(2);
130     }
131     mt_com.mt_op = MTOFFL;
132     mt_com.mt_count = 1;
133     if (ioctl(mtfd, MTIOCTOP, (char *)&mt_com) < 0) {
134 /*
135     If the drive already ejected the tape due an error, or because it
136     was a cleaning tape, threre can be an error, which we should ignore 
137
138        perror(tapedev);
139        exit(2);
140 */
141     }
142     return(CloseDevice(tapedev, mtfd));
143 }
144
145
146 /* 
147  * this routine checks a specified slot to see if it is empty 
148  */
149 int isempty(int fd, int slot)
150 {
151 struct changer_element_status  ces;
152 int                            i,rc;
153 int type=CHET_ST;
154
155     get_changer_info(fd);
156
157     ces.ces_type = type;
158     ces.ces_data = malloc(changer_info.cp_nslots);
159
160     rc = ioctl(fd, CHIOGSTATUS, &ces);
161     if (rc) {
162         dbprintf(_("changer status query failed: 0x%x %s\n"), rc,strerror(errno));
163         return -1;
164     }
165
166     i = ces.ces_data[slot] & CESTATUS_FULL;
167
168     free(ces.ces_data);
169     return !i;
170 }
171
172 /*
173  * find the first empty slot 
174  */
175 int find_empty(int fd, int start, int count)
176 {
177 struct changer_element_status  ces;
178 int                            i,rc;
179 int type=CHET_ST;
180
181     (void)start;
182     (void)count;
183
184     get_changer_info(fd);
185
186     ces.ces_type = type;
187     ces.ces_data = malloc(changer_info.cp_nslots);
188
189     rc = ioctl(fd,CHIOGSTATUS,&ces);
190     if (rc) {
191         dbprintf(_("changer status query failed: 0x%x %s\n"), rc, strerror(errno));
192         return -1;
193     }
194
195     i = 0; 
196     while ((i < changer_info.cp_nslots)&&(ces.ces_data[i] & CESTATUS_FULL))
197         i++;
198     free(ces.ces_data);
199     return i;
200 }
201
202 /*
203  * returns one if there is a tape loaded in the drive 
204  */
205 int drive_loaded(int fd, int drivenum)
206 {
207 struct changer_element_status  ces;
208 int                            i,rc;
209 int type=CHET_DT;
210
211     get_changer_info(fd);
212
213     ces.ces_type = type;
214     ces.ces_data = malloc(changer_info.cp_ndrives);
215
216     rc = ioctl(fd, CHIOGSTATUS, &ces);
217     if (rc) {
218         dbprintf(_("drive status query failed: 0x%x %s\n"), rc, strerror(errno));
219         return -1;
220     }
221
222     i = (ces.ces_data[drivenum] & CESTATUS_FULL);
223
224     free(ces.ces_data);
225     return i;
226 }
227
228
229 /*
230  * unloads the drive, putting the tape in the specified slot 
231  */
232 int unload(int fd, int drive, int slot)
233 {
234 struct changer_move  move;
235 int rc;
236
237     dbprintf(_("unload : fd = %d, drive = %d, slot =%d\n"),fd, drive, slot);
238
239     move.cm_fromtype = CHET_DT;
240     move.cm_fromunit = drive;
241     move.cm_totype = CHET_ST;
242     move.cm_tounit = slot;
243     move.cm_flags = 0;
244
245     rc = ioctl(fd, CHIOMOVE, &move);
246     if (rc){
247         dbprintf(_("drive unload failed (MOVE): 0x%x %s\n"), rc, strerror(errno));
248         return(-2);
249     }
250     return 0;
251 }
252
253
254 /*
255  * moves tape from the specified slot into the drive 
256  */
257 int load(int fd, int drive, int slot)
258 {
259 struct changer_move  move;
260 int rc;
261
262     dbprintf(_("load : fd = %d, drive = %d, slot =%d\n"),fd, drive, slot);
263
264     move.cm_fromtype = CHET_ST;
265     move.cm_fromunit = slot;
266     move.cm_totype = CHET_DT;
267     move.cm_tounit = drive;
268     move.cm_flags = 0;
269
270     rc = ioctl(fd,CHIOMOVE,&move);
271     if (rc){
272         dbprintf(_("drive load failed (MOVE): 0x%x %s\n"), rc, strerror(errno));
273         return(-2);
274     }
275     return(0);
276 }
277
278 int get_slot_count(int fd)
279
280 int rc;
281
282     rc = get_changer_info(fd);
283     if (rc) {
284         dbprintf(_("slot count query failed: 0x%x %s\n"), rc, strerror(errno));
285         return -1;
286     }
287
288     return changer_info.cp_nslots;
289 }
290
291 int get_drive_count(int fd)
292
293 int rc;
294
295     rc = get_changer_info(fd);
296     if (rc) {
297         dbprintf(_("drive count query failed: 0x%x %s\n"), rc, strerror(errno));
298         return -1;
299     }
300
301     return changer_info.cp_ndrives;
302 }
303
304 /* This function should ask the drive if it is ready */
305 int Tape_Ready1 ( char *tapedev , int wait)
306 #if defined(BUILTIN)
307 {
308   FILE *out=NULL;
309   int cnt=0;
310   
311   while ((cnt < wait) && (NULL==(out=fopen(tapedev,"w+")))){
312     cnt++;
313     sleep(1);
314   }
315   if (out != NULL)
316     fclose(out);
317   return 0;
318 }
319
320 #else
321 {
322   int cnt=0;
323
324   dbprintf(_("Tape_Ready1 : wait for BOT : max %d seconds\n"),wait);
325   /* loop on status BOT */
326   while ((cnt < wait)) {
327     if ( GMT_BOT(GetDeviceStatus(tapedev)) ) {
328      break;
329     }
330     /* dbprintf(("Tape_Ready1 : cnt %d\n",cnt)); */
331     cnt++;
332     sleep(1);
333   }
334   if (cnt >= wait) {
335    dbprintf(_("Tape_Ready1 : BOT not found : %d seconds\n"),cnt);
336    return(-1);
337   } else {
338    dbprintf(_("Tape_Ready1 : BOT : %d seconds\n"),cnt);
339   return 0;
340   }
341 }
342 #endif  /* BUILTIN */
343
344 int GetDeviceStatus (char *tapedev)
345 {
346   struct mtget status;
347   int mtfd, rc;
348
349   mtfd = OpenDevice(tapedev);
350   ioctl (mtfd, MTIOCGET, (char *)&status);
351   CloseDevice(tapedev, mtfd);
352   rc = status.mt_gstat;
353   return rc;
354 }
355
356 int OpenDevice (char *tapedev)
357 {
358   int DeviceFD;
359
360   DeviceFD = open(tapedev, O_RDWR);
361   return DeviceFD;
362 }
363
364 int CloseDevice (char *device, int DeviceFD)
365 {
366    int rc;
367
368    dbprintf(_("CloseDevice(%s)\n"), device);
369    rc = close(DeviceFD);
370
371    return rc;
372 }
373
374 /*
375  * Local variables:
376  * indent-tabs-mode: nil
377  * c-default-style: gnu
378  * End:
379  */