{"id":132,"date":"2013-02-03T10:13:40","date_gmt":"2013-02-03T16:13:40","guid":{"rendered":"http:\/\/tommysprinkle.com\/mvssp\/?p=132"},"modified":"2013-06-24T21:07:06","modified_gmt":"2013-06-25T02:07:06","slug":"dasd-io-programming","status":"publish","type":"post","link":"https:\/\/tommysprinkle.com\/mvssp\/2013\/02\/03\/dasd-io-programming\/","title":{"rendered":"DASD I\/O Programming"},"content":{"rendered":"<p>Now we can look specifically at CCW programming to access DASD devices.\u00a0 For this discussion I will work with the 3350 device.\u00a0 The concepts here can be applied to other types of DASD devices.\u00a0 The reason I am using the 3350 is because this device is natively supported in MVS 3.8 and does not require any additional usermod support.\u00a0 It is also the device I have used the most over the years.<\/p>\n<p>In programming for DASD devices we have to think about how the devices were originally constructed.\u00a0 There were a series of round platters stacked on about the other.\u00a0 There was an access arm the contained read\/write heads with one head for each platter.\u00a0 The arm could move inward and outward from the center of the platter to the outer edge in specific increments.\u00a0 Each of these increments defined a circular track at some offset on the platter.\u00a0 The collection of tracks (one for each platter) made up a cylinder.\u00a0 If you are not familiar with this concept there are sevearl sources of documents that explain it better using pictures.<\/p>\n<p>With a basic understanding of the structure of the DASD device we can understand how a specific location (data record) is referenced.\u00a0 Each track has a unique address that consists of a two byte cylinder address and a two byte head address.\u00a0 These addresses are fixed by the physical layout and construction of the device.\u00a0 Each track may contain a variable number of data records based on the size of the records and the size of the track.\u00a0 Therefore to identify a specific record we have an address in the form CCHHR (2 byte cylinder address, 2 byte head address, 1 byte record address).<\/p>\n<p>Each track contains some special records that are created when the device is formatted and normally there is no need to accees them.\u00a0 These include the Home Address (HA) and Record Zero.\u00a0 Data records begin with record number one.<\/p>\n<p>The 3350 has 555 cylinders.\u00a0 Each cylinder has 19 tracks (heads).\u00a0 Each track has a maximum capacity of 19,069 bytes.\u00a0 This infomation will be needed when writing CCWs to access the device.\u00a0 This will be different for different types of DASD devices.<\/p>\n<p>To read a specific record we have to first position the heads to the correct cylinder this is done with the SEEK command.\u00a0 The command code for SEEK is X&#8217;07&#8217; and it expects six bytes of data containing the seek address in the format 00CCHH where 00 is two bytes of binary zeros, CC is the two byte cylinder address and HH is the two byte head address.<\/p>\n<pre>SEEKCCW  DC    X'07',AL3(SEEKADDR),X'40',x'00',AL2(6)\r\n            :\r\n            :\r\n*                  C C H H \r\nSEEKADDR DC    X'0001000001'    Cyl=256, H=1<\/pre>\n<p>This CCW command would cause the heads to be positioned at cylinder 256 and select the head for track one.\u00a0 Notice that the X&#8217;40&#8217; flag bit is set indicating Command Chaining.\u00a0 Simply seeking to a specific cylinder would not accomplish much so we need to follow up with additional CCW commands to actually do something useful.\u00a0 Setting the Command Chain bit tells the channel that another CCW immediately follows this one.<\/p>\n<p>When using EXCP to access a DASD device we don&#8217;t issue a SEEK command.\u00a0 In fact MVS will prevent us from issuing a SEEK command.\u00a0 This is because there are usually multiple datasets contained on a DASD volume.\u00a0 MVS keeps us from reading or writing to areas of the device we are not authorized to access.\u00a0 We will quickly review how this is accomplished.<\/p>\n<p>Each dataset is made up of one or more extents.\u00a0 An extent is a set of contiguous tracks or cylinders.\u00a0 The VTOC is a special file on each volume that keeps track of where datasets are located.\u00a0 This information is maintained in a Dataset Control Block (DSCB).\u00a0 The DSCB has a list of the extents that make up the dataset.\u00a0 Open processing reads the DSCB and uses the extent information to build the DEB.\u00a0 The DEB is contained in protected storage and can not be modified by a non-authorized user.<\/p>\n<p>When an EXCP request is submitted for a DASD device MVS gets the seek address from the IOB, validates it against the DEB to verify it is contained within an extent of the dataset.\u00a0 If the seek address is not contained within a valid dataset extent the request is rejected.\u00a0 If the seek address is valid then MVS builds a SEEK CCW using the IOB seek address.\u00a0 A SET FILE MASK CCW is then chained on to the SEEK CCW.\u00a0 The SET FILE MASK specifies what types of CCW commands may follow.<\/p>\n<pre>         DC    X'1F',AL3(FILEMASK),X'40',x'00',AL2(1)         --- Set File Mask CCW\r\n             :\r\n             :\r\nFIELMASK DC  X'file-mask-bits'\r\n\r\nFile Mask\r\n00......  - Do not allow Write Home Address and Write Record Zero\r\n01......  - Do not allow any write commands\r\n10......  - Do not allow Write Format commands\r\n11......  - Allow all write commands\r\n...00...  - Allow all Seek commands\r\n...01...  - Allow Seek Cylinder and Seek Head commands \r\n...10...  - Allow Seek Head commands\r\n...11...  - Do not allow Seek commands or head switching\r\n......0.  - Do not allow Diagnostic Write commands\r\n......1.  - Allow Diagnostic Write commands\r\n.......0  - Not PCI Fetch mode\r\n.......1  - PCI Fetch mode\r\n..0..0..  - Must always be Zero<\/pre>\n<p>There may only be one SET FILE MASK command in a CCW sequence. This keeps the user CCW program from accessing tracks outside the dataset extents. It also enforces read-only for datasets opened for input.\u00a0 The users CCWs follow the SET FILE MASK command.<\/p>\n<p>Once the correct cylinder and head have been selected by the SEEK command we need to position for the record we wish to read or write.\u00a0 This is done with a SEARCH command.\u00a0 To understand how to use SEARCH we have to understand the physical layout of the track.<\/p>\n<p>As we said earlier the track always begins with two special records, the Home Address and Record Zero.\u00a0 Data records are made up of three components, the count, the key, and the data area.\u00a0 The key is optional an may be omitted.\u00a0 The count is always required.\u00a0 It is made up of 8 bytes in the format CCHHRKDL.\u00a0 CC is the cylinder number, HH is the head, R is the record number, K is the length of the key area, and DL is two-byte length of the data area.\u00a0 If the key length is zero then there is no key area for the record.\u00a0 If the key length and data length of the block are both zero the record is an end of file indicator.<\/p>\n<pre>+---+---+---+---+---+---+---+---+ \r\n| C   C | H   H | R | K |  DL   |\r\n+---+---+---+---+---+---+---+---+<\/pre>\n<p>Below is the layout of a track. The track begins at the Index Point which physically identifies the beginning of every track. Immediately following the index point is the Homa Address (HA).\u00a0 The Home Address contains track information and is used to indicate if an alternate track is in use.\u00a0 Alternate tracks are special reserved tracks used to replace a defective track.\u00a0 A special record called Record Zero (R0) is always present immediately following the Home Address.\u00a0 R0 does not contain any user data but is part of the standard track formatting.\u00a0 It is necessary to allow track positioning using the SEARCH CCW command.\u00a0 The HA and R0 are written using special CCW commands when the volume is formatted.\u00a0 There is not normally any reason to read or write these special records.\u00a0 User data begins with Record One (R1) and may be followed by additional user records.\u00a0 An empty track contains only the HA and R0.<\/p>\n<pre>[IX] [HA] [R0-CKD] [R1-CKD] [R2-CKD] ... [Rn-CKD]<\/pre>\n<p>When setting our position around a track (a position to a specific record) we use the SEARCH CCW command.\u00a0 The SERACH command compares the serach value (specified by the SRARCH CCW) against the next record that passes the read heads.\u00a0 If there is not a match the CCW completes normally.\u00a0 If the values to match the CCW completes but also sets the Status Modifier bit in the CSW.\u00a0 This tells the channel that a match has occured and causes the channel to skip over the next CCW immediately following the SEARCH.\u00a0 This allows us to set up a loop in our channel program to locate the desired record:<\/p>\n<pre>        CCW   SEARCH\r\n        CCW   TIC,*-8\r\n        CCW   READ<\/pre>\n<p>In this example we have three CCW commands. The first is a SEARCH followed by a Transfer In Channel (TIC) CCW. A TIC is an unconditional branch in a channel program. The address portion of the TIC CCW points to the next CCW to be executed by the channel. In this case the TIC will branch back to the SEARCH (*-8 refers to the previous CCW since each is eight bytes in length). When we start this channel program the first CCW executed is the SEARCH. If the search does not match then the channel will fall through to the next command, a TIC that branches back to the SEARCH. This will be repeated until the SERACH matches a record on the track at which point the channel will skip the command immediately following the SEARCH (in this case the TIC) and the READ CCW will be executed by the channel to read the selected record.<\/p>\n<p>We do have to deal with the situation where the SEARCH never matches. In this case the Status Modifier bit will never be set and it would appar that we would be in a infinite loop that never ends. The loop is broken when the dasd device detects two Index Points during an uninterrupted search CCW sequence. By the time the Index Point has passed the read heads twice the deivce knows that every record on the track has been checked at least once. When this happens the CCW is terminated abnormally and the Unit Check bit is set in the CSW. This causes the channel to end the current program.<\/p>\n<p>There are two types of SERACH commands, one searches by ID which is the CCHHR in the count area.\u00a0 The othter type searches by key data contents.\u00a0 Both of the types search for either an equal condition, high condition, or a equal or high condition.\u00a0 The following table shows the results of various combinations of the SEARCH ID CCW in relation to a record.\u00a0 The values are in the format CC-HH-R. (The SEARCH ID command may search for R0).<\/p>\n<pre><b>\r\nSearch CCW Value | Count Area for Record | ID Equal | ID High | ID Equal or High\r\n--------------------------------------------------------------------------------<\/b>\r\n   01-01-3       |      01-01-1          |  False   |  False  |      False\r\n   01-01-3       |      01-01-3          |  True    |  False  |      False\r\n   01-01-3       |      01-01-4          |  False   |  True   |      True<\/pre>\n<p>There are also three SEARCH KEY commands (key equal, key high, key high or equal) that compare the search contents of the CCW against the data in the key area of the record.<\/p>\n<p>When we indicated what happens when two Index Points are encountered is true for the normal SEARCH commands but there is a second type of each of the SEARCH commands that are Multi-Track commands.\u00a0 If the SEARCH is a multi-track request and the end of the track is reached (two Index Points encountered) the device will switch to the next head and continue the search.\u00a0 This allows an entire cylinder to be searched using one CCW program and an single I\/O request.\u00a0 If the end of the last trrack of a cylinder is detected and the search has not been satsified the CCW terminates with the Unit Check bit set in the CSW.\u00a0 It is important to note that the multi-track CCWs can only be used if allowed by the settings in the SET MASK instruction that preceeded the SEARCH.\u00a0 MVS sets the authorization in the SET MASK based on how the dataset was allocated.\u00a0 If it was allocated in cylinders then MVS will allow SEEK HEAD and Multi-Track operations.\u00a0 If the dataset was allocated in tracks then SEEK HEAD and Multi-Track operations are not allowed so that the user program can never access tracks not belonging to the data set.<\/p>\n<p>Below are the various CCW command codes for the SEARCH commands:<\/p>\n<pre><b>\r\n   CCW Command     Normal  Multi-Track<\/b>\r\nSearch ID Equal      31         B1\r\nSearch ID High       51         D1\r\nSearch ID Eq\/High    71         F1\r\n\r\nSearch Key Equal     29         A9\r\nSearch KEY High      49         C9\r\nSearch KEY Eq\/High   69         E9<\/pre>\n<p>Now one thing we do have to consider is which record to search for.\u00a0 If we want to read or write the Key\u00a0 or Data area of a record we search for the ID of the record we want to access.\u00a0 If we want to read or write the Count area we must position based on the ID of the previous record.\u00a0 This is because once the device has read the count area for a Search ID equal the count area for that record is now past the read\/write heads.\u00a0 So if we want to read the Count, Key and Data area for record number two we would have to do a search ID for record number one.\u00a0 If we just want to read the Data area for record number two we would do a search for record number two.\u00a0 This can get a little confusing but it does make great sense when you consider what is physically happening on a dasd device.\u00a0 Using Hercules we need to think in terms of how an actual 3350 device was constructed and how it operated since that behaviour is emulated.<\/p>\n<p>Here are additional CCW Command Codes for accessing dasd devices:<\/p>\n<pre><b>\r\n   CCW Command     Normal  Multi-Track<\/b>\r\nRead Count           12         91\r\nRead R0              16         96\r\nRead Data            06         86\r\nRead Key &amp; Data      0E         8E\r\nRead CKD             1E         9E\r\nRead Multiple CKD    5E\r\n\r\nWrite CKD            1D         -\r\nWrite Data           05         -\r\nWrite Key &amp; Data     0D         -\r\n\r\nErase                11         -<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Now we can look specifically at CCW programming to access DASD devices.\u00a0 For this discussion I will work with the 3350 device.\u00a0 The concepts here can be applied to other types of DASD devices.\u00a0 The reason I am using the 3350 is because this device is natively supported in MVS 3.8 and does not require &#8230;<\/p>\n<p><a href=\"https:\/\/tommysprinkle.com\/mvssp\/2013\/02\/03\/dasd-io-programming\/\" class=\"more-link\">Continue reading &lsquo;DASD I\/O Programming&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":[30],"tags":[],"class_list":["post-132","post","type-post","status-publish","format-standard","hentry","category-dasd-io-programming"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3x7AW-28","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/posts\/132","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=132"}],"version-history":[{"count":12,"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/posts\/132\/revisions"}],"predecessor-version":[{"id":209,"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/posts\/132\/revisions\/209"}],"wp:attachment":[{"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/media?parent=132"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/categories?post=132"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tommysprinkle.com\/mvssp\/wp-json\/wp\/v2\/tags?post=132"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}