diff options
author | kraxel <kraxel> | 2005-02-09 12:01:53 +0000 |
---|---|---|
committer | kraxel <kraxel> | 2005-02-09 12:01:53 +0000 |
commit | e94be4b2a1c8504a615108f617881eaa7745961a (patch) | |
tree | 852f12c8b9124336fb3f77a51606e3d88ce50e70 | |
parent | b00ae68a83de451edb86a2bb3bbaa1a16021d199 (diff) | |
download | scsi-changer-master.tar.gz |
-rw-r--r-- | misc/errno | 9 | ||||
-rw-r--r-- | misc/sense | 5 | ||||
-rw-r--r-- | todo/autojuke.c | 355 | ||||
-rw-r--r-- | todo/mailtext | 29 | ||||
-rw-r--r-- | todo/putback | 43 | ||||
-rw-r--r-- | todo/putback.c | 100 |
6 files changed, 541 insertions, 0 deletions
diff --git a/misc/errno b/misc/errno new file mode 100644 index 0000000..a13069e --- /dev/null +++ b/misc/errno @@ -0,0 +1,9 @@ +from /usr/src/linux/include/asm/errno.h +seems they are for media changer devices... + +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ diff --git a/misc/sense b/misc/sense new file mode 100644 index 0000000..5c2a3a5 --- /dev/null +++ b/misc/sense @@ -0,0 +1,5 @@ +felix kraxel /usr/src/linux/drivers/scsi# grep ",M," constants.c + {0x21,0x01,M,"Invalid element address"}, + {0x28,0x01,M,"Import or export element accessed"}, + {0x3B,0x0D,M,"Medium destination element full"}, + {0x3B,0x0E,M,"Medium source element empty"}, diff --git a/todo/autojuke.c b/todo/autojuke.c new file mode 100644 index 0000000..f6aa0b5 --- /dev/null +++ b/todo/autojuke.c @@ -0,0 +1,355 @@ +/* + * program "map-file" for linux autofs + * + * usage: /usr/sbin/automount /jukebox program /usr/sbin/autojuke + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <linux/chio.h> + +#define PROG "autojuke" +#define CHANGER "/dev/sch0" +#define CONFIG "/etc/autojuke.conf" +#define PID "/var/run/automount.pid" + +#define DEBUG 0 /* set to 1 for debug output */ + +/* ---------------------------------------------------------------------- */ + +int +check_mtab(int n, char **devs) +{ + int i,res; + FILE *fp; + struct stat st; + char line[79],dev[32]; + int *fl; + + /* check for lock file */ + for (i = 0; i < 5; i++) { + if (-1 == stat("/etc/mtab~",&st)) + break; + sleep(1); + } + if (5 == i) { + fprintf(stderr,PROG ": /etc/mtab locked\n"); + exit(1); + } + + if (NULL == (fp = fopen("/etc/mtab", "r"))) { + perror(PROG ": open /etc/mtab"); + exit(1); + } + fl = malloc(n*sizeof(int)); + memset(fl,0,n*sizeof(int)); + while (NULL != fgets(line,79,fp)) { + sscanf(line," %31s",dev); + for (i = 0; i < n; i++) { + if (0 == strcmp(dev,devs[i])) + fl[i] = 1; + } + } + res = -1; + for (i = 0; i < n; i++) { + if (0 == fl[i]) + res = i; + } + free(fl); + fclose(fp); + return res; +} + +int +getautopid() +{ + FILE *fp; + char line[80]; + int pid = -1; + + if (NULL == (fp = fopen(PID, "r"))) { + perror(PROG ": open " PID); + exit(1); + } + + if (NULL != fgets(line, 79, fp)) { + pid = atoi(line); + } + + fclose(fp); + return pid; +} + +void +getSlotandSide(char *line, int *slot, int *side) +{ + int i; + int l = strlen(line) - 1; + + if ((l < 1) || (l > 2)) { + fprintf(stderr, PROG ": invalid requested slot or side, %s", line); + exit(1); + } + + for (i = 0; i < l; i++) { + if (!isdigit(line[i])) { + fprintf(stderr, PROG ": invalid requested slot or side, %s", line); + exit(1); + } + } + + if ((line[l] != 'a') && (line[l] != 'b')) { + fprintf(stderr, PROG ": invalid requested slot or side, %s", line); + exit(1); + } + + *side = (line[l] == 'b'); + line[l] = 0; + /*bm>*/ + *slot = atoi(line); + /*<bm*/ +} + +int +main(int argc, char *argv[]) +{ + struct changer_params params; + struct changer_get_element st; + struct changer_get_element *dt; + struct changer_move move; + char **devs,line[80],mopt[80],*h; + int fd,i,slot,drive,try_umount,cside,side; + FILE *fp; + + if (argc != 2) { + fprintf(stderr,"Please use the automounter to run this program."); + exit(1); + } + + if (-1 == (fd = open(CHANGER,O_RDONLY))) { + perror(PROG ": open " CHANGER); + exit(1); + } + + /* read changer status information */ + if (ioctl(fd,CHIOGPARAMS,¶ms)) { + perror(PROG ": ioctl CHIOGPARAMS"); + exit(1); + } +#if DEBUG + fprintf(stderr,PROG ": %d drives, %d slots\n", + params.cp_ndrives,params.cp_nslots); +#endif + + dt = malloc(sizeof(struct changer_get_element)*params.cp_ndrives); + for (i = 0; i < params.cp_ndrives; i++) { + dt[i].cge_type=CHET_DT; + dt[i].cge_unit=i; + if (ioctl(fd,CHIOGELEM,dt+i)) { + fprintf(stderr,PROG ":ioctl CHIOGELEM mt %d: %s\n", + i,strerror(errno)); + exit(1); + } + if (NULL != (h = strchr(dt[i].cge_pvoltag,' '))) *h = '\0'; + if (NULL != (h = strchr(dt[i].cge_avoltag,' '))) *h = '\0'; + } + + /* read config file */ + if (NULL == (fp = fopen(CONFIG, "r"))) { + perror(PROG ": open " CONFIG); + exit(1); + } + devs = malloc(sizeof(char*)*params.cp_ndrives); + for (i = 0; NULL != fgets(line,79,fp);) { + if (line[0] == '#' || line[0] == '\n') + continue; + if (sscanf(line,"try_umount= %d",&try_umount)) + continue; + if (line==strstr(line,"mopt=")) { + strncpy(mopt,line+5,79); + mopt[strlen(mopt)-1]='\0'; + continue; + } + + devs[i] = malloc(32); + if (!sscanf(line,"dev= %31s",devs[i])) { + fprintf(stderr,PROG ": config syntax error: %s",line); + exit(1); + } +#if DEBUG + fprintf(stderr,PROG ": drive %d: %s\n",i,devs[i]); +#endif + i++; + } + fclose(fp); + if (i != params.cp_ndrives) { + fprintf(stderr, + PROG ": number of drives (%d) does'nt match the\n" + PROG ": number of dev=... lines (%d) in " CONFIG "\n", + params.cp_ndrives,i); + exit(1); + } + + /* everything fine so far, lets check what key we got... */ + getSlotandSide(argv[1], &slot, &side); + + if (slot < 0 || slot >= params.cp_nslots) { + fprintf(stderr,PROG ": slot %d is out of range\n",slot); + exit(1); + } + +#if DEBUG + fprintf(stderr,PROG ": slot %d side %d\n", slot, side); +#endif + + /* check drives */ + for (drive = -1, i = 0; i < params.cp_ndrives; i++) { + if ((dt[i].cge_status & CESTATUS_FULL) && + (dt[i].cge_flags & CGE_SRC) && + (dt[i].cge_srctype == CHET_ST) && + (dt[i].cge_srcunit == slot)) { + drive = i; + break; + } + } + + if (-1 != drive) { + /* Requested media is still in a drive. Do we need to flip it? */ + cside = ((dt[drive].cge_flags & CGE_INVERT) == CGE_INVERT); + + /* if current side is requested side do nothing otherwise attempt invert */ + if (cside != side) { + /* ok attempt to unmount the disk */ + if (0 != check_mtab(1, &devs[drive])) { +#if DEBUG + fprintf(stderr,PROG ": sending SIGUSR1 to automount\n"); +#endif + kill(getautopid(), SIGUSR1); + sleep(1); /* XXX */ + if (0 != check_mtab(1, &devs[drive])) { + fprintf(stderr,PROG ": drive is busy with disk %d on other side\n",slot); + exit(1); + } + } + + /* flip the disk */ + memset(&move,0,sizeof(struct changer_move)); + + move.cm_totype = CHET_DT; + move.cm_tounit = drive; + move.cm_fromtype = CHET_DT; + move.cm_fromunit = drive; + move.cm_flags = CM_INVERT; + + if (ioctl(fd,CHIOMOVE,&move)) { + fprintf(stderr,PROG ": ioctl MOVE (load): %s\n", + sys_errlist[errno]); + exit(1); + } + } + + /* tell automounter we are good to go */ + printf("%s\t:%s\n",mopt,devs[drive]); + exit(0); + } + + /* verify info for the slot */ + st.cge_type=CHET_ST; + st.cge_unit=slot; + if (ioctl(fd,CHIOGELEM,&st)) { + fprintf(stderr,PROG ": ioctl CHIOGELEM st %d: %s\n", + slot,strerror(errno)); + exit(1); + } + + if (!(st.cge_status & CESTATUS_FULL)) { + fprintf(stderr,PROG ": slot %d has no media\n",slot); + exit(1); + } + + /* ok, requested media found, check where to put it now */ + + /* look for a empty drive first... */ + for (i = 0, drive = -1; i < params.cp_ndrives; i++) { + if (!(dt[i].cge_status & CESTATUS_FULL)) { + drive = i; + break; + } + } + + if (-1 == drive) + /* failing that, look for a unmounted drive */ + drive = check_mtab(params.cp_ndrives,devs); + + if (-1 == drive && try_umount) { + /* still no success -- tell automount to umount idle mount-points */ +#if DEBUG + fprintf(stderr,PROG ": sending SIGUSR1 to automount\n"); +#endif + /*kill(getppid(), SIGUSR1); */ + kill(getautopid(), SIGUSR1); + sleep(1); /* XXX */ + drive = check_mtab(params.cp_ndrives,devs); + } + + if (-1 == drive) { + /* bad luck */ + fprintf(stderr,PROG ": all drives busy, sorry\n"); + exit(1); + } + + if (dt[drive].cge_status & CESTATUS_FULL) { + /* Hmm, full. Ok, put back the old media ... */ + if (!(dt[drive].cge_flags & CGE_SRC)) { + fprintf(stderr,PROG ": source element for drive %d unknown\n", + drive); + exit(1); + } + memset(&move,0,sizeof(struct changer_move)); + move.cm_totype = dt[drive].cge_srctype; + move.cm_tounit = dt[drive].cge_srcunit; + move.cm_fromtype = CHET_DT; + move.cm_fromunit = drive; + /*bm>*/ + cside = ((dt[drive].cge_flags & CGE_INVERT) == CGE_INVERT); + move.cm_flags = (cside == 0) ? 0 : CM_INVERT; + /*<bm*/ + if (ioctl(fd,CHIOMOVE,&move)) { + fprintf(stderr,PROG ": ioctl MOVE (unload): %s\n", + sys_errlist[errno]); + exit(1); + } + } + + memset(&move,0,sizeof(struct changer_move)); + move.cm_totype = CHET_DT; + move.cm_tounit = drive; + move.cm_fromtype = CHET_ST; + move.cm_fromunit = slot; + + /*bm>*/ + /* if current side is not requested side invert*/ + move.cm_flags = (0 == side) ? 0 : CM_INVERT; + /*<bm*/ + if (ioctl(fd,CHIOMOVE,&move)) { + fprintf(stderr,PROG ": ioctl MOVE (load): %s\n", + sys_errlist[errno]); + exit(1); + } + + /* tell automounter we are good to go */ + printf("%s\t:%s\n",mopt,devs[drive]); + exit(0); +} + diff --git a/todo/mailtext b/todo/mailtext new file mode 100644 index 0000000..26a964c --- /dev/null +++ b/todo/mailtext @@ -0,0 +1,29 @@ +Date: Tue, 04 Jun 2002 17:08:50 +0200 +From: Bernd Machenschalk <b.machenschalk@q-bus.de> +Subject: Re: SCSI-Changer +To: Gerd Knorr <kraxel@bytesex.org> + +Hi! + +So, da das System jetzt (bei uns) ganz gut zu funktionieren scheint, +hier +nochmal die von mir modifizierten Dateien. + +Bei autojuke.c habe ich gegenüber +der letzten Version nur die "sleep 8"s herausgenommen, die übrigen +Änderungen gegenüber der Version von Elis Pomales sind zwischen +den Marken /*bm>*/ bzw. /*<bm*/ eingeschlossen. + +putback.c ist ein zusammengestrichenes autojuke und legt nur die Medien +aus allen Drives zurück. Das Binary daraus gehört nach /usr/sbin/putback +. + +putback ist aus dem Gerüst von SuSE 7.2 Runlevel Skripts gebaut +und gehört in /etc/init.d mit "K"-Links in den geeigneten Runleveln +(bei uns K10putback in rc3.d und rc5.d). In /etc/rc.config muß dazu +PUTBACK_MEDIA="yes" eingetragen werden. + +Gruß, +Bernd Machenschalk +q~bus Mediatektur GmbH + diff --git a/todo/putback b/todo/putback new file mode 100644 index 0000000..00ec1e4 --- /dev/null +++ b/todo/putback @@ -0,0 +1,43 @@ +#! /bin/sh +# +# System stop script for putback +# +### BEGIN INIT INFO +# Provides: putback +# Default-Start: % +# Default-Stop: 3 5 +# Description: Puts back media from jukebox +### END INIT INFO + +# Source SuSE config +. /etc/rc.config + +# Determine the base and follow a runlevel link name. +base=${0##*/} +link=${base#*[SK][0-9][0-9]} + +# Force execution if not called by a runlevel directory. +test $link = $base && PUTBACK_MEDIA=yes +test "$PUTBACK_MEDIA" = yes || exit 0 + +PUTBACK_BIN=/usr/sbin/putback +test -x $FOO_BIN || exit 5 + +. /etc/rc.status + +# First reset status of this service +rc_reset + +case "$1" in + stop) + echo -n "Putting back media" + $PUTBACK_BIN + rc_status -v + ;; + *) + echo -n "Putback is only useful when shutting down" + rc_status -v + ;; +esac +rc_exit + diff --git a/todo/putback.c b/todo/putback.c new file mode 100644 index 0000000..89c54e2 --- /dev/null +++ b/todo/putback.c @@ -0,0 +1,100 @@ +/* + * program putback + * + * puts back media in scsi-changer + * + * usage: /usr/sbin/putback + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <linux/chio.h> + +#define PROG "putback" +#define CHANGER "/dev/sch0" + +#define DEBUG 0 /* set to 1 for debug output */ + +/* ---------------------------------------------------------------------- */ + +int main(int argc, char *argv[]) +{ + struct changer_params params; + struct changer_get_element *dt; + struct changer_move move; + char *h; + int fd,i,drive,cside; + + if (argc != 1) { + fprintf(stderr,"Usage: %s\n",argv[0]); + exit(1); + } + + if (-1 == (fd = open(CHANGER,O_RDONLY))) { + perror(PROG ": open " CHANGER); + exit(1); + } + + /* read changer status information */ + if (ioctl(fd,CHIOGPARAMS,¶ms)) { + perror(PROG ": ioctl CHIOGPARAMS"); + exit(1); + } +#if DEBUG + fprintf(stderr,PROG ": %d drives, %d slots\n", + params.cp_ndrives,params.cp_nslots); +#endif + + dt = malloc(sizeof(struct changer_get_element)*params.cp_ndrives); + for (i = 0; i < params.cp_ndrives; i++) { + dt[i].cge_type=CHET_DT; + dt[i].cge_unit=i; + if (ioctl(fd,CHIOGELEM,dt+i)) { + fprintf(stderr,PROG ":ioctl CHIOGELEM mt %d: %s\n", + i,strerror(errno)); + exit(1); + } + if (NULL != (h = strchr(dt[i].cge_pvoltag,' '))) *h = '\0'; + if (NULL != (h = strchr(dt[i].cge_avoltag,' '))) *h = '\0'; + } + + + for (drive=0; drive<params.cp_ndrives; drive++) { + + if (dt[drive].cge_status & CESTATUS_FULL) { + /* put back the old media ... */ + if (!(dt[drive].cge_flags & CGE_SRC)) { + fprintf(stderr,PROG ": source element for drive %d unknown\n", + drive); + exit(1); + } + memset(&move,0,sizeof(struct changer_move)); + move.cm_totype = dt[drive].cge_srctype; + move.cm_tounit = dt[drive].cge_srcunit; + move.cm_fromtype = CHET_DT; + move.cm_fromunit = drive; + cside = ((dt[drive].cge_flags & CGE_INVERT) == CGE_INVERT); + move.cm_flags = (cside == 0) ? 0 : CM_INVERT; + if (ioctl(fd,CHIOMOVE,&move)) { + fprintf(stderr,PROG ": ioctl MOVE (unload): %s\n", + sys_errlist[errno]); + exit(1); + } + } + } + + exit(0); +} + + |