{"id":162,"date":"2013-02-07T20:14:30","date_gmt":"2013-02-08T02:14:30","guid":{"rendered":"http:\/\/tommysprinkle.com\/mvssp\/?p=162"},"modified":"2013-06-18T20:16:35","modified_gmt":"2013-06-19T01:16:35","slug":"in-search-of-eof","status":"publish","type":"post","link":"https:\/\/tommysprinkle.com\/mvssp\/2013\/02\/07\/in-search-of-eof\/","title":{"rendered":"In Search of EOF"},"content":{"rendered":"<p>When I first ran the EXCP01 program I expected the EOF to be written on the same track as the data blocks.\u00a0 There is no reason the EOF could not be contained on the same track.\u00a0 Over the years I have learned that EOF marks don&#8217;t always appear exactly where you might expect to find them.\u00a0 In fact sometimes there is no EOF record.\u00a0 If all tracks in all extents are full and there is no room for an EOF record then end of file is assumed to occur after the last block on the last track.\u00a0 What we do see from our first example is that just because we read a short track (a track that could contain more blocks) it doesn&#8217;t mean we shouldn&#8217;t continue on with the next track.<\/p>\n<p>Here we will modify the EXCP01 program to continue reading until the EOF record is encountered.\u00a0 After a great amount of time and consideration I have decided to name it EXCP02.\u00a0 See the downloads for the full program.<\/p>\n<h2>Track Balance<\/h2>\n<p>Before continuing we need to consider how many blocks will fit on a track.\u00a0 I normally think of a 3350 as having a track size of 19,069 bytes.\u00a0 This is a number that has been etched into my brain.\u00a0 This is not the track size, it is actually the size of the largest non-keyed block you can write on a track.\u00a0 The 3350 track size is 19254.\u00a0 This leads to the next question &#8211; why the difference?\u00a0 To answer the question we need to go back to the physical layout of a track.<\/p>\n<pre>[HA] [R0-C] [R0-D] [R1-C] [R1-K] [R1-D] ... [Rn-C] [Rn-K] [Rn-D]<\/pre>\n<p>A track always begins with the Home Address record followed by the special Record Zero. The read of the track is used for data records which consist of a Count area, an optional Key area, and a Data area. What we failed to show was the gaps between the records. A gap is some physical space between records that is necessary for the electronics of the read\/write heads to function.<\/p>\n<pre>^Ix^ {G1} [HA] {G2} [R0-C] {G2} [R0-D] {G3} ---&gt;\r\n[R1-C] {G2} [R1-K] {G2} [R1-D] {G3} ... ---&gt;\r\n[Rn-C] {G2} [Rn-K] {G2} [Rn-D] {G4}<\/pre>\n<p>Here is a more detailed picture of a track.\u00a0 It begins with the Index Mark.\u00a0 Next is a Gap-1 that occurs between the index mark and the home address.\u00a0 Next is the Home Address which is followed by a Gap-2.\u00a0 A Gap-2 occurs inbetween the count, key, and data areas of a record.\u00a0 A Gap-3 occurs inbetween records (after a data area and before the next count area).\u00a0 Finally a Gap-4 occurs after the last data record on the track.\u00a0 Gap-1, Gap-2, and Gap-3 all have specific sizes.\u00a0 Gap-4 is always as large as the unused space after the last block.<\/p>\n<p>When we are writing blocks to a track we need to remember that we must account for the size of the gaps in addition to the size of the blocks.\u00a0 Earlier I said the 3350 track size was 19,254.\u00a0 Actually that is the size after accounting for the Home Address, Record Zero, and their associated gaps.\u00a0 For non-keyed records there is a overhad size of 185 bytes for each record.\u00a0 This 185 bytes is for the count area and gaps.\u00a0 If we take our useable track size (19,254) and subtract the overhead for one block (185) we get the maximum record size 19,069.\u00a0 For keyed blocks we have to add in the key length and use an overhead of 267 to account for the additional gap.<\/p>\n<p>Now we can calculate how much space remains on a track as we write blocks to it.\u00a0 Here is an example using 4,096 blocks with no keys.<\/p>\n<pre><b>\r\nTrackBal  Blocksize Overhead New TrkBal<\/b>\r\n 19,254      -4096     -185    14,973\r\n 14,973      -4096     -185    10,692\r\n 10,692      -4096     -185     6,411\r\n  6,411      -4096     -185     2,130\r\n  2,130         *        *        *<\/pre>\n<p>We start with our maximum useable track size, subtract out the blocksize and overhead and get a new Track Balance of 14,973.\u00a0 We continue until we get a result less than the blocksize + overhead and at that point no additional records will fit on the track.\u00a0 Here we find that four 4K blocks will fit on one 3350 track.\u00a0 For fixed length blocks we can do a one-time calcuation.\u00a0 For variable length blocks we must calculate as we go.<\/p>\n<h2>Reading A Block of Unknown Blocksize<\/h2>\n<p>In our first program we read blocks with a blocksize of 80.\u00a0 We knew what the blocksize was and was able to specify it in our CCW.\u00a0 What if we don&#8217;t know the size of the block?\u00a0 We can issue a read for a size greater than the largest block (19,069 for a 3350) and see how much data we get back.\u00a0 The only problem is if the size of the block read does not match the size specified in the Read CCW we will get an Incorrect Length exceptional condition.\u00a0 We can cause the channel to ignore this condition by setting the Supress Length Indication (SLI) bit our Read CCW.\u00a0 When the read completes the residual length in the CSW will tell us the number of bytes NOT transfered by the Read command.\u00a0 In other words it will contain the value of the CCW count minus the size of the data transfered.\u00a0 We can use this number to calculate how many bytes were read.\u00a0 We simply subtract the residual count from the CCW length value.<\/p>\n<pre>         DS    0D                                   \r\nCCWSRCH  DC    X'31',AL3(IOBSRCH),X'40',X'00',AL2(5)\r\nCCWTIC   DC    X'08',AL3(CCWSRCH),X'40',X'00',AL2(0)\r\nCCWREAD  DC    X'06',AL3(*-*),X'20',X'00',AL2(32768)<\/pre>\n<p>Here is our updated CCW channel program. Notice I set the size on the Read CCW to 32,768. For a 3350 we can use any number greater than 19,069. Also note that I used zero A(*-*) for the address in the Reac CCW. This is because I will getmain a 32K buffer and update the CCW with the address returned from GETMAIN.<\/p>\n<pre>         GETMAIN R,LV=32768        \r\n*                                  \r\n         STCM  R1,B'0111',CCWREAD+1<\/pre>\n<p>Now all that is left is to calculate the actual size of the record we just read.<\/p>\n<pre>         SLR   R1,R1                                             \r\n         ICM   R1,B'0011',CCWREAD+6         DATA LENGTH FROM CCW \r\n         SLR   R2,R2                                             \r\n         ICM   R2,B'0011',IOBRESDL          RESIDUAL LEN FROM CSW\r\n         SR    R1,R2                        CALC BYTES READ<\/pre>\n<p>And now we can format and print this value as part of our IOB formatting.<\/p>\n<pre>\r\nREAD020  DS    0H                                          \r\n         CLI   IOBECBAD,X'41'     DEVICE STATUS AVAILABLE ?\r\n         BNE   EXIT               NO - BRANCH              \r\n*                                                          \r\n         TM    IOBCSWFL,X'02'     UNIT CHECK ?             \r\n         BNO   EXIT                 NO - BRANCH            \r\n*                                                          \r\n         TM    IOBSENSE+1,X'08'   NO RECORD FOUND          \r\n         BNO   EXIT                 NO - BRANCH            \r\n*                                                          \r\n         LA    R7,1(,R7)          NEXT TRACK               \r\n         B     READ000            LOOP BACK TO READ        <\/pre>\n<p>Here we modify our code to deal with a No Record Found condition.  If we get a Unit Check we look at the sense bytes to see if it was a No Reocrd Found.  If so we increment our relative track number and loop back to process the next track.  If the exception is anything else we end execution.<\/p>\n<p>I wanted to use a larger blocksize for testing.\u00a0 I could still use blocked records with IEBGENER but IEBDG makes more sense.<\/p>\n<pre>\/\/IEBDG  EXEC  PGM=IEBDG                               \r\n\/\/SYSPRINT DD  SYSOUT=*                                \r\n\/\/SEQOUT   DD  DSN=TCS3.EXCP02.DATA,                   \r\n\/\/         DISP=(NEW,CATLG),                           \r\n\/\/         UNIT=SYSDA,VOL=SER=WORK01,                  \r\n\/\/         SPACE=(CYL,(2,2)),                          \r\n\/\/         DCB=(BLKSIZE=4096,LRECL=4096,RECFM=F)       \r\n\/\/SYSIN    DD  *                                       \r\n  DSD OUTPUT=(SEQOUT)                                  \r\n  FD NAME=FLD1,LENGTH=8,STARTLOC=1,FORMAT=AL,ACTION=TL \r\n  CREATE QUANTITY=12,NAME=(FLD1),FILL=X'00'            \r\n  END<\/pre>\n<p>bla<\/p>\n<pre>                                                                      \r\nI\/O REQUEST                                                           \r\n   COMPLETION CODE = 7F                                               \r\n   CSW = 095EC0 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 7000 (28,672) \r\n   --- DEVICE STATUS  = CE DE                                         \r\n   --- CHANNEL STATUS =                                               \r\n   SENSE = 0000                                                       \r\n   SEEK = 00000001AE000001                                            \r\n   BYTES READ = 1000 ( 4,096)                                         \r\n\r\nI\/O REQUEST                                                           \r\n   COMPLETION CODE = 7F                                               \r\n   CSW = 095EC0 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 7000 (28,672) \r\n   --- DEVICE STATUS  = CE DE                                         \r\n   --- CHANNEL STATUS =                                               \r\n   SENSE = 0000                                                       \r\n   SEEK = 00000001AE000002                                            \r\n   BYTES READ = 1000 ( 4,096)                                         \r\n\r\nI\/O REQUEST                                                           \r\n   COMPLETION CODE = 7F                                               \r\n   CSW = 095EC0 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 7000 (28,672) \r\n   --- DEVICE STATUS  = CE DE                                         \r\n   --- CHANNEL STATUS =                                               \r\n   SENSE = 0000                                                       \r\n   SEEK = 00000001AE000003                                            \r\n   BYTES READ = 1000 ( 4,096)                                         \r\n\r\nI\/O REQUEST                                                           \r\n   COMPLETION CODE = 7F                                               \r\n   CSW = 095EC0 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 7000 (28,672) \r\n   --- DEVICE STATUS  = CE DE                                         \r\n   --- CHANNEL STATUS =                                               \r\n   SENSE = 0000                                                       \r\n   SEEK = 00000001AE000004                                            \r\n   BYTES READ = 1000 ( 4,096)                                         \r\n\r\nI\/O REQUEST                                                           \r\n   COMPLETION CODE = 41                                               \r\n   CSW = 095EB0 DEV STAT = 0E CHAN STAT = 40 RESIDUAL = 0005 (     5) \r\n   --- DEVICE STATUS  = CE DE UC                                      \r\n   --- CHANNEL STATUS = IL                                            \r\n   SENSE = 0008                                                       \r\n   SEEK = 00000001AE000005                                            \r\n\r\nI\/O REQUEST                                                           \r\n   COMPLETION CODE = 7F                                               \r\n   CSW = 095EC0 DEV STAT = 0C CHAN STAT = 00 RESIDUAL = 7000 (28,672) \r\n   --- DEVICE STATUS  = CE DE                                         \r\n   --- CHANNEL STATUS =                                               \r\n   SENSE = 0000                                                       \r\n   SEEK = 00000001AE000101                                            \r\n   BYTES READ = 1000 ( 4,096)                                         \r\n\r\nI\/O REQUEST                                                           \r\n   COMPLETION CODE = 41                                               \r\n   CSW = 095EB0 DEV STAT = 0E CHAN STAT = 40 RESIDUAL = 0005 (     5) \r\n   --- DEVICE STATUS  = CE DE UC                                      \r\n   --- CHANNEL STATUS = IL                                            \r\n   SENSE = 0008                                                       \r\n   SEEK = 00000001AE000102                                            \r\n\r\nI\/O REQUEST                                                           \r\n   COMPLETION CODE = 41                                              \r\n   CSW = 095EC0 DEV STAT = 0D CHAN STAT = 00 RESIDUAL = 8000 (32,768)\r\n   --- DEVICE STATUS  = CE DE UE                                     \r\n   --- CHANNEL STATUS =                                              \r\n   SENSE = 0000                                                      \r\n   SEEK = 00000001AE000201<\/pre>\n<p>Here is a summary of what happened &#8211;<\/p>\n<ul>\n<li>Four records were successfully read from Cyl=01A3 Trk=0000<\/li>\n<li>The attempt to read a fifth record terminated with No Record Found<\/li>\n<li>We incremented the track to Cyl=01A3 Trk=0001<\/li>\n<li>We successfully read one record<\/li>\n<li>The attempt to read a second record terminated with No Record Found<\/li>\n<li>We incremented the track to Cyl=01A3 Trk=0002<\/li>\n<li>The attempt to read the first record terminated with Unit Exception<\/li>\n<\/ul>\n<p>Unit Execption indicates a record with a data length of zero was read which indicates a End Of File.\u00a0 We are successful in our quest to find the EOF record!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When I first ran the EXCP01 program I expected the EOF to be written on the same track as the data blocks.\u00a0 There is no reason the EOF could not be contained on the same track.\u00a0 Over the years I have learned that EOF marks don&#8217;t always appear exactly where you might expect to find &#8230;<\/p>\n<p><a href=\"https:\/\/tommysprinkle.com\/mvssp\/2013\/02\/07\/in-search-of-eof\/\" class=\"more-link\">Continue reading &lsquo;In Search of EOF&rsquo; &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[31],"tags":[],"class_list":["post-162","post","type-post","status-publish","format-standard","hentry","category-in-search-of-eof"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3x7AW-2C","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/posts\/162","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/comments?post=162"}],"version-history":[{"count":15,"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/posts\/162\/revisions"}],"predecessor-version":[{"id":178,"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/posts\/162\/revisions\/178"}],"wp:attachment":[{"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/media?parent=162"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/categories?post=162"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/tags?post=162"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}