1 /* TAPEDEV.C (c) Copyright Roger Bowler, 1999-2009 */
2 /* Hercules Tape Device Handler */
3
4 /* Original Author: Roger Bowler */
5 /* Prime Maintainer: Ivan Warren */
6 /* Secondary Maintainer: "Fish" (David B. Trout) */
7
8 /*-------------------------------------------------------------------*/
9 /* This module contains device handling functions for emulated */
10 /* magnetic tape devices for the Hercules ESA/390 emulator. */
11 /*-------------------------------------------------------------------*/
12 /* Messages issued by the TAPEDEV.C module are prefixed HHCTA0nn */
13 /* CCW processing functions have been moved to module TAPECCW.C */
14 /* */
15 /* Five emulated tape formats are supported: */
16 /* */
17 /* 1. AWSTAPE This is the format used by the P/390. */
18 /* The entire tape is contained in a single flat file. */
19 /* A tape block consists of one or more block segments. */
20 /* Each block segment is preceded by a 6-byte header. */
21 /* Files are separated by tapemarks, which consist */
22 /* of headers with zero block length. */
23 /* AWSTAPE files are readable and writable. */
24 /* */
25 /* Support for AWSTAPE is in the "AWSTAPE.C" member. */
26 /* */
27 /* 2. OMATAPE This is the Optical Media Attach device format. */
28 /* Each physical file on the tape is represented by */
29 /* a separate flat file. The collection of files that */
30 /* make up the physical tape is obtained from an ASCII */
31 /* text file called the "tape description file", whose */
32 /* file name is always tapes/xxxxxx.tdf (where xxxxxx */
33 /* is the volume serial number of the tape). */
34 /* Three formats of tape files are supported: */
35 /* * FIXED files contain fixed length EBCDIC blocks */
36 /* with no headers or delimiters. The block length */
37 /* is specified in the TDF file. */
38 /* * TEXT files contain variable length ASCII blocks */
39 /* delimited by carriage return line feed sequences. */
40 /* The data is translated to EBCDIC by this module. */
41 /* * HEADER files contain variable length blocks of */
42 /* EBCDIC data prefixed by a 16-byte header. */
43 /* The TDF file and all of the tape files must reside */
44 /* reside under the same directory which is normally */
45 /* on CDROM but can be on disk. */
46 /* OMATAPE files are supported as read-only media. */
47 /* */
48 /* OMATAPE tape Support is in the "OMATAPE.C" member. */
49 /* */
50 /* 3. SCSITAPE This format allows reading and writing of 4mm or */
51 /* 8mm DAT tape, 9-track open-reel tape, or 3480-type */
52 /* cartridge on an appropriate SCSI-attached drive. */
53 /* All SCSI tapes are processed using the generalized */
54 /* SCSI tape driver (st.c) which is controlled using */
55 /* the MTIOCxxx set of IOCTL commands. */
56 /* PROGRAMMING NOTE: the 'tape' portability macros for */
57 /* physical (SCSI) tapes MUST be used for all tape i/o! */
58 /* */
59 /* SCSI tape Support is in the "SCSITAPE.C" member. */
60 /* */
61 /* 4. HET This format is based on the AWSTAPE format but has */
62 /* been extended to support compression. Since the */
63 /* basic file format has remained the same, AWSTAPEs */
64 /* can be read/written using the HET routines. */
65 /* */
66 /* Support for HET is in the "HETTAPE.C" member. */
67 /* */
68 /* 5. FAKETAPE This is the format used by Fundamental Software */
69 /* on their FLEX-ES systems. It it similar to the AWS */
70 /* format. The entire tape is contained in a single */
71 /* flat file. A tape block is preceded by a 12-ASCII- */
72 /* hex-characters header which indicate the size of */
73 /* the previous and next blocks. Files are separated */
74 /* by tapemarks which consist of headers with a zero */
75 /* current block length. FakeTapes are both readable */
76 /* and writable. */
77 /* */
78 /* Support for FAKETAPE is in the "FAKETAPE.C" member. */
79 /* */
80 /*-------------------------------------------------------------------*/
81
82 /*-------------------------------------------------------------------*/
83 /* Additional credits: */
84 /* 3480 commands contributed by Jan Jaeger */
85 /* Sense byte improvements by Jan Jaeger */
86 /* 3480 Read Block ID and Locate CCWs by Brandon Hill */
87 /* Unloaded tape support by Brandon Hill v209*/
88 /* HET format support by Leland Lucius v209*/
89 /* JCS - minor changes by John Summerfield 2003*/
90 /* PERFORM SUBSYSTEM FUNCTION / CONTROL ACCESS support by */
91 /* Adrian Trenkwalder (with futher enhancements by Fish) */
92 /* **INCOMPLETE** 3590 support by Fish (David B. Trout) */
93 /*-------------------------------------------------------------------*/
94
95 /*-------------------------------------------------------------------*/
96 /* Reference information: */
97 /* SC53-1200 S/370 and S/390 Optical Media Attach/2 User's Guide */
98 /* SC53-1201 S/370 and S/390 Optical Media Attach/2 Technical Ref */
99 /* SG24-2506 IBM 3590 Tape Subsystem Technical Guide */
100 /* GA32-0331 IBM 3590 Hardware Reference */
101 /* GA32-0329 IBM 3590 Introduction and Planning Guide */
102 /* SG24-2594 IBM 3590 Multiplatform Implementation */
103 /* ANSI INCITS 131-1994 (R1999) SCSI-2 Reference */
104 /* GA32-0127 IBM 3490E Hardware Reference */
105 /* GC35-0152 EREP Release 3.5.0 Reference */
106 /* SA22-7204 ESA/390 Common I/O-Device Commands */
107 /*-------------------------------------------------------------------*/
108
109 #include "hstdinc.h"
110 #include "hercules.h" /* need Hercules control blocks */
111 #include "tapedev.h" /* Main tape handler header file */
112
113 //#define ENABLE_TRACING_STMTS // (Fish: DEBUGGING)
114
115 #ifdef ENABLE_TRACING_STMTS
116 #if !defined(DEBUG)
117 #warning DEBUG required for ENABLE_TRACING_STMTS
118 #endif
119 // (TRACE, ASSERT, and VERIFY macros are #defined in hmacros.h)
120 #else
121 #undef TRACE
122 #undef ASSERT
123 #undef VERIFY
124 #define TRACE 1 ? ((void)0) : logmsg
125 #define ASSERT(a)
126 #define VERIFY(a) ((void)(a))
127 #endif
128
129 /*-------------------------------------------------------------------*/
130
131 #if defined(WIN32) && defined(OPTION_DYNAMIC_LOAD) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
132 SYSBLK *psysblk;
133 #define sysblk (*psysblk)
134 #endif
135
136 /*-------------------------------------------------------------------*/
137
138 DEVHND tapedev_device_hndinfo =
139 {
140 &tapedev_init_handler, /* Device Initialisation */
141 &tapedev_execute_ccw, /* Device CCW execute */
142 &tapedev_close_device, /* Device Close */
143 &tapedev_query_device, /* Device Query */
144 NULL, /* Device Start channel pgm */
145 NULL, /* Device End channel pgm */
146 NULL, /* Device Resume channel pgm */
147 NULL, /* Device Suspend channel pgm */
148 NULL, /* Device Read */
149 NULL, /* Device Write */
150 NULL, /* Device Query used */
151 NULL, /* Device Reserve */
152 NULL, /* Device Release */
153 NULL, /* Device Attention */
154 TapeImmedCommands, /* Immediate CCW Codes */
155 NULL, /* Signal Adapter Input */
156 NULL, /* Signal Adapter Output */
157 NULL, /* Hercules suspend */
158 NULL /* Hercules resume */
159 };
160
161 /*-------------------------------------------------------------------*/
162 /* Libtool static name colision resolution... */
163 /* Note: lt_dlopen will look for symbol & modulename_LTX_symbol */
164 /*-------------------------------------------------------------------*/
165
166 #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
167
168 #define hdl_ddev hdt3420_LTX_hdl_ddev
169 #define hdl_depc hdt3420_LTX_hdl_depc
170 #define hdl_reso hdt3420_LTX_hdl_reso
171 #define hdl_init hdt3420_LTX_hdl_init
172 #define hdl_fini hdt3420_LTX_hdl_fini
173
174 #endif
175
176 /*-------------------------------------------------------------------*/
177
178 #if defined(OPTION_DYNAMIC_LOAD)
179
180 HDL_DEPENDENCY_SECTION;
181 {
182 HDL_DEPENDENCY ( HERCULES );
183 HDL_DEPENDENCY ( DEVBLK );
184 HDL_DEPENDENCY ( SYSBLK );
185 }
186 END_DEPENDENCY_SECTION
187
188 /*-------------------------------------------------------------------*/
189
190 HDL_DEVICE_SECTION;
191 {
192 HDL_DEVICE ( 3410, tapedev_device_hndinfo );
193 HDL_DEVICE ( 3411, tapedev_device_hndinfo );
194 HDL_DEVICE ( 3420, tapedev_device_hndinfo );
195 HDL_DEVICE ( 3422, tapedev_device_hndinfo );
196 HDL_DEVICE ( 3430, tapedev_device_hndinfo );
197 HDL_DEVICE ( 3480, tapedev_device_hndinfo );
198 HDL_DEVICE ( 3490, tapedev_device_hndinfo );
199 HDL_DEVICE ( 3590, tapedev_device_hndinfo );
200 HDL_DEVICE ( 8809, tapedev_device_hndinfo );
201 HDL_DEVICE ( 9347, tapedev_device_hndinfo );
202 HDL_DEVICE ( 9348, tapedev_device_hndinfo );
203 }
204 END_DEVICE_SECTION
205
206 /*-------------------------------------------------------------------*/
207
208 #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
209
210 #undef sysblk
211
212 HDL_RESOLVER_SECTION;
213 {
214 HDL_RESOLVE_PTRVAR ( psysblk, sysblk );
215 }
216 END_RESOLVER_SECTION
217
218 #endif // defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
219
220 #endif // defined(OPTION_DYNAMIC_LOAD)
221
222 /*-------------------------------------------------------------------*/
223 /* (see 'tapedev.h' for layout of TAPEMEDIA_HANDLER structure) */
224 /*-------------------------------------------------------------------*/
225
226 TAPEMEDIA_HANDLER tmh_aws =
227 {
228 &generic_tmhcall,
229 &open_awstape,
230 &close_awstape,
231 &read_awstape,
232 &write_awstape,
233 &rewind_awstape,
234 &bsb_awstape,
235 &fsb_awstape,
236 &bsf_awstape,
237 &fsf_awstape,
238 &write_awsmark,
239 &sync_awstape,
240 &no_operation, // (DSE) ZZ FIXME: not coded yet
241 &no_operation, // (ERG)
242 &is_tapeloaded_filename,
243 &passedeot_awstape,
244 &readblkid_virtual,
245 &locateblk_virtual
246 };
247
248 /*-------------------------------------------------------------------*/
249
250 TAPEMEDIA_HANDLER tmh_het =
251 {
252 &generic_tmhcall,
253 &open_het,
254 &close_het,
255 &read_het,
256 &write_het,
257 &rewind_het,
258 &bsb_het,
259 &fsb_het,
260 &bsf_het,
261 &fsf_het,
262 &write_hetmark,
263 &sync_het,
264 &no_operation, // (DSE) ZZ FIXME: not coded yet
265 &no_operation, // (ERG)
266 &is_tapeloaded_filename,
267 &passedeot_het,
268 &readblkid_virtual,
269 &locateblk_virtual
270 };
271
272 /*-------------------------------------------------------------------*/
273
274 TAPEMEDIA_HANDLER tmh_fake =
275 {
276 &generic_tmhcall,
277 &open_faketape,
278 &close_faketape,
279 &read_faketape,
280 &write_faketape,
281 &rewind_faketape,
282 &bsb_faketape,
283 &fsb_faketape,
284 &bsf_faketape,
285 &fsf_faketape,
286 &write_fakemark,
287 &sync_faketape,
288 &no_operation, // (DSE) ZZ FIXME: not coded yet
289 &no_operation, // (ERG)
290 &is_tapeloaded_filename,
291 &passedeot_faketape,
292 &readblkid_virtual,
293 &locateblk_virtual
294 };
295
296 /*-------------------------------------------------------------------*/
297
298 TAPEMEDIA_HANDLER tmh_oma =
299 {
300 &generic_tmhcall,
301 &open_omatape,
302 &close_omatape,
303 &read_omatape,
304 &write_READONLY5, // WRITE
305 &rewind_omatape,
306 &bsb_omatape,
307 &fsb_omatape,
308 &bsf_omatape,
309 &fsf_omatape,
310 &write_READONLY, // WTM
311 &write_READONLY, // SYNC
312 &write_READONLY, // DSE
313 &write_READONLY, // ERG
314 &is_tapeloaded_filename,
315 &return_false1, // passedeot
316 &readblkid_virtual,
317 &locateblk_virtual
318 };
319
320 /*-------------------------------------------------------------------*/
321
322 #if defined(OPTION_SCSI_TAPE)
323
324 TAPEMEDIA_HANDLER tmh_scsi =
325 {
326 &generic_tmhcall,
327 &open_scsitape,
328 &close_scsitape,
329 &read_scsitape,
330 &write_scsitape,
331 &rewind_scsitape,
332 &bsb_scsitape,
333 &fsb_scsitape,
334 &bsf_scsitape,
335 &fsf_scsitape,
336 &write_scsimark,
337 &sync_scsitape,
338 &dse_scsitape,
339 &erg_scsitape,
340 &is_tape_mounted_scsitape,
341 &passedeot_scsitape,
342 &readblkid_scsitape,
343 &locateblk_scsitape
344 };
345
346 #endif /* defined(OPTION_SCSI_TAPE) */
347
348 /*-------------------------------------------------------------------*/
349 /* Device-Type Initialization Table (DEV/CU MODEL, FEATURES, ETC) */
350 /*-------------------------------------------------------------------*/
351 /*
352 PROGRAMMING NOTE: the MDR/OBR code (Device Characteristics bytes
353 40-41) are apparently CRITICALLY IMPORTANT for proper tape drive
354 functioning for certain operating systems. If the bytes are not
355 provided (set to zero) or are set incorrectly, certain operating
356 systems end up using unusual/undesirable Mode Set values in their
357 Channel Programs (such as x'20' Write Immediate for example). I
358 only note it here because these two particular bytes are rather
359 innocuous looking based upon their name and sparsely documented
360 and largely unexplained values, thereby possibly misleading one
361 into believing they weren't important and thus could be safely
362 set to zero if their values were unknown. Rest assured they are
363 NOT unimportant! Quite the opposite: the are, for some operating
364 systems, CRITICALLY IMPORTANT and must NOT be returned as zeros.
365
366 The following were obtained from "EREP Release 3.5.0 Reference"
367 (GC35-0152-03):
368
369 Model MDR OBR
370 ------- ----- -----
371
372 3480 0x41 0x80
373 3490 0x42 0x81
374
375 3590 0x46 0x83
376 3590 (3591/3490 EMU) 0x47 0x84
377 3590 (3590/3490 EMU) 0x48 0x85
378
379
380 NOTE: only models 3480, 3490 and 3590 support the RDC (Read
381 Device Characteristics) channel command, and thus they're the
382 only ones we must know the MDR/OBR codes for (since the MDR/OBR
383 codes are only used in the RDC CCW and not anwhere else). That
384 is to say, NONE of the Channel Commands (CCWs) that all the
385 OTHER models happen to support have an MDR/OBR code anywhere
386 in their data. Only models 3480, 3490 and 3590 have MDR/OBR
387 codes buried in their CCW data (specifically the RDC CCW data).
388
389 Also note that, at the moment, we do not support emulating 3590's
390 or 3591's running in 3490 Emulation Mode (i.e. 3591/3490 EMU or
391 3590/3490 EMU). The user is free to use such a device with Herc-
392 ules however, but if they do, it should be specified as a 3490.
393
394 ---------------------------------------------------------------------*/
395
396 typedef struct DEVINITTAB /* Initialization values */
397 {
398 U16 devtype; /* Device type */
399 BYTE devmodel; /* Device model number */
400 U16 cutype; /* Control unit type */
401 BYTE cumodel; /* Control unit model number */
402 U32 sctlfeat; /* Storage control features */
403 BYTE devclass; /* Device class code */
404 BYTE devtcode; /* Device type code */
405 BYTE MDR; /* Misc. Data Record ID */
406 BYTE OBR; /* Outboard Recorder ID */
407 int numdevid; /* #of SNSID bytes (see NOTE)*/
408 int numsense; /* #of SENSE bytes */
409 int haverdc; /* RDC Supported */
410 int displayfeat; /* Has LCD display */
411 }
412 DEVINITTAB;
413 DEVINITTAB DevInitTab[] = /* Initialization table */
414 {
415 // PROGRAMMING NOTE: we currently do not support a #of Sense-ID bytes
416 // value (numdevid) greater than 7 since our current channel-subsystem
417 // design does not support the concept of hardware physical attachment
418 // "Nodes" (i.e. separate control-unit, device and interface elements).
419 // Supporting more than 7 bytes of Sense-ID information would require
420 // support for Node Descriptors (ND) and Node Element Descriptors (NED)
421 // and the associated commands (CCWs) to query them (Read Configuration
422 // Data (0xFA) , Set Interface Identifier (0x73) and associated support
423 // in the Read Subsystem Data (0x3E) command), which is vast overkill
424 // and a complete waste of time given our current overly-simple channel
425 // subsystem design.
426 //
427 //--------------------------------------------------------------------
428 // 3410/3411/3420/3422/3430/8809/9347/9348
429 //--------------------------------------------------------------------
430 //
431 // devtype/mod cutype/mod sctlfeat cls typ MDR OBR sid sns rdc dsp
432 { 0x3410,0x01, 0x3115,0x01, 0x00000000, 0, 0, 0, 0, 0, 9, 0, 0 },
433 { 0x3411,0x01, 0x3115,0x01, 0x00000000, 0, 0, 0, 0, 0, 9, 0, 0 },
434 { 0x3420,0x06, 0x3803,0x02, 0x00000000, 0, 0, 0, 0, 0, 24, 0, 0 }, // (DEFAULT: 3420)
435 { 0x3422,0x01, 0x3422,0x01, 0x00000000, 0, 0, 0, 0, 7, 32, 0, 0 },
436 { 0x3430,0x01, 0x3422,0x01, 0x00000000, 0, 0, 0, 0, 7, 32, 0, 0 },
437 { 0x8809,0x01, 0x8809,0x01, 0x00000000, 0, 0, 0, 0, 0, 32, 0, 0 },
438 { 0x9347,0x01, 0x9347,0x01, 0x00000000, 0, 0, 0, 0, 7, 32, 0, 0 },
439 { 0x9348,0x01, 0x9348,0x01, 0x00000000, 0, 0, 0, 0, 7, 32, 0, 0 },
440
441 //--------------------------------------------------------------------
442 // 3480/3490/3590
443 //--------------------------------------------------------------------
444 //
445 // PROGRAMMING NOTE: we currently do not support a #of Sense-ID bytes
446 // value (numdevid) greater than 7 since our current channel-subsystem
447 // design does not support the concept of hardware physical attachment
448 // "Nodes" (i.e. separate control-unit, device and interface elements).
449 // Supporting more than 7 bytes of Sense-ID information would require
450 // support for Node Descriptors (ND) and Node Element Descriptors (NED)
451 // and the associated commands (CCWs) to query them (Read Configuration
452 // Data (0xFA) , Set Interface Identifier (0x73) and associated support
453 // in the Read Subsystem Data (0x3E) command), which is vast overkill
454 // and a complete waste of time given our current overly-simple channel
455 // subsystem design.
456 //
457 // PROGRAMMING NOTE: if you change the below devtype/mod or cutype/mod
458 // values, be sure to ALSO change tapeccws.c's READ CONFIGURATION DATA
459 // (CCW opcode 0xFA) values as well!
460 //
461 // PROGRAMMING NOTE: the bit values of the 'sctlfeat' field are:
462 //
463 // ....40.. (unknown)
464 // ....08.. Set Special Intercept Condition (SIC) supported
465 // ....04.. Channel Path No-Operation supported (always
466 // on if Library Attachment Facility installed)
467 // ....02.. Logical Write-Protect supported (always on
468 // if Read Device Characteristics is supported)
469 // ....01.. Extended Buffered Log support enabled (if 64
470 // bytes of buffered log data, else 32 bytes)
471 // ......80 Automatic Cartridge Loader installed/enabled
472 // ......40 Improved Data Recording Capability (i.e.
473 // compression support) installed/enabled
474 // ......20 Suppress Volume Fencing
475 // ......10 Library Interface online/enabled
476 // ......08 Library Attachment Facility installed
477 // ......04 (unknown)
478 //
479 // PROGRAMMING NOTE: the below "0x00004EC4" value for the 'sctlfeat'
480 // field for Model 3590 was determined empirically on a real machine.
481 //
482 // devtype/mod cutype/mod sctlfeat cls typ MDR OBR sid sns rdc dsp
483 { 0x3480,0x31, 0x3480,0x31, 0x000002C0, 0x80,0x80, 0x41,0x80, 7, 24, 1, 1 }, // 0x31 = D31
484 { 0x3490,0x50, 0x3490,0x50, 0x000002C0, 0x80,0x80, 0x42,0x81, 7, 32, 1, 1 }, // 0x50 = C10
485 { 0x3590,0x10, 0x3590,0x50, 0x00004EC4, 0x80,0x80, 0x46,0x83, 7, 32, 1, 1 }, // 0x10 = B1A, 0x50 = A50
486 { 0xFFFF,0xFF, 0xFFFF,0xFF, 0xFFFFFFFF, 0xFF,0xFF, 0xFF,0xFF, -1, -1, -1, -1 }, //**** END OF TABLE ****
487 { 0x3420,0x06, 0x3803,0x02, 0x00000000, 0, 0, 0, 0, 0, 24, 0, 0 }, // (DEFAULT: 3420)
488 };
489
490 /*-------------------------------------------------------------------*/
491 /* Initialize the device handler */
492 /*-------------------------------------------------------------------*/
tapedev_init_handler(DEVBLK * dev,int argc,char * argv[])493 int tapedev_init_handler (DEVBLK *dev, int argc, char *argv[])
494 {
495 int rc;
496 DEVINITTAB* pDevInitTab;
497 int attn = 0;
498
499 /* Set flag so attention will be raised for re-init */
500 if(dev->devtype)
501 {
502 attn = 1;
503 }
504
505 /* Close current tape */
506 if(dev->fd>=0)
507 {
508 /* Prevent accidental re-init'ing of already loaded tape drives */
509 if (sysblk.nomountedtapereinit)
510 {
511 char* devclass;
512
513 tapedev_query_device(dev, &devclass, 0, NULL);
514
515 if (1
516 && strcmp(devclass,"TAPE") == 0
517 && (0
518 || TAPEDEVT_SCSITAPE == dev->tapedevt
519 || (argc >= 3 && strcmp(argv[2], TAPE_UNLOADED) != 0)
520 )
521 )
522 {
523 ASSERT( dev->tmh && dev->tmh->tapeloaded );
524 if (dev->tmh->tapeloaded( dev, NULL, 0 ))
525 {
526 release_lock (&dev->lock);
527 logmsg(_("HHCPN183E Reinit rejected for drive %u:%4.4X; drive not empty\n"),
528 SSID_TO_LCSS(dev->ssid), dev->devnum);
529 return -1;
530 }
531 }
532 }
533
534 dev->tmh->close(dev);
535 dev->fd=-1;
536 }
537
538 autoload_close(dev);
539 dev->tdparms.displayfeat=0;
540
541 /* Determine the control unit type and model number */
542 /* Support for 3490/3422/3430/8809/9347, etc.. */
543 if (!sscanf( dev->typname, "%hx", &dev->devtype ))
544 dev->devtype = 0x3420;
545
546 // PROGAMMING NOTE: we use hard-coded values from our DevInitTab
547 // for virtual (non-SCSI) devices and, for the time being, for non-
548 // virtual (SCSI) devices too. Once we add direct SCSI I/O support
549 // we will need to add code to get this information directly from
550 // the actual SCSI device itself.
551 for
552 (
553 pDevInitTab = &DevInitTab[0];
554 pDevInitTab->devtype != 0xFFFF && pDevInitTab->devtype != dev->devtype;
555 pDevInitTab++
556 );
557
558 if (pDevInitTab->devtype == 0xFFFF) /* (entry not found?) */
559 {
560 logmsg ( _("Unsupported device type specified %4.4x\n"), dev->devtype );
561
562 pDevInitTab++; /* (default entry; s/b same as 0x3420) */
563 pDevInitTab->devtype = dev->devtype; /* (don't know what else to do really) */
564 pDevInitTab->cutype = dev->devtype; /* (don't know what else to do really) */
565 }
566
567 /* Allow SENSE ID for certain specific legacy devices if requested */
568
569 dev->numdevid = pDevInitTab->numdevid; // (default == from table)
570
571 if (1
572 && sysblk.legacysenseid // (if option requested, AND is)
573 && (0 // (for allowable legacy device)
574 || 0x3410 == dev->devtype
575 || 0x3411 == dev->devtype
576 || 0x3420 == dev->devtype
577 || 0x8809 == dev->devtype
578 )
579 )
580 {
581 dev->numdevid = 7; // (allow for this legacy device)
582 }
583
584 /* Initialize the Sense-Id bytes if needed... */
585 if (dev->numdevid > 0)
586 {
587 dev->devid[0] = 0xFF;
588
589 dev->devid[1] = (pDevInitTab->cutype >> 8) & 0xFF;
590 dev->devid[2] = (pDevInitTab->cutype >> 0) & 0xFF;
591 dev->devid[3] = pDevInitTab->cumodel;
592
593 dev->devid[4] = (pDevInitTab->devtype >> 8) & 0xFF;
594 dev->devid[5] = (pDevInitTab->devtype >> 0) & 0xFF;
595 dev->devid[6] = pDevInitTab->devmodel;
596
597 /* Initialize the CIW information if needed... */
598 if (dev->numdevid > 7)
599 {
600 // PROGRAMMING NOTE: see note near 'DEVINITTAB'
601 // struct definition regarding requirements for
602 // supporting more than 7 bytes of SNSID info.
603
604 memcpy (&dev->devid[8], "\x40\xFA\x00\xA0", 4); // CIW Read Configuration Data (0xFA)
605 memcpy (&dev->devid[12], "\x41\x73\x00\x04", 4); // CIW Set Interface Identifier (0x73)
606 memcpy (&dev->devid[16], "\x42\x3E\x00\x60", 4); // CIW Read Subsystem Data (0x3E)
607 }
608 }
609
610 /* Initialize the Read Device Characteristics (RDC) bytes... */
611 if (pDevInitTab->haverdc)
612 {
613 dev->numdevchar = 64;
614
615 memset (dev->devchar, 0, sizeof(dev->devchar));
616 memcpy (dev->devchar, dev->devid+1, 6);
617
618 // Bytes 6-9: Subsystem Facilities...
619
620 dev->devchar[6] = (pDevInitTab->sctlfeat >> 24) & 0xFF;
621 dev->devchar[7] = (pDevInitTab->sctlfeat >> 16) & 0xFF;
622 dev->devchar[8] = (pDevInitTab->sctlfeat >> 8) & 0xFF;
623 dev->devchar[9] = (pDevInitTab->sctlfeat >> 0) & 0xFF;
624
625 // Bytes 10/11: Device Class/Type ...
626
627 dev->devchar[10] = pDevInitTab->devclass;
628 dev->devchar[11] = pDevInitTab->devtcode;
629
630 // Bytes 24-29: cutype/model & devtype/model ...
631 // (Note: undocumented; determined empirically)
632
633 dev->devchar[24] = (pDevInitTab->cutype >> 8) & 0xFF;
634 dev->devchar[25] = (pDevInitTab->cutype >> 0) & 0xFF;
635 dev->devchar[26] = pDevInitTab->cumodel;
636
637 dev->devchar[27] = (pDevInitTab->devtype >> 8) & 0xFF;
638 dev->devchar[28] = (pDevInitTab->devtype >> 0) & 0xFF;
639 dev->devchar[29] = pDevInitTab->devmodel;
640
641 // Bytes 40-41: MDR/OBR code...
642
643 dev->devchar[40] = pDevInitTab->MDR;
644 dev->devchar[41] = pDevInitTab->OBR;
645 }
646
647 /* Initialize other fields */
648 // dev->numdevid = pDevInitTab->numdevid; // (handled above)
649 dev->numsense = pDevInitTab->numsense;
650 dev->tdparms.displayfeat = pDevInitTab->displayfeat;
651
652 dev->fenced = 0; // (always, initially)
653 dev->SIC_active = 0; // (always, initially)
654 dev->SIC_supported = 0; // (until we're sure)
655 dev->forced_logging = 0; // (always, initially)
656 #if defined( OPTION_TAPE_AUTOMOUNT )
657 dev->noautomount = 0; // (always, initially)
658 #endif
659
660 /* Initialize SCSI tape control fields */
661 #if defined(OPTION_SCSI_TAPE)
662 dev->sstat = GMT_DR_OPEN(-1);
663 #endif
664
665 /* Clear the DPA */
666 memset (dev->pgid, 0, sizeof(dev->pgid));
667 /* Clear Drive password - Adrian */
668 memset (dev->drvpwd, 0, sizeof(dev->drvpwd));
669
670 /* Request the channel to merge data chained write CCWs into
671 a single buffer before passing data to the device handler */
672 dev->cdwmerge = 1;
673
674 /* ISW */
675 /* Build a 'clear' sense */
676 memset (dev->sense, 0, sizeof(dev->sense));
677 dev->sns_pending = 0;
678
679 // Initialize the [non-SCSI] auto-loader...
680
681 // PROGRAMMING NOTE: we don't [yet] know at this early stage
682 // what type of tape device we're dealing with (SCSI (non-virtual)
683 // or non-SCSI (virtual)) since 'mountnewtape' hasn't been called
684 // yet (which is the function that determines which media handler
685 // should be used and is the one that initializes dev->tapedevt)
686
687 // The only thing we know (or WILL know once 'autoload_init'
688 // is called) is whether or not there was a [non-SCSI] auto-
689 // loader defined for the device. That's it and nothing more.
690
691 autoload_init( dev, argc, argv );
692
693 // Was an auto-loader defined for this device?
694 if ( !dev->als )
695 {
696 // No. Just mount whatever tape there is (if any)...
697 rc = mountnewtape( dev, argc, argv );
698 }
699 else
700 {
701 // Yes. Try mounting the FIRST auto-loader slot...
702 if ( (rc = autoload_mount_first( dev )) != 0 )
703 {
704 // If that doesn't work, try subsequent slots...
705 while
706 (
707 dev->als
708 &&
709 (rc = autoload_mount_next( dev )) != 0
710 )
711 {
712 ; // (nop; just go on to next slot)
713 }
714 rc = dev->als ? rc : -1;
715 }
716 }
717
718 if (dev->devchar[8] & 0x08) // SIC supported?
719 dev->SIC_supported = 1; // remember that fact
720
721 if (dev->tapedevt == TAPEDEVT_SCSITAPE)
722 dev->syncio = 0; // (SCSI i/o too slow; causes Machine checks)
723 else
724 dev->syncio = 2; // (aws/het/etc are fast; syncio likely safe)
725
726 /* Make attention pending if necessary */
727 if(attn)
728 {
729 release_lock (&dev->lock);
730 device_attention (dev, CSW_DE);
731 obtain_lock (&dev->lock);
732 }
733
734 return rc;
735
736 } /* end function tapedev_init_handler */
737
738
739 /*-------------------------------------------------------------------*/
740 /* Close the device */
741 /*-------------------------------------------------------------------*/
tapedev_close_device(DEVBLK * dev)742 int tapedev_close_device ( DEVBLK *dev )
743 {
744 autoload_close(dev);
745 dev->tmh->close(dev);
746 ASSERT( dev->fd < 0 );
747
748 dev->curfilen = 1;
749 dev->nxtblkpos = 0;
750 dev->prvblkpos = -1;
751 dev->curblkrem = 0;
752 dev->curbufoff = 0;
753 dev->blockid = 0;
754 dev->fenced = 0;
755
756 return 0;
757 } /* end function tapedev_close_device */
758
759
760 /*-------------------------------------------------------------------*/
761 /* Tape format determination REGEXPS. Used by gettapetype below */
762 /*-------------------------------------------------------------------*/
763
764 struct tape_format_entry /* (table layout) */
765 {
766 char* fmtreg; /* A regular expression */
767 int fmtcode; /* the device code */
768 TAPEMEDIA_HANDLER* tmh; /* The media dispatcher */
769 char* descr; /* readable description */
770 char* short_descr; /* (same but shorter) */
771 };
772
773 /*-------------------------------------------------------------------*/
774 /* Tape format determination REGEXPS. Used by gettapetype below */
775 /*-------------------------------------------------------------------*/
776
777 struct tape_format_entry fmttab [] = /* (table itself) */
778 {
779 /* This entry matches a filename ending with .aws */
780 #define AWSTAPE_FMTENTRY 0
781 #define DEFAULT_FMTENTRY AWSTAPE_FMTENTRY
782 {
783 "\\.aws$",
784 TAPEDEVT_AWSTAPE,
785 &tmh_aws,
786 "AWS Format tape file",
787 "AWS tape"
788 },
789
790 /* This entry matches a filename ending with .het */
791 #define HETTAPE_FMTENTRY 1
792 {
793 "\\.het$",
794 TAPEDEVT_HETTAPE,
795 &tmh_het,
796 "Hercules Emulated Tape file",
797 "HET tape"
798 },
799
800 /* This entry matches a filename ending with .tdf */
801 #define OMATAPE_FMTENTRY 2
802 {
803 "\\.tdf$",
804 TAPEDEVT_OMATAPE,
805 &tmh_oma,
806 "Optical Media Attachment (OMA) tape",
807 "OMA tape"
808 },
809
810 /* This entry matches a filename ending with .fkt */
811 #define FAKETAPE_FMTENTRY 3
812 {
813 "\\.fkt$",
814 TAPEDEVT_FAKETAPE,
815 &tmh_fake,
816 "Flex FakeTape file",
817 "FakeTape"
818 },
819
820 #if defined(OPTION_SCSI_TAPE)
821
822 /* This entry matches a filename starting with /dev/ */
823 #define SCSITAPE_FMTENTRY 4
824 {
825 "^/dev/",
826 TAPEDEVT_SCSITAPE,
827 &tmh_scsi,
828 "SCSI attached tape drive",
829 "SCSI tape"
830 },
831
832 #if defined(_MSVC_)
833
834 /* (same idea but for Windows SCSI tape device names) */
835 #undef SCSITAPE_FMTENTRY
836 #define SCSITAPE_FMTENTRY 5
837 {
838 "^\\\\\\\\\\.\\\\\\w",
839 TAPEDEVT_SCSITAPE,
840 &tmh_scsi,
841 "SCSI attached tape drive",
842 "SCSI tape"
843 },
844
845 #endif // _MSVC_
846 #endif // OPTION_SCSI_TAPE
847 };
848
849
850 /*-------------------------------------------------------------------*/
851 /* gettapetype_byname determine tape device type by filename */
852 /*-------------------------------------------------------------------*/
853 /* returns fmttab entry# on success, -1 on error/unable to determine */
854 /*-------------------------------------------------------------------*/
gettapetype_byname(DEVBLK * dev)855 int gettapetype_byname (DEVBLK *dev)
856 {
857 #if defined(HAVE_REGEX_H) || defined(HAVE_PCRE)
858 regex_t regwrk; /* REGEXP work area */
859 regmatch_t regwrk2; /* REGEXP match area */
860 char errbfr[1024]; /* Working storage */
861 int i; /* Loop control */
862 #endif // HAVE_REGEX_H
863 int rc; /* various rtns return codes */
864
865 /* Use the file name to determine the device type */
866
867 #if defined(HAVE_REGEX_H) || defined(HAVE_PCRE)
868
869 for (i=0; i < (int)arraysize( fmttab ); i++)
870 {
871 rc = regcomp (®wrk, fmttab[i].fmtreg, REG_ICASE);
872 if (rc < 0)
873 {
874 regerror (rc, ®wrk, errbfr, 1024);
875 logmsg (_("HHCTA001E %4.4X: Unable to determine tape format type for %s: Internal error: Regcomp error %s on index %d\n"),
876 dev->devnum, dev->filename, errbfr, i);
877 return -1;
878 }
879
880 rc = regexec (®wrk, dev->filename, 1, ®wrk2, 0);
881 if (rc < 0)
882 {
883 regerror (rc, ®wrk, errbfr, 1024);
884 regfree ( ®wrk );
885 logmsg (_("HHCTA002E %4.4X: Unable to determine tape format type for %s: Internal error: Regexec error %s on index %d\n"),
886 dev->devnum, dev->filename, errbfr, i);
887 return -1;
888 }
889
890 regfree (®wrk);
891
892 if (rc == 0) /* MATCH? */
893 return i;
894
895 ASSERT( rc == REG_NOMATCH );
896 }
897
898 #else // !HAVE_REGEX_H
899
900 if (1
901 && (rc = strlen(dev->filename)) > 4
902 && (rc = strcasecmp( &dev->filename[rc-4], ".aws" )) == 0
903 )
904 {
905 return AWSTAPE_FMTENTRY;
906 }
907
908 if (1
909 && (rc = strlen(dev->filename)) > 4
910 && (rc = strcasecmp( &dev->filename[rc-4], ".het" )) == 0
911 )
912 {
913 return HETTAPE_FMTENTRY;
914 }
915
916 if (1
917 && (rc = strlen(dev->filename)) > 4
918 && (rc = strcasecmp( &dev->filename[rc-4], ".tdf" )) == 0
919 )
920 {
921 return OMATAPE_FMTENTRY;
922 }
923
924 if (1
925 && (rc = strlen(dev->filename)) > 4
926 && (rc = strcasecmp( &dev->filename[rc-4], ".fkt" )) == 0
927 )
928 {
929 return FAKETAPE_FMTENTRY;
930 }
931
932 #if defined(OPTION_SCSI_TAPE)
933 if (1
934 && (rc = strlen(dev->filename)) > 5
935 && (rc = strncasecmp( dev->filename, "/dev/", 5 )) == 0
936 )
937 {
938 if (strncasecmp( dev->filename+5, "st", 2 ) == 0)
939 dev->stape_close_rewinds = 1; // (rewind at close)
940 else
941 dev->stape_close_rewinds = 0; // (otherwise don't)
942
943 return SCSITAPE_FMTENTRY;
944 }
945 #if defined(_MSVC_)
946 if (1
947 && strncasecmp(dev->filename, "\\\\.\\", 4) == 0
948 && *(dev->filename + 4) != 0
949 )
950 {
951 return SCSITAPE_FMTENTRY;
952 }
953 #endif // _MSVC_
954 #endif // OPTION_SCSI_TAPE
955 #endif // HAVE_REGEX_H
956
957 return -1; /* -1 == "unable to determine" */
958
959 } /* end function gettapetype_byname */
960
961
962 /*-------------------------------------------------------------------*/
963 /* gettapetype_bydata determine tape device type by file data */
964 /*-------------------------------------------------------------------*/
965 /* returns fmttab entry# on success, -1 on error/unable to determine */
966 /*-------------------------------------------------------------------*/
gettapetype_bydata(DEVBLK * dev)967 int gettapetype_bydata (DEVBLK *dev)
968 {
969 char pathname[MAX_PATH]; /* file path in host format */
970 int rc; /* various rtns return codes */
971
972 /* Try to determine the type based on actual file contents */
973 hostpath( pathname, dev->filename, sizeof(pathname) );
974 rc = hopen( pathname, O_RDONLY | O_BINARY );
975 if (rc >= 0)
976 {
977 BYTE hdr[6]; /* block header i/o buffer */
978 int fd = rc; /* save file descriptor */
979
980 /* Read the header. If bytes 0-3 are ASCII "0000", then the
981 * tape is likely a Flex FakeTape. Otherwise if bytes 2-3 are
982 * binary zero (x'0000'), it's likely an AWS type tape. If byte
983 * 4 (first flag byte) has either of the ZLIB or BZIP2 flags on,
984 * then it's a HET tape. Otherwise it's just an ordinary AWS tape.
985 */
986 rc = read (fd, hdr, sizeof(hdr));
987 close(fd);
988 if (rc >= 6)
989 {
990 /* Use the data to make the possible determination */
991 if (memcmp(hdr, "@TDF", 4) == 0)
992 return OMATAPE_FMTENTRY;
993
994 if (1
995 && hdr[0] == 0x30 /* "ASCII"-zero len prev block? */
996 && hdr[1] == 0x30
997 && hdr[2] == 0x30
998 && hdr[3] == 0x30
999 )
1000 return FAKETAPE_FMTENTRY; /* Then obviously Flex FakeTape */
1001
1002 if (hdr[2] == 0 && hdr[3] == 0) /* 0 len prev blk? */
1003 {
1004 if (hdr[4] & HETHDR_FLAGS1_TAPEMARK) /* If tapemark then */
1005 return -1; /* can't tell type. */
1006 if (hdr[4] & HETHDR_FLAGS1_COMPRESS || /* ZLIB or BZIP2 or */
1007 hdr[5] & HETHDR_FLAGS2_COMPRESS) /* Bus-Tech ZLIB? */
1008 return HETTAPE_FMTENTRY; /* Then HET format. */
1009 else
1010 return AWSTAPE_FMTENTRY; /* Else default AWS */
1011 }
1012 }
1013 }
1014 return -1; /* -1 == "unable to determine" */
1015
1016 } /* end function gettapetype_bydata */
1017
1018
1019 /*-------------------------------------------------------------------*/
1020 /* gettapetype determine tape device type */
1021 /*-------------------------------------------------------------------*/
1022 /* returns fmttab entry# on success, -1 on error/unable to determine */
1023 /*-------------------------------------------------------------------*/
gettapetype(DEVBLK * dev,char ** short_descr)1024 int gettapetype (DEVBLK *dev, char **short_descr)
1025 {
1026 char* descr; /* Device descr from fmttab */
1027 int i; /* fmttab entry# */
1028
1029 i = gettapetype_byname( dev ); /* Get type based on name */
1030
1031 #if defined(OPTION_SCSI_TAPE)
1032 if (i != SCSITAPE_FMTENTRY) /* If not SCSI tape... */
1033 #endif
1034 {
1035 int i2 = gettapetype_bydata( dev ); // Get type based on data..
1036
1037 if (i2 >= 0 && // If valid type by data, AND
1038 (i2 != AWSTAPE_FMTENTRY || // *not* AWS by data (or if it
1039 i != HETTAPE_FMTENTRY) // is, if it's not HET by name)..
1040 )
1041 i = i2; // ..Use type based on data.
1042 }
1043
1044 /* If file type still unknown, use a reasonable default value... */
1045 if (i < 0)
1046 {
1047 i = DEFAULT_FMTENTRY;
1048 if (strcmp (dev->filename, TAPE_UNLOADED) != 0)
1049 logmsg (_("HHCTA003W %4.4X: Unable to determine tape format type for %s; presuming %s.\n"),
1050 dev->devnum, dev->filename, fmttab[i].short_descr );
1051 }
1052
1053 dev->tapedevt = fmttab[i].fmtcode;
1054 dev->tmh = fmttab[i].tmh;
1055 descr = fmttab[i].descr;
1056 *short_descr = fmttab[i].short_descr;
1057
1058 if (strcmp (dev->filename, TAPE_UNLOADED) != 0)
1059 logmsg (_("HHCTA004I %4.4X: %s is a %s\n"),
1060 dev->devnum, dev->filename, descr);
1061
1062 return 0; // (success)
1063
1064 } /* end function gettapetype */
1065
1066
1067 /*-------------------------------------------------------------------*/
1068 /* The following table goes hand-in-hand with the 'enum' values */
1069 /* that immediately follow. Used by 'mountnewtape' function. */
1070 /*-------------------------------------------------------------------*/
1071
1072 PARSER ptab [] =
1073 {
1074 { "awstape", NULL },
1075 { "idrc", "%d" },
1076 { "compress", "%d" },
1077 { "method", "%d" },
1078 { "level", "%d" },
1079 { "chunksize", "%d" },
1080 { "maxsize", "%d" },
1081 { "maxsizeK", "%d" },
1082 { "maxsizeM", "%d" },
1083 { "eotmargin", "%d" },
1084 { "strictsize", "%d" },
1085 { "readonly", "%d" },
1086 { "ro", NULL },
1087 { "noring", NULL },
1088 { "rw", NULL },
1089 { "ring", NULL },
1090 { "deonirq", "%d" },
1091 #if defined( OPTION_TAPE_AUTOMOUNT )
1092 { "noautomount",NULL },
1093 #endif
1094 { "--blkid-22", NULL },
1095 { "--blkid-24", NULL }, /* (synonym for --blkid-22) */
1096 { "--blkid-32", NULL },
1097 { "--no-erg", NULL },
1098 { NULL, NULL }, /* (end of table) */
1099 };
1100
1101 /*-------------------------------------------------------------------*/
1102 /* The following table goes hand-in-hand with the 'ptab' PARSER */
1103 /* table immediately above. Used by 'mountnewtape' function. */
1104 /*-------------------------------------------------------------------*/
1105
1106 enum
1107 {
1108 TDPARM_NONE,
1109 TDPARM_AWSTAPE,
1110 TDPARM_IDRC,
1111 TDPARM_COMPRESS,
1112 TDPARM_METHOD,
1113 TDPARM_LEVEL,
1114 TDPARM_CHKSIZE,
1115 TDPARM_MAXSIZE,
1116 TDPARM_MAXSIZEK,
1117 TDPARM_MAXSIZEM,
1118 TDPARM_EOTMARGIN,
1119 TDPARM_STRICTSIZE,
1120 TDPARM_READONLY,
1121 TDPARM_RO,
1122 TDPARM_NORING,
1123 TDPARM_RW,
1124 TDPARM_RING,
1125 TDPARM_DEONIRQ,
1126 #if defined( OPTION_TAPE_AUTOMOUNT )
1127 TDPARM_NOAUTOMOUNT,
1128 #endif
1129 TDPARM_BLKID22,
1130 TDPARM_BLKID24,
1131 TDPARM_BLKID32,
1132 TDPARM_NOERG
1133 };
1134
1135 /*-------------------------------------------------------------------*/
1136 /* mountnewtape -- mount a tape in the drive */
1137 /*-------------------------------------------------------------------*/
1138 /* */
1139 /* Syntax: filename [options] */
1140 /* */
1141 /* where options are any of the entries in the 'ptab' PARSER */
1142 /* table defined further above. Some commonly used options are: */
1143 /* */
1144 /* awstape sets the HET parms to be compatible with the */
1145 /* R|P/390|'s tape file Format (HET files) */
1146 /* */
1147 /* idrc|compress 0|1: Write tape blocks with compression */
1148 /* (std deviation: Read backward allowed on */
1149 /* compressed HET tapes while it is not on */
1150 /* IDRC formated 3480 tapes) */
1151 /* */
1152 /* --no-erg for SCSI tape only, means the hardware does */
1153 /* not support the "Erase Gap" command and all */
1154 /* such i/o's should return 'success' instead. */
1155 /* */
1156 /* --blkid-32 for SCSI tape only, means the hardware */
1157 /* only supports full 32-bit block-ids. */
1158 /* */
1159 /*-------------------------------------------------------------------*/
mountnewtape(DEVBLK * dev,int argc,char ** argv)1160 int mountnewtape ( DEVBLK *dev, int argc, char **argv )
1161 {
1162 char* short_descr; /* Short descr from fmttab */
1163 int i; /* Loop control */
1164 int rc, optrc; /* various rtns return codes */
1165 union { /* Parser results */
1166 U32 num; /* Parser results */
1167 BYTE str[ 80 ]; /* Parser results */
1168 } res; /* Parser results */
1169
1170 /* Release the previous OMA descriptor array if allocated */
1171 if (dev->omadesc != NULL)
1172 {
1173 free (dev->omadesc);
1174 dev->omadesc = NULL;
1175 }
1176
1177 /* The first argument is the file name */
1178 if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1)
1179 strcpy (dev->filename, TAPE_UNLOADED);
1180 else
1181 /* Save the file name in the device block */
1182 strcpy (dev->filename, argv[0]);
1183
1184 /* Determine tape device type... */
1185 VERIFY( gettapetype( dev, &short_descr ) == 0 );
1186
1187 /* (sanity check) */
1188 ASSERT(dev->tapedevt != TAPEDEVT_UNKNOWN);
1189 ASSERT(dev->tmh != NULL);
1190 ASSERT(short_descr != NULL);
1191
1192 /* Initialize device dependent fields */
1193 dev->fd = -1;
1194 #if defined(OPTION_SCSI_TAPE)
1195 dev->sstat = GMT_DR_OPEN(-1);
1196 #endif
1197 dev->omadesc = NULL;
1198 dev->omafiles = 0;
1199 dev->curfilen = 1;
1200 dev->nxtblkpos = 0;
1201 dev->prvblkpos = -1;
1202 dev->curblkrem = 0;
1203 dev->curbufoff = 0;
1204 dev->readonly = 0;
1205 dev->hetb = NULL;
1206 dev->tdparms.compress = HETDFLT_COMPRESS;
1207 dev->tdparms.method = HETDFLT_METHOD;
1208 dev->tdparms.level = HETDFLT_LEVEL;
1209 dev->tdparms.chksize = HETDFLT_CHKSIZE;
1210 dev->tdparms.maxsize = 0; // no max size (default)
1211 dev->eotmargin = 128*1024; // 128K EOT margin (default)
1212 dev->tdparms.logical_readonly = 0; // read/write (default)
1213 #if defined( OPTION_TAPE_AUTOMOUNT )
1214 dev->noautomount = 0;
1215 #endif
1216
1217 #if defined(OPTION_SCSI_TAPE)
1218 // Real 3590's support Erase Gap and use 32-bit blockids.
1219
1220 if (TAPEDEVT_SCSITAPE == dev->tapedevt
1221 && 0x3590 == dev->devtype)
1222 {
1223 dev->stape_no_erg = 0; // (default for 3590 SCSI)
1224 dev->stape_blkid_32 = 1; // (default for 3590 SCSI)
1225 }
1226 #endif
1227
1228 #define HHCTA078E() logmsg (_("HHCTA078E %4.4X: option '%s' not valid for %s\n"), \
1229 dev->devnum, argv[i], short_descr)
1230
1231 /* Process remaining options */
1232 rc = 0;
1233 for (i = 1; i < argc; i++)
1234 {
1235 optrc = 0;
1236 switch (parser (&ptab[0], argv[i], &res))
1237 {
1238 case TDPARM_NONE:
1239 logmsg (_("HHCTA067E %4.4X: option '%s' unrecognized\n"),
1240 dev->devnum, argv[i]);
1241 optrc = -1;
1242 break;
1243
1244 case TDPARM_AWSTAPE:
1245 if (0
1246 || TAPEDEVT_SCSITAPE == dev->tapedevt
1247 || TAPEDEVT_FAKETAPE == dev->tapedevt
1248 )
1249 {
1250 HHCTA078E(); optrc = -1; break;
1251 }
1252 dev->tdparms.compress = FALSE;
1253 dev->tdparms.chksize = 4096;
1254 break;
1255
1256 case TDPARM_IDRC:
1257 case TDPARM_COMPRESS:
1258 if (0
1259 || TAPEDEVT_SCSITAPE == dev->tapedevt
1260 || TAPEDEVT_FAKETAPE == dev->tapedevt
1261 )
1262 {
1263 HHCTA078E(); optrc = -1; break;
1264 }
1265 dev->tdparms.compress = (res.num ? TRUE : FALSE);
1266 break;
1267
1268 case TDPARM_METHOD:
1269 if (0
1270 || TAPEDEVT_SCSITAPE == dev->tapedevt
1271 || TAPEDEVT_FAKETAPE == dev->tapedevt
1272 )
1273 {
1274 HHCTA078E(); optrc = -1; break;
1275 }
1276 if (res.num < HETMIN_METHOD || res.num > HETMAX_METHOD)
1277 {
1278 logmsg(_("HHCTA068E %4.4X: option '%s': method must be within %u-%u\n"),
1279 dev->devnum, argv[i], HETMIN_METHOD, HETMAX_METHOD);
1280 optrc = -1;
1281 break;
1282 }
1283 dev->tdparms.method = res.num;
1284 break;
1285
1286 case TDPARM_LEVEL:
1287 if (0
1288 || TAPEDEVT_SCSITAPE == dev->tapedevt
1289 || TAPEDEVT_FAKETAPE == dev->tapedevt
1290 )
1291 {
1292 HHCTA078E(); optrc = -1; break;
1293 }
1294 if (res.num < HETMIN_LEVEL || res.num > HETMAX_LEVEL)
1295 {
1296 logmsg(_("HHCTA069E %4.4X: option '%s': level must be within %u-%u\n"),
1297 dev->devnum, argv[i], HETMIN_LEVEL, HETMAX_LEVEL);
1298 optrc = -1;
1299 break;
1300 }
1301 dev->tdparms.level = res.num;
1302 break;
1303
1304 case TDPARM_CHKSIZE:
1305 if (0
1306 || TAPEDEVT_SCSITAPE == dev->tapedevt
1307 || TAPEDEVT_FAKETAPE == dev->tapedevt
1308 )
1309 {
1310 HHCTA078E(); optrc = -1; break;
1311 }
1312 if (res.num < HETMIN_CHUNKSIZE || res.num > HETMAX_CHUNKSIZE)
1313 {
1314 logmsg (_("HHCTA070E %4.4X: option '%s': chunksize must be within %u-%u\n"),
1315 dev->devnum, argv[i], HETMIN_CHUNKSIZE, HETMAX_CHUNKSIZE);
1316 optrc = -1;
1317 break;
1318 }
1319 dev->tdparms.chksize = res.num;
1320 break;
1321
1322 case TDPARM_MAXSIZE:
1323 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1324 {
1325 HHCTA078E(); optrc = -1; break;
1326 }
1327 dev->tdparms.maxsize=res.num;
1328 break;
1329
1330 case TDPARM_MAXSIZEK:
1331 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1332 {
1333 HHCTA078E(); optrc = -1; break;
1334 }
1335 dev->tdparms.maxsize=res.num*1024;
1336 break;
1337
1338 case TDPARM_MAXSIZEM:
1339 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1340 {
1341 HHCTA078E(); optrc = -1; break;
1342 }
1343 dev->tdparms.maxsize=res.num*1024*1024;
1344 break;
1345
1346 case TDPARM_EOTMARGIN:
1347 dev->eotmargin=res.num;
1348 break;
1349
1350 case TDPARM_STRICTSIZE:
1351 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1352 {
1353 HHCTA078E(); optrc = -1; break;
1354 }
1355 dev->tdparms.strictsize=res.num;
1356 break;
1357
1358 case TDPARM_READONLY:
1359 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1360 {
1361 HHCTA078E(); optrc = -1; break;
1362 }
1363 dev->tdparms.logical_readonly=(res.num ? 1 : 0 );
1364 break;
1365
1366 case TDPARM_RO:
1367 case TDPARM_NORING:
1368 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1369 {
1370 HHCTA078E(); optrc = -1; break;
1371 }
1372 dev->tdparms.logical_readonly=1;
1373 break;
1374
1375 case TDPARM_RW:
1376 case TDPARM_RING:
1377 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1378 {
1379 HHCTA078E(); optrc = -1; break;
1380 }
1381 dev->tdparms.logical_readonly=0;
1382 break;
1383
1384 case TDPARM_DEONIRQ:
1385 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1386 {
1387 HHCTA078E(); optrc = -1; break;
1388 }
1389 dev->tdparms.deonirq=(res.num ? 1 : 0 );
1390 break;
1391
1392 #if defined( OPTION_TAPE_AUTOMOUNT )
1393
1394 case TDPARM_NOAUTOMOUNT:
1395 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1396 {
1397 HHCTA078E(); optrc = -1; break;
1398 }
1399 dev->noautomount = 1;
1400 break;
1401
1402 #endif /* OPTION_TAPE_AUTOMOUNT */
1403
1404 #if defined(OPTION_SCSI_TAPE)
1405 case TDPARM_BLKID22:
1406 case TDPARM_BLKID24:
1407 if (TAPEDEVT_SCSITAPE != dev->tapedevt)
1408 {
1409 HHCTA078E(); optrc = -1; break;
1410 }
1411 dev->stape_blkid_32 = 0;
1412 break;
1413
1414 case TDPARM_BLKID32:
1415 if (TAPEDEVT_SCSITAPE != dev->tapedevt)
1416 {
1417 HHCTA078E(); optrc = -1; break;
1418 }
1419 dev->stape_blkid_32 = 1;
1420 break;
1421
1422 case TDPARM_NOERG:
1423 if (TAPEDEVT_SCSITAPE != dev->tapedevt)
1424 {
1425 HHCTA078E(); optrc = -1; break;
1426 }
1427 dev->stape_no_erg = 1;
1428 break;
1429 #endif /* defined(OPTION_SCSI_TAPE) */
1430
1431 default:
1432 logmsg(_("HHCTA071E %4.4X: option '%s': parse error\n"),
1433 dev->devnum, argv[i]);
1434 optrc = -1;
1435 break;
1436
1437 } // end switch (parser (&ptab[0], argv[i], &res))
1438
1439 if (optrc < 0)
1440 rc = -1;
1441 else
1442 logmsg (_("HHCTA066I %4.4X: option '%s' accepted.\n"),
1443 dev->devnum, argv[i]);
1444
1445 } // end for (i = 1; i < argc; i++)
1446
1447 if (0 != rc)
1448 return -1;
1449
1450 /* Adjust the display if necessary */
1451 if(dev->tdparms.displayfeat)
1452 {
1453 if(strcmp(dev->filename,TAPE_UNLOADED)==0)
1454 {
1455 /* NO tape is loaded */
1456 if(TAPEDISPTYP_UMOUNTMOUNT == dev->tapedisptype)
1457 {
1458 /* A new tape SHOULD be mounted */
1459 dev->tapedisptype = TAPEDISPTYP_MOUNT;
1460 dev->tapedispflags |= TAPEDISPFLG_REQAUTOMNT;
1461 strlcpy( dev->tapemsg1, dev->tapemsg2, sizeof(dev->tapemsg1) );
1462 }
1463 else if(TAPEDISPTYP_UNMOUNT == dev->tapedisptype)
1464 {
1465 dev->tapedisptype = TAPEDISPTYP_IDLE;
1466 }
1467 }
1468 else
1469 {
1470 /* A tape IS already loaded */
1471 dev->tapedisptype = TAPEDISPTYP_IDLE;
1472 }
1473 }
1474 UpdateDisplay(dev);
1475 ReqAutoMount(dev);
1476 return 0;
1477
1478 } /* end function mountnewtape */
1479
1480
1481 /*-------------------------------------------------------------------*/
1482 /* Query the device definition */
1483 /*-------------------------------------------------------------------*/
tapedev_query_device(DEVBLK * dev,char ** class,int buflen,char * buffer)1484 void tapedev_query_device ( DEVBLK *dev, char **class,
1485 int buflen, char *buffer )
1486 {
1487 char devparms[ MAX_PATH+1 + 128 ];
1488 char dispmsg [ 256 ];
1489
1490 BEGIN_DEVICE_CLASS_QUERY( "TAPE", dev, class, buflen, buffer );
1491
1492 *buffer = 0;
1493 devparms[0]=0;
1494 dispmsg [0]=0;
1495
1496 GetDisplayMsg( dev, dispmsg, sizeof(dispmsg) );
1497
1498 if (strchr(dev->filename,' ')) strlcat( devparms, "\"", sizeof(devparms));
1499 strlcat( devparms, dev->filename, sizeof(devparms));
1500 if (strchr(dev->filename,' ')) strlcat( devparms, "\"", sizeof(devparms));
1501
1502 #if defined( OPTION_TAPE_AUTOMOUNT )
1503
1504 if (dev->noautomount)
1505 strlcat( devparms, " noautomount", sizeof(devparms));
1506
1507 #endif /* OPTION_TAPE_AUTOMOUNT */
1508
1509 if ( strcmp( dev->filename, TAPE_UNLOADED ) == 0 )
1510 {
1511 #if defined(OPTION_SCSI_TAPE)
1512 if ( TAPEDEVT_SCSITAPE == dev->tapedevt )
1513 {
1514 if (0x3590 == dev->devtype) // emulating 3590
1515 {
1516 if (!dev->stape_blkid_32 ) strlcat( devparms, " --blkid-22", sizeof(devparms) );
1517 }
1518 else // emulating 3480, 3490
1519 {
1520 if ( dev->stape_blkid_32 ) strlcat( devparms, " --blkid-32", sizeof(devparms) );
1521 }
1522 if ( dev->stape_no_erg ) strlcat( devparms, " --no-erg", sizeof(devparms) );
1523 }
1524 #endif
1525 snprintf(buffer, buflen, "%s%s%s",
1526 devparms,
1527 dev->tdparms.displayfeat ? ", Display: " : "",
1528 dev->tdparms.displayfeat ? dispmsg : "");
1529 }
1530 else // (filename was specified)
1531 {
1532 char tapepos[64]; tapepos[0]=0;
1533
1534 if ( TAPEDEVT_SCSITAPE != dev->tapedevt )
1535 {
1536 snprintf( tapepos, sizeof(tapepos), "[%d:%08"I64_FMT"X] ",
1537 dev->curfilen, dev->nxtblkpos );
1538 tapepos[sizeof(tapepos)-1] = 0;
1539 }
1540 #if defined(OPTION_SCSI_TAPE)
1541 else // (this is a SCSI tape drive)
1542 {
1543 if (STS_BOT( dev ))
1544 {
1545 dev->eotwarning = 0;
1546 strlcat(tapepos,"*BOT* ",sizeof(tapepos));
1547 }
1548
1549 // If tape has a display, then GetDisplayMsg already
1550 // appended *FP* for us. Otherwise we need to do it.
1551
1552 if ( !dev->tdparms.displayfeat )
1553 if (STS_WR_PROT( dev ))
1554 strlcat(tapepos,"*FP* ",sizeof(tapepos));
1555
1556 if (0x3590 == dev->devtype) // emulating 3590
1557 {
1558 if (!dev->stape_blkid_32 ) strlcat( devparms, " --blkid-22", sizeof(devparms) );
1559 }
1560 else // emulating 3480, 3490
1561 {
1562 if ( dev->stape_blkid_32 ) strlcat( devparms, " --blkid-32", sizeof(devparms) );
1563 }
1564 if ( dev->stape_no_erg ) strlcat( devparms, " --no-erg", sizeof(devparms) );
1565 }
1566 #endif
1567
1568 if ( TAPEDEVT_SCSITAPE != dev->tapedevt
1569 #if defined(OPTION_SCSI_TAPE)
1570 || STS_MOUNTED(dev)
1571 #endif
1572 )
1573 {
1574 // Not a SCSI tape, -or- mounted SCSI tape...
1575
1576 snprintf (buffer, buflen, "%s%s %s%s%s",
1577
1578 devparms, (dev->readonly ? " ro" : ""),
1579
1580 tapepos,
1581 dev->tdparms.displayfeat ? "Display: " : "",
1582 dev->tdparms.displayfeat ? dispmsg : "");
1583 }
1584 else /* ( TAPEDEVT_SCSITAPE == dev->tapedevt && STS_NOT_MOUNTED(dev) ) */
1585 {
1586 // UNmounted SCSI tape...
1587
1588 snprintf (buffer, buflen, "%s%s (%sNOTAPE)%s%s",
1589
1590 devparms, (dev->readonly ? " ro" : ""),
1591
1592 dev->fd < 0 ? "closed; " : "",
1593 dev->tdparms.displayfeat ? ", Display: " : "",
1594 dev->tdparms.displayfeat ? dispmsg : "" );
1595 }
1596 }
1597
1598 buffer[buflen-1] = 0;
1599
1600 } /* end function tapedev_query_device */
1601
1602
1603 /*-------------------------------------------------------------------*/
1604 /* Issue a message on the console indicating the display status */
1605 /*-------------------------------------------------------------------*/
UpdateDisplay(DEVBLK * dev)1606 void UpdateDisplay( DEVBLK *dev )
1607 {
1608 if ( dev->tdparms.displayfeat )
1609 {
1610 char msgbfr[256];
1611
1612 GetDisplayMsg( dev, msgbfr, sizeof(msgbfr) );
1613
1614 if ( dev->prev_tapemsg )
1615 {
1616 if ( strcmp( msgbfr, dev->prev_tapemsg ) == 0 )
1617 return;
1618 free( dev->prev_tapemsg );
1619 dev->prev_tapemsg = NULL;
1620 }
1621
1622 dev->prev_tapemsg = strdup( msgbfr );
1623
1624 logmsg(_("HHCTA010I %4.4X: Now Displays: %s\n"),
1625 dev->devnum, msgbfr );
1626 }
1627 #if defined(OPTION_SCSI_TAPE)
1628 else
1629 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1630 int_scsi_status_update( dev, 1 );
1631 #endif
1632 }
1633
1634
1635 /*-------------------------------------------------------------------*/
1636 /* Issue Automatic Mount Requests as defined by the display */
1637 /*-------------------------------------------------------------------*/
ReqAutoMount(DEVBLK * dev)1638 void ReqAutoMount( DEVBLK *dev )
1639 {
1640 char volser[7];
1641 BYTE tapeloaded, autoload, mountreq, unmountreq, stdlbled, ascii, scratch;
1642 char* lbltype;
1643 char* tapemsg = "";
1644
1645 ///////////////////////////////////////////////////////////////////
1646
1647 // The Automatic Cartridge Loader or "ACL" (sometimes also referred
1648 // to as an "Automatic Cartridge Feeder" (ACF) too) automatically
1649 // loads the next cartridge [from the magazine] whenever a tape is
1650 // unloaded, BUT ONLY IF the 'Index Automatic Load' bit (bit 7) of
1651 // the FCB (Format Control Byte, byte 0) was on whenever the Load
1652 // Display ccw was sent to the drive. If the bit was not on when
1653 // the Load Display ccw was issued, then the requested message (if
1654 // any) is displayed until the next tape mount/dismount and the ACL
1655 // is NOT activated (i.e. the next tape is NOT automatically loaded).
1656 // If the bit was on however, then, as stated, the ACF component of
1657 // the drive will automatically load the next [specified] cartridge.
1658
1659 // Whenever the ACL facility is activated (via bit 7 of byte 0 of
1660 // the Load Display ccw), then only bytes 1-8 of the "Display Until
1661 // Mounted" message (or bytes 9-17 of a "Display Until Dismounted
1662 // Then Mounted" message) are displayed to let the operator know
1663 // which tape is currently being processed by the autoloader and
1664 // thus is basically for informational purposes only (the operator
1665 // does NOT need to do anything since the auto-loader is handling
1666 // tape mounts for them automatically; i.e. the message is NOT an
1667 // operator mount/dismount request).
1668
1669 // If the 'Index Automatic Load' bit was not set in the Load Display
1670 // CCW however, then the specified "Display Until Mounted", "Display
1671 // Until Unmounted" or "Display Until Unmounted Then Display Until
1672 // Mounted" message is meant as a mount, unmount, or unmount-then-
1673 // mount request for the actual [human being] operator, and thus
1674 // they DO need to take some sort of action (since the ACL automatic
1675 // loader facility is not active; i.e. the message is a request to
1676 // the operator to manually unload, load or unload then load a tape).
1677
1678 // THUS... If the TAPEDISPFLG_AUTOLOADER flag is set (indicating
1679 // the autoloader is (or should be) active), then the message we
1680 // issue is simply for INFORMATIONAL purposes only (i.e. "FYI: the
1681 // following tape is being *automatically* loaded; you don't need
1682 // to actually do anything")
1683
1684 // If the TAPEDISPFLG_AUTOLOADER is flag is NOT set however, then
1685 // we need to issue a message notifying the operator of what they
1686 // are *expected* to do (e.g. either unload, load or unload/load
1687 // the specified tape volume).
1688
1689 // Also please note that while there are no formally established
1690 // standards regarding the format of the Load Display CCW message
1691 // text, there are however certain established conventions (estab-
1692 // lished by IBM naturally). If the first character is an 'M', it
1693 // means "Please MOUNT the indicated volume". An 'R' [apparently]
1694 // means "Retain", and, similarly, 'K' means "Keep" (same thing as
1695 // "Retain"). If the LAST character is an 'S', then it means that
1696 // a Standard Labeled volume is being requested, whereas an 'N'
1697 // (or really, anything OTHER than an 'S' (except 'A')) means an
1698 // unlabeled (or non-labeled) tape volume is being requested. An
1699 // 'A' as the last character means a Standard Labeled ASCII tape
1700 // is being requested. If the message is "SCRTCH" (or something
1701 // similar), then a either a standard labeled or unlabeled scratch
1702 // tape is obviously being requested (there doesn't seem to be any
1703 // convention/consensus regarding the format for requesting scratch
1704 // tapes; some shops for example use 'XXXSCR' to indicate that a
1705 // scratch tape from tape pool 'XXX' should be mounted).
1706
1707 ///////////////////////////////////////////////////////////////////
1708
1709 /* Open the file/drive if needed (kick off auto-mount if needed) */
1710 if (dev->fd < 0)
1711 {
1712 BYTE unitstat = 0, code = 0;
1713 BYTE *sensebkup;
1714
1715 /* Save any pending sense */
1716 sensebkup=malloc(dev->numsense);
1717 memcpy(sensebkup,dev->sense,dev->numsense);
1718
1719 dev->tmh->open( dev, &unitstat, code );
1720
1721 /* Restore pending sense */
1722 memcpy(dev->sense,sensebkup,dev->numsense);
1723 free(sensebkup);
1724
1725 #if defined(OPTION_SCSI_TAPE)
1726 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1727 {
1728 // PROGRAMMING NOTE: it's important to do TWO refreshes here
1729 // to cause the auto-mount thread to get created. Doing only
1730 // one doesn't work and doing two shouldn't cause any harm.
1731
1732 GENTMH_PARMS gen_parms;
1733
1734 gen_parms.action = GENTMH_SCSI_ACTION_UPDATE_STATUS;
1735 gen_parms.dev = dev;
1736
1737 // (refresh potentially stale status)
1738 VERIFY( dev->tmh->generic( &gen_parms ) == 0 );
1739
1740 // (force auto-mount thread creation)
1741 VERIFY( dev->tmh->generic( &gen_parms ) == 0 );
1742 }
1743 #endif /* defined(OPTION_SCSI_TAPE) */
1744 }
1745
1746 /* Disabled when [non-SCSI] ACL in use */
1747 if ( dev->als )
1748 return;
1749
1750 /* Do we actually have any work to do? */
1751 if ( !( dev->tapedispflags & TAPEDISPFLG_REQAUTOMNT ) )
1752 return; // (nothing to do!)
1753
1754 /* Reset work flag */
1755 dev->tapedispflags &= ~TAPEDISPFLG_REQAUTOMNT;
1756
1757 /* If the drive doesn't have a display,
1758 then it can't have an auto-loader either */
1759 if ( !dev->tdparms.displayfeat )
1760 return;
1761
1762 /* Determine if mount or unmount request
1763 and get pointer to correct message */
1764
1765 tapeloaded = dev->tmh->tapeloaded( dev, NULL, 0 ) ? TRUE : FALSE;
1766
1767 mountreq = FALSE; // (default)
1768 unmountreq = FALSE; // (default)
1769
1770 if (tapeloaded)
1771 {
1772 // A tape IS already loaded...
1773
1774 // 1st byte of message1 non-blank, *AND*,
1775 // unmount request or,
1776 // unmountmount request and not message2-only flag?
1777
1778 if (' ' != *(tapemsg = dev->tapemsg1) &&
1779 (0
1780 || TAPEDISPTYP_UNMOUNT == dev->tapedisptype
1781 || (1
1782 && TAPEDISPTYP_UMOUNTMOUNT == dev->tapedisptype
1783 && !(dev->tapedispflags & TAPEDISPFLG_MESSAGE2)
1784 )
1785 )
1786 )
1787 unmountreq = TRUE;
1788 }
1789 else
1790 {
1791 // NO TAPE is loaded yet...
1792
1793 // mount request and 1st byte of msg1 non-blank, *OR*,
1794 // unmountmount request and 1st byte of msg2 non-blank?
1795
1796 if (
1797 (1
1798 && TAPEDISPTYP_MOUNT == dev->tapedisptype
1799 && ' ' != *(tapemsg = dev->tapemsg1)
1800 )
1801 ||
1802 (1
1803 && TAPEDISPTYP_UMOUNTMOUNT == dev->tapedisptype
1804 && ' ' != *(tapemsg = dev->tapemsg2)
1805 ))
1806 mountreq = TRUE;
1807 }
1808
1809 /* Extract volser from message */
1810 strncpy( volser, tapemsg+1, 6 ); volser[6]=0;
1811
1812 /* Set some boolean flags */
1813 autoload = ( dev->tapedispflags & TAPEDISPFLG_AUTOLOADER ) ? TRUE : FALSE;
1814 stdlbled = ( 'S' == tapemsg[7] ) ? TRUE : FALSE;
1815 ascii = ( 'A' == tapemsg[7] ) ? TRUE : FALSE;
1816 scratch = ( 'S' == tapemsg[0] ) ? TRUE : FALSE;
1817
1818 lbltype = stdlbled ? "SL" : "UL";
1819
1820 #if defined(OPTION_SCSI_TAPE)
1821 #if 1
1822 // ****************************************************************
1823 // ZZ FIXME: ZZ TODO: *** Programming Note ***
1824
1825 // Since we currently don't have any way of activating a SCSI tape
1826 // drive's REAL autoloader mechanism whenever we receive an auto-
1827 // mount message [from the guest o/s via the Load Display CCW], we
1828 // leave it to the operator to action the mount message displayed
1829
1830 // Once ASPI code eventually gets added to Herc (and/or something
1831 // similar for the Linux world), then the following workaround can
1832 // be safely removed.
1833
1834 autoload = FALSE; // (temporarily forced; see above)
1835
1836 // ****************************************************************
1837 #endif
1838 #endif /* defined(OPTION_SCSI_TAPE) */
1839
1840 if ( autoload )
1841 {
1842 // ZZ TODO: Here is where we'd issue i/o (ASPI?) to the actual
1843 // hardware autoloader facility (i.e. the SCSI medium changer)
1844 // to unload and/or load the tape(s) if this were a SCSI auto-
1845 // loading tape drive.
1846
1847 if ( unmountreq )
1848 {
1849 if ( scratch )
1850 logmsg(_("AutoMount: %s%s scratch tape being auto-unloaded on %4.4X = %s\n"),
1851 ascii ? "ASCII " : "",lbltype,
1852 dev->devnum, dev->filename);
1853 else
1854 logmsg(_("AutoMount: %s%s tape volume \"%s\" being auto-unloaded on %4.4X = %s\n"),
1855 ascii ? "ASCII " : "",lbltype,
1856 volser, dev->devnum, dev->filename);
1857 }
1858 if ( mountreq )
1859 {
1860 if ( scratch )
1861 logmsg(_("AutoMount: %s%s scratch tape being auto-loaded on %4.4X = %s\n"),
1862 ascii ? "ASCII " : "",lbltype,
1863 dev->devnum, dev->filename);
1864 else
1865 logmsg(_("AutoMount: %s%s tape volume \"%s\" being auto-loaded on %4.4X = %s\n"),
1866 ascii ? "ASCII " : "",lbltype,
1867 volser, dev->devnum, dev->filename);
1868 }
1869 }
1870
1871
1872 } /* end function ReqAutoMount */
1873
1874
1875 /*-------------------------------------------------------------------*/
1876 /* Get 3480/3490/3590 Display text in 'human' form */
1877 /* If not a 3480/3490/3590, then just update status if a SCSI tape */
1878 /*-------------------------------------------------------------------*/
GetDisplayMsg(DEVBLK * dev,char * msgbfr,size_t lenbfr)1879 void GetDisplayMsg( DEVBLK *dev, char *msgbfr, size_t lenbfr )
1880 {
1881 msgbfr[0]=0;
1882
1883 if ( !dev->tdparms.displayfeat )
1884 {
1885 // (drive doesn't have a display)
1886 #if defined(OPTION_SCSI_TAPE)
1887 if (TAPEDEVT_SCSITAPE == dev->tapedevt)
1888 int_scsi_status_update( dev, 1 );
1889 #endif
1890 return;
1891 }
1892
1893 if ( !IS_TAPEDISPTYP_SYSMSG( dev ) )
1894 {
1895 // -------------------------
1896 // Display Host message
1897 // -------------------------
1898
1899 // "When bit 3 (alternate) is set to 1, then
1900 // bits 4 (blink) and 5 (low/high) are ignored."
1901
1902 strlcpy( msgbfr, "\"", lenbfr );
1903
1904 if ( dev->tapedispflags & TAPEDISPFLG_ALTERNATE )
1905 {
1906 char msg1[9];
1907 char msg2[9];
1908
1909 strlcpy ( msg1, dev->tapemsg1, sizeof(msg1) );
1910 strlcat ( msg1, " ", sizeof(msg1) );
1911 strlcpy ( msg2, dev->tapemsg2, sizeof(msg2) );
1912 strlcat ( msg2, " ", sizeof(msg2) );
1913
1914 strlcat ( msgbfr, msg1, lenbfr );
1915 strlcat ( msgbfr, "\" / \"", lenbfr );
1916 strlcat ( msgbfr, msg2, lenbfr );
1917 strlcat ( msgbfr, "\"", lenbfr );
1918 strlcat ( msgbfr, " (alternating)", lenbfr );
1919 }
1920 else
1921 {
1922 if ( dev->tapedispflags & TAPEDISPFLG_MESSAGE2 )
1923 strlcat( msgbfr, dev->tapemsg2, lenbfr );
1924 else
1925 strlcat( msgbfr, dev->tapemsg1, lenbfr );
1926
1927 strlcat ( msgbfr, "\"", lenbfr );
1928
1929 if ( dev->tapedispflags & TAPEDISPFLG_BLINKING )
1930 strlcat ( msgbfr, " (blinking)", lenbfr );
1931 }
1932
1933 if ( dev->tapedispflags & TAPEDISPFLG_AUTOLOADER )
1934 strlcat( msgbfr, " (AUTOLOADER)", lenbfr );
1935
1936 return;
1937 }
1938
1939 // ----------------------------------------------
1940 // Display SYS message (Unit/Device message)
1941 // ----------------------------------------------
1942
1943 // First, build the system message, then move it into
1944 // the caller's buffer...
1945
1946 strlcpy( dev->tapesysmsg, "\"", sizeof(dev->tapesysmsg) );
1947
1948 switch ( dev->tapedisptype )
1949 {
1950 case TAPEDISPTYP_IDLE:
1951 case TAPEDISPTYP_WAITACT:
1952 default:
1953 // Blank display if no tape loaded...
1954 if ( !dev->tmh->tapeloaded( dev, NULL, 0 ) )
1955 {
1956 strlcat( dev->tapesysmsg, " ", sizeof(dev->tapesysmsg) );
1957 break;
1958 }
1959
1960 // " NT RDY " if tape IS loaded, but not ready...
1961 // (IBM docs say " NT RDY " means "Loaded but not ready")
1962
1963 ASSERT( dev->tmh->tapeloaded( dev, NULL, 0 ) );
1964
1965 if (0
1966 || dev->fd < 0
1967 #if defined(OPTION_SCSI_TAPE)
1968 || (1
1969 && TAPEDEVT_SCSITAPE == dev->tapedevt
1970 && !STS_ONLINE( dev )
1971 )
1972 #endif
1973 )
1974 {
1975 strlcat( dev->tapesysmsg, " NT RDY ", sizeof(dev->tapesysmsg) );
1976 break;
1977 }
1978
1979 // Otherwise tape is loaded and ready --> "READY"
1980
1981 ASSERT( dev->tmh->tapeloaded( dev, NULL, 0 ) );
1982
1983 strlcat ( dev->tapesysmsg, " READY ", sizeof(dev->tapesysmsg) );
1984 strlcat( dev->tapesysmsg, "\"", sizeof(dev->tapesysmsg) );
1985
1986 if (0
1987 || dev->readonly
1988 #if defined(OPTION_SCSI_TAPE)
1989 || (1
1990 && TAPEDEVT_SCSITAPE == dev->tapedevt
1991 && STS_WR_PROT( dev )
1992 )
1993 #endif
1994 )
1995 // (append "file protect" indicator)
1996 strlcat ( dev->tapesysmsg, " *FP*", sizeof(dev->tapesysmsg) );
1997
1998 // Copy system message to caller's buffer
1999 strlcpy( msgbfr, dev->tapesysmsg, lenbfr );
2000 return;
2001
2002 case TAPEDISPTYP_ERASING:
2003 strlcat ( dev->tapesysmsg, " ERASING", sizeof(dev->tapesysmsg) );
2004 break;
2005
2006 case TAPEDISPTYP_REWINDING:
2007 strlcat ( dev->tapesysmsg, "REWINDNG", sizeof(dev->tapesysmsg) );
2008 break;
2009
2010 case TAPEDISPTYP_UNLOADING:
2011 strlcat ( dev->tapesysmsg, "UNLOADNG", sizeof(dev->tapesysmsg) );
2012 break;
2013
2014 case TAPEDISPTYP_CLEAN:
2015 strlcat ( dev->tapesysmsg, "*CLEAN ", sizeof(dev->tapesysmsg) );
2016 break;
2017 }
2018
2019 strlcat( dev->tapesysmsg, "\"", sizeof(dev->tapesysmsg) );
2020
2021 // Copy system message to caller's buffer
2022 strlcpy( msgbfr, dev->tapesysmsg, lenbfr );
2023
2024 } /* end function GetDisplayMsg */
2025
2026
2027 /*-------------------------------------------------------------------*/
2028 /* IsAtLoadPoint */
2029 /*-------------------------------------------------------------------*/
2030 /* Called by the device-type-specific 'build_sense_xxxx' functions */
2031 /* (indirectly via the 'build_senseX' function) when building sense */
2032 /* for any i/o error (non-"TAPE_BSENSE_STATUSONLY" type call) */
2033 /*-------------------------------------------------------------------*/
IsAtLoadPoint(DEVBLK * dev)2034 int IsAtLoadPoint (DEVBLK *dev)
2035 {
2036 int ldpt=0;
2037 if ( dev->fd >= 0 )
2038 {
2039 /* Set load point indicator if tape is at load point */
2040 switch (dev->tapedevt)
2041 {
2042 default:
2043 case TAPEDEVT_AWSTAPE:
2044 if (dev->nxtblkpos==0)
2045 {
2046 ldpt=1;
2047 }
2048 break;
2049
2050 case TAPEDEVT_HETTAPE:
2051 if (dev->hetb->cblk == 0)
2052 {
2053 ldpt=1;
2054 }
2055 break;
2056
2057 #if defined(OPTION_SCSI_TAPE)
2058 case TAPEDEVT_SCSITAPE:
2059 int_scsi_status_update( dev, 0 );
2060 if ( STS_BOT( dev ) )
2061 {
2062 dev->eotwarning = 0;
2063 ldpt=1;
2064 }
2065 break;
2066 #endif /* defined(OPTION_SCSI_TAPE) */
2067
2068 case TAPEDEVT_OMATAPE:
2069 if (dev->nxtblkpos == 0 && dev->curfilen == 1)
2070 {
2071 ldpt=1;
2072 }
2073 break;
2074 } /* end switch(dev->tapedevt) */
2075 }
2076 else // ( dev->fd < 0 )
2077 {
2078 if ( TAPEDEVT_SCSITAPE == dev->tapedevt )
2079 ldpt=0; /* (tape cannot possibly be at loadpoint
2080 if the device cannot even be opened!) */
2081 else if ( strcmp( dev->filename, TAPE_UNLOADED ) != 0 )
2082 {
2083 /* If the tape has a filename but the tape is not yet */
2084 /* opened, then we are at loadpoint */
2085 ldpt=1;
2086 }
2087 }
2088 return ldpt;
2089
2090 } /* end function IsAtLoadPoint */
2091
2092
2093 /*********************************************************************/
2094 /*********************************************************************/
2095 /** **/
2096 /** AUTOLOADER FUNCTIONS **/
2097 /** **/
2098 /*********************************************************************/
2099 /*********************************************************************/
2100
2101 /*-------------------------------------------------------------------*/
2102 /* autoload_init */
2103 /*-------------------------------------------------------------------*/
2104 /* initialise the Autoloader feature */
2105 /*-------------------------------------------------------------------*/
autoload_init(DEVBLK * dev,int ac,char ** av)2106 void autoload_init(DEVBLK *dev,int ac,char **av)
2107 {
2108 char bfr[4096];
2109 char *rec;
2110 FILE *aldf;
2111 char *verb;
2112 int i;
2113 char *strtokw;
2114 char pathname[MAX_PATH];
2115
2116 autoload_close(dev);
2117 if(ac<1)
2118 {
2119 return;
2120 }
2121 if(av[0][0]!='@')
2122 {
2123 return;
2124 }
2125 logmsg(_("TAPE: Autoloader file request fn=%s\n"),&av[0][1]);
2126 hostpath(pathname, &av[0][1], sizeof(pathname));
2127 if(!(aldf=fopen(pathname,"r")))
2128 {
2129 return;
2130 }
2131 for(i=1;i<ac;i++)
2132 {
2133 autoload_global_parms(dev,av[i]);
2134 }
2135 while((rec=fgets(bfr,4096,aldf)))
2136 {
2137 for(i=(strlen(rec)-1);isspace(rec[i]) && i>=0;i--)
2138 {
2139 rec[i]=0;
2140 }
2141 if(strlen(rec)==0)
2142 {
2143 continue;
2144 }
2145 verb=strtok_r(rec," \t",&strtokw);
2146 if(verb==NULL)
2147 {
2148 continue;
2149 }
2150 if(verb[0]==0)
2151 {
2152 continue;
2153 }
2154 if(verb[0]=='#')
2155 {
2156 continue;
2157 }
2158 if(strcmp(verb,"*")==0)
2159 {
2160 while((verb=strtok_r(NULL," \t",&strtokw)))
2161 {
2162 autoload_global_parms(dev,verb);
2163 }
2164 continue;
2165 }
2166 autoload_tape_entry(dev,verb,&strtokw);
2167 } // end while((rec=fgets(bfr,4096,aldf)))
2168 fclose(aldf);
2169 return;
2170
2171 } /* end function autoload_init */
2172
2173
2174 /*-------------------------------------------------------------------*/
2175 /* autoload_close */
2176 /*-------------------------------------------------------------------*/
2177 /* terminate autoloader operations: release all storage that */
2178 /* was allocated by the autoloader facility */
2179 /*-------------------------------------------------------------------*/
autoload_close(DEVBLK * dev)2180 void autoload_close(DEVBLK *dev)
2181 {
2182 int i;
2183 if(dev->al_argv!=NULL)
2184 {
2185 for(i=0;i<dev->al_argc;i++)
2186 {
2187 free(dev->al_argv[i]);
2188 dev->al_argv[i]=NULL;
2189 }
2190 free(dev->al_argv);
2191 dev->al_argv=NULL;
2192 dev->al_argc=0;
2193 }
2194 dev->al_argc=0;
2195 if(dev->als!=NULL)
2196 {
2197 for(i=0;i<dev->alss;i++)
2198 {
2199 autoload_clean_entry(dev,i);
2200 }
2201 free(dev->als);
2202 dev->als=NULL;
2203 dev->alss=0;
2204 }
2205 } /* end function autoload_close */
2206
2207
2208 /*-------------------------------------------------------------------*/
2209 /* autoload_clean_entry */
2210 /*-------------------------------------------------------------------*/
2211 /* release storage allocated for an autoloader slot */
2212 /* (except the slot itself) */
2213 /*-------------------------------------------------------------------*/
autoload_clean_entry(DEVBLK * dev,int ix)2214 void autoload_clean_entry(DEVBLK *dev,int ix)
2215 {
2216 int i;
2217 for(i=0;i<dev->als[ix].argc;i++)
2218 {
2219 free(dev->als[ix].argv[i]);
2220 dev->als[ix].argv[i]=NULL;
2221 }
2222 dev->als[ix].argc=0;
2223 if(dev->als[ix].filename!=NULL)
2224 {
2225 free(dev->als[ix].filename);
2226 dev->als[ix].filename=NULL;
2227 }
2228 } /* end function autoload_clean_entry */
2229
2230
2231 /*-------------------------------------------------------------------*/
2232 /* autoload_global_parms */
2233 /*-------------------------------------------------------------------*/
2234 /* Appends a blank delimited word to the list of parameters */
2235 /* that will be passed for every tape mounted by the autoloader */
2236 /*-------------------------------------------------------------------*/
autoload_global_parms(DEVBLK * dev,char * par)2237 void autoload_global_parms(DEVBLK *dev,char *par)
2238 {
2239 logmsg(_("TAPE Autoloader - Adding global parm %s\n"),par);
2240 if(dev->al_argv==NULL)
2241 {
2242 dev->al_argv=malloc(sizeof(char *)*256);
2243 dev->al_argc=0;
2244 }
2245 dev->al_argv[dev->al_argc]=(char *)malloc(strlen(par)+sizeof(char));
2246 strcpy(dev->al_argv[dev->al_argc],par);
2247 dev->al_argc++;
2248
2249 } /* end function autoload_global_parms */
2250
2251
2252 /*-------------------------------------------------------------------*/
2253 /* autoload_tape_entry */
2254 /*-------------------------------------------------------------------*/
2255 /* populate an autoloader slot (creates new slot if needed) */
2256 /*-------------------------------------------------------------------*/
autoload_tape_entry(DEVBLK * dev,char * fn,char ** strtokw)2257 void autoload_tape_entry(DEVBLK *dev,char *fn,char **strtokw)
2258 {
2259 char *p;
2260 TAPEAUTOLOADENTRY tae;
2261 logmsg(_("TAPE Autoloader: Adding tape entry %s\n"),fn);
2262 memset(&tae,0,sizeof(tae));
2263 tae.filename=malloc(strlen(fn)+sizeof(char)+1);
2264 strcpy(tae.filename,fn);
2265 while((p=strtok_r(NULL," \t",strtokw)))
2266 {
2267 if(tae.argv==NULL)
2268 {
2269 tae.argv=malloc(sizeof(char *)*256);
2270 }
2271 tae.argv[tae.argc]=malloc(strlen(p)+sizeof(char)+1);
2272 strcpy(tae.argv[tae.argc],p);
2273 tae.argc++;
2274 }
2275 if(dev->als==NULL)
2276 {
2277 dev->als=malloc(sizeof(tae));
2278 dev->alss=0;
2279 }
2280 else
2281 {
2282 dev->als=realloc(dev->als,sizeof(tae)*(dev->alss+1));
2283 }
2284 memcpy(&dev->als[dev->alss],&tae,sizeof(tae));
2285 dev->alss++;
2286
2287 } /* end function autoload_tape_entry */
2288
2289
2290 /*-------------------------------------------------------------------*/
2291 /* autoload_wait_for_tapemount_thread */
2292 /*-------------------------------------------------------------------*/
autoload_wait_for_tapemount_thread(void * db)2293 void *autoload_wait_for_tapemount_thread(void *db)
2294 {
2295 int rc = -1;
2296 DEVBLK *dev = (DEVBLK*) db;
2297
2298 obtain_lock(&dev->lock);
2299 {
2300 while
2301 (
2302 dev->als
2303 &&
2304 (rc = autoload_mount_next( dev )) != 0
2305 )
2306 {
2307 release_lock( &dev->lock );
2308 SLEEP(AUTOLOAD_WAIT_FOR_TAPEMOUNT_INTERVAL_SECS);
2309 obtain_lock( &dev->lock );
2310 }
2311 }
2312 release_lock(&dev->lock);
2313 if ( rc == 0 )
2314 device_attention(dev,CSW_DE);
2315 return NULL;
2316
2317 } /* end function autoload_wait_for_tapemount_thread */
2318
2319
2320 /*-------------------------------------------------------------------*/
2321 /* autoload_mount_first */
2322 /*-------------------------------------------------------------------*/
2323 /* mount in the drive the tape which is */
2324 /* positionned in the 1st autoloader slot */
2325 /*-------------------------------------------------------------------*/
autoload_mount_first(DEVBLK * dev)2326 int autoload_mount_first(DEVBLK *dev)
2327 {
2328 dev->alsix=0;
2329 return(autoload_mount_tape(dev,0));
2330 }
2331
2332
2333 /*-------------------------------------------------------------------*/
2334 /* autoload_mount_next */
2335 /*-------------------------------------------------------------------*/
2336 /* mount in the drive the tape whch is */
2337 /* positionned in the slot after the currently mounted tape. */
2338 /* if this is the last tape, close the autoloader */
2339 /*-------------------------------------------------------------------*/
autoload_mount_next(DEVBLK * dev)2340 int autoload_mount_next(DEVBLK *dev)
2341 {
2342 if(dev->alsix>=dev->alss)
2343 {
2344 autoload_close(dev);
2345 return -1;
2346 }
2347 dev->alsix++;
2348 return(autoload_mount_tape(dev,dev->alsix));
2349 }
2350
2351
2352 /*-------------------------------------------------------------------*/
2353 /* autoload_mount_tape */
2354 /*-------------------------------------------------------------------*/
2355 /* mount in the drive the tape which is */
2356 /* positionned in the autoloader slot #alix */
2357 /*-------------------------------------------------------------------*/
autoload_mount_tape(DEVBLK * dev,int alix)2358 int autoload_mount_tape(DEVBLK *dev,int alix)
2359 {
2360 char **pars;
2361 int pcount=1;
2362 int i;
2363 int rc;
2364 if(alix>=dev->alss)
2365 {
2366 return -1;
2367 }
2368 pars=malloc(sizeof(BYTE *)*256);
2369 pars[0]=dev->als[alix].filename;
2370 for(i=0;i<dev->al_argc;i++,pcount++)
2371 {
2372 pars[pcount]=malloc(strlen(dev->al_argv[i])+10);
2373 strcpy(pars[pcount],dev->al_argv[i]);
2374 if(pcount>255)
2375 {
2376 break;
2377 }
2378 }
2379 for(i=0;i<dev->als[alix].argc;i++,pcount++)
2380 {
2381 pars[pcount]=malloc(strlen(dev->als[alix].argv[i])+10);
2382 strcpy(pars[pcount],dev->als[alix].argv[i]);
2383 if(pcount>255)
2384 {
2385 break;
2386 }
2387 }
2388 rc=mountnewtape(dev,pcount,pars);
2389 for(i=1;i<pcount;i++)
2390 {
2391 free(pars[i]);
2392 }
2393 free(pars);
2394 return(rc);
2395
2396 } /* end function autoload_mount_tape */
2397
2398
2399 /*-------------------------------------------------------------------*/
2400 /* is_tapeloaded_filename */
2401 /*-------------------------------------------------------------------*/
is_tapeloaded_filename(DEVBLK * dev,BYTE * unitstat,BYTE code)2402 int is_tapeloaded_filename ( DEVBLK *dev, BYTE *unitstat, BYTE code )
2403 {
2404 UNREFERENCED(unitstat);
2405 UNREFERENCED(code);
2406 // true 1 == tape loaded, false 0 == tape not loaded
2407 return strcmp( dev->filename, TAPE_UNLOADED ) != 0 ? 1 : 0;
2408 }
2409
2410 /*-------------------------------------------------------------------*/
2411 /* return_false1 */
2412 /*-------------------------------------------------------------------*/
return_false1(DEVBLK * dev)2413 int return_false1 ( DEVBLK *dev )
2414 {
2415 UNREFERENCED(dev);
2416 return 0;
2417 }
2418
2419 /*-------------------------------------------------------------------*/
2420 /* write_READONLY */
2421 /*-------------------------------------------------------------------*/
write_READONLY(DEVBLK * dev,BYTE * unitstat,BYTE code)2422 int write_READONLY ( DEVBLK *dev, BYTE *unitstat, BYTE code )
2423 {
2424 build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code);
2425 return -1;
2426 }
2427
2428 /*-------------------------------------------------------------------*/
2429 /* write_READONLY5 */
2430 /*-------------------------------------------------------------------*/
write_READONLY5(DEVBLK * dev,BYTE * bfr,U16 blklen,BYTE * unitstat,BYTE code)2431 int write_READONLY5 ( DEVBLK *dev, BYTE *bfr, U16 blklen, BYTE *unitstat, BYTE code )
2432 {
2433 UNREFERENCED(bfr);
2434 UNREFERENCED(blklen);
2435 build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code);
2436 return -1;
2437 }
2438
2439 /*-------------------------------------------------------------------*/
2440 /* no_operation */
2441 /*-------------------------------------------------------------------*/
no_operation(DEVBLK * dev,BYTE * unitstat,BYTE code)2442 int no_operation ( DEVBLK *dev, BYTE *unitstat, BYTE code )
2443 {
2444 build_senseX( TAPE_BSENSE_STATUSONLY, dev, unitstat, code );
2445 return 0;
2446 }
2447
2448 /*-------------------------------------------------------------------*/
2449 /* readblkid_virtual */
2450 /*-------------------------------------------------------------------*/
readblkid_virtual(DEVBLK * dev,BYTE * logical,BYTE * physical)2451 int readblkid_virtual ( DEVBLK* dev, BYTE* logical, BYTE* physical )
2452 {
2453 // NOTE: returned value is always in guest BIG-ENDIAN format...
2454
2455 BYTE blockid[4];
2456
2457 if (0x3590 == dev->devtype)
2458 {
2459 // Full 32-bit block-id...
2460
2461 blockid[0] = (dev->blockid >> 24) & 0xFF;
2462 blockid[1] = (dev->blockid >> 16) & 0xFF;
2463 blockid[2] = (dev->blockid >> 8 ) & 0xFF;
2464 blockid[3] = (dev->blockid ) & 0xFF;
2465 }
2466 else // (3480 et. al)
2467 {
2468 // "22-bit" block-id...
2469
2470 blockid[0] = 0x01; // ("wrap" value)
2471 blockid[1] = (dev->blockid >> 16) & 0x3F;
2472 blockid[2] = (dev->blockid >> 8 ) & 0xFF;
2473 blockid[3] = (dev->blockid ) & 0xFF;
2474 }
2475
2476 // NOTE: For virtual tape devices, we return the same value
2477 // for both the logical "Channel block ID" value as well as
2478 // the physical "Device block ID" value...
2479
2480 if (logical) memcpy( logical, &blockid[0], 4 );
2481 if (physical) memcpy( physical, &blockid[0], 4 );
2482
2483 return 0;
2484 }
2485
2486 /*-------------------------------------------------------------------*/
2487 /* locateblk_virtual */
2488 /*-------------------------------------------------------------------*/
locateblk_virtual(DEVBLK * dev,U32 blockid,BYTE * unitstat,BYTE code)2489 int locateblk_virtual ( DEVBLK* dev, U32 blockid, BYTE *unitstat, BYTE code )
2490 {
2491 // NOTE: 'blockid' passed in host (little-endian) format...
2492
2493 int rc;
2494
2495 /* Do it the hard way: rewind to load-point and then
2496 keep doing fsb, fsb, fsb... until we find our block
2497 */
2498 if ((rc = dev->tmh->rewind( dev, unitstat, code)) >= 0)
2499 {
2500 /* Reset position counters to start of file */
2501
2502 dev->curfilen = 1;
2503 dev->nxtblkpos = 0;
2504 dev->prvblkpos = -1;
2505 dev->blockid = 0;
2506
2507 /* Do it the hard way */
2508
2509 while ( dev->blockid < blockid && ( rc >= 0 ) )
2510 rc = dev->tmh->fsb( dev, unitstat, code );
2511 }
2512
2513 return rc;
2514 }
2515
2516 /*-------------------------------------------------------------------*/
2517 /* generic_tmhcall generic media-type-handler call... */
2518 /*-------------------------------------------------------------------*/
generic_tmhcall(GENTMH_PARMS * pGenParms)2519 int generic_tmhcall ( GENTMH_PARMS* pGenParms )
2520 {
2521 if (!pGenParms)
2522 {
2523 errno = EINVAL; // (invalid arguments)
2524 return -1; // (return failure)
2525 }
2526
2527 switch (pGenParms->action)
2528 {
2529 #if defined(OPTION_SCSI_TAPE)
2530 case GENTMH_SCSI_ACTION_UPDATE_STATUS:
2531 {
2532 return update_status_scsitape( pGenParms->dev );
2533 }
2534 #endif /* defined(OPTION_SCSI_TAPE) */
2535
2536 default:
2537 {
2538 errno = EINVAL; // (invalid arguments)
2539 return -1; // (return failure)
2540 }
2541 }
2542
2543 return -1; // (never reached)
2544 }
2545