1 /* Copyright 2001 DISC Inc.
2 * Copyright 2007-2008 by Robert Nelson <robertn@the-nelsons.org>
3 * Released under terms of the GNU General Public License as required
4 * by the license on the file "mtxl.c". See file "LICENSE" for details.
9 /* This is a hack to make the NSM modular series jukeboxes stick out
10 * their tongue, then retract tongue, so we can import media. They
11 * automatically stick out their tongue when exporting media, but
12 * importing media is not working, you try to do a MOVE_MEDIUM and
13 * it says "What medium?" before even sticking out its tongue.
14 * My manager has turned in a change request to NSM engineering to direct
15 * their firmware guys to add EEPOS support to the NSM modular jukeboxes so
16 * that we have tongue firmware that's compatible with Exabyte, Sony, Breece
17 * Hill, etc., but until that new firmware is here, this hack will work.
20 /* Note: Perhaps "hack" is an overstatement, since this will also
21 * eventually add pack management and other things of that nature
22 * that are extremely loader dependent.
27 tongue_out <sourceslot>
35 #include "mtxl.h" /* get the SCSI routines out of the main file */
37 /****************************************************************/
39 /****************************************************************/
41 /* the device handle we're operating upon, sigh. */
42 static char *device; /* the text of the device thingy. */
43 static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1;
45 int arg[4]; /* arguments for the command. */
46 #define arg1 (arg[0]) /* for backward compatibility, sigh */
47 static SCSI_Flags_T SCSI_Flags = { 0, 0, 0,0 };
49 static ElementStatus_T *ElementStatus = NULL;
51 /* Okay, now let's do the main routine: */
54 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");
57 static int S_tongue_out(void);
58 static int S_tongue_in(void);
59 static int S_slotinfo(void);
60 static int S_jukeinfo(void);
62 struct command_table_struct {
67 { 1, "tongue_out", S_tongue_out },
68 { 0, "tongue_in", S_tongue_in },
69 { 0, "slotinfo", S_slotinfo },
70 { 0, "jukeinfo", S_jukeinfo },
75 /* open_device() -- set the 'fh' variable.... */
76 void open_device(void) {
78 if (MediumChangerFD != -1) {
79 SCSI_CloseDevice("Unknown",MediumChangerFD); /* close it, sigh... new device now! */
82 MediumChangerFD = SCSI_OpenDevice(device);
86 static int get_arg(char *arg) {
89 if (*arg < '0' || *arg > '9') {
90 return -1; /* sorry! */
97 /* we see if we've got a file open. If not, we open one :-(. Then
98 * we execute the actual command. Or not :-(.
100 int execute_command(struct command_table_struct *command) {
102 /* if the device is not already open, then open it from the
105 if (MediumChangerFD == -1) {
106 /* try to get it from STAPE or TAPE environment variable... */
107 device=getenv("STAPE");
109 device=getenv("TAPE");
118 /* okay, now to execute the command... */
119 return command->command();
123 * Basically, we are parsing argv/argc. We can have multiple commands
124 * on a line now, such as "unload 3 0 load 4 0" to unload one tape and
125 * load in another tape into drive 0, and we execute these commands one
126 * at a time as we come to them. If we don't have a -f at the start, we
127 * barf. If we leave out a drive #, we default to drive 0 (the first drive
131 int parse_args(int argc,char **argv) {
132 int i,cmd_tbl_idx,retval,arg_idx;
133 struct command_table_struct *command;
138 if (strcmp(argv[i],"-f") == 0) {
144 open_device(); /* open the device and do a status scan on it... */
147 command=&command_table[0]; /* default to the first command... */
148 command=&command_table[cmd_tbl_idx];
149 while (command->name) {
150 if (!strcmp(command->name,argv[i])) {
151 /* we have a match... */
154 /* otherwise we don't have a match... */
156 command=&command_table[cmd_tbl_idx];
158 /* if it's not a command, exit.... */
159 if (!command->name) {
162 i++; /* go to the next argument, if possible... */
163 /* see if we need to gather arguments, though! */
164 arg1=-1; /* default it to something */
165 for (arg_idx=0;arg_idx < command->num_args ; arg_idx++) {
167 arg[arg_idx]=get_arg(argv[i]);
168 if (arg[arg_idx] != -1) {
169 i++; /* increment i over the next cmd. */
172 arg[arg_idx]=0; /* default to 0 setmarks or whatever */
175 retval=execute_command(command); /* execute_command handles 'stuff' */
179 return 0; /* should never get here */
182 static void init_param(NSM_Param_T *param, char *command, int paramlen, int resultlen) {
185 /* zero it out first: */
186 memset((char *)param,0,sizeof(NSM_Param_T));
188 resultlen=resultlen+sizeof(NSM_Result_T)-0xffff;
191 param->page_code=0x80;
193 param->page_len_msb=((paramlen+8)>>8) & 0xff;
194 param->page_len_lsb=(paramlen+8) & 0xff;
195 param->allocation_msb=((resultlen + 10) >> 8) & 0xff;
196 param->allocation_lsb= (resultlen+10) & 0xff;
197 param->reserved2[0]=0;
198 param->reserved2[1]=0;
201 param->command_code[i]=command[i];
206 static NSM_Result_T *SendRecHack(NSM_Param_T *param,int param_len,
208 NSM_Result_T *result;
209 /* send the command: */
210 if (SendNSMHack(MediumChangerFD,param,param_len,0)) {
211 PrintRequestSense(&scsi_error_sense);
212 FatalError("SendNSMHack failed.\n");
215 /* Now read the result: */
216 result=RecNSMHack(MediumChangerFD,read_len,0);
218 PrintRequestSense(&scsi_error_sense);
219 FatalError("RecNSMHack failed.\n");
226 /* Print some info about the NSM jukebox. */
227 static int S_jukeinfo(void) {
228 NSM_Result_T *result;
234 /* okay, we have a device: Let's get vendor ID: */
235 init_param(¶m,"1010",0,8);
236 result=SendRecHack(¶m,0,8);
237 /* Okay, we got our result, print out the vendor ID: */
238 result->return_data[8]=0;
239 printf("Vendor ID: %s\n",result->return_data);
242 /* Get our product ID: */
243 init_param(¶m,"1011",0,16);
244 result=SendRecHack(¶m,0,16);
245 result->return_data[16]=0;
246 printf("Product ID: %s\n",result->return_data);
249 init_param(¶m,"1012",0,4);
250 result=SendRecHack(¶m,0,4);
251 result->return_data[4]=0;
252 printf("Product Revision: %s\n",result->return_data);
255 init_param(¶m,"1013",0,8);
256 result=SendRecHack(¶m,0,8);
257 result->return_data[8]=0;
258 printf("Production Date: %s\n",result->return_data);
261 init_param(¶m,"1014",0,8);
262 result=SendRecHack(¶m,0,8);
263 result->return_data[8]=0;
264 printf("Part Number: %s\n",result->return_data);
267 init_param(¶m,"1015",0,12);
268 result=SendRecHack(¶m,0,12);
269 result->return_data[12]=0;
270 printf("Serial Number: %s\n",result->return_data);
273 init_param(¶m,"1016",0,4);
274 result=SendRecHack(¶m,0,4);
275 result->return_data[4]=0;
276 printf("Firmware Release: %s\n",result->return_data);
279 init_param(¶m,"1017",0,8);
280 result=SendRecHack(¶m,0,8);
281 result->return_data[8]=0;
282 printf("Firmware Date: %s\n",result->return_data);
288 static int S_slotinfo(void) {
289 NSM_Result_T *result;
295 /* Okay, let's see what I can get from slotinfo: */
296 init_param(¶m,"1020",0,6);
297 result=SendRecHack(¶m,0,6);
298 result->return_data[6]=0;
299 printf("Layout: %s\n",result->return_data);
305 static int S_tongue_in(void) {
309 /* okay, stick our tongue out. We need a slot ID to grab a caddy from. */
310 static int S_tongue_out(void) {
312 Inquiry_T *inquiry_info; /* needed by MoveMedium etc... */
313 RequestSense_T RequestSense;
315 /* see if we have element status: */
316 if (ElementStatus==NULL) {
317 inquiry_info=RequestInquiry(MediumChangerFD,&RequestSense);
319 PrintRequestSense(&RequestSense);
320 FatalError("INQUIRY Command Failed\n");
322 ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense,inquiry_info,&SCSI_Flags);
323 if (!ElementStatus) {
324 PrintRequestSense(&RequestSense);
325 FatalError("READ ELEMENT STATUS Command Failed\n");
329 /* Okay, we have element status, so now let's assume that */
333 /* See parse_args for the scoop. parse_args does all. */
334 int main(int argc, char **argv) {
336 parse_args(argc,argv);
339 SCSI_CloseDevice(device,MediumChangerFD);