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