diff options
author | Bdale Garbee <bdale@gag.com> | 2009-02-15 18:17:54 +0100 |
---|---|---|
committer | Bdale Garbee <bdale@gag.com> | 2009-02-15 18:17:54 +0100 |
commit | 1c3607e4d1f94869e7887568fb40d16bb0d2407d (patch) | |
tree | f7a37bbbea5791814281affed9da11b47fbd080b /nsmhack.c |
Import mtx_1.3.12.orig.tar.gz
[dgit import orig mtx_1.3.12.orig.tar.gz]
Diffstat (limited to 'nsmhack.c')
-rw-r--r-- | nsmhack.c | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/nsmhack.c b/nsmhack.c new file mode 100644 index 0000000..b2ac2c2 --- /dev/null +++ b/nsmhack.c @@ -0,0 +1,342 @@ +/* Copyright 2001 DISC Inc. + * Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org> + * Released under terms of the GNU General Public License as required + * by the license on the file "mtxl.c". See file "LICENSE" for details. + */ + +#define DEBUG_NSM 1 + +/* This is a hack to make the NSM modular series jukeboxes stick out + * their tongue, then retract tongue, so we can import media. They + * automatically stick out their tongue when exporting media, but + * importing media is not working, you try to do a MOVE_MEDIUM and + * it says "What medium?" before even sticking out its tongue. + * My manager has turned in a change request to NSM engineering to direct + * their firmware guys to add EEPOS support to the NSM modular jukeboxes so + * that we have tongue firmware that's compatible with Exabyte, Sony, Breece + * Hill, etc., but until that new firmware is here, this hack will work. + */ + +/* Note: Perhaps "hack" is an overstatement, since this will also + * eventually add pack management and other things of that nature + * that are extremely loader dependent. + */ + +/* Commands: + -f <devicenode> + tongue_out <sourceslot> + tongue_in + tongue_button_wait + tongue_button_enable + tongue_button_disable +*/ + + +#include "mtxl.h" /* get the SCSI routines out of the main file */ + +/****************************************************************/ +/* Variables: */ +/****************************************************************/ + +/* the device handle we're operating upon, sigh. */ +static char *device; /* the text of the device thingy. */ +static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1; +char *argv0; +int arg[4]; /* arguments for the command. */ +#define arg1 (arg[0]) /* for backward compatibility, sigh */ +static SCSI_Flags_T SCSI_Flags = { 0, 0, 0,0 }; + +static ElementStatus_T *ElementStatus = NULL; + +/* Okay, now let's do the main routine: */ + +void Usage(void) { + FatalError("Usage: nsmhack -f <generic-device> <command> where <command> is:\n [tongue_out] | [tongue_in] | [tongue_button_wait] | [tongue_button_enable]\n | tongue_button_disable. \n"); +} + +static int S_tongue_out(void); +static int S_tongue_in(void); +static int S_slotinfo(void); +static int S_jukeinfo(void); + +struct command_table_struct { + int num_args; + char *name; + int (*command)(void); +} command_table[] = { + { 1, "tongue_out", S_tongue_out }, + { 0, "tongue_in", S_tongue_in }, + { 0, "slotinfo", S_slotinfo }, + { 0, "jukeinfo", S_jukeinfo }, + { 0, NULL, NULL } +}; + + +/* open_device() -- set the 'fh' variable.... */ +void open_device(void) { + + if (MediumChangerFD != -1) { + SCSI_CloseDevice("Unknown",MediumChangerFD); /* close it, sigh... new device now! */ + } + + MediumChangerFD = SCSI_OpenDevice(device); + +} + +static int get_arg(char *arg) { + int retval=-1; + + if (*arg < '0' || *arg > '9') { + return -1; /* sorry! */ + } + + retval=atoi(arg); + return retval; +} + +/* we see if we've got a file open. If not, we open one :-(. Then + * we execute the actual command. Or not :-(. + */ +int execute_command(struct command_table_struct *command) { + + /* if the device is not already open, then open it from the + * environment. + */ + if (MediumChangerFD == -1) { + /* try to get it from STAPE or TAPE environment variable... */ + device=getenv("STAPE"); + if (device==NULL) { + device=getenv("TAPE"); + if (device==NULL) { + Usage(); + } + } + open_device(); + } + + + /* okay, now to execute the command... */ + return command->command(); +} + +/* parse_args(): + * Basically, we are parsing argv/argc. We can have multiple commands + * on a line now, such as "unload 3 0 load 4 0" to unload one tape and + * load in another tape into drive 0, and we execute these commands one + * at a time as we come to them. If we don't have a -f at the start, we + * barf. If we leave out a drive #, we default to drive 0 (the first drive + * in the cabinet). + */ + +int parse_args(int argc,char **argv) { + int i,cmd_tbl_idx,retval,arg_idx; + struct command_table_struct *command; + + i=1; + arg_idx=0; + while (i<argc) { + if (strcmp(argv[i],"-f") == 0) { + i++; + if (i>=argc) { + Usage(); + } + device=argv[i++]; + open_device(); /* open the device and do a status scan on it... */ + } else { + cmd_tbl_idx=0; + command=&command_table[0]; /* default to the first command... */ + command=&command_table[cmd_tbl_idx]; + while (command->name) { + if (!strcmp(command->name,argv[i])) { + /* we have a match... */ + break; + } + /* otherwise we don't have a match... */ + cmd_tbl_idx++; + command=&command_table[cmd_tbl_idx]; + } + /* if it's not a command, exit.... */ + if (!command->name) { + Usage(); + } + i++; /* go to the next argument, if possible... */ + /* see if we need to gather arguments, though! */ + arg1=-1; /* default it to something */ + for (arg_idx=0;arg_idx < command->num_args ; arg_idx++) { + if (i < argc) { + arg[arg_idx]=get_arg(argv[i]); + if (arg[arg_idx] != -1) { + i++; /* increment i over the next cmd. */ + } + } else { + arg[arg_idx]=0; /* default to 0 setmarks or whatever */ + } + } + retval=execute_command(command); /* execute_command handles 'stuff' */ + exit(retval); + } + } + return 0; /* should never get here */ +} + +static void init_param(NSM_Param_T *param, char *command, int paramlen, int resultlen) { + int i; + + /* zero it out first: */ + memset((char *)param,0,sizeof(NSM_Param_T)); + + resultlen=resultlen+sizeof(NSM_Result_T)-0xffff; + + + param->page_code=0x80; + param->reserved=0; + param->page_len_msb=((paramlen+8)>>8) & 0xff; + param->page_len_lsb=(paramlen+8) & 0xff; + param->allocation_msb=((resultlen + 10) >> 8) & 0xff; + param->allocation_lsb= (resultlen+10) & 0xff; + param->reserved2[0]=0; + param->reserved2[1]=0; + + for (i=0;i<4;i++) { + param->command_code[i]=command[i]; + } + +} + +static NSM_Result_T *SendRecHack(NSM_Param_T *param,int param_len, + int read_len) { + NSM_Result_T *result; + /* send the command: */ + if (SendNSMHack(MediumChangerFD,param,param_len,0)) { + PrintRequestSense(&scsi_error_sense); + FatalError("SendNSMHack failed.\n"); + } + + /* Now read the result: */ + result=RecNSMHack(MediumChangerFD,read_len,0); + if (!result) { + PrintRequestSense(&scsi_error_sense); + FatalError("RecNSMHack failed.\n"); + } + + return result; +} + + +/* Print some info about the NSM jukebox. */ +static int S_jukeinfo(void) { + NSM_Result_T *result; + NSM_Param_T param; + + if (!device) + Usage(); + + /* okay, we have a device: Let's get vendor ID: */ + init_param(¶m,"1010",0,8); + result=SendRecHack(¶m,0,8); + /* Okay, we got our result, print out the vendor ID: */ + result->return_data[8]=0; + printf("Vendor ID: %s\n",result->return_data); + free(result); + + /* Get our product ID: */ + init_param(¶m,"1011",0,16); + result=SendRecHack(¶m,0,16); + result->return_data[16]=0; + printf("Product ID: %s\n",result->return_data); + free(result); + + init_param(¶m,"1012",0,4); + result=SendRecHack(¶m,0,4); + result->return_data[4]=0; + printf("Product Revision: %s\n",result->return_data); + free(result); + + init_param(¶m,"1013",0,8); + result=SendRecHack(¶m,0,8); + result->return_data[8]=0; + printf("Production Date: %s\n",result->return_data); + free(result); + + init_param(¶m,"1014",0,8); + result=SendRecHack(¶m,0,8); + result->return_data[8]=0; + printf("Part Number: %s\n",result->return_data); + free(result); + + init_param(¶m,"1015",0,12); + result=SendRecHack(¶m,0,12); + result->return_data[12]=0; + printf("Serial Number: %s\n",result->return_data); + free(result); + + init_param(¶m,"1016",0,4); + result=SendRecHack(¶m,0,4); + result->return_data[4]=0; + printf("Firmware Release: %s\n",result->return_data); + free(result); + + init_param(¶m,"1017",0,8); + result=SendRecHack(¶m,0,8); + result->return_data[8]=0; + printf("Firmware Date: %s\n",result->return_data); + free(result); + + return 0; +} + +static int S_slotinfo(void) { + NSM_Result_T *result; + NSM_Param_T param; + + if (!device) + Usage(); + + /* Okay, let's see what I can get from slotinfo: */ + init_param(¶m,"1020",0,6); + result=SendRecHack(¶m,0,6); + result->return_data[6]=0; + printf("Layout: %s\n",result->return_data); + free(result); + + return 0; +} + +static int S_tongue_in(void) { + return 0; +} + +/* okay, stick our tongue out. We need a slot ID to grab a caddy from. */ +static int S_tongue_out(void) { + int slotnum=arg1; + Inquiry_T *inquiry_info; /* needed by MoveMedium etc... */ + RequestSense_T RequestSense; + + /* see if we have element status: */ + if (ElementStatus==NULL) { + inquiry_info=RequestInquiry(MediumChangerFD,&RequestSense); + if (!inquiry_info) { + PrintRequestSense(&RequestSense); + FatalError("INQUIRY Command Failed\n"); + } + ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense,inquiry_info,&SCSI_Flags); + if (!ElementStatus) { + PrintRequestSense(&RequestSense); + FatalError("READ ELEMENT STATUS Command Failed\n"); + } + } + + /* Okay, we have element status, so now let's assume that */ + return 0; +} + +/* See parse_args for the scoop. parse_args does all. */ +int main(int argc, char **argv) { + argv0=argv[0]; + parse_args(argc,argv); + + if (device) + SCSI_CloseDevice(device,MediumChangerFD); + + exit(0); +} |