d7b03abe5c145a618c8620415a3adb3cbb9ef553
[debian/mtx] / nsmhack.c
1 /* Copyright 2001 DISC Inc. 
2  * Released under terms of the GNU General Public License as required
3  * by the license on the file "mtxl.c". See file "LICENSE" for details.
4  */
5
6 #define DEBUG_NSM 1
7
8 /* This is a hack to make the NSM modular series jukeboxes stick out
9  * their tongue, then retract tongue, so we can import media. They
10  * automatically stick out their tongue when exporting media, but
11  * importing media is not working, you try to do a MOVE_MEDIUM and
12  * it says "What medium?" before even sticking out its tongue. 
13  * My manager has turned in a change request to NSM engineering to direct 
14  * their firmware guys to add EEPOS support to the NSM modular jukeboxes so 
15  * that we have tongue firmware that's compatible with Exabyte, Sony, Breece
16  *  Hill, etc., but until that new firmware is here, this hack will work.
17  */
18
19 /* Note: Perhaps "hack" is an overstatement, since this will also
20  * eventually add pack management and other things of that nature
21  * that are extremely loader dependent.
22  */
23
24 /* Commands:
25    -f <devicenode>
26    tongue_out <sourceslot>
27    tongue_in
28    tongue_button_wait
29    tongue_button_enable
30    tongue_button_disable
31 */
32    
33
34 #include "mtxl.h"  /* get the SCSI routines out of the main file */
35
36 /****************************************************************/
37 /* Variables:  */
38 /****************************************************************/   
39
40 /* the device handle we're operating upon, sigh. */
41 static char *device;  /* the text of the device thingy. */
42 static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1;
43 char *argv0;
44 int arg[4]; /* arguments for the command. */
45 #define arg1 (arg[0])  /* for backward compatibility, sigh */
46 static SCSI_Flags_T SCSI_Flags = { 0, 0, 0,0 };
47
48 static ElementStatus_T *ElementStatus = NULL;
49
50 /* Okay, now let's do the main routine: */
51
52 void Usage(void) {
53   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");
54 }
55
56 static int S_tongue_out(void);
57 static int S_tongue_in(void);
58 static int S_slotinfo(void);
59 static int S_jukeinfo(void);
60
61 struct command_table_struct {
62   int num_args;
63   char *name;
64   int (*command)(void);
65 } command_table[] = {
66   { 1, "tongue_out", S_tongue_out },
67   { 0, "tongue_in", S_tongue_in },
68   { 0, "slotinfo", S_slotinfo },
69   { 0, "jukeinfo", S_jukeinfo },
70   { 0, NULL, NULL }
71 };
72
73
74 /* open_device() -- set the 'fh' variable.... */
75 void open_device(void) {
76
77   if (MediumChangerFD != -1) {
78     SCSI_CloseDevice("Unknown",MediumChangerFD);  /* close it, sigh...  new device now! */
79   }
80
81   MediumChangerFD = SCSI_OpenDevice(device);
82
83 }
84
85 static int get_arg(char *arg) {
86   int retval=-1;
87
88   if (*arg < '0' || *arg > '9') {
89     return -1;  /* sorry! */
90   }
91
92   retval=atoi(arg);
93   return retval;
94 }
95
96 /* we see if we've got a file open. If not, we open one :-(. Then
97  * we execute the actual command. Or not :-(. 
98  */ 
99 int execute_command(struct command_table_struct *command) {
100
101   /* if the device is not already open, then open it from the 
102    * environment.
103    */
104   if (MediumChangerFD == -1) {
105     /* try to get it from STAPE or TAPE environment variable... */
106     device=getenv("STAPE");
107     if (device==NULL) {
108       device=getenv("TAPE");
109       if (device==NULL) {
110         Usage();
111       }
112     }
113     open_device();
114   }
115
116
117   /* okay, now to execute the command... */
118   return command->command();
119 }
120
121 /* parse_args():
122  *   Basically, we are parsing argv/argc. We can have multiple commands
123  * on a line now, such as "unload 3 0 load 4 0" to unload one tape and
124  * load in another tape into drive 0, and we execute these commands one
125  * at a time as we come to them. If we don't have a -f at the start, we
126  * barf. If we leave out a drive #, we default to drive 0 (the first drive
127  * in the cabinet). 
128  */ 
129
130 int parse_args(int argc,char **argv) {
131   int i,cmd_tbl_idx,retval,arg_idx;
132   struct command_table_struct *command;
133
134   i=1;
135   arg_idx=0;
136   while (i<argc) {
137     if (strcmp(argv[i],"-f") == 0) {
138       i++;
139       if (i>=argc) {
140         Usage();
141       }
142       device=argv[i++];
143       open_device(); /* open the device and do a status scan on it... */
144     } else {
145       cmd_tbl_idx=0;
146       command=&command_table[0]; /* default to the first command... */
147       command=&command_table[cmd_tbl_idx];
148       while (command->name) {
149         if (!strcmp(command->name,argv[i])) {
150           /* we have a match... */
151           break;
152         }
153         /* otherwise we don't have a match... */
154         cmd_tbl_idx++;
155         command=&command_table[cmd_tbl_idx];
156       }
157       /* if it's not a command, exit.... */
158       if (!command->name) {
159         Usage();
160       }
161       i++;  /* go to the next argument, if possible... */
162       /* see if we need to gather arguments, though! */
163       arg1=-1; /* default it to something */
164       for (arg_idx=0;arg_idx < command->num_args ; arg_idx++) {
165         if (i < argc) {
166           arg[arg_idx]=get_arg(argv[i]);
167           if (arg[arg_idx] !=  -1) {
168             i++; /* increment i over the next cmd. */
169           }
170         } else {
171           arg[arg_idx]=0; /* default to 0 setmarks or whatever */
172         } 
173       }
174       retval=execute_command(command);  /* execute_command handles 'stuff' */
175       exit(retval);
176     }
177   }
178   return 0; /* should never get here */
179 }
180
181 static void init_param(NSM_Param_T *param, char *command, int paramlen, int resultlen) {
182   int i;
183
184   /* zero it out first: */
185   memset((char *)param,0,sizeof(NSM_Param_T));
186
187   resultlen=resultlen+sizeof(NSM_Result_T)-0xffff;
188
189   
190   param->page_code=0x80;
191   param->reserved=0;
192   param->page_len_msb=((paramlen+8)>>8) & 0xff;
193   param->page_len_lsb=(paramlen+8) & 0xff;
194   param->allocation_msb=((resultlen + 10) >> 8) & 0xff;
195   param->allocation_lsb= (resultlen+10) & 0xff;
196   param->reserved2[0]=0;
197   param->reserved2[1]=0;
198
199   for (i=0;i<4;i++) {
200     param->command_code[i]=command[i];
201   }
202
203 }
204
205 static NSM_Result_T *SendRecHack(NSM_Param_T *param,int param_len, 
206                                  int read_len) {
207   NSM_Result_T *result;
208   /* send the command: */
209   if (SendNSMHack(MediumChangerFD,param,param_len,0)) {
210     PrintRequestSense(&scsi_error_sense);                   
211     FatalError("SendNSMHack failed.\n");    
212   }
213
214   /* Now read the result: */
215   result=RecNSMHack(MediumChangerFD,read_len,0);
216   if (!result) {
217     PrintRequestSense(&scsi_error_sense);                   
218     FatalError("RecNSMHack failed.\n");    
219   }  
220
221   return result;
222 }
223
224
225 /* Print some info about the NSM jukebox. */
226 static int S_jukeinfo(void) {
227   NSM_Result_T *result;
228   NSM_Param_T param;
229
230   if (!device)
231     Usage();
232
233   /* okay, we have a device: Let's get vendor ID: */
234   init_param(&param,"1010",0,8);
235   result=SendRecHack(&param,0,8);
236   /* Okay, we got our result, print out the vendor ID: */
237   result->return_data[8]=0;
238   printf("Vendor ID: %s\n",result->return_data);
239   free(result);
240   
241   /* Get our product ID: */
242   init_param(&param,"1011",0,16);
243   result=SendRecHack(&param,0,16);
244   result->return_data[16]=0;
245   printf("Product ID: %s\n",result->return_data);
246   free(result);
247
248   init_param(&param,"1012",0,4);
249   result=SendRecHack(&param,0,4);
250   result->return_data[4]=0;
251   printf("Product Revision: %s\n",result->return_data);
252   free(result);
253
254   init_param(&param,"1013",0,8);
255   result=SendRecHack(&param,0,8);
256   result->return_data[8]=0;
257   printf("Production Date: %s\n",result->return_data);
258   free(result);
259
260   init_param(&param,"1014",0,8);
261   result=SendRecHack(&param,0,8);
262   result->return_data[8]=0;
263   printf("Part Number: %s\n",result->return_data);
264   free(result);
265
266   init_param(&param,"1015",0,12);
267   result=SendRecHack(&param,0,12);
268   result->return_data[12]=0;
269   printf("Serial Number: %s\n",result->return_data);
270   free(result);
271
272   init_param(&param,"1016",0,4);
273   result=SendRecHack(&param,0,4);
274   result->return_data[4]=0;
275   printf("Firmware Release: %s\n",result->return_data);
276   free(result);
277
278   init_param(&param,"1017",0,8);
279   result=SendRecHack(&param,0,8);
280   result->return_data[8]=0;
281   printf("Firmware Date: %s\n",result->return_data);
282   free(result);
283
284   return 0;
285 }
286
287 static int S_slotinfo(void) {
288   NSM_Result_T *result;
289   NSM_Param_T param;
290
291   if (!device)
292     Usage();
293
294   /* Okay, let's see what I can get from slotinfo: */
295   init_param(&param,"1020",0,6);
296   result=SendRecHack(&param,0,6);
297   result->return_data[6]=0;
298   printf("Layout: %s\n",result->return_data);
299   free(result);
300   
301   return 0;
302 }
303
304 static int S_tongue_in(void) {
305   return 0;
306 }
307
308 /* okay, stick our tongue out. We need a slot ID to grab a caddy from. */
309 static int S_tongue_out(void) {
310   int slotnum=arg1;
311   Inquiry_T *inquiry_info;  /* needed by MoveMedium etc... */
312   RequestSense_T RequestSense;
313
314   /* see if we have element status: */
315   if (ElementStatus==NULL) {
316     inquiry_info=RequestInquiry(MediumChangerFD,&RequestSense);
317     if (!inquiry_info) {
318       PrintRequestSense(&RequestSense);                   
319       FatalError("INQUIRY Command Failed\n"); 
320     }
321     ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense,inquiry_info,&SCSI_Flags);
322     if (!ElementStatus) {
323       PrintRequestSense(&RequestSense);                   
324       FatalError("READ ELEMENT STATUS Command Failed\n"); 
325     }
326   }
327   
328   /* Okay, we have element status, so now let's assume that */
329   return 0;
330 }
331
332 /* See parse_args for the scoop. parse_args does all. */
333 int main(int argc, char **argv) {
334   argv0=argv[0];
335   parse_args(argc,argv);
336
337   if (device) 
338     SCSI_CloseDevice(device,MediumChangerFD);
339
340   exit(0);
341 }