1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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);
}
|