Files
org-hyperion-cules/html/cckddasd.html
Greg Smith 37387ec2f6 30 May 2002 Preliminary cfba (compressed fba) support - Greg Smith
30 May 2002 Various dasd fixes - Greg Smith


git-svn-id: file:///home/jj/hercules.svn/trunk@905 956126f8-22a0-4046-8f4a-272fa8102e63
2002-05-30 23:37:39 +00:00

1097 lines
54 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN" "html.dtd">
<HTML>
<HEAD><TITLE>
Hercules: Compressed CKD Dasd Emulation</TITLE>
<LINK REL=STYLESHEET TYPE="text/css" HREF="hercules.css">
</HEAD>
<BODY BGCOLOR="#ffffcc" TEXT="#000000" LINK="#0000A0"
VLINK="#008040" ALINK="#000000">
<h1>Compressed CKD Dasd Emulation</h1>
<hr noshade>
<h2>Contents</h2>
<ul>
<li><a href="#introduction"> Introduction </a>
<li><a href="#shadowfiles"> Shadow Files </a>
<li><a href="#filestructure"> File Structure </a>
<li><a href="#methodology"> Methodology </a>
<li><a href="#quickstart"> Quick Start </a>
<li><a href="#usingsfiles"> Using Shadow Files </a>
<li><a href="#options"> Options </a>
<li><a href="#utilities"> Utilities </a>
<li><a href="#faq"> FAQ </a>
<li><a href="#changes"> Changes </a>
<li><a href="#bugs"> Bugs </a>
<li><a href="#cckddump"> cckddump os/390 hlasm program</a>
</ul>
<hr noshade>
<h3><a NAME="introduction">Introduction</a></h3>
Using compressed CKD files, or <b>cckd</b> files, you can significantly
reduce the file space required for emulated CKD dasd and possibly gain
a performance benefit because less physical i/o occurs. Using the
<i>shadow</i> function, you can minimize the amount of data loss in the
event of file corruption.
<p>
A <b>cckd</b> file contains <i>track images</i>, which may be <i>compressed</i>
or <i>uncompressed</i>, and overhead blocks which are <i>headers</i>,
<i>lookup tables</i>, and <i>free space</i>. Compressed track images
may be compressed by
<a href="http://www.info-zip.org/pub/infozip/zlib/"><b>zlib</b></a> or
<a href="http://sourceware.cygnus.com/bzip2/"><b>bzip2</b></a>.
<p>
Track images are addressed by <i>track number</i> using a two table
lookup method: <i>track number</i> divided by 256 (<code>trk >> 8</code>)
indexes into the <i>primary lookup table</i>, which contains the file offset
to the <i>secondary lookup table</i>; the remainder of <i>track number</i>
divided by 256 (<code>trk & 0xff</code>) indexes into the corresponding
<i>secondary lookup table</i>, which contains the <i>offset</i> and
<i>length</i> of the track image.
<p>
There is a single <i>primary lookup table</i> and a variable number of
<i>secondary lookup tables</i>. The maximum number of <i>secondary lookup
tables</i> is the number of tracks for the device type divided by 256, rounded up.
For example, a 3390-3 contains 50085 tracks and would require at most 196
<i>secondary lookup tables</i>.
<p>
<a NAME="formula1">
A regular CKD file contains a 512 byte <i>header</i> followed by <i>track
images</i>, each taking the same amount of space: the maximum track size.
The offset of a track image can be readily calculated by the track number:
<center>
<code>offset = 512 + trk * maxtrksz </code>
</center>
</a>
<p>
A <b>cckd</b> file can take significantly less file space than a regular
CKD file because
<p>
<ul><li>A track image only occupies its <i>length</i> in the file and
not the <i>maximum track size</i>
<li>A track image may be compressed, reducing its <i>length</i>
<li>Unused or <i>null</i> tracks do not occupy any space at all
</ul>
Performance improvements may also occur because less data is read and
written to the hard drive.
<br>However, the <i>lookup tables</i> must be
accurately maintained, <i>track images</i> must be compressed and
uncompressed, and <i>free space</i> must be kept track of, and dealt
with by a <i>garbage collector</i>. This results in a more complicated
file structure, more CPU activity, and the possibility of file corruption
due to program failure or bug. The introduction of <i>shadow files</i>,
however, reduces the impact of possible file corruption.
<p>
<hr noshade>
<p><h3><a NAME="shadowfiles">Shadow Files</a></h3>
Malcom Beattie originally introduced the concept of <i>shadow</i>
files in a <a href="http://www.egroups.com/message/hercules-390/6695">
post</a> to the <a href="http://www.egroups.com/community/hercules-390">newsgroup</a>
8 December 2000. The function is actually implemented as a kind of
<i>snapshot</i>, where a new shadow file can be created on demand.
A CKD emulated dasd is represented by a <i>base</i> file and 0 or more
shadow files. All files are opened <i>read-only</i>
except for the <i>current</i> file, which is opened <i>read-write</i>.
<p>
Shadow files are implemented using the same file structure as base <b>cckd</b> files.
By default, there can be up to 8 shadow files in use at any time for an
emulated CKD device. The base file is designated file <b>[0]</b> and
the shadow files are files <b>[1]</b> up to file <b>[8]</b>.
The <i>highest</i> numbered file in use at a given time is the <i>current</i>
file, where all writes will occur. Track reads start with the <i>current</i>
file and proceed down until a file is found that actually contains the track
image.
<p>
A shadow file, then, contains all the changes made to the emulated CKD dasd
since its creation, until the creation of the next shadow file. The moment
of the shadow file's creation can be thought of as taking a <i>snapshot</i>
of the current emulated CKD dasd at that time, because if the shadow file is
later removed, then the emulated CKD dasd will revert to the state it was at
when the <i>snapshot</i> was taken.
<p>
Using shadow files, you can keep the base CKD file on a read-only device
such as cdrom, or change the base CKD file attributes to read-only,
ensuring that this file can never be corrupted.
<p>
Hercules console commands are provided to add a new shadow file, remove
the current shadow file (with or without backward merge), compress the
curent shadow file, and display the shadow file status and statistics.
<p>
<hr noshade>
<p><h3><a NAME="filestructure">CCKD File Structure</a></h3>
Like a regular CKD emulation file, the first 512 bytes
of a compressed or shadow file contains a <code>CKDDASD_DEVHDR</code>
block. The eye-catcher at the beginning is different to distinguish
the file:
<ul><li><b>CKD_P370</b>&nbsp&nbsp&nbsp Regular CKD file
<li><b>CKD_C370</b>&nbsp&nbsp&nbsp Compressed CKD file
<li><b>CKD_S370</b>&nbsp&nbsp&nbsp Shadow CKD file
</ul>
The next 512 bytes contain a compressed device
header or <code>CCKDDASD_DEVHDR</code> block. This contains the
version-release-mod level of the file, options, space statistics,
and total number of cylinders for the device. Next is
the primary lookup table or the <code>L1TAB</code>. Each 4 byte
entry in the <code>L1TAB</code> contains the file offset to a secondary
lookup table (or <code>L2TAB</code>) or <code>0x00000000</code> (indicating that
the secondary lookup table is <i>null</i>), or <code>0xffffffff</code> (indicating
that the previous file should be searched instead).<br>
The size of the <code>L1TAB</code> is dependent on the number
of tracks on the emulated device.
<p>
<center>
<table border=1>
<tr><td align="left"><code>CKDDASD_DEVHDR</code><br><br><br><br></td>
<tr><td align="left"><code>CCKDDASD_DEVHDR</code><br><br><br><br></td>
<tr><td align="left"><code>L1TAB</code><br><br>
<center>.&nbsp&nbsp.&nbsp&nbsp.</center><br><br></td>
</table>
</center>
<p>
Following the <code>L1TAB</code>,
in no particular order, are <code>L2TAB</code>s, compressed track
images, and free spaces.
<p>
<code><b>L2TAB</b></code>s contain 256 8-byte
entries,and each are, consequently, 2048 bytes in length. Each entry
contains the <i>offset</i> and <i>length</i> of a track image. If
the <i>offset</i> is <code>0x00000000</code> then the track image is <i>null</i>;
if the <i>offset</i> is <code>0xffffffff</code> then the previous file should be
searched instead.
<p>
<center><code><b>L2TAB</b></code> entry
<table border=1>
<tr><td><code><b>offset</b></code><br>4 bytes</td>
<td><code><b>length</b></code><br>2 bytes</td>
<td><code>[unused]</code><br>2 bytes</td>
</table>
</center>
<p>
A <b>compressed track image</b> contains the following two fields:
<ul>
<li> A <i>track header</i>, also called a <i>home address</i> or a <i>track index</i>.
The track header is <b>never</b> compressed.
<li> The track image, beginning with the <i>R0 count</i> and ending with the
<i>end-of-track</i> marker, which is a count field containing all hex 0xff's.
The track image may or may not be compressed.
</ul>
<center><table border=1>
<tr><td><code><b>HA</b></code><br>5 bytes</td>
<td><b>track image</b> (compressed or uncompressed)</br><i>length</i>-5 bytes</td>
</table></center>
<p>
The <b>HA</b> contains <code>0CCHH</code>, that is, a byte of zeroes, 2 bytes indicating
the <i>cylinder</i> of the track, and 2 bytes indicating the <i>head</i> of the track
on the cylinder. Both <code>CC</code> and <code>HH</code> are stored in
<i>big-endian</i> byte order. The track is computed by
<br><center><code>
trk = (((CC[0] << 8) + CC[1]) * <i>trks_per_cyl</i>) + (HH[0] << 8) + HH[1]
</code></center><br>
Since the first byte of the <code>HA</code> is always 0x00 (at least in emulated
CKD files), this byte as stored in the file actually indicates the compression
algorithm used for the remainder of the track image
(<b>0</b> = no compression, <b>1</b> = zlib compression, <b>2</b> = bzip2 compression).
The hi-order bit (<b>0x80</b>) may also be on, indicating the track image was written
under <i>stress</i>.
<p>
<b>Free space</b> contains a 4-byte <i>offset</i> to the next free space,
a 4-byte <i>length</i> of the free space, and zero or more bytes of residual data.
<p>
<center><b>Free Space</b> entry
<table border=1>
<tr><td><code><b>offset</b></code><br>4 bytes</td>
<td><code><b>length</b></code><br>4 bytes</td>
<td><code><b>residual</b></code><br>(<i>length</i> - 8) bytes</td>
</table>
</center>
<p>The minimum length of a free space is 8 bytes.
Since free space is ordered by file offset and no two free spaces are adjacent,
<i>offset</i> in the free space entry is always greater than the current free space
offset + the current free space <i>length</i>, unless the <i>offset</i> is zero,
which indicates the free space chain is terminated.<br>
The free space chain is read when the file is opened for read-write and
written when the file is closed; while the file is opened, the free space chain is
maintained in storage.
<p>
<hr noshade>
<p><h3><a NAME="methodology">Methodology</a></h3>
This section is tedious; you probably want to skip to the
<a href="#quickstart">next section</a> unless you are genuinely
curious as to how cckd actually works. This section is for my edification
as much as anything...
<p>
<b>The interface</b>
<p>
All Hercules emulated devices have standard interface routines described
by the <code>DEVHND</code> structure. These routines are
<table>
<tr><td><b>init</b></td><td>Device initialization (attach)</td>
<tr><td><b>exec</b></td><td>Device execute channel command</td>
<tr><td><b>close</b></td><td>Device close (detach)</td>
<tr><td><b>query</b></td><td>Device query</td>
<tr><td><b>start</b></td><td>Device channel program start</td>
<tr><td><b>end</b></td><td>Device channel program end</td>
<tr><td><b>resume</b></td><td>Device channel program resume</td>
<tr><td><b>suspend</b></td><td>Device channel program suspend</td>
</table>
<p>
Emulated CKD DASD devices have two additional routines:
<table>
<tr><td><b>ckdrdtrk</b></td><td>Read CKD track image</td>
<tr><td><b>ckdupdtrk</b></td><td>Update CKD track image</td>
</table>
<code>ckdrdtrk</code> is called whenever a <code>SEEK</code>
type channel command is executed and <code>ckdupdtrk</code> is
called whenever any of the various <code>WRITE</code> channel
commands modifies the current track image.
<p>
The <b>cckd</b> code implements the following routines:
<table>
<tr><td><code>cckddasd_init_handler</code></td>
<td>cckd device initialization (attach)</td>
<tr><td><code>cckddasd_close_device</code></td><td>cckd device close (detach)</td>
<tr><td><code>cckd_start</code></td><td>cckd channel program start/resume</td>
<tr><td><code>cckd_end</code></td><td>cckd channel program end/suspend</td>
</table>
<p>
<b>The cache</b>
<p>
The implementation is <i>cache</i> table driven. The cache table contains
16 to 1024 entries, each representing a track image, and is shared by <em>all</em>
cckd devices. Each entry contains a pointer to a track image buffer which
is 64K bytes. That is, every 16 entries represents 1M of buffer space.
The size of the cache can be changed by a configuration file statement
or by a hercules console command.
<p>
Each entry can be in one (or certain combinations) of the following states:
<table>
<tr><td><b>active</b></td><td>A channel program is active for the device
and the track image is the last <code>SEEK</code>ed
track image.</td>
<tr><td><b>updated</b></td><td>The track image has been updated by a
<code>WRITE</code> command.</td>
<tr><td><b>write</b></td><td>The track image is not <b>active</b> and has
been <b>updated</b> and is eligible to be written.</td>
<tr><td><b>reading</b></td><td>The track image is currently being read.</td>
<tr><td><b>writing</b></td><td>The track image is currently being written.</td>
<tr><td><b>inactive</b></td><td>The track image is not <i>busy</i> and is eligible
to be <i>stolen</i></td>
</table>
When the <code>ckdrdtrk</code> routine is called, and the track to be
read is not the <em>active</em> track, then a <em>track switch</em> event
occurs. The cache is scanned to see if it contains the track image. If
it does, then a <em>cache hit</em> occurs else a <em>cache miss</em>
occurs.
<p>
In the case of a <em>cache hit</em>, if the entry status is <em>reading</em>
or <em>writing</em> then the code waits for the read or write to complete.
If the entry is <em>write</em>-pending, then the entry is changed back
to <em>updated</em>.
<p>
Otherwise, for a <em>cache miss</em>, the oldest <em>inactive</em> cache
entry will then be <em>stolen</em>.
If no inactive cache entry was found then the cache is <em>flushed</em>
and the code will have to wait for an inactive cache entry to become
available. This is called a <em>cache wait</em> event. When the cache
is flushed, all cache entries that have been <em>updated</em> and are
not <em>active</em> are set to <em>write</em>-pending and the <b>writer</b>
thread is signalled. After an entry has been stolen the track image will
then be read and uncompressed.
If sequential access is detected then track <em>readaheads</em> will be
scheduled.
<p>
<b>L1 tables</b>
<p>
The L1 tables, or <i>primary lookup</i> tables, contain the file offsets
to each <b>L2 table</b>, or <i>secondary lookup</i> table. Each L1 table
4-byte entry represents 256 track images and there is an L1 table for the base
file and each opened shadow file (if any). These tables are memory resident.
<p>
<b>The L2 cache</b>
<p>
The L2 tables, or <i>secondary lookup</i> tables contain the file offsets
and lengths of 256 track images. Each table is 2K in length. These tables
are cached in the <em>l2cache</em>, which is shared for all cckd devices.
The cache can contain 128 (512K) entries to 1024 entries (2M). Each cckd
device has one active l2cache entry implying that, architecturally speaking,
there can be no more than 1024 cckd devices. If this is a problem for
you then I'll buy you a beer ;-)
<p>
The size of the l2cache can be specified by a configuration statement or
changed by a hercules console command. If a cache miss occurs and no
inactive entries are found, then the cache is automatically extended
(unless the 1024 entry barrier would be crossed).
<p>
L2 tables are read but never written. Instead, as track images are
written, the individual 8-byte L2 entries are updated in the file.
<p>
<b>Writing</b>
<p>
Whenever the <code>ckdupdtrk</code> is called, indicating the active
track image has been updated, the <em>updated</em> flag bit is turned
on for the cache entry. However, the updated cache entries are never
scheduled to be written until a <em>cache flush</em> occurs (routine
<code>cckd_flush_cache</code>). A cache flush occurs whenever a cache
entry couldn't be <em>stolen</em> during read or at the beginning of
the <em>garbage collection</em> cycle.
<p>
When a <em>cache flush</em> occurs, all cache entries that are <em>updated</em>
(but not <em>active</em>) get the <em>write</em>-pending bit turned on
and one of the <b>writer</b> threads is signalled (or created).
<p>
The <em>writer</em> thread selects the oldest cache entry with the
<em>write</em>-pending bit on and changes the status to <em>writing</em>.
If there are other writes pending and other writer threads are waiting then
they are signalled. Otherwise if there are writes pending and the maximum
number of writer threads hasn't been created yet, then a new writer thread
is created.
<p>
The writer thread, because it performs track image compression, is cpu
intensive. Therefore, the writer thread resets its priority to 1 below
the cpu thread(s) (except under Cygwin (Windows)). In periods of
<em>write stress</em> then the level of compression is downgraded.
Write stress occurs when more than a quarter of the cache entries are
pending write, or when there are threads waiting for a cache entry, or
when a thread is waiting for this track image to be written. When a
track image is written under stress, a bit is turned on in the track
image so that the <em>garbage collector</em> can later rewrite the
track image properly compressed during a period of no stress.
<p>
A track image is always written to a new location in the file.
After a successful write, its L2 entry is updated and then the
space it previously occupied is freed.
<p>
The <em>writer</em> threads
<p>
<b>The Garbage Collector</b>
<p>
For some reason, this seems to be everyone's favorite routine.
For me, it has to do with the fact that the garbage man only has
to apparently work on Fridays ;-).
<p>
Simply, the garbage collector moves occupied spaces (track images
and level 2 tables) towards the beginning of the file while moving
free spaces towards the end of the file. When a free space reaches
the end of the file, then the file is <em>truncated</em>, that is,
reduced in size. Another important job the garbage collector performs
is to combine free spaces to make a larger free space that will be
more likely to satisfy a <i>get space</i> request. Finally, the
garbage collector will cause track images that were written under
stress to be rewritten (with optimal compression).
<p>
The garbage collector runs in a separate thread. There is a single
garbage collector for all cckd devices. The collector waits for
some number of seconds and then performs collection for each cckd
device in turn. The wait interval and the aggressiveness parameter
can be specified by a configuration file statement or by a hercules
console command.
<p>
The garbage collector algorithm simply selects an occupied space after
some free space, obtains a new space for that space, writes it to the
new space, updates the meta-data for that space to point to the new
space, frees the previously occupied space, and repeats the process
until some number of bytes have been moved. In other words, the collector
shifts the spaces around <i>coherently</i> such that in the event of
a crash then the space occupies at least one space in the file
(the original and possibly the new).
<p>
The garbage collector on each interval (or round ;-) flushes the cache
and waits for all pending writes to complete. Therefore, the collector
doesn't run while <em>write stress</em> is occurring.
<hr noshade>
<p><h3><a NAME="quickstart">Quick Start</a></h3>
The <i>ckd2cckd</i> utility can be used to create a new compressed CKD file from a
regular CKD file. Your disk images can be a combination of regular CKD files and
compressed CKD files. Simply specify the names of your new compressed ckd files in
<code>hercules.cnf</code> in place of the regular CKD file names.
<p>
You can also use the <i>cckddump</i> program on an os/390 system to build a
compressed CKD file from a real disk that can be transferred to your Hercules machine
and used right away.
<p>
<hr noshade>
<p><h3><a NAME="usingsfiles">Using Shadow Files</a></h3>
Shadow files enable you to make updates to <b>cckd</b> emulation files and
not worry about possibly corrupting your entire disk image. I strongly urge
those of you who use <b>cckd</b> to start using shadow files immediately and
change your base file to read-only. This, in turn, reduces the amount of
data you have to back up, increasing the amount of file savings cckd has to
offer. You can even change shadow files to read-only, as long as a new shadow
file can be created. You can also use shadow files for regular (non-cckd)
files.
<p>
Shadow files are automatically enabled for <b>cckd</b> files; you <em>must</em>
explicitly enable them for regular CKD files. To enable shadowing for a CKD
device, specify
<p><center>sf=<i>shadow_file_name</i></center><br>
on the device statement in the <i>hercules.cnf</i> file. <i>shadow_file_name</i>
should include a spot in the file name, similar to multiple CKD dasd files,
that can be used as a sequence number, for example, <b>sf=../mvs/shadows/mvsres_1.500</b>.
The naming convention substitutes the shadow file number (1 thru 8) on the
character preceding the period after the last slash, or the last character
if no period follows the last slash. Example <p>
<b>0500 3390 ../mvs/disks/mvsres.500 sf=../mvs/shadows/mvsres_1.500</b>
<p>
If you did not specify <i>sf=</i> for a cckd file, or you wish to change
the shadow file name for a cckd or regular file, but no shadow files are
in use, then you can issue the following command on the Hercules console:
<br><center>sf=<i>xxxx</i> &nbsp <i>shadow_file_name</i></center><br>
where <i>xxxx</i> is the device unit address. For example,
<b>sf=0500 ../mvs/shadows/mvsres_1.500</b>.
<p>
Specifying a <i>shadow_file_name</i> does not explicitly create a shadow file
if the base file or current shadow file
is able to be opened read-write. Otherwise, if the base file and all existing
shadow files (if any) can only be opened read-only, then a new shadow file is created.
<p>
To explicitly create a new shadow file, issue the following command on the Hercules console:
<p><center>sf+<i>xxxx</i></center><br>
where <i>xxxx</i> is the device unit address or <b>*</b> (for all eligible units).
For example, <b>sf+0500</b>.
All updated track images that haven't been written are written and the <i>current</i>
file is hardened. Note that if a lot of write activity is ocurring at the time the
<b>sf+</b> command is entered, then the exact state of the hardened file can not
be predicted. A new shadow file is created and all new writes are directed to it.
<p>
To remove the <i>current</i> shadow file, issue either of the following commands
on the Hercules console:
<p><center>sf-<i>xxxx</i></center>
<center>sf-<i>xxxx</i> nomerge</center><br>
where <i>xxxx</i> is the device unit address or <b>*</b> (for all eligible units).
For example, <b>sf-0500</b>.
If <b>nomerge</b> was not specified, then the <i>current</i> shadow file contents
are merged into the preceding shadow file or base file. The <i>current</i> shadow
file is deleted and the preceding shadow file or base file is made the <i>current</i>
file. If the preceding file is read-only, then an error message is issued.
If possible, you can make the preceding file read-write and re-issue the command.
Note that if <b>merge</b> is specified or implied, then the command may take some
amount of time depending on the size of the old <i>shadow</i> file.
<br>[<i>hmmm... note to myself -- if sf-xxxx nomerge was specified and preceding file is
read-only, then delete the current file and recreate it ??</i>]
<p>
To compress the current shadow file
issue the following command on the Hercules console:
<p><center>sfc<i>xxxx</i></center><br>
where <i>xxxx</i> is the device unit address or <b>*</b> (for all eligible units).
For example, <b>sfc0500</b>.
<p>
To display the status and statistics for a shadow-enabled file,
issue the following command on the Hercules console:
<p><center>sfd<i>xxxx</i></center><br>
where <i>xxxx</i> is the device unit address or <b>*</b> (for all eligible units).
For example, <b>sfd0500</b>.
This command displays status and statistics for the base file and all shadow files
representing the emulated dasd. The following data is displayed:
<table>
<tr><td>&nbsp <td valign="top"><b>size</b> <td>The total size of the file
<tr><td>&nbsp <td valign="top"><b>free</b> <td>The amount of free space in the file as a percentage
of the file size
<tr><td>&nbsp <td valign="top"><b>nbr</b> <td>The number of free spaces in a file
<tr><td>&nbsp <td valign="top"><b>st</b> <td>File open status - <b>ro</b>=read-only;
<b>rd</b>=read-only, but can be opened read-write;
<b>rw</b>=read-write
<tr><td>&nbsp <td valign="top"><b>reads</b> <td>Number of times <i>cckd_read_trkimg</i> performed
physical read i/o
<tr><td>&nbsp <td valign="top"><b>writes</b> <td>Number of times <i>cckd_write_trkimg</i> performed
physical write i/o
<tr><td>&nbsp <td valign="top"><b>l2reads</b> <td>Number of times a secondary lookup table was read
<tr><td>&nbsp <td valign="top"><b>hits</b> <td>Number of times <i>cckd_read_trk</i> found a track
image in the <i>track cache</i> when called by the
i/o thread
<tr><td>&nbsp <td valign="top"><b>switches</b><td>Number of times <i>cckd_read_trk</i> was called by
the i/o thread (<i>cckd_lseek</i>)
<tr><td>&nbsp <td valign="top"><b>readaheads</b><td>Number of track images read by the <i>readahead</i>
threads
<tr><td>&nbsp <td valign="top"><b>misses</b> <td>Number of track images read by the <i>readahead</i>
threads that were never referenced when the
<i>track cache</i> entry was <i>stolen</i>
</table>
<p>
<hr noshade>
<p><h3><a NAME="options">CKD Options</a></h3>
In this section I will attempt to document all the options that can be
specified for a CKD file (regular or compressed) in the <code>hercules.cnf</code>
file (or on the <i>attach</i> panel command).
<table border=1>
<th><td>Regular<td>cckd<td>Function
<tr><td valign="top" align="left"> syncio<br> syio<br>
nosyncio<br>nosyio<br><td align="center">X<td align="center"> X
<td>Specifies whether or not synchronous I/O will be attempted for the device.
For synchronous I/O, the channel program will be executed within the scope
of the <b>SIO</b> or <b>SSCH</b> instruction as long as all data referenced
by the channel program is already cached. If a ccw attempts to reference data
that is not cached, then the channel program is restarted asynchronously at
that ccw. Synchronous I/O reduces threading overhead, which may resut in a
performance boost. The default is <i>syncio</i> for cckd files and <i>nosyncio</i>
for regular ckd files.
<tr><td valign="top" align="left">lazywrite<br>nolazywrite<td align="center">X<td> &nbsp
<td>Data written to a cached track image will not be immediately written,
but will be written when a track switch occurs. Thus, only one write
will occur for a track image while it is the <i>active</i> image.
<i>nolazywrite</i>, the default, specifies that all writes are performed
when requested.
<tr><td valign="top" align="left"> fulltrackio<br> fulltrkio<br>ftio<br>
nofulltrackio<br>nofulltrkio<br>noftio<td align="center">X<td> &nbsp
<td>Specifies whether or not a full track will be read when a track switch
occurs. Subsequent reads to this track image will not cause any physical I/Os.
Turning on <i>fulltrackio</i> can considerably enhance CKD device response time.
However, if you are sharing CKD disk images with more than 1 instance of Hercules
at the same time when writes could occur, you should specify <i>nofulltrackio</i>.
The default is <i>fulltrackio</i>.
<tr><td valign="top" align="left">readonly<br>rdonly<br>ro<br><td align="center">X<td align="center"> X
<td>Causes the CKD file image to be opened <i>read-only</i>. Attempts to write to
the emulated device will cause an I/O error unless option <i>fakewrite</i> is
also specified. If <i>readonly</i> is specified for shadowed
file images, then the base file will be opened readonly and a shadow file will be
created if one doesn't exist.
<tr><td valign="top" align="left">fakewrite<br>fakewrt<br>fw<br>
<td align="center">X<td align="center"> X
<td>Writes to a <i>readonly</i> file will be considered successful even though no write
actually occurred. This option is only meaningful if <i>readonly</i> is also specified.
<i>Fakewrite</i> is ignored for shadowed file images.
<tr><td valign="top" align="left">cache=<i>n</i><td align="center">X<td align="center">X
<td>Specifies the number of track images that will be cached. The default is the number
of tracks per cylinder for the device. [For <b>cckd</b> files, the default is the
number of tracks per cylinder <i>plus</i> the number of readahead threads]. If
<i>nofulltrackio</i> is specified for a regular CKD file, then no caching occurs.
Caching <em>always</em> occurs for <b>cckd</b> files, although you can set the cache
value to 1.
<tr><td valign="top" align="left">sf=<i>file_name</i><td align="center">X<td align="center">X
<td>Specifies the name of the shadow file(s) for the emulated device. The name should have
a spot where the shadow file number can be inserted into the name (see
<a href="#usingsfiles">above</a>).
<tr><td valign="top" align="left">l2cache=<i>n</i><td align="center">* <td align="center">X
<td>Specifies the number of Secondary Lookup Tables (l2tabs) that will be cached for the
<b>cckd</b> or <i>shadowed</i> device. (Each l2tab is 2048 bytes). The default is 32.
<tr><td valign="top" align="left">dfwq=<i>n</i><td align="center">* <td align="center">X
<td>Specifies a threshold for the size of <i>deferred-write-queue</i> where processing will be
<i>throttled</i> if the size exceeds this number. Each entry in the <i>deferred-
write-queue</i> contains a pointer to a buffer whose size is <i>max-track-size</i>.
The default is 64.
<tr><td valign="top" align="left">wt=<i>n</i><td align="center">*<td align="center">X
<td>Specifies the time in seconds that an updated track image will be written after its
last reference. The <i>garbage collector</i> is responsible for scheduling these
old track images to be updated. The default is 60 seconds.
<tr><td valign="top" align="left">ra=<i>n</i><td align="center">*<td align="center">X
<td>Specifies the number of <i>readahead</i> threads (and number of tracks to be read ahead)
when sequential access to the emulated device is detected. That is, each track that
is read ahead of time is read by a different thread. A value between 0 and 9 can be
specified. Currently, readahead should be <em>disabled</em> for Windows32 due to
an unknown error involving the pthreads implementation. Default for WIN32 is 0
otherwise the default is 2.
<tr><td valign="top" align="left">dfw=<i>n</i><td align="center">*<td align="center">X
<td>Specifies the number of <i>deferred write</i> threads. A number between 1 and 9
may be specified; the default is 1. It has not been shown that specifying a greater
number results in any performance improvements.
</table>
<font size=-1><b> * </b>Option is only applicable if shadowing is active for the regular CKD file.
</font>
<p>
Generally, the defaults for all options (except <b>sf=</b>) should not be changed unless there
is an explicit reason for doing so. If you use <b>cckd</b> files, then I strongly recommend
that you start using <i>shadow</i> files. If you use regular CKD files, then you can use
<i>shadow</i> files if you want to gain the <i>snapshot</i> benefit .
<hr noshade>
<p><h3><a NAME="utilities">Utilities</a></h3>
<a NAME="ckd2cckd">
<li><b>ckd2cckd</b> <i>[options] source-file target-file</i>
<ul><li><small><b>Description</b></small> Copies a regular CKD Dasd emulation
file to a compressed CKD Dasd emulation file. The target
file cannot previously exist. If the emulated Dasd device
is in more than 1 file then specify the <em>first</em> file.
After the copy completes, the target file contains no
free space, imbedded or otherwise.
<li><small><b>Options</b></small>
<ul><li><b>-c</b>ompress <i>n</i><br>Compression Algorithm
<ul><li><b>0</b> don't compress
<li><b>1</b> compress using zlib
<li><b>2</b> compress using bzip2
</ul>
<li><b>-d</b>ontcompress <i>n</i><br>Same as <i>-compress 0</i>
<li><b>-m</b>axerrs <i>errs</i><br>Maximum number of errors
that can occur before the copy is terminated;
if 0 then errors are ignored. Default is 5.
<li><b>-n</b>ofudge<br>[deprecated]
<li><b>-q</b>uiet<br>Quiet mode; don't display status
<li><b>-z</b> <i>parm</i><br>Parameter passed to compression
<br>
<br>zlib compression level:
<br>0 = no compression
<br>1=fastest ... 9=best
<br>
<br>bzip2 blockSize100k value:
<br>1=fastest ... 9=best
</ul>
</ul>
</ul>
<a NAME="cckd2ckd">
<li><b>cckd2ckd</b> <i>[options] source-file target-file</i>
<ul><li><small><b>Description</b></small> Copies a compressed CKD Dasd emulation
file to a regular CKD Dasd emulation file. The target
file cannot previously exist. More than 1 target file may
be created.
<li><small><b>Options</b></small>
<ul><li><b>-c</b>yls <i>n</i><br>Number of cylinders to copy
if the entire file isn't to be copied. If <b>0</b>
then only the number of cylinders in use are copied.
<li><b>-m</b>axerrs <i>errs</i><br>Maximum number of errors
that can occur before the copy is terminated;
if 0 then errors are ignored. Default is 5.
<li><b>-q</b>uiet<br>Quiet mode; don't display status
<li><b>-v</b>alidate<br>Validate track images [default]
<li><b>-n</b>ovalidate<br>Don't Validate track images
</ul>
</ul>
</ul>
<a NAME="cckdcdsk">
<li><b>cckdcdsk</b> <i>[-level] file-name</i>
<ul><li><small><b>Description</b></small> Performs compressed or shadowed CKD Dasd emulation
file integrity verification and recovery and repair.
<li><small><b>Options</b></small>
<ul><li>-<i>level</i><br>A digit 0, 1 or 3 that specifies
the level of checking. The higher the level, the
longer the integrity check takes.
<ul><li><b>0</b> Minimal checking. Device headers are verified,
free space is verified, primary lookup table and secondary
lookup tables are verified.
<li><b>1</b> Same checks as level 0 plus all 5-byte track headers
are verified.
<li><b>3</b> Same checks as level 1 plus all track images are
read, uncompressed and verified.
</ul>
</ul>
</ul>
</ul>
<a NAME="cckdcomp">
<li><b>cckdcomp</b> <i>[-level] file-name</i>
<ul><li><small><b>Description</b></small> Removes all free space from a compressed
or shadow CKD Dasd emulation file. (Compresses or compacts a cckd
file ... your choice!).
If <i>level</i> is specified, then <b>cckdcdsk</b> is called first
with the specified level; this is a short-hand method to call both
functions in one utility call.
<li><small><b>Options</b></small>
<ul><li>-<i>level</i><br>A digit 0, 1 or 3 that specifies
the level of checking. The higher the level, the
longer the integrity check takes.
<ul><li><b>0</b> Minimal checking. Device headers are verified,
free space is verified, primary lookup table and secondary
lookup tables are verified.
<li><b>1</b> Same checks as level 0 plus all 5-byte track headers
are verified.
<li><b>3</b> Same checks as level 1 plus all track images are
read, uncompressed and verified.
</ul>
</ul>
</ul>
</ul>
<a NAME="cckdfix">
<li><b>cckdfix</b> <i>file-name</i>
<ul><li><small><b>Description</b></small> This is a skeleton program that is
not compiled during make. It can be edited to change/repair
the device headers.
<li><small><b>Compiling</b></small> Enter `<i>cc -o cckdfix -DARCH=390 cckdfix.c</i>'
to compile and link the edited program.
</ul>
<li><b>cckddump</b>
<ul><li><small><b>Description</b></small> This is an os/390 hlasm (High Level
Assembler) program that will create a compressed CKD emulation file
from an actual CKD device. See <a href="#cckddump">below</a> for
a description on how to build and run this program.
</ul>
</ul>
<hr noshade>
<p><h3><a NAME="faq">FAQ</a></h3>
<table>
<tr><td valign="top"><b>Q.</b><td>
What devices are supported ?
<tr><td valign="top"><b>A.</b><td>
2311, 2314, 3330, 3340, 3350, 3375, 3380, 3390 and 9345.
<br><br>
<tr><td valign="top"><b>Q.</b><td>
Is a 3390 model 9 supported ?
<tr><td valign="top"><b>A.</b><td>
Yes, maybe. A 3390-9 is a little over 8G in size.
A cckd file cannot exceed 2G on a system that does
not support large files, otherwise it cannot exceed
4G. If the data on the 3390-9 compresses to below
these limits then the answer is Yes.
<br><br>
<tr><td valign="top"><b>Q.</b><td>
How can I get rid of the free space in my files ?
<tr><td valign="top"><b>A.</b><td>
Once the total amount of free space falls below 6% of
the total file size, the garbage collector is not very
aggressive about eliminating free space. To remove
all free space from the file while Hercules is running
use the <b>sfc</b> console command. See
<a href="#usingsfiles">Using Shadow Files</a> above.
Otherwise, you can use the <b>cckdcomp</b> utility.
See <a href="#utilities">Utilities</a> above.
<br><br>
<tr><td valign="top"><b>Q.</b><td>
How can I display the space statistics for a compressed
file ?
<tr><td valign="top"><b>A.</b><td>
The statistics are displayed when the compressed file
is opened. Currently, there is no supplied method to
display these statistics at any other time. However,
it shouldn't be too hard to write a shell script
(similar to <code>dasdlist</code>) to display these
statistics. The statistics are contained in the
<code>CCKDDASD_DEVHDR</code> which is at offset 512
in the compressed file; the header is mapped in
<code>hercules.h</code>.
<br><br>
<tr><td valign="top"><b>Q.</b><td>
What is a "null track" anyway ?
<tr><td valign="top"><b>A.</b><td>
The term "null track" is just something I made up. It is
what is returned when a zero offset is found in either the
primary or secondary lookup table for the track. It contains
the folllowing fields:
<table>
<tr><td><code>0CCHH</code></td><td>Home address</td>
<tr><td><code>CCHH0008 00000000</code></td><td>standard R0</td>
<tr><td><code>CCHH1000</code></td><td>end-of-file marker</td>
<tr><td><code>ffffffff</code></td><td>end-of-track marker</td>
</table>
When a null track is written, space previously occupied by
the track is freed and the offset in the secondary lookup table
is set to zero. If all offsets in the secondary lookup table
are zero, then the secondary lookup table is freed and the
primary lookup table entry is zeroed.
<br><br>
<tr><td valign="top"><b>Q.</b><td>
I want to try bzip2 but I'm getting compiler errors.
What am I doing wrong ?
<tr><td valign="top"><b>A.</b><td>
Probably bzip2 is not installed or is not installed
properly. You can obtain bzip2 from
<a href="http://sourceware.cygnus.com/bzip2/">here</a>.
If bzip2 is installed, then you need to find the directory
where <code>bzlib.h</code> is installed and the
directory where <code>libbz2.a</code> is installed.
You can then add "-I <i>bzlib.h-directory</i>" to the
CFLAGS in the make file and add "-L <i>libbz2.a-directory</i>"
to the LFLAGS.
<br><br>
<tr><td valign="top"><b>Q.</b><td>
Which is better, zlib or bzip2 ?
<tr><td valign="top"><b>A.</b><td>
This is a religious question. I have no actual preference,
I just wanted to make a choice available.
<br><br>
<tr><td valign="top"><b>Q.</b><td>
Can other compression programs be used ?
<tr><td valign="top"><b>A.</b><td>
Yes. The program is architecturally structured so that other
compression algorithms can be added rather painlessly. This
will require, of course, an update to the source.
<br><br>
<tr><td valign="top"><b>Q.</b><td>
Can this compression scheme be used for FBA devices too ?
<tr><td valign="top"><b>A.</b><td>
I have not worked with FBA devices for over 20 years.
However, it seems to me that a similar program for FBA
devices should be simpler than this program for CKD devices
(none of those count/key/data fields mucking everything
up). Since an FBA block is 512 bytes, it might not
be efficient to have each block compressed individually;
it might be better to compress blocks in 32K or 64K chunks.
If someone asks very nicely, I may consider looking into it;-)
<br><br>
</table>
<hr noshade>
<p><h3><a NAME="changes">Changes</a></h3>
<ul>
<li>0.2.0
<ul>
<li>This release greatly enhances the stability of cckd files.
<li>Free spaces are read at file open time, maintained in storage,
and written at file close time. If a file is not successfully
closed, then free spaces are easily recovered by the chkdsk
function when the file is opened next.
<li>Imbedded free space is deprecated. Because the free space chain
is now in storage, the overhead required to keep an updated track
image at its same location in the file is no longer necessary;
the penalty for traversing the free space chain to find a new location
is greatly reduced. Also, because a free space header is no longer
written at the beginning of a freed space when it is freed, that space
is eligible for recovery in the event of a failure.
<li>Garbage collection is more efficient because it can combine the
most free spaces per iteration now that the penalty for scanning
free space is gone.
<li>Secondary lookup tables (or l2tabs) are now cached. Most overhead
I/O for cckd files is now eliminated.
<li>Support for read-only files is added.
<li>Utility <i>cckdcomp</i> is provided to remove all free space from
a cckd file.
</ul>
<li>0.2.1
<ul>
<li>The concept of shadow files is implemented, which logically performs
a snapshot function.
<li>Windows 32 support is enabled.
<li>Seems like there should be more but I can't mush my brain much farther.
Some new options have been added so #defines in hercules.cnf don't have
to be changed; overflow tracks are supported (I hope) -- Thanks Valery!!
</ul>
</ul>
<hr noshade>
<p><h3><a NAME="bugs">BUGS</a></h3>
This code is absolutely bug free; if you encounter any problems then
it must be a personal problem and you've done something wrong. Also,
there are no enhancements that can be made because I've already thought
of them all and implemented them. By the way, I have some prime soon to be
ocean front property in Tennessee to sell to the highest bidder;-)
<hr noshade>
<p><h3><a NAME="cckddump">cckddump os/390 hlasm program</a></h3>
The cckddump program (supplied in file <code>cckddump.hla</code>) is an
os/390 assembler language program that creates a compressed CKD Dasd emulation
file from a real DASD volume. This program must be APF-authorized since
it modifies the DEB to be able to read all tracks from the real device.
The program executes 16 or so instructions while in supervisor state/key 0;
otherwise the program runs entirely in problem state/key 8.
It is not the prettiest assembler language program I've ever written, and
there are plenty of enhancements that I originally intended to put into the
program that I haven't yet; once I got the program working good enough, I
spent the rest of my time writing the fun stuff, the Hercules part.
<p>The real CKD Dasd volume that is dumped must be an ECKD device (ie support
'Locate Record' and 'Read Track' CCWs); this shouldn't be a problem because
I don't think any os/390 release supports a non-ECKD device. The output file
must be a DASD file; its characteristics are LRECL=4096, BLKSIZE=4096, RECFM=F.
The program only dumps allocated tracks (plus track 0) and only dumps tracks up
to DS1LSTAR for DSORG=PS and DSORG=PO files. The program will call zlib
to compress the track images if the zlib routines have been linked with the
program; however, I don't think the program will be advantageous if it can't
call zlib.
<p>
<h4>Preparing zlib</h4>
<ul>
<li>zlib can be obtained from
<a href="http://www.info-zip.org/pub/infozip/zlib/"><b>here</b></a>
<li>Copy or ftp the *.c files to a LRECL=255,RECFM=VB partitioned dataset;
here we will call the dataset <i>prefix</i>.ZLIB.C
<li>Similarly, copy or ftp the *.h files to a LRECL=255,RECFM=VB partitioned
dataset; we'll call it <i>prefix</i>.ZLIB.H
<li>Edit member <i>prefix</i>.ZLIB.H(ZCONF). Near the bottom, before the 2nd
to last <code>#endif</code>, add the following lines:<br><pre>
# pragma map(compress,"COMPRESS")
# pragma map(compress2,"COMPRES2")
# pragma map(uncompress,"UNCOMPRE")
</pre>
<li>Allocate an object partitioned dataset <i>prefix</i>.ZLIB.OBJ;
LRECL=80,BLKSIZE=3200,RECFM=FB.<br>Submit the following job to compile zlib:
<pre>
// JOB
//CC JCLLIB ORDER=(CBC.SCBCPRC)
//*
//ADLER32 EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(ADLER32)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(ADLER32),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//COMPRESS EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(COMPRESS)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(COMPRESS),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//CRC32 EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(CRC32)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(CRC32),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//DEFLATE EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(DEFLATE)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(DEFLATE),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//EXAMPLE EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(EXAMPLE)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(EXAMPLE),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//GZIO EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(GZIO)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(GZIO),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//INFBLOCK EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(INFBLOCK)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(INFBLOCK),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//INFCODES EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(INFCODES)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(INFCODES),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//INFFAST EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(INFFAST)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(INFFAST),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//INFLATE EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(INFLATE)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(INFLATE),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//INFTREES EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(INFTREES)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(INFTREES),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//INFUTIL EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(INFUTIL)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(INFUTIL),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//TREES EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(TREES)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(TREES),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//UNCOMPR EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(UNCOMPR)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(UNCOMPR),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
//*
//ZUTIL EXEC EDCC,INFILE='<i>prefix</i>.ZLIB.C(ZUTIL)',
// CPARM='RENT,LIST,SOURCE,LONGNAME,AGG,OPT(2)',
// OUTFILE='<i>prefix</i>.ZLIB.OBJ(ZUTIL),DISP=SHR'
//USERLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.H
</pre>
<li>Prelink zlib using the following job:
<pre>
// JOB
//PLKED EXEC PGM=EDCPRLK
//SYSMSGS DD DISP=SHR,DSN=CEE.SCEEMSGP(EDCPMSGE)
//SYSLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ
// DD DISP=SHR,DSN=CEE.SCEEOBJ
//SYSOUT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSIN DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(ADLER32)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(COMPRESS)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(CRC32)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(DEFLATE)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(GZIO)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(INFBLOCK)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(INFCODES)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(INFFAST)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(INFLATE)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(INFTREES)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(INFUTIL)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(TREES)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(UNCOMPR)
// DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(ZUTIL)
//SYSMOD DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ(ZLIB)
</pre>
</ul>
<h4>Assemble and linkedit cckddump</h4>
<ul>
<li>Allocate partitioned dataset <i>prefix.cckddump.source</i>;
LRECL=80,RECFM=FB and copy or ftp file cckddump.hla
<li>Submit the following job:
<pre>
// JOB
//C EXEC PGM=ASMA90
//SYSLIB DD DISP=SHR,DSN=SYS1.MACLIB
// DD DISP=SHR,DSN=SYS1.MODGEN
//SYSPRINT DD SYSOUT=*
//SYSIN DD DISP=SHR,DSN=<i>prefix.cckddump.source</i>(CCKDDUMP)
//SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSLIN DD DISP=(,PASS),DSN=&&OBJ,UNIT=SYSDA,SPACE=(CYL,(1,1))
// LRECL=80,BLKSIZE=3200,RECFM=FB
//L EXEC PGM=HEWL
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSLIB DD DISP=SHR,DSN=CEE.SCEESPC
// DD DISP=SHR,DSN=CEE.SCEELKED
//ZLIB DD DISP=SHR,DSN=<i>prefix</i>.ZLIB.OBJ
//SYSLMOD DD DISP=SHR,DSN=<i>apfauth.load</i>
//SYSLIN DD DISP=(OLD,DELETE),DSN=&&OBJ
// DD *
INCLUDE ZLIB(ZLIB)
INCLUDE SYSLIB(EDCXHOTL)
INCLUDE SYSLIB(EDCXHOTU)
INCLUDE SYSLIB(EDCXHOTT)
ORDER MAIN(P)
ENTRY MAIN
SETCODE AC(1)
NAME CCKDDUMP(R)
</pre>
<li>The assemble step (C) should complete with condition code 4.
This is a `feature' due to the way IBM macro IECSDSL1 is coded.
The linkedit step (L) should complete with condition code 0.
</ul>
<h4>Executing cckddump</h4>
<ul>
<li>The volume to be dumped is identified by the SYSUT1 DD statement;
the output compressed CKD Dasd emulation file is identified by the
SYSUT2 DD statement.
<li>Submit a job similar to the following:
<pre>
// JOB
//S1 EXEC PGM=CCKDDUMP
//STEPLIB DD DISP=SHR,DSN=<i>apfauth.load</i>
//SYSPRINT DD SYSOUT=*,RECFM=VB,LRECL=255,BLKSIZE=4096
//SYSUT1 DD DISP=OLD,UNIT=SYSDA,VOL=SER=<i>volser</i>
//SYSUT2 DD DISP=(,CATLG),DSN=<i>prefix.volser.cckd</i>,
// UNIT=SYSDA,SPACE=(TRK,(7500,1500),RLSE),
// LRECL=4096,BLKSIZE=4096,RECFM=F
</pre>
</ul>
<h4>Make the file available to Hercules</h4>
<ul>
<li>Copy or ftp <i>prefix.volser.cckd</i> in <b>binary</b> mode
to your platform running Hercules.
</ul>
<hr noshade>
<p><h3><a NAME="feedback">Feedback</a></h3>
Questions ?? Problems ?? Comments ?? Suggestions ?? Corrections ?? Bugs ??<br>
Let me know at <a href="mailto:gsmith@nc.rr.com"><em>gsmith</em>&#064;<em>nc.rr.com</em></a>
<p>
greg smith
<p><small>Last updated 1 May 2002</small>
</BODY>
</HTML>