1 /* CKDDASD.C    (c) Copyright Roger Bowler, 1999-2009                */
2 /*              ESA/390 CKD Direct Access Storage Device Handler     */
3 
4 /*-------------------------------------------------------------------*/
5 /* This module contains device handling functions for emulated       */
6 /* count-key-data direct access storage devices.                     */
7 /*-------------------------------------------------------------------*/
8 
9 /*-------------------------------------------------------------------*/
10 /* Additional credits:                                               */
11 /*      Write Update Key and Data CCW by Jan Jaeger                  */
12 /*      Track overflow support added by Jay Maynard                  */
13 /*      Track overflow fixes by Jay Maynard, suggested by Valery     */
14 /*        Pogonchenko                                                */
15 /*      Track overflow write fix by Roger Bowler, thanks to Valery   */
16 /*        Pogonchenko and Volker Bandke             V1.71 16/01/2001 */
17 /*-------------------------------------------------------------------*/
18 
19 #include "hstdinc.h"
20 
21 #define _CKDDASD_C_
22 #define _HDASD_DLL_
23 
24 #include "hercules.h"
25 #include "devtype.h"
26 #include "sr.h"
27 
28 /*-------------------------------------------------------------------*/
29 /* Bit definitions for File Mask                                     */
30 /*-------------------------------------------------------------------*/
31 #define CKDMASK_WRCTL           0xC0    /* Write control bits...     */
32 #define CKDMASK_WRCTL_INHWR0    0x00    /* ...inhibit write HA/R0    */
33 #define CKDMASK_WRCTL_INHWRT    0x40    /* ...inhibit all writes     */
34 #define CKDMASK_WRCTL_ALLWRU    0x80    /* ...write update only      */
35 #define CKDMASK_WRCTL_ALLWRT    0xC0    /* ...allow all writes       */
36 #define CKDMASK_RESV            0x20    /* Reserved bits - must be 0 */
37 #define CKDMASK_SKCTL           0x18    /* Seek control bits...      */
38 #define CKDMASK_SKCTL_ALLSKR    0x00    /* ...allow all seek/recalib */
39 #define CKDMASK_SKCTL_CYLHD     0x08    /* ...allow seek cyl/head    */
40 #define CKDMASK_SKCTL_HEAD      0x10    /* ...allow seek head only   */
41 #define CKDMASK_SKCTL_INHSMT    0x18    /* ...inhibit seek and MT    */
42 #define CKDMASK_AAUTH           0x06    /* Access auth bits...       */
43 #define CKDMASK_AAUTH_NORMAL    0x00    /* ...normal authorization   */
44 #define CKDMASK_AAUTH_DSF       0x02    /* ...device support auth    */
45 #define CKDMASK_AAUTH_DIAG      0x04    /* ...diagnostic auth        */
46 #define CKDMASK_AAUTH_DSFNCR    0x06    /* ...device support with no
47                                               correction or retry    */
48 #define CKDMASK_PCI_FETCH       0x01    /* PCI fetch mode            */
49 
50 /*-------------------------------------------------------------------*/
51 /* Bit definitions for Define Extent global attributes byte          */
52 /*-------------------------------------------------------------------*/
53 #define CKDGATR_ARCH            0xC0    /* Architecture mode...      */
54 #define CKDGATR_ARCH_ECKD       0xC0    /* ...extended CKD mode      */
55 #define CKDGATR_CKDCONV         0x20    /* CKD conversion mode       */
56 #define CKDGATR_SSOP            0x1C    /* Subsystem operation mode..*/
57 #define CKDGATR_SSOP_NORMAL     0x00    /* ...normal cache           */
58 #define CKDGATR_SSOP_BYPASS     0x04    /* ...bypass cache           */
59 #define CKDGATR_SSOP_INHIBIT    0x08    /* ...inhibit cache loading  */
60 #define CKDGATR_SSOP_SEQACC     0x0C    /* ...sequential access      */
61 #define CKDGATR_SSOP_LOGGING    0x10    /* ...logging mode           */
62 #define CKDGATR_USE_CACHE_FW    0x02    /* Use cache fast write      */
63 #define CKDGATR_INH_DASD_FW     0x01    /* Inhibit DASD fast write   */
64 
65 /*-------------------------------------------------------------------*/
66 /* Bit definitions for Locate operation byte                         */
67 /*-------------------------------------------------------------------*/
68 #define CKDOPER_ORIENTATION     0xC0    /* Orientation bits...       */
69 #define CKDOPER_ORIENT_COUNT    0x00    /* ...orient to count        */
70 #define CKDOPER_ORIENT_HOME     0x40    /* ...orient to home address */
71 #define CKDOPER_ORIENT_DATA     0x80    /* ...orient to data area    */
72 #define CKDOPER_ORIENT_INDEX    0xC0    /* ...orient to index        */
73 #define CKDOPER_CODE            0x3F    /* Operation code bits...    */
74 #define CKDOPER_ORIENT          0x00    /* ...orient                 */
75 #define CKDOPER_WRITE           0x01    /* ...write data             */
76 #define CKDOPER_FORMAT          0x03    /* ...format write           */
77 #define CKDOPER_RDDATA          0x06    /* ...read data              */
78 #define CKDOPER_WRTANY          0x09    /* ...write any              */
79 #define CKDOPER_RDANY           0x0A    /* ...read any               */
80 #define CKDOPER_WRTTRK          0x0B    /* ...write track            */
81 #define CKDOPER_RDTRKS          0x0C    /* ...read tracks            */
82 #define CKDOPER_RDTSET          0x0E    /* ...read track set         */
83 #define CKDOPER_READ            0x16    /* ...read                   */
84 #define CKDOPER_EXTOP           0x3F    /* ...extended operation     */
85 
86 /*-------------------------------------------------------------------*/
87 /* Bit definitions for Locate auxiliary byte                         */
88 /*-------------------------------------------------------------------*/
89 #define CKDLAUX_TLFVALID        0x80    /* TLF field is valid        */
90 #define CKDLAUX_RESV            0x7E    /* Reserved bits - must be 0 */
91 #define CKDLAUX_RDCNTSUF        0x01    /* Suffixed read count CCW   */
92 
93 /*-------------------------------------------------------------------*/
94 /* Definitions for ckdorient field in device block                   */
95 /*-------------------------------------------------------------------*/
96 #define CKDORIENT_NONE          0       /* Orientation unknown       */
97 #define CKDORIENT_INDEX         1       /* Oriented after track hdr  */
98 #define CKDORIENT_COUNT         2       /* Oriented after count field*/
99 #define CKDORIENT_KEY           3       /* Oriented after key field  */
100 #define CKDORIENT_DATA          4       /* Oriented after data field */
101 #define CKDORIENT_EOT           5       /* Oriented after end of trk */
102 
103 /* Path state byte for Sense Path Group ID command */
104 #define SPG_PATHSTAT            0xC0    /* Pathing status bits...    */
105 #define SPG_PATHSTAT_RESET      0x00    /* ...reset                  */
106 #define SPG_PATHSTAT_RESV       0x40    /* ...reserved bit setting   */
107 #define SPG_PATHSTAT_UNGROUPED  0x80    /* ...ungrouped              */
108 #define SPG_PATHSTAT_GROUPED    0xC0    /* ...grouped                */
109 #define SPG_PARTSTAT            0x30    /* Partitioning status bits..*/
110 #define SPG_PARTSTAT_IENABLED   0x00    /* ...implicitly enabled     */
111 #define SPG_PARTSTAT_RESV       0x10    /* ...reserved bit setting   */
112 #define SPG_PARTSTAT_DISABLED   0x20    /* ...disabled               */
113 #define SPG_PARTSTAT_XENABLED   0x30    /* ...explicitly enabled     */
114 #define SPG_PATHMODE            0x08    /* Path mode bit...          */
115 #define SPG_PATHMODE_SINGLE     0x00    /* ...single path mode       */
116 #define SPG_PATHMODE_RESV       0x08    /* ...reserved bit setting   */
117 #define SPG_RESERVED            0x07    /* Reserved bits, must be 0  */
118 
119 /* Function control byte for Set Path Group ID command */
120 #define SPG_SET_MULTIPATH       0x80    /* Set multipath mode        */
121 #define SPG_SET_COMMAND         0x60    /* Set path command bits...  */
122 #define SPG_SET_ESTABLISH       0x00    /* ...establish group        */
123 #define SPG_SET_DISBAND         0x20    /* ...disband group          */
124 #define SPG_SET_RESIGN          0x40    /* ...resign from group      */
125 #define SPG_SET_COMMAND_RESV    0x60    /* ...reserved bit setting   */
126 #define SPG_SET_RESV            0x1F    /* Reserved bits, must be 0  */
127 
128 /*-------------------------------------------------------------------*/
129 /* Bit definitions for Diagnostic Control subcommand byte            */
130 /*-------------------------------------------------------------------*/
131 #define DIAGCTL_INHIBIT_WRITE   0x02    /* Inhibit Write             */
132 #define DIAGCTL_SET_GUAR_PATH   0x04    /* Set Guaranteed Path       */
133 #define DIAGCTL_ENABLE_WRITE    0x08    /* Enable Write              */
134 #define DIAGCTL_3380_TC_MODE    0x09    /* 3380 Track Compat Mode    */
135 #define DIAGCTL_INIT_SUBSYS     0x0B    /* Diagnostic Init Subsys    */
136 #define DIAGCTL_UNFENCE         0x0C    /* Unfence                   */
137 #define DIAGCTL_ACCDEV_UNKCOND  0x0F    /* Access Device Unknown Cond*/
138 #define DIAGCTL_MAINT_RESERVE   0x10    /* Media Maintenance Reserve */
139 #define DIAGCTL_MAINT_RELEASE   0x11    /* Media Maintenance Release */
140 #define DIAGCTL_MAINT_QUERY     0x12    /* Media Maintenance Query   */
141 
142 /*-------------------------------------------------------------------*/
143 /* Definitions for sense data format codes and message codes         */
144 /*-------------------------------------------------------------------*/
145 #define FORMAT_0                0       /* Program or System Checks  */
146 #define FORMAT_1                1       /* Device Equipment Checks   */
147 #define FORMAT_2                2       /* 3990 Equipment Checks     */
148 #define FORMAT_3                3       /* 3990 Control Checks       */
149 #define FORMAT_4                4       /* Data Checks               */
150 #define FORMAT_5                5       /* Data Check + Displacement */
151 #define FORMAT_6                6       /* Usage Stats/Overrun Errors*/
152 #define FORMAT_7                7       /* Device Control Checks     */
153 #define FORMAT_8                8       /* Device Equipment Checks   */
154 #define FORMAT_9                9       /* Device Rd/Wrt/Seek Checks */
155 #define FORMAT_F                15      /* Cache Storage Checks      */
156 #define MESSAGE_0               0       /* Message 0                 */
157 #define MESSAGE_1               1       /* Message 1                 */
158 #define MESSAGE_2               2       /* Message 2                 */
159 #define MESSAGE_3               3       /* Message 3                 */
160 #define MESSAGE_4               4       /* Message 4                 */
161 #define MESSAGE_5               5       /* Message 5                 */
162 #define MESSAGE_6               6       /* Message 6                 */
163 #define MESSAGE_7               7       /* Message 7                 */
164 #define MESSAGE_8               8       /* Message 8                 */
165 #define MESSAGE_9               9       /* Message 9                 */
166 #define MESSAGE_A               10      /* Message A                 */
167 #define MESSAGE_B               11      /* Message B                 */
168 #define MESSAGE_C               12      /* Message C                 */
169 #define MESSAGE_D               13      /* Message D                 */
170 #define MESSAGE_E               14      /* Message E                 */
171 #define MESSAGE_F               15      /* Message F                 */
172 
173 /*-------------------------------------------------------------------*/
174 /* Definitions for Read Configuration Data command                   */
175 /*-------------------------------------------------------------------*/
176 #define CONFIG_DATA_SIZE        256     /* Number of bytes returned
177                                            by Read Config Data CCW   */
178 
179 /*
180  * ISW20060207
181  * EXTENT_CHECK0 is just to shut up a stupid gcc 4 warning..
182  * It doesn't hurt otherwise
183  * EXTENT_CHECK0(dev) is the same as EXTENT_CHECK(dev,0,0)
184  */
185 #define EXTENT_CHECK0(_dev) ((_dev)->ckdxbcyl > 0                            \
186             || ((_dev)->ckdxbcyl==0 && (_dev)->ckdxbhead>0))
187 
188 #define EXTENT_CHECK(_dev, _cyl, _head)                                        \
189         ( (_cyl) < (_dev)->ckdxbcyl || (_cyl) > (_dev)->ckdxecyl               \
190             || ((_cyl) == (_dev)->ckdxbcyl && (_head) < (_dev)->ckdxbhead)     \
191             || ((_cyl) == (_dev)->ckdxecyl && (_head) > (_dev)->ckdxehead) )
192 
193 /*-------------------------------------------------------------------*/
194 /* Static data areas                                                 */
195 /*-------------------------------------------------------------------*/
196 static  BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
197 
198 /*-------------------------------------------------------------------*/
199 /* Initialize the device handler                                     */
200 /*-------------------------------------------------------------------*/
ckddasd_init_handler(DEVBLK * dev,int argc,char * argv[])201 int ckddasd_init_handler ( DEVBLK *dev, int argc, char *argv[] )
202 {
203 int             rc;                     /* Return code               */
204 struct stat     statbuf;                /* File information          */
205 CKDDASD_DEVHDR  devhdr;                 /* Device header             */
206 CCKDDASD_DEVHDR cdevhdr;                /* Compressed device header  */
207 int             i;                      /* Loop index                */
208 int             fileseq;                /* File sequence number      */
209 char           *sfxptr;                 /* -> Last char of file name */
210 char            sfxchar;                /* Last char of file name    */
211 int             heads;                  /* #of heads in CKD file     */
212 int             trksize;                /* Track size of CKD file    */
213 int             trks;                   /* #of tracks in CKD file    */
214 int             cyls;                   /* #of cylinders in CKD file */
215 int             highcyl;                /* Highest cyl# in CKD file  */
216 char           *cu = NULL;              /* Specified control unit    */
217 char           *kw;                     /* Argument keyword          */
218 int             cckd=0;                 /* 1 if compressed CKD       */
219 char            pathname[MAX_PATH];     /* file path in host format  */
220 
221     if(!sscanf(dev->typname,"%hx",&(dev->devtype)))
222         dev->devtype = 0x3380;
223 
224     /* The first argument is the file name */
225     if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1)
226     {
227         logmsg (_("HHCDA001E File name missing or invalid\n"));
228         return -1;
229     }
230 
231     /* Save the file name in the device block */
232     hostpath(pathname, argv[0], sizeof(pathname));
233     strcpy (dev->filename, pathname);
234 
235     /* Device is shareable */
236     dev->shared = 1;
237 
238     /* Check for possible remote device */
239     hostpath(pathname, dev->filename, sizeof(pathname));
240     if (stat(pathname, &statbuf) < 0)
241     {
242         rc = shared_ckd_init ( dev, argc, argv);
243         if (rc < 0)
244         {
245             logmsg (_("HHCDA002E %4.4X:File not found or invalid '%s'\n"),
246                     dev->devnum,dev->filename);
247             return -1;
248         }
249         else
250             return rc;
251     }
252 
253     /* Default to synchronous I/O */
254     dev->syncio = 1;
255 
256     /* No active track or cache entry */
257     dev->bufcur = dev->cache = -1;
258 
259     /* Locate and save the last character of the file name */
260     sfxptr = strrchr (dev->filename, '/');
261     if (sfxptr == NULL) sfxptr = dev->filename + 1;
262     sfxptr = strchr (sfxptr, '.');
263     if (sfxptr == NULL) sfxptr = dev->filename + strlen(dev->filename);
264     sfxptr--;
265     sfxchar = *sfxptr;
266 
267     /* process the remaining arguments */
268     for (i = 1; i < argc; i++)
269     {
270         if (strcasecmp ("lazywrite", argv[i]) == 0)
271         {
272             dev->ckdnolazywr = 0;
273             continue;
274         }
275         if (strcasecmp ("nolazywrite", argv[i]) == 0)
276         {
277             dev->ckdnolazywr = 1;
278             continue;
279         }
280         if (strcasecmp ("fulltrackio", argv[i]) == 0 ||
281             strcasecmp ("fulltrkio",   argv[i]) == 0 ||
282             strcasecmp ("ftio",        argv[i]) == 0)
283         {
284             dev->ckdnolazywr = 0;
285             continue;
286         }
287         if (strcasecmp ("nofulltrackio", argv[i]) == 0 ||
288             strcasecmp ("nofulltrkio",   argv[i]) == 0 ||
289             strcasecmp ("noftio",        argv[i]) == 0)
290         {
291             dev->ckdnolazywr = 1;
292             continue;
293         }
294         if (strcasecmp ("readonly", argv[i]) == 0 ||
295             strcasecmp ("rdonly",   argv[i]) == 0 ||
296             strcasecmp ("ro",       argv[i]) == 0)
297         {
298             dev->ckdrdonly = 1;
299             continue;
300         }
301         if (strcasecmp ("fakewrite", argv[i]) == 0 ||
302             strcasecmp ("fakewrt",   argv[i]) == 0 ||
303             strcasecmp ("fw",        argv[i]) == 0)
304         {
305             dev->ckdfakewr = 1;
306             continue;
307         }
308         if (strlen (argv[i]) > 3 &&
309             memcmp ("sf=", argv[i], 3) == 0)
310         {
311             if ('\"' == argv[i][3]) argv[i]++;
312             hostpath(pathname, argv[i]+3, sizeof(pathname));
313             dev->dasdsfn = strdup(pathname);
314             if (dev->dasdsfn)
315             {
316                 /* Set the pointer to the suffix character */
317                 dev->dasdsfx = strrchr (dev->dasdsfn, '/');
318                 if (dev->dasdsfx == NULL)
319                     dev->dasdsfx = dev->dasdsfn + 1;
320                 dev->dasdsfx = strchr (dev->dasdsfx, '.');
321                 if (dev->dasdsfx == NULL)
322                     dev->dasdsfx = dev->dasdsfn + strlen(dev->dasdsfn);
323                 dev->dasdsfx--;
324             }
325             continue;
326         }
327         if (strlen (argv[i]) > 3
328          && memcmp("cu=", argv[i], 3) == 0)
329         {
330             kw = strtok (argv[i], "=");
331             cu = strtok (NULL, " \t");
332             continue;
333         }
334         if (strcasecmp ("nosyncio", argv[i]) == 0 ||
335             strcasecmp ("nosyio",   argv[i]) == 0)
336         {
337             dev->syncio = 0;
338             continue;
339         }
340         if (strcasecmp ("syncio", argv[i]) == 0 ||
341             strcasecmp ("syio",   argv[i]) == 0)
342         {
343             dev->syncio = 1;
344             continue;
345         }
346 
347         logmsg (_("HHCDA003E parameter %d is invalid: %s\n"),
348                 i + 1, argv[i]);
349         return -1;
350     }
351 
352     /* Initialize the total tracks and cylinders */
353     dev->ckdtrks = 0;
354     dev->ckdcyls = 0;
355 
356     /* Open all of the CKD image files which comprise this volume */
357     if (dev->ckdrdonly)
358         logmsg (_("HHCDA004I opening %s readonly%s\n"), dev->filename,
359                 dev->ckdfakewr ? " with fake writing" : "");
360     for (fileseq = 1;;)
361     {
362         /* Open the CKD image file */
363         hostpath(pathname, dev->filename, sizeof(pathname));
364         dev->fd = hopen(pathname, dev->ckdrdonly ?
365                         O_RDONLY|O_BINARY : O_RDWR|O_BINARY);
366         if (dev->fd < 0)
367         {   /* Try read-only if shadow file present */
368             if (!dev->ckdrdonly && dev->dasdsfn != NULL)
369                 dev->fd = hopen(pathname, O_RDONLY|O_BINARY);
370             if (dev->fd < 0)
371             {
372                 logmsg (_("HHCDA005E %s open error: %s\n"),
373                         dev->filename, strerror(errno));
374                 return -1;
375             }
376         }
377 
378         /* If shadow file, only one base file is allowed */
379         if (fileseq > 1 && dev->dasdsfn != NULL)
380         {
381             logmsg (_("HHCDA006E %s not in a single file for shadowing\n"),
382                     dev->filename);
383             return -1;
384         }
385 
386         /* Determine the device size */
387         rc = fstat (dev->fd, &statbuf);
388         if (rc < 0)
389         {
390             logmsg (_("HHCDA007E %s fstat error: %s\n"),
391                     dev->filename, strerror(errno));
392             return -1;
393         }
394 
395         /* Read the device header */
396         rc = read (dev->fd, &devhdr, CKDDASD_DEVHDR_SIZE);
397         if (rc < (int)CKDDASD_DEVHDR_SIZE)
398         {
399             if (rc < 0)
400                 logmsg (_("HHCDA008E %s read error: %s\n"),
401                         dev->filename, strerror(errno));
402             else
403                 logmsg (_("HHCDA09E %s CKD header incomplete\n"),
404                         dev->filename);
405             return -1;
406         }
407 
408         /* Check the device header identifier */
409         if (memcmp(devhdr.devid, "CKD_P370", 8) != 0)
410         {
411             if (memcmp(devhdr.devid, "CKD_C370", 8) != 0)
412             {
413                 logmsg (_("HHCDA010E %s CKD header invalid\n"),
414                         dev->filename);
415                 return -1;
416             }
417             else
418             {
419                 cckd = 1;
420                 if (fileseq != 1)
421                 {
422                     logmsg (_("HHCDA011E %s Only 1 CCKD file allowed\n"),
423                             dev->filename);
424                     return -1;
425                 }
426             }
427         }
428 
429         /* Read the compressed device header */
430         if ( cckd )
431         {
432             rc = read (dev->fd, &cdevhdr, CCKDDASD_DEVHDR_SIZE);
433             if (rc < (int)CCKDDASD_DEVHDR_SIZE)
434             {
435                 if (rc < 0)
436                 {
437                     logmsg (_("HHCDA012E %s read error: %s\n"),
438                             dev->filename, strerror(errno));
439                 }
440                 else
441                 {
442                     logmsg (_("HHCDA013E %s CCKD header incomplete\n"),
443                             dev->filename);
444                 }
445                 return -1;
446             }
447         }
448 
449         /* Extract fields from device header */
450         heads   = ((U32)(devhdr.heads[3]) << 24)
451                 | ((U32)(devhdr.heads[2]) << 16)
452                 | ((U32)(devhdr.heads[1]) << 8)
453                 | (U32)(devhdr.heads[0]);
454         trksize = ((U32)(devhdr.trksize[3]) << 24)
455                 | ((U32)(devhdr.trksize[2]) << 16)
456                 | ((U32)(devhdr.trksize[1]) << 8)
457                 | (U32)(devhdr.trksize[0]);
458         highcyl = ((U32)(devhdr.highcyl[1]) << 8)
459                 | (U32)(devhdr.highcyl[0]);
460 
461         if (cckd == 0)
462         {
463             if (dev->dasdcopy == 0)
464             {
465                 trks = (statbuf.st_size - CKDDASD_DEVHDR_SIZE) / trksize;
466                 cyls = trks / heads;
467                 if (fileseq == 1 && highcyl == cyls)
468                 {
469                     devhdr.fileseq = 0;
470                     highcyl = 0;
471                 }
472             }
473             else
474             {
475                 /*
476                  * For dasdcopy we get the number of cylinders and tracks from
477                  * the highcyl in the device header.  The last file will have
478                  * a sequence number of 0xFF.
479                  */
480                 cyls = highcyl - dev->ckdcyls + 1;
481                 trks = cyls * heads;
482                 if (devhdr.fileseq == 0xFF)
483                 {
484                     devhdr.fileseq = fileseq == 1 ? 0 : fileseq;
485                     highcyl = 0;
486                     devhdr.highcyl[0] = devhdr.highcyl[1] = 0;
487                     lseek (dev->fd, 0, SEEK_SET);
488                     rc = write (dev->fd, &devhdr, CKDDASD_DEVHDR_SIZE);
489                 }
490             }
491         }
492         else
493         {
494             cyls = ((U32)(cdevhdr.cyls[3]) << 24)
495                  | ((U32)(cdevhdr.cyls[2]) << 16)
496                  | ((U32)(cdevhdr.cyls[1]) << 8)
497                  |  (U32)(cdevhdr.cyls[0]);
498             trks = cyls * heads;
499         }
500 
501         /* Check for correct file sequence number */
502         if (devhdr.fileseq != fileseq
503             && !(devhdr.fileseq == 0 && fileseq == 1))
504         {
505             logmsg (_("HHCDA014E %s CKD file out of sequence\n"),
506                     dev->filename);
507             return -1;
508         }
509 
510         if (devhdr.fileseq > 0)
511         {
512             logmsg (_("HHCDA015I %s seq=%d cyls=%d-%d\n"),
513                     dev->filename, devhdr.fileseq, dev->ckdcyls,
514                     (highcyl > 0 ? highcyl : dev->ckdcyls + cyls - 1));
515         }
516 
517         /* Save device geometry of first file, or check that device
518            geometry of subsequent files matches that of first file */
519         if (fileseq == 1)
520         {
521             dev->ckdheads = heads;
522             dev->ckdtrksz = trksize;
523         }
524         else if (heads != dev->ckdheads || trksize != dev->ckdtrksz)
525         {
526             logmsg (_("HHCDA016E %s heads=%d trklen=%d, "
527                     "expected heads=%d trklen=%d\n"),
528                     dev->filename, heads, trksize,
529                     dev->ckdheads, dev->ckdtrksz);
530             return -1;
531         }
532 
533         /* Consistency check device header */
534         if (cckd == 0 && dev->dasdcopy == 0 && (cyls * heads != trks
535             || ((off_t)trks * trksize) + CKDDASD_DEVHDR_SIZE
536                             != statbuf.st_size
537             || (highcyl != 0 && highcyl != dev->ckdcyls + cyls - 1)))
538         {
539             logmsg (_("HHCDA017E %s CKD header inconsistent with file size\n"),
540                     dev->filename);
541             return -1;
542         }
543 
544         /* Check for correct high cylinder number */
545         if (highcyl != 0 && highcyl != dev->ckdcyls + cyls - 1)
546         {
547             logmsg (_("HHCDA018E %s CKD header high cylinder incorrect\n"),
548                     dev->filename);
549             return -1;
550         }
551 
552         /* Accumulate total volume size */
553         dev->ckdtrks += trks;
554         dev->ckdcyls += cyls;
555 
556         /* Save file descriptor and high track number */
557         dev->ckdfd[fileseq-1] = dev->fd;
558         dev->ckdhitrk[fileseq-1] = dev->ckdtrks;
559         dev->ckdnumfd = fileseq;
560 
561         /* Exit loop if this is the last file */
562         if (highcyl == 0) break;
563 
564         /* Increment the file sequence number */
565         fileseq++;
566 
567         /* Alter the file name suffix ready for the next file */
568         if (fileseq <= 9)
569             *sfxptr = '0' + fileseq;
570         else
571             *sfxptr = 'A' - 10 + fileseq;
572 
573         /* Check that maximum files has not been exceeded */
574         if (fileseq > CKD_MAXFILES)
575         {
576             logmsg (_("HHCDA019E %s exceeds maximum %d CKD files\n"),
577                     dev->filename, CKD_MAXFILES);
578             return -1;
579         }
580 
581     } /* end for(fileseq) */
582 
583     /* Restore the last character of the file name */
584     *sfxptr = sfxchar;
585 
586     /* Log the device geometry */
587     logmsg (_("HHCDA020I %s cyls=%d heads=%d tracks=%d trklen=%d\n"),
588             dev->filename, dev->ckdcyls,
589             dev->ckdheads, dev->ckdtrks, dev->ckdtrksz);
590 
591     /* Locate the CKD dasd table entry */
592     dev->ckdtab = dasd_lookup (DASD_CKDDEV, NULL, dev->devtype, dev->ckdcyls);
593     if (dev->ckdtab == NULL)
594     {
595         logmsg (_("HHCDA021E %4.4X device type %4.4X not found in dasd table\n"),
596                 dev->devnum, dev->devtype);
597         return -1;
598     }
599 
600     /* Locate the CKD control unit dasd table entry */
601     dev->ckdcu = dasd_lookup (DASD_CKDCU, cu ? cu : dev->ckdtab->cu, 0, 0);
602     if (dev->ckdcu == NULL)
603     {
604         logmsg (_("HHCDA022E %4.4X control unit %s not found in dasd table\n"),
605                 dev->devnum, cu ? cu : dev->ckdtab->cu);
606         return -1;
607     }
608 
609     /* Set number of sense bytes according to controller specification */
610     dev->numsense = dev->ckdcu->senselength;
611 
612     /* Set flag bit if 3990 controller */
613     if (dev->ckdcu->devt == 0x3990)
614         dev->ckd3990 = 1;
615 
616     /* Build the devid area */
617     dev->numdevid = dasd_build_ckd_devid (dev->ckdtab, dev->ckdcu,
618                                           (BYTE *)&dev->devid);
619 
620     /* Build the devchar area */
621     dev->numdevchar = dasd_build_ckd_devchar (dev->ckdtab, dev->ckdcu,
622                                   (BYTE *)&dev->devchar, dev->ckdcyls);
623 
624     /* Clear the DPA */
625     memset(dev->pgid, 0, sizeof(dev->pgid));
626 
627     /* Activate I/O tracing */
628 //  dev->ccwtrace = 1;
629 
630     /* Request the channel to merge data chained write CCWs into
631        a single buffer before passing data to the device handler */
632     dev->cdwmerge = 1;
633 
634     if (!cckd) return 0;
635     else return cckddasd_init_handler(dev, argc, argv);
636 
637 } /* end function ckddasd_init_handler */
638 
639 
640 /*-------------------------------------------------------------------*/
641 /* Query the device definition                                       */
642 /*-------------------------------------------------------------------*/
ckddasd_query_device(DEVBLK * dev,char ** class,int buflen,char * buffer)643 void ckddasd_query_device (DEVBLK *dev, char **class,
644                 int buflen, char *buffer)
645 {
646     BEGIN_DEVICE_CLASS_QUERY( "DASD", dev, class, buflen, buffer );
647 
648     snprintf (buffer, buflen, "%s [%d cyls]",
649             dev->filename,
650             dev->ckdcyls);
651 
652 } /* end function ckddasd_query_device */
653 
654 /*-------------------------------------------------------------------*/
655 /* Release cache entries                                             */
656 /*-------------------------------------------------------------------*/
ckddasd_purge_cache(int * answer,int ix,int i,void * data)657 int ckddasd_purge_cache (int *answer, int ix, int i, void *data)
658 {
659 U16             devnum;                 /* Cached device number      */
660 int             trk;                    /* Cached track              */
661 DEVBLK         *dev = data;             /* -> device block           */
662 
663     UNREFERENCED(answer);
664     CKD_CACHE_GETKEY(i, devnum, trk);
665     if (dev->devnum == devnum)
666         cache_release (ix, i, CACHE_FREEBUF);
667     return 0;
668 }
669 
670 
671 static int ckddasd_read_track (DEVBLK *dev, int trk, BYTE *unitstat);
672 /*-------------------------------------------------------------------*/
673 /* Close the device                                                  */
674 /*-------------------------------------------------------------------*/
ckddasd_close_device(DEVBLK * dev)675 int ckddasd_close_device ( DEVBLK *dev )
676 {
677 int     i;                              /* Index                     */
678 BYTE    unitstat;                       /* Unit Status               */
679 
680     /* Write the last track image if it's modified */
681     (dev->hnd->read) (dev, -1, &unitstat);
682 
683     /* Free the cache */
684     cache_lock(CACHE_DEVBUF);
685     cache_scan(CACHE_DEVBUF, ckddasd_purge_cache, dev);
686     cache_unlock(CACHE_DEVBUF);
687 
688     if (!dev->batch)
689         logmsg (_("HHCDA023I %4.4X cache hits %d, misses %d, waits %d\n"),
690                 dev->devnum, dev->cachehits, dev->cachemisses,
691                 dev->cachewaits);
692 
693     /* Close all of the CKD image files */
694     for (i = 0; i < dev->ckdnumfd; i++)
695         if (dev->ckdfd[i] > 2)
696             close (dev->ckdfd[i]);
697 
698     dev->buf = NULL;
699     dev->bufsize = 0;
700 
701     return 0;
702 } /* end function ckddasd_close_device */
703 
704 
705 /*-------------------------------------------------------------------*/
706 /* Read a track image at CCHH                                        */
707 /*-------------------------------------------------------------------*/
708 static
ckd_read_cchh(DEVBLK * dev,int cyl,int head,BYTE * unitstat)709 int ckd_read_cchh (DEVBLK *dev, int cyl, int head, BYTE *unitstat)
710 {
711 int             rc;                     /* Return code               */
712 int             trk;                    /* Track number              */
713 
714     /* Command reject if seek position is outside volume */
715     if (cyl >= dev->ckdcyls || head >= dev->ckdheads)
716     {
717         ckd_build_sense (dev, SENSE_CR, 0, 0,
718                         FORMAT_0, MESSAGE_4);
719         *unitstat = CSW_CE | CSW_DE | CSW_UC;
720         return -1;
721     }
722 
723     /* Calculate the track number */
724     trk = cyl * dev->ckdheads + head;
725 
726     /* Call the read exit */
727     rc = (dev->hnd->read) (dev, trk, unitstat);
728 
729     return rc;
730 } /* end function ckd_read_cchh */
731 
732 /*-------------------------------------------------------------------*/
733 /* Return track image length                                         */
734 /*-------------------------------------------------------------------*/
ckd_trklen(DEVBLK * dev,BYTE * buf)735 int ckd_trklen (DEVBLK *dev, BYTE *buf)
736 {
737 int             sz;                     /* Size so far               */
738 
739     for (sz = CKDDASD_TRKHDR_SIZE;
740          memcmp (buf + sz, &eighthexFF, 8) != 0; )
741     {
742         /* add length of count, key, and data fields */
743         sz += CKDDASD_RECHDR_SIZE +
744                 buf[sz+5] +
745                 (buf[sz+6] << 8) + buf[sz+7];
746         if (sz > dev->ckdtrksz - 8) break;
747     }
748 
749     /* add length for end-of-track indicator */
750     sz += CKDDASD_RECHDR_SIZE;
751 
752     if (sz > dev->ckdtrksz)
753         sz = dev->ckdtrksz;
754 
755     return sz;
756 }
757 
758 /*-------------------------------------------------------------------*/
759 /* Read a track image                                                */
760 /*-------------------------------------------------------------------*/
761 static
ckddasd_read_track(DEVBLK * dev,int trk,BYTE * unitstat)762 int ckddasd_read_track (DEVBLK *dev, int trk, BYTE *unitstat)
763 {
764 int             rc;                     /* Return code               */
765 int             cyl;                    /* Cylinder                  */
766 int             head;                   /* Head                      */
767 off_t           offset;                 /* File offsets              */
768 int             i,o,f;                  /* Indexes                   */
769 int             active;                 /* 1=Synchronous I/O active  */
770 CKDDASD_TRKHDR *trkhdr;                 /* -> New track header       */
771 
772     logdevtr (dev, _("HHCDA024I read trk %d cur trk %d\n"), trk, dev->bufcur);
773 
774     /* Calculate cylinder and head */
775     cyl = trk / dev->ckdheads;
776     head = trk % dev->ckdheads;
777 
778     /* Reset buffer offsets */
779     dev->bufoff = 0;
780     dev->bufoffhi = dev->ckdtrksz;
781 
782     /* Return if reading the same track image */
783     if (trk >= 0 && trk == dev->bufcur)
784         return 0;
785 
786     /* Turn off the synchronous I/O bit if trk overflow or trk 0 */
787     active = dev->syncio_active;
788     if (dev->ckdtrkof || trk <= 0)
789         dev->syncio_active = 0;
790 
791     /* Write the previous track image if modified */
792     if (dev->bufupd)
793     {
794         /* Retry if synchronous I/O */
795         if (dev->syncio_active)
796         {
797             dev->syncio_retry = 1;
798             return -1;
799         }
800 
801         logdevtr (dev, _("HHCDA025I read track: updating track %d\n"),
802                   dev->bufcur);
803 
804         dev->bufupd = 0;
805 
806         /* Seek to the old track image offset */
807         offset = (off_t)(dev->ckdtrkoff + dev->bufupdlo);
808         offset = lseek (dev->fd, offset, SEEK_SET);
809         if (offset < 0)
810         {
811             /* Handle seek error condition */
812             logmsg (_("HHCDA026E error writing trk %d: lseek error: %s\n"),
813                     dev->bufcur, strerror(errno));
814             ckd_build_sense (dev, SENSE_EC, 0, 0,
815                             FORMAT_1, MESSAGE_0);
816             *unitstat = CSW_CE | CSW_DE | CSW_UC;
817             cache_lock(CACHE_DEVBUF);
818             cache_setflag(CACHE_DEVBUF, dev->cache, ~CKD_CACHE_ACTIVE, 0);
819             cache_unlock(CACHE_DEVBUF);
820             dev->bufupdlo = dev->bufupdhi = 0;
821             dev->bufcur = dev->cache = -1;
822             return -1;
823         }
824 
825         /* Write the portion of the track image that was modified */
826         rc = write (dev->fd, &dev->buf[dev->bufupdlo],
827                     dev->bufupdhi - dev->bufupdlo);
828         if (rc < dev->bufupdhi - dev->bufupdlo)
829         {
830             /* Handle seek error condition */
831             logmsg (_("HHCDA027E error writing trk %d: write error: %s\n"),
832                     dev->bufcur, strerror(errno));
833             ckd_build_sense (dev, SENSE_EC, 0, 0,
834                             FORMAT_1, MESSAGE_0);
835             *unitstat = CSW_CE | CSW_DE | CSW_UC;
836             cache_lock(CACHE_DEVBUF);
837             cache_setflag(CACHE_DEVBUF, dev->cache, ~CKD_CACHE_ACTIVE, 0);
838             cache_unlock(CACHE_DEVBUF);
839             dev->bufupdlo = dev->bufupdhi = 0;
840             dev->bufcur = dev->cache = -1;
841             return -1;
842         }
843 
844         dev->bufupdlo = dev->bufupdhi = 0;
845     }
846 
847     cache_lock (CACHE_DEVBUF);
848 
849     /* Make the previous cache entry inactive */
850     if (dev->cache >= 0)
851         cache_setflag(CACHE_DEVBUF, dev->cache, ~CKD_CACHE_ACTIVE, 0);
852     dev->bufcur = dev->cache = -1;
853 
854     /* Return on special case when called by the close handler */
855     if (trk < 0)
856     {
857         cache_unlock (CACHE_DEVBUF);
858         return 0;
859     }
860 
861 ckd_read_track_retry:
862 
863     /* Search the cache */
864     i = cache_lookup (CACHE_DEVBUF, CKD_CACHE_SETKEY(dev->devnum, trk), &o);
865 
866     /* Cache hit */
867     if (i >= 0)
868     {
869         cache_setflag(CACHE_DEVBUF, i, ~0, CKD_CACHE_ACTIVE);
870         cache_setage(CACHE_DEVBUF, i);
871         cache_unlock(CACHE_DEVBUF);
872 
873         logdevtr (dev, _("HHCDA028I read trk %d cache hit, using cache[%d]\n"),
874                   trk, i);
875 
876         dev->cachehits++;
877         dev->cache = i;
878         dev->buf = cache_getbuf(CACHE_DEVBUF, dev->cache, 0);
879         dev->bufcur = trk;
880         dev->bufoff = 0;
881         dev->bufoffhi = dev->ckdtrksz;
882         dev->buflen = ckd_trklen (dev, dev->buf);
883         dev->bufsize = cache_getlen(CACHE_DEVBUF, dev->cache);
884 
885         /* Set the file descriptor */
886         for (f = 0; f < dev->ckdnumfd; f++)
887             if (trk < dev->ckdhitrk[f]) break;
888         dev->fd = dev->ckdfd[f];
889 
890         /* Calculate the track offset */
891         dev->ckdtrkoff = CKDDASD_DEVHDR_SIZE +
892              (off_t)(trk - (f ? dev->ckdhitrk[f-1] : 0)) * dev->ckdtrksz;
893 
894         dev->syncio_active = active;
895 
896         return 0;
897      }
898 
899     /* Retry if synchronous I/O */
900     if (dev->syncio_active)
901     {
902         cache_unlock(CACHE_DEVBUF);
903         dev->syncio_retry = 1;
904         return -1;
905     }
906 
907     /* Wait if no available cache entry */
908     if (o < 0)
909     {
910         logdevtr (dev, _("HHCDA029I read trk %d no available cache entry, waiting\n"),
911                   trk);
912         dev->cachewaits++;
913         cache_wait(CACHE_DEVBUF);
914         goto ckd_read_track_retry;
915     }
916 
917     /* Cache miss */
918     logdevtr (dev, _("HHCDA030I read trk %d cache miss, using cache[%d]\n"),
919               trk, o);
920 
921     dev->cachemisses++;
922 
923     /* Make this cache entry active */
924     cache_setkey (CACHE_DEVBUF, o, CKD_CACHE_SETKEY(dev->devnum, trk));
925     cache_setflag(CACHE_DEVBUF, o, 0, CKD_CACHE_ACTIVE|DEVBUF_TYPE_CKD);
926     cache_setage (CACHE_DEVBUF, o);
927     dev->buf = cache_getbuf(CACHE_DEVBUF, o, dev->ckdtrksz);
928     cache_unlock (CACHE_DEVBUF);
929 
930     /* Set the file descriptor */
931     for (f = 0; f < dev->ckdnumfd; f++)
932         if (trk < dev->ckdhitrk[f]) break;
933     dev->fd = dev->ckdfd[f];
934 
935     /* Calculate the track offset */
936     dev->ckdtrkoff = CKDDASD_DEVHDR_SIZE +
937          (off_t)(trk - (f ? dev->ckdhitrk[f-1] : 0)) * dev->ckdtrksz;
938 
939     dev->syncio_active = active;
940 
941     logdevtr (dev, _("HHCDA031I read trk %d reading file %d offset %" I64_FMT "d len %d\n"),
942               trk, f+1, (long long)dev->ckdtrkoff, dev->ckdtrksz);
943 
944     /* Seek to the track image offset */
945     offset = (off_t)dev->ckdtrkoff;
946     offset = lseek (dev->fd, offset, SEEK_SET);
947     if (offset < 0)
948     {
949         /* Handle seek error condition */
950         logmsg (_("HHCDA032E error reading trk %d: lseek error: %s\n"),
951                 trk, strerror(errno));
952         ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0);
953         *unitstat = CSW_CE | CSW_DE | CSW_UC;
954         dev->bufcur = dev->cache = -1;
955         cache_lock(CACHE_DEVBUF);
956         cache_release(CACHE_DEVBUF, o, 0);
957         cache_unlock(CACHE_DEVBUF);
958         return -1;
959     }
960 
961     /* Read the track image */
962     if (dev->dasdcopy == 0)
963     {
964         rc = read (dev->fd, dev->buf, dev->ckdtrksz);
965         if (rc < dev->ckdtrksz)
966         {
967             /* Handle read error condition */
968             logmsg (_("HHCDA033E error reading trk %d: read error: %s\n"),
969                trk, (rc < 0 ? strerror(errno) : "unexpected end of file"));
970             ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0);
971             *unitstat = CSW_CE | CSW_DE | CSW_UC;
972             dev->bufcur = dev->cache = -1;
973             cache_lock(CACHE_DEVBUF);
974             cache_release(CACHE_DEVBUF, o, 0);
975             cache_unlock(CACHE_DEVBUF);
976             return -1;
977         }
978     }
979     else
980     {
981         trkhdr = (CKDDASD_TRKHDR *)dev->buf;
982         trkhdr->bin = 0;
983         trkhdr->cyl[0] = (cyl >> 8);
984         trkhdr->cyl[1] = (cyl & 0xFF);
985         trkhdr->head[0] = (head >> 8);
986         trkhdr->head[1] = (head & 0xFF);
987         memset (dev->buf + CKDDASD_TRKHDR_SIZE, 0xFF, 8);
988     }
989 
990     /* Validate the track header */
991     logdevtr (dev, _("HHCDA034I read trk %d trkhdr %2.2x %2.2x%2.2x %2.2x%2.2x\n"),
992        trk, dev->buf[0], dev->buf[1], dev->buf[2], dev->buf[3], dev->buf[4]);
993     trkhdr = (CKDDASD_TRKHDR *)dev->buf;
994     if (trkhdr->bin != 0
995       || trkhdr->cyl[0] != (cyl >> 8)
996       || trkhdr->cyl[1] != (cyl & 0xFF)
997       || trkhdr->head[0] != (head >> 8)
998       || trkhdr->head[1] != (head & 0xFF))
999     {
1000         logmsg (_("HHCDA035E %4.4X invalid track header for cyl %d head %d "
1001                 " %2.2x%2.2x%2.2x%2.2x%2.2x\n"), dev->devnum, cyl, head,
1002                 trkhdr->bin,trkhdr->cyl[0],trkhdr->cyl[1],trkhdr->head[0],trkhdr->head[1]);
1003         ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0);
1004         *unitstat = CSW_CE | CSW_DE | CSW_UC;
1005         dev->bufcur = dev->cache = -1;
1006         cache_lock(CACHE_DEVBUF);
1007         cache_release(CACHE_DEVBUF, o, 0);
1008         cache_unlock(CACHE_DEVBUF);
1009         return -1;
1010     }
1011 
1012     dev->cache = o;
1013     dev->buf = cache_getbuf(CACHE_DEVBUF, dev->cache, 0);
1014     dev->bufcur = trk;
1015     dev->bufoff = 0;
1016     dev->bufoffhi = dev->ckdtrksz;
1017     dev->buflen = ckd_trklen (dev, dev->buf);
1018     dev->bufsize = cache_getlen(CACHE_DEVBUF, dev->cache);
1019 
1020     return 0;
1021 } /* end function ckdread_read_track */
1022 
1023 
1024 /*-------------------------------------------------------------------*/
1025 /* Update a track image                                              */
1026 /*-------------------------------------------------------------------*/
1027 static
ckddasd_update_track(DEVBLK * dev,int trk,int off,BYTE * buf,int len,BYTE * unitstat)1028 int ckddasd_update_track (DEVBLK *dev, int trk, int off,
1029                       BYTE *buf, int len, BYTE *unitstat)
1030 {
1031 int             rc;                     /* Return code               */
1032 
1033     /* Immediately return if fake writing */
1034     if (dev->ckdfakewr)
1035         return len;
1036 
1037     /* Error if opened read-only */
1038     if (dev->ckdrdonly)
1039     {
1040         ckd_build_sense (dev, SENSE_EC, SENSE1_WRI, 0,
1041                         FORMAT_1, MESSAGE_0);
1042         *unitstat = CSW_CE | CSW_DE | CSW_UC;
1043         return -1;
1044     }
1045 
1046     /* Read the track if it's not current */
1047     if (trk != dev->bufcur)
1048     {
1049         rc = (dev->hnd->read) (dev, trk, unitstat);
1050         if (rc < 0)
1051         {
1052             dev->bufcur = dev->cache = -1;
1053             return -1;
1054         }
1055     }
1056 
1057     /* Invalid track format if going past buffer end */
1058     if (off + len > dev->bufoffhi)
1059     {
1060         ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0);
1061         *unitstat = CSW_CE | CSW_DE | CSW_UC;
1062         return -1;
1063     }
1064 
1065     /* Copy the data into the buffer */
1066     if (buf) memcpy (dev->buf + off, buf, len);
1067 
1068     /* Set low and high updated offsets */
1069     if (!dev->bufupd || off < dev->bufupdlo)
1070         dev->bufupdlo = off;
1071     if (off + len > dev->bufupdhi)
1072         dev->bufupdhi = off + len;
1073 
1074     /* Indicate track image has been modified */
1075     if (!dev->bufupd)
1076     {
1077         dev->bufupd = 1;
1078         shared_update_notify (dev, trk);
1079     }
1080 
1081     return len;
1082 } /* end function ckd_update_track */
1083 
1084 /*-------------------------------------------------------------------*/
1085 /* CKD start/resume channel program                                  */
1086 /*-------------------------------------------------------------------*/
ckddasd_start(DEVBLK * dev)1087 void ckddasd_start (DEVBLK *dev)
1088 {
1089     /* Reset buffer offsets */
1090     dev->bufoff = 0;
1091     dev->bufoffhi = dev->ckdtrksz;
1092 }
1093 
1094 /*-------------------------------------------------------------------*/
1095 /* CKD end/suspend channel program                                   */
1096 /*-------------------------------------------------------------------*/
ckddasd_end(DEVBLK * dev)1097 void ckddasd_end (DEVBLK *dev)
1098 {
1099 BYTE    unitstat;                       /* Unit Status               */
1100 
1101     /* Write the last track image if it's modified */
1102     (dev->hnd->read) (dev, -1, &unitstat);
1103 }
1104 
1105 /*-------------------------------------------------------------------*/
1106 /* Return used cylinders                                             */
1107 /*-------------------------------------------------------------------*/
ckddasd_used(DEVBLK * dev)1108 int ckddasd_used (DEVBLK *dev)
1109 {
1110     return dev->ckdcyls;
1111 }
1112 
1113 /*-------------------------------------------------------------------*/
1114 /* Hercules suspend/resume text unit key values                      */
1115 /*-------------------------------------------------------------------*/
1116 #define SR_DEV_CKD_BUFCUR       ( SR_DEV_CKD | 0x001 )
1117 #define SR_DEV_CKD_BUFOFF       ( SR_DEV_CKD | 0x002 )
1118 #define SR_DEV_CKD_CURCYL       ( SR_DEV_CKD | 0x003 )
1119 #define SR_DEV_CKD_CURHEAD      ( SR_DEV_CKD | 0x004 )
1120 #define SR_DEV_CKD_CURREC       ( SR_DEV_CKD | 0x005 )
1121 #define SR_DEV_CKD_CURKL        ( SR_DEV_CKD | 0x006 )
1122 #define SR_DEV_CKD_ORIENT       ( SR_DEV_CKD | 0x007 )
1123 #define SR_DEV_CKD_CUROPER      ( SR_DEV_CKD | 0x008 )
1124 #define SR_DEV_CKD_CURDL        ( SR_DEV_CKD | 0x009 )
1125 #define SR_DEV_CKD_REM          ( SR_DEV_CKD | 0x00a )
1126 #define SR_DEV_CKD_POS          ( SR_DEV_CKD | 0x00b )
1127 #define SR_DEV_CKD_DXBLKSZ      ( SR_DEV_CKD | 0x010 )
1128 #define SR_DEV_CKD_DXBCYL       ( SR_DEV_CKD | 0x011 )
1129 #define SR_DEV_CKD_DXBHEAD      ( SR_DEV_CKD | 0x012 )
1130 #define SR_DEV_CKD_DXECYL       ( SR_DEV_CKD | 0x013 )
1131 #define SR_DEV_CKD_DXEHEAD      ( SR_DEV_CKD | 0x014 )
1132 #define SR_DEV_CKD_DXFMASK      ( SR_DEV_CKD | 0x015 )
1133 #define SR_DEV_CKD_DXGATTR      ( SR_DEV_CKD | 0x016 )
1134 #define SR_DEV_CKD_LRTRANLF     ( SR_DEV_CKD | 0x020 )
1135 #define SR_DEV_CKD_LROPER       ( SR_DEV_CKD | 0x021 )
1136 #define SR_DEV_CKD_LRAUX        ( SR_DEV_CKD | 0x022 )
1137 #define SR_DEV_CKD_LRCOUNT      ( SR_DEV_CKD | 0x023 )
1138 #define SR_DEV_CKD_3990         ( SR_DEV_CKD | 0x040 )
1139 #define SR_DEV_CKD_XTDEF        ( SR_DEV_CKD | 0x041 )
1140 #define SR_DEV_CKD_SETFM        ( SR_DEV_CKD | 0x042 )
1141 #define SR_DEV_CKD_LOCAT        ( SR_DEV_CKD | 0x043 )
1142 #define SR_DEV_CKD_SPCNT        ( SR_DEV_CKD | 0x044 )
1143 #define SR_DEV_CKD_SEEK         ( SR_DEV_CKD | 0x045 )
1144 #define SR_DEV_CKD_SKCYL        ( SR_DEV_CKD | 0x046 )
1145 #define SR_DEV_CKD_RECAL        ( SR_DEV_CKD | 0x047 )
1146 #define SR_DEV_CKD_RDIPL        ( SR_DEV_CKD | 0x048 )
1147 #define SR_DEV_CKD_XMARK        ( SR_DEV_CKD | 0x049 )
1148 #define SR_DEV_CKD_HAEQ         ( SR_DEV_CKD | 0x04a )
1149 #define SR_DEV_CKD_IDEQ         ( SR_DEV_CKD | 0x04b )
1150 #define SR_DEV_CKD_KYEQ         ( SR_DEV_CKD | 0x04c )
1151 #define SR_DEV_CKD_WCKD         ( SR_DEV_CKD | 0x04d )
1152 #define SR_DEV_CKD_TRKOF        ( SR_DEV_CKD | 0x04e )
1153 #define SR_DEV_CKD_SSI          ( SR_DEV_CKD | 0x04f )
1154 #define SR_DEV_CKD_WRHA         ( SR_DEV_CKD | 0x050 )
1155 
1156 /*-------------------------------------------------------------------*/
1157 /* Hercules suspend                                                  */
1158 /*-------------------------------------------------------------------*/
ckddasd_hsuspend(DEVBLK * dev,void * file)1159 int ckddasd_hsuspend(DEVBLK *dev, void *file) {
1160     if (dev->bufcur >= 0)
1161     {
1162         SR_WRITE_VALUE(file, SR_DEV_CKD_BUFCUR, dev->bufcur, sizeof(dev->bufcur));
1163         SR_WRITE_VALUE(file, SR_DEV_CKD_BUFOFF, dev->bufoff, sizeof(dev->bufoff));
1164     }
1165     SR_WRITE_VALUE(file, SR_DEV_CKD_CURCYL, dev->ckdcurcyl, sizeof(dev->ckdcurcyl));
1166     SR_WRITE_VALUE(file, SR_DEV_CKD_CURHEAD, dev->ckdcurhead, sizeof(dev->ckdcurhead));
1167     SR_WRITE_VALUE(file, SR_DEV_CKD_CURREC, dev->ckdcurrec, sizeof(dev->ckdcurrec));
1168     SR_WRITE_VALUE(file, SR_DEV_CKD_CURKL, dev->ckdcurkl, sizeof(dev->ckdcurkl));
1169     SR_WRITE_VALUE(file, SR_DEV_CKD_ORIENT, dev->ckdorient, sizeof(dev->ckdorient));
1170     SR_WRITE_VALUE(file, SR_DEV_CKD_CUROPER, dev->ckdcuroper, sizeof(dev->ckdcuroper));
1171     SR_WRITE_VALUE(file, SR_DEV_CKD_CURDL, dev->ckdcurdl, sizeof(dev->ckdcurdl));
1172     SR_WRITE_VALUE(file, SR_DEV_CKD_REM, dev->ckdrem, sizeof(dev->ckdrem));
1173     SR_WRITE_VALUE(file, SR_DEV_CKD_POS, dev->ckdpos, sizeof(dev->ckdpos));
1174     SR_WRITE_VALUE(file, SR_DEV_CKD_DXBLKSZ, dev->ckdxblksz, sizeof(dev->ckdxblksz));
1175     SR_WRITE_VALUE(file, SR_DEV_CKD_DXBCYL, dev->ckdxbcyl, sizeof(dev->ckdxbcyl));
1176     SR_WRITE_VALUE(file, SR_DEV_CKD_DXBHEAD, dev->ckdxbhead, sizeof(dev->ckdxbhead));
1177     SR_WRITE_VALUE(file, SR_DEV_CKD_DXECYL, dev->ckdxecyl, sizeof(dev->ckdxecyl));
1178     SR_WRITE_VALUE(file, SR_DEV_CKD_DXEHEAD, dev->ckdxehead, sizeof(dev->ckdxehead));
1179     SR_WRITE_VALUE(file, SR_DEV_CKD_DXFMASK, dev->ckdfmask, sizeof(dev->ckdfmask));
1180     SR_WRITE_VALUE(file, SR_DEV_CKD_DXGATTR, dev->ckdxgattr, sizeof(dev->ckdxgattr));
1181     SR_WRITE_VALUE(file, SR_DEV_CKD_LRTRANLF, dev->ckdltranlf, sizeof(dev->ckdltranlf));
1182     SR_WRITE_VALUE(file, SR_DEV_CKD_LROPER, dev->ckdloper, sizeof(dev->ckdloper));
1183     SR_WRITE_VALUE(file, SR_DEV_CKD_LRAUX, dev->ckdlaux, sizeof(dev->ckdlaux));
1184     SR_WRITE_VALUE(file, SR_DEV_CKD_LRCOUNT, dev->ckdlcount, sizeof(dev->ckdlcount));
1185     SR_WRITE_VALUE(file, SR_DEV_CKD_3990, dev->ckd3990, 1);
1186     SR_WRITE_VALUE(file, SR_DEV_CKD_XTDEF, dev->ckdxtdef, 1);
1187     SR_WRITE_VALUE(file, SR_DEV_CKD_SETFM, dev->ckdsetfm, 1);
1188     SR_WRITE_VALUE(file, SR_DEV_CKD_LOCAT, dev->ckdlocat, 1);
1189     SR_WRITE_VALUE(file, SR_DEV_CKD_SPCNT, dev->ckdspcnt, 1);
1190     SR_WRITE_VALUE(file, SR_DEV_CKD_SEEK, dev->ckdseek, 1);
1191     SR_WRITE_VALUE(file, SR_DEV_CKD_SKCYL, dev->ckdskcyl, 1);
1192     SR_WRITE_VALUE(file, SR_DEV_CKD_RECAL, dev->ckdrecal, 1);
1193     SR_WRITE_VALUE(file, SR_DEV_CKD_RDIPL, dev->ckdrdipl, 1);
1194     SR_WRITE_VALUE(file, SR_DEV_CKD_XMARK, dev->ckdxmark, 1);
1195     SR_WRITE_VALUE(file, SR_DEV_CKD_HAEQ, dev->ckdhaeq, 1);
1196     SR_WRITE_VALUE(file, SR_DEV_CKD_IDEQ, dev->ckdideq, 1);
1197     SR_WRITE_VALUE(file, SR_DEV_CKD_KYEQ, dev->ckdkyeq, 1);
1198     SR_WRITE_VALUE(file, SR_DEV_CKD_WCKD, dev->ckdwckd, 1);
1199     SR_WRITE_VALUE(file, SR_DEV_CKD_TRKOF, dev->ckdtrkof, 1);
1200     SR_WRITE_VALUE(file, SR_DEV_CKD_SSI, dev->ckdssi, 1);
1201     SR_WRITE_VALUE(file, SR_DEV_CKD_WRHA, dev->ckdwrha, 1);
1202     return 0;
1203 }
1204 
1205 /*-------------------------------------------------------------------*/
1206 /* Hercules resume                                                   */
1207 /*-------------------------------------------------------------------*/
ckddasd_hresume(DEVBLK * dev,void * file)1208 int ckddasd_hresume(DEVBLK *dev, void *file)
1209 {
1210 u_int   rc;
1211 size_t  key, len;
1212 BYTE byte;
1213 
1214     do {
1215         SR_READ_HDR(file, key, len);
1216         switch (key) {
1217         case SR_DEV_CKD_BUFCUR:
1218             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1219             rc = (dev->hnd->read) ? (dev->hnd->read)(dev, rc, &byte) : -1;
1220             if ((int)rc < 0) return -1;
1221             break;
1222         case SR_DEV_CKD_BUFOFF:
1223             SR_READ_VALUE(file, len, &dev->bufoff, sizeof(dev->bufoff));
1224             break;
1225         case SR_DEV_CKD_CURCYL:
1226             SR_READ_VALUE(file, len, &dev->ckdcurcyl, sizeof(dev->ckdcurcyl));
1227             break;
1228         case SR_DEV_CKD_CURHEAD:
1229             SR_READ_VALUE(file, len, &dev->ckdcurhead, sizeof(dev->ckdcurhead));
1230             break;
1231         case SR_DEV_CKD_CURREC:
1232             SR_READ_VALUE(file, len, &dev->ckdcurrec, sizeof(dev->ckdcurrec));
1233             break;
1234         case SR_DEV_CKD_CURKL:
1235             SR_READ_VALUE(file, len, &dev->ckdcurkl, sizeof(dev->ckdcurkl));
1236             break;
1237         case SR_DEV_CKD_ORIENT:
1238             SR_READ_VALUE(file, len, &dev->ckdorient, sizeof(dev->ckdorient));
1239             break;
1240         case SR_DEV_CKD_CUROPER:
1241             SR_READ_VALUE(file, len, &dev->ckdcuroper, sizeof(dev->ckdcuroper));
1242             break;
1243         case SR_DEV_CKD_CURDL:
1244             SR_READ_VALUE(file, len, &dev->ckdcurdl, sizeof(dev->ckdcurdl));
1245             break;
1246         case SR_DEV_CKD_REM:
1247             SR_READ_VALUE(file, len, &dev->ckdrem, sizeof(dev->ckdrem));
1248             break;
1249         case SR_DEV_CKD_POS:
1250             SR_READ_VALUE(file, len, &dev->ckdpos, sizeof(dev->ckdpos));
1251             break;
1252         case SR_DEV_CKD_DXBLKSZ:
1253             SR_READ_VALUE(file, len, &dev->ckdxblksz, sizeof(dev->ckdxblksz));
1254             break;
1255         case SR_DEV_CKD_DXBCYL:
1256             SR_READ_VALUE(file, len, &dev->ckdxbcyl, sizeof(dev->ckdxbcyl));
1257             break;
1258         case SR_DEV_CKD_DXBHEAD:
1259             SR_READ_VALUE(file, len, &dev->ckdxbhead, sizeof(dev->ckdxbhead));
1260             break;
1261         case SR_DEV_CKD_DXECYL:
1262             SR_READ_VALUE(file, len, &dev->ckdxecyl, sizeof(dev->ckdxecyl));
1263             break;
1264         case SR_DEV_CKD_DXEHEAD:
1265             SR_READ_VALUE(file, len, &dev->ckdxehead, sizeof(dev->ckdxehead));
1266             break;
1267         case SR_DEV_CKD_DXFMASK:
1268             SR_READ_VALUE(file, len, &dev->ckdfmask, sizeof(dev->ckdfmask));
1269             break;
1270         case SR_DEV_CKD_DXGATTR:
1271             SR_READ_VALUE(file, len, &dev->ckdxgattr, sizeof(dev->ckdxgattr));
1272             break;
1273         case SR_DEV_CKD_LRTRANLF:
1274             SR_READ_VALUE(file, len, &dev->ckdltranlf, sizeof(dev->ckdltranlf));
1275             break;
1276         case SR_DEV_CKD_LROPER:
1277             SR_READ_VALUE(file, len, &dev->ckdloper, sizeof(dev->ckdloper));
1278             break;
1279         case SR_DEV_CKD_LRAUX:
1280             SR_READ_VALUE(file, len, &dev->ckdlaux, sizeof(dev->ckdlaux));
1281             break;
1282         case SR_DEV_CKD_LRCOUNT:
1283             SR_READ_VALUE(file, len, &dev->ckdltranlf, sizeof(dev->ckdltranlf));
1284             break;
1285         case SR_DEV_CKD_3990:
1286             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1287             dev->ckd3990 = rc;
1288             break;
1289         case SR_DEV_CKD_XTDEF:
1290             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1291             dev->ckdxtdef = rc;
1292             break;
1293         case SR_DEV_CKD_SETFM:
1294             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1295             dev->ckdsetfm = rc;
1296             break;
1297         case SR_DEV_CKD_LOCAT:
1298             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1299             dev->ckdlocat = rc;
1300             break;
1301         case SR_DEV_CKD_SPCNT:
1302             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1303             dev->ckdspcnt = rc;
1304             break;
1305         case SR_DEV_CKD_SEEK:
1306             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1307             dev->ckdseek = rc;
1308             break;
1309         case SR_DEV_CKD_SKCYL:
1310             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1311             dev->ckdskcyl = rc;
1312             break;
1313         case SR_DEV_CKD_RECAL:
1314             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1315             dev->ckdrecal = rc;
1316             break;
1317         case SR_DEV_CKD_RDIPL:
1318             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1319             dev->ckdrdipl = rc;
1320             break;
1321         case SR_DEV_CKD_XMARK:
1322             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1323             dev->ckdxmark = rc;
1324             break;
1325         case SR_DEV_CKD_HAEQ:
1326             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1327             dev->ckdhaeq = rc;
1328             break;
1329         case SR_DEV_CKD_IDEQ:
1330             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1331             dev->ckdideq = rc;
1332             break;
1333         case SR_DEV_CKD_KYEQ:
1334             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1335             dev->ckdkyeq = rc;
1336             break;
1337         case SR_DEV_CKD_WCKD:
1338             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1339             dev->ckdwckd = rc;
1340             break;
1341         case SR_DEV_CKD_TRKOF:
1342             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1343             dev->ckdtrkof = rc;
1344             break;
1345         case SR_DEV_CKD_SSI:
1346             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1347             dev->ckdssi = rc;
1348             break;
1349         case SR_DEV_CKD_WRHA:
1350             SR_READ_VALUE(file, len, &rc, sizeof(rc));
1351             dev->ckdwrha = rc;
1352             break;
1353         default:
1354             SR_READ_SKIP(file, len);
1355             break;
1356         } /* switch (key) */
1357     } while ((key & SR_DEV_MASK) == SR_DEV_CKD);
1358     return 0;
1359 }
1360 
1361 /*-------------------------------------------------------------------*/
1362 /* Build sense data                                                  */
1363 /*-------------------------------------------------------------------*/
ckd_build_sense(DEVBLK * dev,BYTE sense0,BYTE sense1,BYTE sense2,BYTE format,BYTE message)1364 void ckd_build_sense ( DEVBLK *dev, BYTE sense0, BYTE sense1,
1365                        BYTE sense2, BYTE format, BYTE message )
1366 {
1367 int shift;  /* num of bits to shift left 'high cyl' in sense6 */
1368     /* Clear the sense bytes */
1369     memset (dev->sense, 0, sizeof(dev->sense));
1370 
1371     /* Sense bytes 0-2 are specified by caller */
1372     dev->sense[0] = sense0;
1373     dev->sense[1] = sense1;
1374     dev->sense[2] = sense2;
1375 
1376     /* Sense byte 3 contains the residual locate record count
1377        if imprecise ending is indicated in sense byte 1 */
1378     if (sense1 & SENSE1_IE)
1379     {
1380         if (dev->ckdtrkof)
1381             dev->sense[3] = dev->ckdcuroper;
1382         else
1383             dev->sense[3] = dev->ckdlcount;
1384     }
1385 
1386     /* Sense byte 4 is the physical device address */
1387     dev->sense[4] = 0;
1388 
1389     if (dev->devtype == 0x2305)
1390     {
1391        /*             0x40=ONLINE             0x04=END OF CYL */
1392         dev->sense[3] = (((dev->sense[1]) & 0x20) >> 3) | 0x40;
1393     }
1394     if (dev->devtype == 0x2311)
1395     {
1396        /* 0x80=READY, 0x40=ONLINE 0x08=ONLINE 0x04=END OF CYL */
1397         dev->sense[3] = (((dev->sense[1]) & 0x20) >> 3) | 0xC8;
1398     }
1399     if (dev->devtype == 0x2314)
1400     {
1401        /*             0x40=ONLINE             0x04=END OF CYL */
1402         dev->sense[3] = (((dev->sense[1]) & 0x20) >> 3) | 0x40;
1403     }
1404     if (dev->devtype == 0x3330)
1405     {
1406      /* bits 0-1 = controller address */
1407      /* bits 2-7: drive A = 111000, B = 110001, ... H = 000111 */
1408        dev->sense[4] = (dev->devnum & 0x07) | ((~(dev->devnum) & 0x07) << 3);
1409     }
1410     if (dev->devtype == 0x3340)
1411     {
1412      /* X'01' = 35 MB drive, X'02' = 70 MB drive  (same as 'model') */
1413      /* X'80' RPS feature installed */
1414        dev->sense[2] |= 0x80 | dev->devid[6];  /* RPS + model */
1415        /* drive A = bit 0 (0x80), ... drive H = bit 7 (0x01) */
1416        dev->sense[4] =  0x80 >> (dev->devnum & 0x07);
1417     }
1418     if (dev->devtype == 0x3350)
1419     {
1420        /* drive 0 = bit 0 (0x80), ... drive 7 = bit 7 (0x01) */
1421        dev->sense[4] =  0x80 >> (dev->devnum & 0x07);
1422     }
1423     if (dev->devtype == 0x3375)
1424     {
1425        /* bits 3-4 = controller address, bits 5-7 = device address */
1426        dev->sense[4] = dev->devnum & 0x07;
1427     }
1428     if (dev->devtype == 0x3380)
1429     {
1430        /* bits 4-7 = device address */
1431        dev->sense[4] = dev->devnum & 0x0F;
1432     }
1433 
1434     /* Sense byte 5 contains bits 8-15 of the cylinder address
1435        and sense byte 6 contains bits 4-7 of the cylinder
1436        address followed by bits 12-15 of the head address,
1437        unless the device has more than 4095 cylinders, in
1438        which case sense bytes 5 and 6 both contain X'FF' */
1439     if (dev->ckdcyls > 4095)
1440     {
1441         dev->sense[5] = 0xFF;
1442         dev->sense[6] = 0xFF;
1443     }
1444     else
1445     {
1446      if ((dev->devtype == 0x2311 ) || (dev->devtype == 0x2314 )
1447       || (dev->devtype == 0x2305 ))
1448      {
1449      }
1450      else
1451      {
1452         dev->sense[5] = dev->ckdcurcyl & 0xFF;
1453 
1454      /* sense byte 6 bits     c = cyl high byte, h=head    */
1455      /*                          0 1 2 3 4 5 6 7   shift   */
1456      /* 3330-1                   - c - h h h h h      6    */
1457      /* 3330-11 3350             - c c h h h h h      5    */
1458      /* 3340                     - c c - h h h h      5    */
1459      /* 3375                     c c - - h h h h      6    */
1460      /* 3380                     c c c c h h h h      4    */
1461        switch (dev->devtype) {
1462         case 0x3330:
1463              if (dev->devid[6] == 0x01)
1464                                    shift = 6; /* 3330-1 */
1465              else
1466                                    shift = 5; /* 3330-11 */
1467         case 0x3340: case 0x3350:  shift = 5;
1468         case 0x3375:               shift = 6;
1469         default:                   shift = 4;
1470        }
1471         dev->sense[6] = ( (dev->ckdcurcyl >> 8) << shift )
1472                         | (dev->ckdcurhead & 0x1F);
1473      }
1474     }
1475 
1476     /* Sense byte 7 contains the format code and message type */
1477     dev->sense[7] = (format << 4) | (message & 0x0F);
1478 
1479     /* Sense bytes 8-23 depend on the format code */
1480     switch (format) {
1481 
1482     case FORMAT_4: /* Data check */
1483     case FORMAT_5: /* Data check with displacement information */
1484         /* Sense bytes 8-12 contain the CCHHR of the record in error */
1485         dev->sense[8] = dev->ckdcurcyl >> 8;
1486         dev->sense[9] = dev->ckdcurcyl & 0xFF;
1487         dev->sense[10] = dev->ckdcurhead >> 8;
1488         dev->sense[11] = dev->ckdcurhead & 0xFF;
1489         dev->sense[12] = dev->ckdcurrec;
1490         break;
1491 
1492     } /* end switch(format) */
1493 
1494     /* Sense byte 27 bit 0 indicates 24-byte compatability sense data*/
1495     dev->sense[27] = 0x80;
1496 
1497     /* Sense bytes 29-30 contain the cylinder address */
1498     dev->sense[29] = dev->ckdcurcyl >> 8;
1499     dev->sense[30] = dev->ckdcurcyl & 0xFF;
1500 
1501     /* Sense byte 31 contains the head address */
1502     dev->sense[31] = dev->ckdcurhead & 0xFF;
1503 
1504 } /* end function ckd_build_sense */
1505 
1506 /*-------------------------------------------------------------------*/
1507 /* Seek to a specified cylinder and head                             */
1508 /*-------------------------------------------------------------------*/
ckd_seek(DEVBLK * dev,int cyl,int head,CKDDASD_TRKHDR * trkhdr,BYTE * unitstat)1509 static int ckd_seek ( DEVBLK *dev, int cyl, int head,
1510                       CKDDASD_TRKHDR *trkhdr, BYTE *unitstat )
1511 {
1512 int             rc;                     /* Return code               */
1513 
1514     logdevtr (dev, _("HHCDA038I seeking to cyl %d head %d\n"), cyl, head);
1515 
1516     /* Read the track image */
1517     rc = ckd_read_cchh (dev, cyl, head, unitstat);
1518     if (rc < 0) return -1;
1519 
1520     /* Set device orientation fields */
1521     dev->ckdcurcyl = cyl;
1522     dev->ckdcurhead = head;
1523     dev->ckdcurrec = 0;
1524     dev->ckdcurkl = 0;
1525     dev->ckdcurdl = 0;
1526     dev->ckdrem = 0;
1527     dev->ckdorient = CKDORIENT_INDEX;
1528 
1529     /* Copy the track header */
1530     if (trkhdr) memcpy (trkhdr, &dev->buf[dev->bufoff], CKDDASD_TRKHDR_SIZE);
1531 
1532     /* Increment offset past the track header */
1533     dev->bufoff += CKDDASD_TRKHDR_SIZE;
1534 
1535     return 0;
1536 } /* end function ckd_seek */
1537 
1538 
1539 /*-------------------------------------------------------------------*/
1540 /* Advance to next track for multitrack operation                    */
1541 /*-------------------------------------------------------------------*/
mt_advance(DEVBLK * dev,BYTE * unitstat,int trks)1542 static int mt_advance ( DEVBLK *dev, BYTE *unitstat, int trks )
1543 {
1544 int             rc;                     /* Return code               */
1545 int             cyl;                    /* Next cyl for multitrack   */
1546 int             head;                   /* Next head for multitrack  */
1547 
1548     /* File protect error if not within domain of Locate Record
1549        and file mask inhibits seek and multitrack operations */
1550     if (dev->ckdlcount == 0 &&
1551         (dev->ckdfmask & CKDMASK_SKCTL) == CKDMASK_SKCTL_INHSMT)
1552     {
1553         logdevtr (dev, _("HHCDA039E MT advance error: "
1554                  "locate record %d file mask %2.2X\n"),
1555                  dev->ckdlcount, dev->ckdfmask);
1556         if (dev->ckdtrkof)
1557             ckd_build_sense (dev, 0, SENSE1_FP | SENSE1_IE, 0, 0, 0);
1558         else
1559            ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0);
1560         *unitstat = CSW_CE | CSW_DE | CSW_UC;
1561         return -1;
1562     }
1563 
1564     /* End of cylinder error if not within domain of Locate Record
1565        and current track is last track of cylinder */
1566     if (dev->ckdlcount == 0
1567         && dev->ckdcurhead + trks >= dev->ckdheads)
1568     {
1569         if (dev->ckdtrkof)
1570             ckd_build_sense (dev, 0, SENSE1_EOC | SENSE1_IE, 0, 0, 0);
1571         else
1572             ckd_build_sense (dev, 0, SENSE1_EOC, 0, 0, 0);
1573         *unitstat = CSW_CE | CSW_DE | CSW_UC;
1574         return -1;
1575     }
1576 
1577     /* Advance to next track */
1578     cyl = dev->ckdcurcyl;
1579     head = dev->ckdcurhead + trks;
1580     while (head >= dev->ckdheads)
1581     {
1582         head -= dev->ckdheads;
1583         cyl++;
1584     }
1585     logdevtr (dev, _("HHCDA040I MT advance to cyl %d head %d\n"), cyl, head);
1586 
1587     /* File protect error if next track is outside the
1588        limits of the device or outside the defined extent */
1589     if ( EXTENT_CHECK(dev, cyl, head) )
1590     {
1591         if (dev->ckdtrkof)
1592             ckd_build_sense (dev, 0, SENSE1_FP | SENSE1_IE, 0, 0, 0);
1593         else
1594             ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0);
1595         *unitstat = CSW_CE | CSW_DE | CSW_UC;
1596         return -1;
1597     }
1598 
1599     /* Seek to next track */
1600     rc = ckd_seek (dev, cyl, head, NULL, unitstat);
1601     if (rc < 0) return -1;
1602 
1603     /* Successful return */
1604     return 0;
1605 
1606 } /* end function mt_advance */
1607 
1608 /*-------------------------------------------------------------------*/
1609 /* Read count field                                                  */
1610 /*-------------------------------------------------------------------*/
ckd_read_count(DEVBLK * dev,BYTE code,CKDDASD_RECHDR * rechdr,BYTE * unitstat)1611 static int ckd_read_count ( DEVBLK *dev, BYTE code,
1612                 CKDDASD_RECHDR *rechdr, BYTE *unitstat)
1613 {
1614 int             rc;                     /* Return code               */
1615 int             skipr0 = 0;             /* 1=Skip record zero        */
1616 int             cyl;                    /* Cylinder number for seek  */
1617 int             head;                   /* Head number for seek      */
1618 char           *orient[] = {"none", "index", "count", "key", "data", "eot"};
1619 
1620     /* Skip record 0 for all operations except READ TRACK, READ R0,
1621        SEARCH ID EQUAL, SEARCH ID HIGH, SEARCH ID EQUAL OR HIGH,
1622        LOCATE RECORD, and WRITE CKD NEXT TRACK */
1623     if (code != 0xDE
1624         && (code & 0x7F) != 0x16
1625         && (code & 0x7F) != 0x31
1626         && (code & 0x7F) != 0x51
1627         && (code & 0x7F) != 0x71
1628         && code != 0x47
1629         && code != 0x4B
1630         && code != 0x9D)
1631         skipr0 = 1;
1632 
1633     logdevtr (dev, _("HHCDA041I read count orientation is %s\n"),
1634               orient[dev->ckdorient]);
1635 
1636     /* If orientation is at End-Of_Track then a multi-track advance
1637        failed previously during synchronous I/O */
1638     if (dev->ckdorient == CKDORIENT_EOT)
1639     {
1640         rc = mt_advance (dev, unitstat, 1);
1641         if (rc < 0) return -1;
1642     }
1643 
1644     /* Search for next count field */
1645     for ( ; ; )
1646     {
1647         /* If oriented to count or key field, skip key and data */
1648         if (dev->ckdorient == CKDORIENT_COUNT)
1649             dev->bufoff += dev->ckdcurkl + dev->ckdcurdl;
1650         else if (dev->ckdorient == CKDORIENT_KEY)
1651             dev->bufoff += dev->ckdcurdl;
1652 
1653         /* Make sure we don't copy past the end of the buffer */
1654         if (dev->bufoff + CKDDASD_RECHDR_SIZE >= dev->bufoffhi)
1655         {
1656             /* Handle error condition */
1657             logmsg (_("HHCDA042E attempt to read past end of track %d %d\n"),
1658                     dev->bufoff, dev->bufoffhi);
1659 
1660             /* Set unit check with equipment check */
1661             ckd_build_sense (dev, SENSE_EC, 0, 0,
1662                             FORMAT_1, MESSAGE_0);
1663             *unitstat = CSW_CE | CSW_DE | CSW_UC;
1664             return -1;
1665         }
1666 
1667         /* Copy the record header (count field) */
1668         memcpy (rechdr, &dev->buf[dev->bufoff], CKDDASD_RECHDR_SIZE);
1669         dev->bufoff += CKDDASD_RECHDR_SIZE;
1670 
1671         /* Set the device orientation fields */
1672         dev->ckdcurrec = rechdr->rec;
1673         dev->ckdrem = 0;
1674         dev->ckdorient = CKDORIENT_COUNT;
1675         dev->ckdcurkl = rechdr->klen;
1676         dev->ckdcurdl = (rechdr->dlen[0] << 8) + rechdr->dlen[1];
1677         if(dev->ckdcyls < 32768)
1678             dev->ckdtrkof = (rechdr->cyl[0] == 0xFF) ? 0 : rechdr->cyl[0] >> 7;
1679         else
1680             dev->ckdtrkof = 0;
1681 
1682         logdevtr (dev, _("HHCDA043I cyl %d head %d record %d kl %d dl %d of %d\n"),
1683                 dev->ckdcurcyl, dev->ckdcurhead, dev->ckdcurrec,
1684                 dev->ckdcurkl, dev->ckdcurdl, dev->ckdtrkof);
1685 
1686         /* Skip record zero if user data record required */
1687         if (skipr0 && rechdr->rec == 0)
1688             continue;
1689 
1690         /* Test for logical end of track and exit if not */
1691         if (memcmp(rechdr, eighthexFF, 8) != 0)
1692             break;
1693         dev->ckdorient = CKDORIENT_EOT;
1694 
1695         /* For READ TRACK or READ MULTIPLE CKD, return with the
1696            end of track marker in the record header field */
1697         if (code == 0xDE || code == 0x5E)
1698             break;
1699 
1700         /* End of track found, so terminate with no record found
1701            error if this is a LOCATE RECORD or WRITE CKD NEXT TRACK
1702            command; or if this is the second end of track in this
1703            channel program without an intervening read of the home
1704            address or data area and without an intervening write,
1705            sense, or control command --
1706            -- except when multitrack READ or SEARCH [KEY?] command
1707            operates outside the domain of a locate record */
1708         if (code == 0x47 || code == 0x4B || code == 0x9D
1709             || (dev->ckdxmark
1710                 && !((dev->ckdlcount == 0)
1711                      && ( (IS_CCW_READ(code) && (code&0x80))
1712                          || code==0xA9 || code==0xC9 || code==0xE9) )))
1713         {
1714             ckd_build_sense (dev, 0, SENSE1_NRF, 0, 0, 0);
1715             *unitstat = CSW_CE | CSW_DE | CSW_UC;
1716             return -1;
1717         }
1718 
1719         /* Test for multitrack operation */
1720         if ((code & 0x80) == 0)
1721         {
1722             /* If non-multitrack, return to start of current track */
1723             cyl = dev->ckdcurcyl;
1724             head = dev->ckdcurhead;
1725             rc = ckd_seek (dev, cyl, head, NULL, unitstat);
1726             if (rc < 0) return -1;
1727 
1728             /* Set index marker found flag */
1729             dev->ckdxmark = 1;
1730         }
1731         else
1732         {
1733             /* If multitrack, attempt to advance to next track */
1734             rc = mt_advance (dev, unitstat, 1);
1735             if (rc < 0) return -1;
1736 
1737             /* Set index marker flag if non-search command */
1738             if ((code & 0x7F) != 0x31
1739                 && (code & 0x7F) != 0x51
1740                 && (code & 0x7F) != 0x71
1741                 && (code & 0x7F) != 0x29
1742                 && (code & 0x7F) != 0x49
1743                 && (code & 0x7F) != 0x69)
1744                 dev->ckdxmark = 1;
1745         }
1746 
1747     } /* end for */
1748 
1749     return 0;
1750 
1751 } /* end function ckd_read_count */
1752 
1753 
1754 /*-------------------------------------------------------------------*/
1755 /* Read key field                                                    */
1756 /*-------------------------------------------------------------------*/
ckd_read_key(DEVBLK * dev,BYTE code,BYTE * buf,BYTE * unitstat)1757 static int ckd_read_key ( DEVBLK *dev, BYTE code,
1758                 BYTE *buf, BYTE *unitstat)
1759 {
1760 int             rc;                     /* Return code               */
1761 CKDDASD_RECHDR  rechdr;                 /* CKD record header         */
1762 
1763     /* If not oriented to count field, read next count field */
1764     if (dev->ckdorient != CKDORIENT_COUNT)
1765     {
1766         rc = ckd_read_count (dev, code, &rechdr, unitstat);
1767         if (rc < 0) return rc;
1768     }
1769 
1770     logdevtr (dev, _("HHCDA044I read key %d bytes\n"), dev->ckdcurkl);
1771 
1772     /* Read key field */
1773     if (dev->ckdcurkl > 0)
1774     {
1775         if (dev->bufoffhi - dev->bufoff < dev->ckdcurkl)
1776         {
1777             /* Handle error condition */
1778             logmsg (_("ckddasd: attempt to read past end of track\n"));
1779 
1780             /* Set unit check with equipment check */
1781             ckd_build_sense (dev, SENSE_EC, 0, 0,
1782                             FORMAT_1, MESSAGE_0);
1783             *unitstat = CSW_CE | CSW_DE | CSW_UC;
1784             return -1;
1785         }
1786 
1787         memcpy (buf, &dev->buf[dev->bufoff], dev->ckdcurkl);
1788         dev->bufoff += dev->ckdcurkl;
1789     }
1790 
1791     /* Set the device orientation fields */
1792     dev->ckdrem = 0;
1793     dev->ckdorient = CKDORIENT_KEY;
1794 
1795     return 0;
1796 } /* end function ckd_read_key */
1797 
1798 
1799 /*-------------------------------------------------------------------*/
1800 /* Read data field                                                   */
1801 /*-------------------------------------------------------------------*/
ckd_read_data(DEVBLK * dev,BYTE code,BYTE * buf,BYTE * unitstat)1802 static int ckd_read_data ( DEVBLK *dev, BYTE code,
1803                 BYTE *buf, BYTE *unitstat)
1804 {
1805 int             rc;                     /* Return code               */
1806 CKDDASD_RECHDR  rechdr;                 /* Record header             */
1807 
1808     /* If not oriented to count or key field, read next count field */
1809     if (dev->ckdorient != CKDORIENT_COUNT
1810         && dev->ckdorient != CKDORIENT_KEY)
1811     {
1812         rc = ckd_read_count (dev, code, &rechdr, unitstat);
1813         if (rc < 0) return rc;
1814     }
1815 
1816     /* If oriented to count field, skip the key field */
1817     if (dev->ckdorient == CKDORIENT_COUNT)
1818         dev->bufoff += dev->ckdcurkl;
1819 
1820     logdevtr (dev, _("HHCDA045I read data %d bytes\n"), dev->ckdcurdl);
1821 
1822     /* Read data field */
1823     if (dev->ckdcurdl > 0)
1824     {
1825         if (dev->bufoff + dev->ckdcurdl >= dev->bufoffhi)
1826         {
1827             /* Handle error condition */
1828             logmsg (_("HHCDA046E attempt to read past end of track\n"));
1829 
1830             /* Set unit check with equipment check */
1831             ckd_build_sense (dev, SENSE_EC, 0, 0,
1832                             FORMAT_1, MESSAGE_0);
1833             *unitstat = CSW_CE | CSW_DE | CSW_UC;
1834             return -1;
1835         }
1836         memcpy (buf, &dev->buf[dev->bufoff], dev->ckdcurdl);
1837         dev->bufoff += dev->ckdcurdl;
1838     }
1839 
1840     /* Set the device orientation fields */
1841     dev->ckdrem = 0;
1842     dev->ckdorient = CKDORIENT_DATA;
1843 
1844     return 0;
1845 } /* end function ckd_read_data */
1846 
1847 
1848 /*-------------------------------------------------------------------*/
1849 /* Erase remainder of track                                          */
1850 /*-------------------------------------------------------------------*/
ckd_erase(DEVBLK * dev,BYTE * buf,int len,int * size,BYTE * unitstat)1851 static int ckd_erase ( DEVBLK *dev, BYTE *buf, int len, int *size,
1852                 BYTE *unitstat)
1853 {
1854 int             rc;                     /* Return code               */
1855 CKDDASD_RECHDR  rechdr;                 /* CKD record header         */
1856 int             keylen;                 /* Key length                */
1857 int             datalen;                /* Data length               */
1858 int             ckdlen;                 /* Count+key+data length     */
1859 
1860     /* If oriented to count or key field, skip key and data */
1861     if (dev->ckdorient == CKDORIENT_COUNT)
1862         dev->bufoff += dev->ckdcurkl + dev->ckdcurdl;
1863     else if (dev->ckdorient == CKDORIENT_KEY)
1864         dev->bufoff += dev->ckdcurdl;
1865 
1866     /* Copy the count field from the buffer */
1867     memset (&rechdr, 0, CKDDASD_RECHDR_SIZE);
1868     memcpy (&rechdr, buf, (len < CKDDASD_RECHDR_SIZE) ?
1869                                 len : CKDDASD_RECHDR_SIZE);
1870 
1871     /* Extract the key length and data length */
1872     keylen = rechdr.klen;
1873     datalen = (rechdr.dlen[0] << 8) + rechdr.dlen[1];
1874 
1875     /* Calculate total count key and data size */
1876     ckdlen = CKDDASD_RECHDR_SIZE + keylen + datalen;
1877 
1878     /* Check that there is enough space on the current track to
1879        contain the complete erase plus an end of track marker */
1880     if (dev->bufoff + ckdlen + 8 >= dev->bufoffhi)
1881     {
1882         /* Unit check with invalid track format */
1883         ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0);
1884         *unitstat = CSW_CE | CSW_DE | CSW_UC;
1885         return -1;
1886     }
1887 
1888     /* Logically erase rest of track by writing end of track marker */
1889     rc = (dev->hnd->write) (dev, dev->bufcur, dev->bufoff, eighthexFF, 8, unitstat);
1890     if (rc < 0) return -1;
1891 
1892     /* Return total count key and data size */
1893     *size = ckdlen;
1894 
1895     /* Set the device orientation fields */
1896     dev->ckdrem = 0;
1897     dev->ckdorient = CKDORIENT_DATA;
1898 
1899     return 0;
1900 } /* end function ckd_erase */
1901 
1902 
1903 /*-------------------------------------------------------------------*/
1904 /* Write count key and data fields                                   */
1905 /*-------------------------------------------------------------------*/
ckd_write_ckd(DEVBLK * dev,BYTE * buf,int len,BYTE * unitstat,BYTE trk_ovfl)1906 static int ckd_write_ckd ( DEVBLK *dev, BYTE *buf, int len,
1907                 BYTE *unitstat, BYTE trk_ovfl)
1908 {
1909 int             rc;                     /* Return code               */
1910 CKDDASD_RECHDR  rechdr;                 /* CKD record header         */
1911 int             recnum;                 /* Record number             */
1912 int             keylen;                 /* Key length                */
1913 int             datalen;                /* Data length               */
1914 int             ckdlen;                 /* Count+key+data length     */
1915 
1916     /* If oriented to count or key field, skip key and data */
1917     if (dev->ckdorient == CKDORIENT_COUNT)
1918         dev->bufoff += dev->ckdcurkl + dev->ckdcurdl;
1919     else if (dev->ckdorient == CKDORIENT_KEY)
1920         dev->bufoff += dev->ckdcurdl;
1921 
1922     /* Copy the count field from the buffer */
1923     memset (&rechdr, 0, CKDDASD_RECHDR_SIZE);
1924     memcpy (&rechdr, buf, (len < CKDDASD_RECHDR_SIZE) ?
1925                                 len : CKDDASD_RECHDR_SIZE);
1926 
1927     /* Extract the record number, key length and data length */
1928     recnum = rechdr.rec;
1929     keylen = rechdr.klen;
1930     datalen = (rechdr.dlen[0] << 8) + rechdr.dlen[1];
1931 
1932     /* Calculate total count key and data size */
1933     ckdlen = CKDDASD_RECHDR_SIZE + keylen + datalen;
1934 
1935     if (dev->bufoff + ckdlen + 8 >= dev->bufoffhi)
1936     {
1937         /* Unit check with invalid track format */
1938         ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0);
1939         *unitstat = CSW_CE | CSW_DE | CSW_UC;
1940         return -1;
1941     }
1942 
1943     /* Pad the I/O buffer with zeroes if necessary */
1944     while (len < ckdlen) buf[len++] = '\0';
1945 
1946     logdevtr (dev, _("HHCDA047I writing cyl %d head %d record %d kl %d dl %d\n"),
1947             dev->ckdcurcyl, dev->ckdcurhead, recnum, keylen, datalen);
1948 
1949     /* Set track overflow flag if called for */
1950     if (trk_ovfl)
1951     {
1952         logdevtr (dev, _("HHCDA048I setting track overflow flag for "
1953                  "cyl %d head %d record %d\n"),
1954                  dev->ckdcurcyl, dev->ckdcurhead, recnum);
1955         buf[0] |= 0x80;
1956     }
1957 
1958     /* Write count key and data */
1959     rc = (dev->hnd->write) (dev, dev->bufcur, dev->bufoff, buf, ckdlen, unitstat);
1960     if (rc < 0) return -1;
1961     dev->bufoff += ckdlen;
1962 
1963     /* Clear track overflow flag if we set it above */
1964     if (trk_ovfl)
1965     {
1966         buf[0] &= 0x7F;
1967     }
1968 
1969     /* Logically erase rest of track by writing end of track marker */
1970     rc = (dev->hnd->write) (dev, dev->bufcur, dev->bufoff, eighthexFF, 8, unitstat);
1971     if (rc < 0) return -1;
1972 
1973     /* Set the device orientation fields */
1974     dev->ckdcurrec = recnum;
1975     dev->ckdcurkl = keylen;
1976     dev->ckdcurdl = datalen;
1977     dev->ckdrem = 0;
1978     dev->ckdorient = CKDORIENT_DATA;
1979     dev->ckdtrkof = dev->ckdcyls < 32768 ? trk_ovfl & 1 : 0;
1980 
1981     return 0;
1982 } /* end function ckd_write_ckd */
1983 
1984 
1985 /*-------------------------------------------------------------------*/
1986 /* Write key and data fields                                         */
1987 /*-------------------------------------------------------------------*/
ckd_write_kd(DEVBLK * dev,BYTE * buf,int len,BYTE * unitstat)1988 static int ckd_write_kd ( DEVBLK *dev, BYTE *buf, int len,
1989                 BYTE *unitstat)
1990 {
1991 int             rc;                     /* Return code               */
1992 int             kdlen;                  /* Key+data length           */
1993 
1994     /* Unit check if not oriented to count area */
1995     if (dev->ckdorient != CKDORIENT_COUNT)
1996     {
1997         logmsg (_("HHCDA049E Write KD orientation error\n"));
1998         ckd_build_sense (dev, SENSE_CR, 0, 0,
1999                         FORMAT_0, MESSAGE_2);
2000         *unitstat = CSW_CE | CSW_DE | CSW_UC;
2001         return -1;
2002     }
2003 
2004     /* Calculate total key and data size */
2005     kdlen = dev->ckdcurkl + dev->ckdcurdl;
2006 
2007     /* Pad the I/O buffer with zeroes if necessary */
2008     while (len < kdlen) buf[len++] = '\0';
2009 
2010     logdevtr (dev, _("HHCDA050I updating cyl %d head %d record %d kl %d dl %d\n"),
2011             dev->ckdcurcyl, dev->ckdcurhead, dev->ckdcurrec,
2012             dev->ckdcurkl, dev->ckdcurdl);
2013 
2014     /* Write key and data */
2015     rc = (dev->hnd->write) (dev, dev->bufcur, dev->bufoff, buf, kdlen, unitstat);
2016     if (rc < 0) return -1;
2017     dev->bufoff += kdlen;
2018 
2019     /* Set the device orientation fields */
2020     dev->ckdrem = 0;
2021     dev->ckdorient = CKDORIENT_DATA;
2022 
2023     return 0;
2024 } /* end function ckd_write_kd */
2025 
2026 
2027 /*-------------------------------------------------------------------*/
2028 /* Write data field                                                  */
2029 /*-------------------------------------------------------------------*/
ckd_write_data(DEVBLK * dev,BYTE * buf,int len,BYTE * unitstat)2030 static int ckd_write_data ( DEVBLK *dev, BYTE *buf, int len,
2031                 BYTE *unitstat)
2032 {
2033 int             rc;                     /* Return code               */
2034 
2035     /* Unit check if not oriented to count or key areas */
2036     if (dev->ckdorient != CKDORIENT_COUNT
2037         && dev->ckdorient != CKDORIENT_KEY)
2038     {
2039         logmsg (_("HHCDA051E Write data orientation error\n"));
2040         ckd_build_sense (dev, SENSE_CR, 0, 0,
2041                         FORMAT_0, MESSAGE_2);
2042         *unitstat = CSW_CE | CSW_DE | CSW_UC;
2043         return -1;
2044     }
2045 
2046     /* If oriented to count field, skip the key field */
2047     if (dev->ckdorient == CKDORIENT_COUNT)
2048         dev->bufoff += dev->ckdcurkl;
2049 
2050     /* Pad the I/O buffer with zeroes if necessary */
2051     while (len < dev->ckdcurdl) buf[len++] = '\0';
2052 
2053     logdevtr (dev, _("HHCDA052I updating cyl %d head %d record %d dl %d\n"),
2054             dev->ckdcurcyl, dev->ckdcurhead, dev->ckdcurrec,
2055             dev->ckdcurdl);
2056 
2057     /* Write data */
2058     rc = (dev->hnd->write) (dev, dev->bufcur, dev->bufoff, buf, dev->ckdcurdl, unitstat);
2059     if (rc < 0) return -1;
2060     dev->bufoff += dev->ckdcurdl;
2061 
2062     /* Set the device orientation fields */
2063     dev->ckdrem = 0;
2064     dev->ckdorient = CKDORIENT_DATA;
2065 
2066     return 0;
2067 } /* end function ckd_write_data */
2068 
2069 
2070 /*-------------------------------------------------------------------*/
2071 /* Execute a Channel Command Word                                    */
2072 /*-------------------------------------------------------------------*/
ckddasd_execute_ccw(DEVBLK * dev,BYTE code,BYTE flags,BYTE chained,U16 count,BYTE prevcode,int ccwseq,BYTE * iobuf,BYTE * more,BYTE * unitstat,U16 * residual)2073 void ckddasd_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags,
2074         BYTE chained, U16 count, BYTE prevcode, int ccwseq,
2075         BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual )
2076 {
2077 int             rc;                     /* Return code               */
2078 int             i, j;                   /* Loop index                */
2079 CKDDASD_TRKHDR  trkhdr;                 /* CKD track header (HA)     */
2080 CKDDASD_RECHDR  rechdr;                 /* CKD record header (count) */
2081 int             size;                   /* Number of bytes available */
2082 int             num;                    /* Number of bytes to move   */
2083 int             offset;                 /* Offset into buf for I/O   */
2084 int             bin;                    /* Bin number                */
2085 int             cyl;                    /* Cylinder number           */
2086 int             head;                   /* Head number               */
2087 BYTE            cchhr[5];               /* Search argument           */
2088 BYTE            sector;                 /* Sector number             */
2089 BYTE            key[256];               /* Key for search operations */
2090 BYTE            trk_ovfl;               /* == 1 if track ovfl write  */
2091 
2092     /* If this is a data-chained READ, then return any data remaining
2093        in the buffer which was not used by the previous CCW */
2094     if (chained & CCW_FLAGS_CD)
2095     {
2096         memmove (iobuf, iobuf + dev->ckdpos, dev->ckdrem);
2097         num = (count < dev->ckdrem) ? count : dev->ckdrem;
2098         *residual = count - num;
2099         if (count < dev->ckdrem) *more = 1;
2100         dev->ckdrem -= num;
2101         dev->ckdpos = num;
2102         *unitstat = CSW_CE | CSW_DE;
2103         return;
2104     }
2105 
2106     /* Command reject if data chaining and command is not READ */
2107     if ((flags & CCW_FLAGS_CD) && code != 0x02 && code != 0x5E
2108         && (code & 0x7F) != 0x1E && (code & 0x7F) != 0x1A
2109         && (code & 0x7F) != 0x16 && (code & 0x7F) != 0x12
2110         && (code & 0x7F) != 0x0E && (code & 0x7F) != 0x06)
2111     {
2112         logmsg(_("HHCDA053E Data chaining not supported for CCW %2.2X\n"),
2113                 code);
2114         ckd_build_sense (dev, SENSE_CR, 0, 0,
2115                         FORMAT_0, MESSAGE_1);
2116         *unitstat = CSW_CE | CSW_DE | CSW_UC;
2117         return;
2118     }
2119 
2120     /* Reset flags at start of CCW chain */
2121     if (chained == 0 && !dev->syncio_retry)
2122     {
2123         dev->ckdlocat = 0;
2124         dev->ckdspcnt = 0;
2125         dev->ckdseek = 0;
2126         dev->ckdskcyl = 0;
2127         dev->ckdrecal = 0;
2128         dev->ckdrdipl = 0;
2129         dev->ckdfmask = 0;
2130         dev->ckdxmark = 0;
2131         dev->ckdhaeq = 0;
2132         dev->ckdideq = 0;
2133         dev->ckdkyeq = 0;
2134         dev->ckdwckd = 0;
2135         dev->ckdlcount = 0;
2136         dev->ckdlmask = 0;
2137         dev->ckdtrkof = 0;
2138         /* ISW20030819-1 : Clear Write HA flag */
2139         dev->ckdwrha = 0;
2140         dev->ckdssdlen = 0;
2141 
2142         /* Set initial define extent parameters */
2143         dev->ckdxtdef = 0;
2144         dev->ckdsetfm = 0;
2145         dev->ckdfmask = 0;
2146         dev->ckdxgattr = 0;
2147         dev->ckdxblksz = 0;
2148         dev->ckdxbcyl = 0;
2149         dev->ckdxbhead = 0;
2150         dev->ckdxecyl = dev->ckdcyls - 1;
2151         dev->ckdxehead = dev->ckdheads - 1;
2152     }
2153     /* Reset ckdlmask on retry of LRE */
2154     else if (dev->syncio_retry && code == 0x4B)
2155         dev->ckdlmask = 0;
2156     dev->syncio_retry = 0;
2157 
2158     /* Reset index marker flag if sense or control command,
2159        or any write command (other search ID or search key),
2160        or any read command except read sector --
2161        -- and except single track Read Count */
2162     if (IS_CCW_SENSE(code) || IS_CCW_CONTROL(code)
2163         || (IS_CCW_WRITE(code)
2164             && (code & 0x7F) != 0x31
2165             && (code & 0x7F) != 0x51
2166             && (code & 0x7F) != 0x71
2167             && (code & 0x7F) != 0x29
2168             && (code & 0x7F) != 0x49
2169             && (code & 0x7F) != 0x69)
2170         || (IS_CCW_READ(code)
2171             &&  code         != 0x12
2172             && (code & 0x7F) != 0x22))
2173         dev->ckdxmark = 0;
2174 
2175     /* Note current operation for track overflow sense byte 3 */
2176     dev->ckdcuroper = (IS_CCW_READ(code)) ? 6 :
2177         ((IS_CCW_WRITE(code)) ? 5 : 0);
2178 
2179     /* If subsystem data has been prepared in the channel buffer by
2180        a previous Perform Subsystem Function command, generate a
2181        command reject if next command is not Read Subsystem Data */
2182     if (dev->ckdssdlen > 0 && code != 0x3E)
2183     {
2184         ckd_build_sense (dev, SENSE_CR, 0, 0,
2185                         FORMAT_0, MESSAGE_2);
2186         *unitstat = CSW_CE | CSW_DE | CSW_UC;
2187         return;
2188     }
2189 
2190     /* If within Locate Record Extended domain and not RT command
2191        reject with status that includes Unit Check (Command Reject,
2192        format X'02', Invalid Command Sequence) */
2193     if (dev->ckdlmask && code != 0xDE)
2194     {
2195         ckd_build_sense (dev, SENSE_CR, 0, 0,FORMAT_0, MESSAGE_2);
2196         *unitstat = CSW_CE | CSW_DE | CSW_UC;
2197         return;
2198     }
2199 
2200     /* Process depending on CCW opcode */
2201     switch (code) {
2202 
2203     case 0x02:
2204     /*---------------------------------------------------------------*/
2205     /* READ IPL                                                      */
2206     /*---------------------------------------------------------------*/
2207         /* Command reject if preceded by a Define Extent or
2208            Set File Mask, or within the domain of a Locate Record */
2209         if (dev->ckdxtdef || dev->ckdsetfm || dev->ckdlcount > 0)
2210         {
2211             ckd_build_sense (dev, SENSE_CR, 0, 0,
2212                             FORMAT_0, MESSAGE_2);
2213             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2214             break;
2215         }
2216 
2217         /* No more define extend allowed */
2218         dev->ckdxtdef = 1;
2219         dev->ckdsetfm = 1;
2220 
2221         /* Set locate record parameters */
2222         dev->ckdloper = CKDOPER_ORIENT_DATA | CKDOPER_RDDATA;
2223         dev->ckdlaux = 0;
2224         dev->ckdlcount = 2;
2225         dev->ckdltranlf = 0;
2226 
2227         /* Seek to start of cylinder zero track zero */
2228         rc = ckd_seek (dev, 0, 0, &trkhdr, unitstat);
2229         if (rc < 0) break;
2230 
2231         /* Read count field for first record following R0 */
2232         rc = ckd_read_count (dev, code, &rechdr, unitstat);
2233         if (rc < 0) break;
2234 
2235         /* Calculate number of bytes to read and set residual count */
2236         size = dev->ckdcurdl;
2237         num = (count < size) ? count : size;
2238         *residual = count - num;
2239         if (count < size) *more = 1;
2240 
2241         /* Read data field */
2242         rc = ckd_read_data (dev, code, iobuf, unitstat);
2243         if (rc < 0) break;
2244 
2245         /* Set command processed flag */
2246         dev->ckdrdipl = 1;
2247 
2248         /* Save size and offset of data not used by this CCW */
2249         dev->ckdrem = size - num;
2250         dev->ckdpos = num;
2251 
2252         /* Return unit exception if data length is zero */
2253         if (dev->ckdcurdl == 0)
2254             *unitstat = CSW_CE | CSW_DE | CSW_UX;
2255         else
2256             *unitstat = CSW_CE | CSW_DE;
2257 
2258         break;
2259 
2260     case 0x03:
2261     /*---------------------------------------------------------------*/
2262     /* CONTROL NO-OPERATION                                          */
2263     /*---------------------------------------------------------------*/
2264         /* Command reject if within the domain of a Locate Record,   */
2265         /* except if Read IPL                          2012-08-14    */
2266         if (dev->ckdlcount > 0 && dev->prevcode != 0x02)
2267         {
2268             ckd_build_sense (dev, SENSE_CR, 0, 0,
2269                             FORMAT_0, MESSAGE_2);
2270             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2271             break;
2272         }
2273 
2274         /* Return normal status */
2275         *unitstat = CSW_CE | CSW_DE;
2276         break;
2277 
2278     case 0x17:
2279     /*---------------------------------------------------------------*/
2280     /* RESTORE                                                       */
2281     /*---------------------------------------------------------------*/
2282         /* Command reject if within the domain of a Locate Record */
2283         if (dev->ckdlcount > 0)
2284         {
2285             ckd_build_sense (dev, SENSE_CR, 0, 0,
2286                             FORMAT_0, MESSAGE_2);
2287             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2288             break;
2289         }
2290 
2291         /* Return normal status */
2292         *unitstat = CSW_CE | CSW_DE;
2293         break;
2294 
2295     case 0xA6:
2296 //FIXME: 0xA6 ccw is undoc'd.  We are treating it as 0x86 except
2297 //       we will allow a DX ccw to follow.
2298     case 0x06:
2299     case 0x86:
2300     /*---------------------------------------------------------------*/
2301     /* READ DATA                                                     */
2302     /*---------------------------------------------------------------*/
2303         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
2304            Locate Record, Read IPL, or Recalibrate command */
2305         if (dev->ckd3990
2306             && dev->ckdseek == 0 && dev->ckdskcyl == 0
2307             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
2308             && dev->ckdrecal == 0)
2309         {
2310             ckd_build_sense (dev, SENSE_CR, 0, 0,
2311                             FORMAT_0, MESSAGE_2);
2312             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2313             break;
2314         }
2315 
2316         /* Check operation code if within domain of a Locate Record */
2317         if (dev->ckdlcount > 0)
2318         {
2319             if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA
2320                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDANY
2321                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ))
2322             {
2323                 ckd_build_sense (dev, SENSE_CR, 0, 0,
2324                                 FORMAT_0, MESSAGE_2);
2325                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
2326                 break;
2327             }
2328         }
2329 
2330         /* If not oriented to count or key field, read next count */
2331         if (dev->ckdorient != CKDORIENT_COUNT
2332             && dev->ckdorient != CKDORIENT_KEY)
2333         {
2334             rc = ckd_read_count (dev, code, &rechdr, unitstat);
2335             if (rc < 0) break;
2336         }
2337 
2338         /* Calculate number of bytes to read and set residual count */
2339         size = dev->ckdcurdl;
2340         num = (count < size) ? count : size;
2341         *residual = count - num;
2342         if (count < size) *more = 1;
2343         offset = 0;
2344 
2345         /* Read data field */
2346         rc = ckd_read_data (dev, code, iobuf, unitstat);
2347         if (rc < 0) break;
2348 
2349         /* If track overflow, keep reading */
2350         while (dev->ckdtrkof)
2351         {
2352             /* Advance to next track */
2353             rc = mt_advance (dev, unitstat, 1);
2354             if (rc < 0) break;
2355 
2356             /* Read the first count field */
2357             rc = ckd_read_count (dev, code, &rechdr, unitstat);
2358             if (rc < 0) break;
2359 
2360             /* Skip the key field if present */
2361             if (dev->ckdcurkl > 0)
2362                 dev->bufoff += dev->ckdcurkl;
2363 
2364             /* Set offset into buffer for this read */
2365             offset += num;
2366 
2367             /* Account for size of this overflow record */
2368             size = dev->ckdcurdl;
2369             num = (*residual < size) ? *residual : size;
2370             if (*residual < size) *more = 1;
2371             else *more = 0;
2372             *residual -= num;
2373 
2374             /* Read the next data field */
2375             rc = ckd_read_data (dev, code, iobuf+offset, unitstat);
2376             if (rc < 0) break;
2377         }
2378 
2379         /* Bail out if track overflow produced I/O error */
2380         if (rc < 0) break;
2381 
2382         /* Save size and offset of data not used by this CCW */
2383         dev->ckdrem = size - num;
2384         dev->ckdpos = num;
2385 
2386         /* Return unit exception if data length is zero */
2387         if (dev->ckdcurdl == 0)
2388             *unitstat = CSW_CE | CSW_DE | CSW_UX;
2389         else
2390             *unitstat = CSW_CE | CSW_DE;
2391 
2392         break;
2393 
2394     case 0x0E:
2395     case 0x8E:
2396     /*---------------------------------------------------------------*/
2397     /* READ KEY AND DATA                                             */
2398     /*---------------------------------------------------------------*/
2399         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
2400            Locate Record, Read IPL, or Recalibrate command */
2401         if (dev->ckd3990
2402             && dev->ckdseek == 0 && dev->ckdskcyl == 0
2403             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
2404             && dev->ckdrecal == 0)
2405         {
2406             ckd_build_sense (dev, SENSE_CR, 0, 0,
2407                             FORMAT_0, MESSAGE_2);
2408             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2409             break;
2410         }
2411 
2412         /* Check operation code if within domain of a Locate Record */
2413         if (dev->ckdlcount > 0)
2414         {
2415             /*
2416              * 3990 reference says LRE CKDOPER_RDANY "must be followed
2417              * by a sequence of multi-track Read Count, Read Count Key
2418              * and Data, or Read Data commands".  That is, it doesn't
2419              * mention Read Key and Data.
2420              */
2421             if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA
2422                /* || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDANY */
2423                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ))
2424             {
2425                 ckd_build_sense (dev, SENSE_CR, 0, 0,
2426                                 FORMAT_0, MESSAGE_2);
2427                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
2428                 break;
2429             }
2430         }
2431 
2432         /* If not oriented to count field, read next count */
2433         if (dev->ckdorient != CKDORIENT_COUNT)
2434         {
2435             rc = ckd_read_count (dev, code, &rechdr, unitstat);
2436             if (rc < 0) break;
2437         }
2438 
2439         /* Calculate number of bytes to read and set residual count */
2440         size = dev->ckdcurkl + dev->ckdcurdl;
2441         num = (count < size) ? count : size;
2442         *residual = count - num;
2443         if (count < size) *more = 1;
2444         offset = dev->ckdcurkl;
2445 
2446         /* Read key field */
2447         rc = ckd_read_key (dev, code, iobuf, unitstat);
2448         if (rc < 0) break;
2449 
2450         /* Read data field */
2451         rc = ckd_read_data (dev, code, iobuf+dev->ckdcurkl, unitstat);
2452         if (rc < 0) break;
2453 
2454         /* If track overflow, keep reading */
2455         while (dev->ckdtrkof)
2456         {
2457             /* Advance to next track */
2458             rc = mt_advance (dev, unitstat, 1);
2459             if (rc < 0) break;
2460 
2461             /* Read the first count field */
2462             rc = ckd_read_count (dev, code, &rechdr, unitstat);
2463             if (rc < 0) break;
2464 
2465             /* Skip the key field if present */
2466             if (dev->ckdcurkl > 0)
2467                 dev->bufoff += dev->ckdcurkl;
2468 
2469             /* Set offset into buffer for this read */
2470             offset += num;
2471 
2472             /* Account for size of this overflow record */
2473             size = dev->ckdcurdl;
2474             num = (*residual < size) ? *residual : size;
2475             if (*residual < size) *more = 1;
2476             else *more = 0;
2477             *residual -= num;
2478 
2479             /* Read the next data field */
2480             rc = ckd_read_data (dev, code, iobuf+offset, unitstat);
2481             if (rc < 0) break;
2482         }
2483 
2484         /* Bail out if track overflow produced I/O error */
2485         if (rc < 0) break;
2486 
2487         /* Save size and offset of data not used by this CCW */
2488         dev->ckdrem = size - num;
2489         dev->ckdpos = num;
2490 
2491         /* Return unit exception if data length is zero */
2492         if (dev->ckdcurdl == 0)
2493             *unitstat = CSW_CE | CSW_DE | CSW_UX;
2494         else
2495             *unitstat = CSW_CE | CSW_DE;
2496 
2497         break;
2498 
2499     case 0x12:
2500     case 0x92:
2501     /*---------------------------------------------------------------*/
2502     /* READ COUNT                                                    */
2503     /*---------------------------------------------------------------*/
2504         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
2505            Locate Record, Read IPL, or Recalibrate command */
2506         if (dev->ckd3990
2507             && dev->ckdseek == 0 && dev->ckdskcyl == 0
2508             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
2509             && dev->ckdrecal == 0)
2510         {
2511             ckd_build_sense (dev, SENSE_CR, 0, 0,
2512                             FORMAT_0, MESSAGE_2);
2513             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2514             break;
2515         }
2516 
2517         /* Check operation code if within domain of a Locate Record */
2518         if (dev->ckdlcount > 0)
2519         {
2520             if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA
2521                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDANY
2522                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ
2523                   || ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE
2524                       && (dev->ckdlaux & CKDLAUX_RDCNTSUF)
2525                       && dev->ckdlcount == 1)))
2526             {
2527                 ckd_build_sense (dev, SENSE_CR, 0, 0,
2528                                 FORMAT_0, MESSAGE_2);
2529                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
2530                 break;
2531             }
2532         }
2533 
2534         /* Read next count field */
2535         rc = ckd_read_count (dev, code, &rechdr, unitstat);
2536         if (rc < 0) break;
2537 
2538         /* Calculate number of bytes to read and set residual count */
2539         size = CKDDASD_RECHDR_SIZE;
2540         num = (count < size) ? count : size;
2541         *residual = count - num;
2542         if (count < size) *more = 1;
2543 
2544         /* Copy count field to I/O buffer */
2545         memcpy (iobuf, &rechdr, CKDDASD_RECHDR_SIZE);
2546 
2547         /* Turn off track overflow flag in read record header */
2548         if(dev->ckdcyls < 32768)
2549             *iobuf &= 0x7F;
2550 
2551         /* Save size and offset of data not used by this CCW */
2552         dev->ckdrem = size - num;
2553         dev->ckdpos = num;
2554 
2555         /* Return normal status */
2556         *unitstat = CSW_CE | CSW_DE;
2557         break;
2558 
2559     case 0x16:
2560     case 0x96:
2561     /*---------------------------------------------------------------*/
2562     /* READ RECORD ZERO                                              */
2563     /*---------------------------------------------------------------*/
2564         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
2565            Locate Record, Read IPL, or Recalibrate command */
2566         if (dev->ckd3990
2567             && dev->ckdseek == 0 && dev->ckdskcyl == 0
2568             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
2569             && dev->ckdrecal == 0)
2570         {
2571             ckd_build_sense (dev, SENSE_CR, 0, 0,
2572                             FORMAT_0, MESSAGE_2);
2573             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2574             break;
2575         }
2576 
2577         /* Check operation code if within domain of a Locate Record */
2578         if (dev->ckdlcount > 0)
2579         {
2580             if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA
2581                   || ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ
2582                       && ((dev->ckdloper & CKDOPER_ORIENTATION)
2583                                 == CKDOPER_ORIENT_HOME
2584                           || (dev->ckdloper & CKDOPER_ORIENTATION)
2585                                 == CKDOPER_ORIENT_INDEX
2586                         ))))
2587             {
2588                 ckd_build_sense (dev, SENSE_CR, 0, 0,
2589                                 FORMAT_0, MESSAGE_2);
2590                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
2591                 break;
2592             }
2593         }
2594 
2595         /* For multitrack operation outside domain of a Locate Record,
2596            attempt to advance to the next track before reading R0 */
2597         if ((code & 0x80) && dev->ckdlcount == 0)
2598         {
2599             rc = mt_advance (dev, unitstat, 1);
2600             if (rc < 0) break;
2601         }
2602 
2603         /* Seek to beginning of track */
2604         rc = ckd_seek (dev, dev->ckdcurcyl, dev->ckdcurhead, &trkhdr, unitstat);
2605         if (rc < 0) break;
2606 
2607         /* Read the count field for record zero */
2608         rc = ckd_read_count (dev, code, &rechdr, unitstat);
2609         if (rc < 0) break;
2610 
2611         /* Calculate number of bytes to read and set residual count */
2612         size = CKDDASD_RECHDR_SIZE + dev->ckdcurkl + dev->ckdcurdl;
2613         num = (count < size) ? count : size;
2614         *residual = count - num;
2615         if (count < size) *more = 1;
2616 
2617         /* Copy count field to I/O buffer */
2618         memcpy (iobuf, &rechdr, CKDDASD_RECHDR_SIZE);
2619 
2620         /* Turn off track overflow flag in read record header */
2621         if(dev->ckdcyls < 32768)
2622             *iobuf &= 0x7F;
2623 
2624         /* Read key field */
2625         rc = ckd_read_key (dev, code,
2626                             iobuf + CKDDASD_RECHDR_SIZE, unitstat);
2627         if (rc < 0) break;
2628 
2629         /* Read data field */
2630         rc = ckd_read_data (dev, code,
2631                             iobuf + CKDDASD_RECHDR_SIZE + dev->ckdcurkl,
2632                             unitstat);
2633         if (rc < 0) break;
2634 
2635         /* Save size and offset of data not used by this CCW */
2636         dev->ckdrem = size - num;
2637         dev->ckdpos = num;
2638 
2639         /* Return unit exception if data length is zero */
2640         if (dev->ckdcurdl == 0)
2641             *unitstat = CSW_CE | CSW_DE | CSW_UX;
2642         else
2643             *unitstat = CSW_CE | CSW_DE;
2644 
2645         break;
2646 
2647     case 0x1A:
2648     case 0x9A:
2649     /*---------------------------------------------------------------*/
2650     /* READ HOME ADDRESS                                             */
2651     /*---------------------------------------------------------------*/
2652         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
2653            Locate Record, Read IPL, or Recalibrate command */
2654         if (dev->ckd3990
2655             && dev->ckdseek == 0 && dev->ckdskcyl == 0
2656             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
2657             && dev->ckdrecal == 0)
2658         {
2659             ckd_build_sense (dev, SENSE_CR, 0, 0,
2660                             FORMAT_0, MESSAGE_2);
2661             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2662             break;
2663         }
2664 
2665         /* Check operation code if within domain of a Locate Record */
2666         if (dev->ckdlcount > 0)
2667         {
2668             if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA
2669                   || ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ
2670                       && (dev->ckdloper & CKDOPER_ORIENTATION)
2671                                 == CKDOPER_ORIENT_INDEX
2672                     )))
2673             {
2674                 ckd_build_sense (dev, SENSE_CR, 0, 0,
2675                                 FORMAT_0, MESSAGE_2);
2676                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
2677                 break;
2678             }
2679         }
2680 
2681         /* For multitrack operation outside domain of a Locate Record,
2682            attempt to advance to the next track before reading HA */
2683         if ((code & 0x80) && dev->ckdlcount == 0)
2684         {
2685             rc = mt_advance (dev, unitstat, 1);
2686             if (rc < 0) break;
2687         }
2688 
2689         /* Seek to beginning of track */
2690         rc = ckd_seek (dev, dev->ckdcurcyl, dev->ckdcurhead, &trkhdr, unitstat);
2691         if (rc < 0) break;
2692 
2693         /* Calculate number of bytes to read and set residual count */
2694         size = CKDDASD_TRKHDR_SIZE;
2695         num = (count < size) ? count : size;
2696         *residual = count - num;
2697         if (count < size) *more = 1;
2698 
2699         /* Copy home address field to I/O buffer */
2700         memcpy (iobuf, &trkhdr, CKDDASD_TRKHDR_SIZE);
2701 
2702         /* Save size and offset of data not used by this CCW */
2703         dev->ckdrem = size - num;
2704         dev->ckdpos = num;
2705 
2706         /* Return normal status */
2707         *unitstat = CSW_CE | CSW_DE;
2708 
2709         break;
2710 
2711     case 0x19:
2712     /*---------------------------------------------------------------*/
2713     /* WRITE HOME ADDRESS                                            */
2714     /*---------------------------------------------------------------*/
2715         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
2716            Locate Record, Read IPL, or Recalibrate command */
2717         if (dev->ckd3990
2718             && dev->ckdseek == 0 && dev->ckdskcyl == 0
2719             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
2720             && dev->ckdrecal == 0)
2721         {
2722             ckd_build_sense (dev, SENSE_CR, 0, 0,
2723                             FORMAT_0, MESSAGE_2);
2724             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2725             break;
2726         }
2727 
2728         /* Check operation code if within domain of a Locate Record */
2729         if (dev->ckdlcount > 0)
2730         {
2731             if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA
2732                   || ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ
2733                       && (dev->ckdloper & CKDOPER_ORIENTATION)
2734                                 == CKDOPER_ORIENT_INDEX
2735                     )))
2736             {
2737                 ckd_build_sense (dev, SENSE_CR, 0, 0,
2738                                 FORMAT_0, MESSAGE_2);
2739                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
2740                 break;
2741             }
2742         }
2743 
2744         /* File protected if file mask does not allow Write HA */
2745         if ((dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_ALLWRT)
2746         {
2747             ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0);
2748             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2749             break;
2750         }
2751 
2752         /* Seek to beginning of track */
2753         rc = ckd_seek (dev, dev->ckdcurcyl, dev->ckdcurhead, &trkhdr, unitstat);
2754         if (rc < 0) break;
2755 
2756         /* Calculate number of bytes to write and set residual count */
2757         size = CKDDASD_TRKHDR_SIZE;
2758         num = (count < size) ? count : size;
2759     /* FIXME: what devices want 5 bytes, what ones want 7, and what
2760         ones want 11? Do this right when we figure that out */
2761         /* ISW20030819-1 Indicate WRHA performed */
2762         dev->ckdwrha=1;
2763         *residual = 0;
2764 
2765         /* Return normal status */
2766         *unitstat = CSW_CE | CSW_DE;
2767 
2768         break;
2769 
2770     case 0x1E:
2771     case 0x9E:
2772     /*---------------------------------------------------------------*/
2773     /* READ COUNT KEY AND DATA                                       */
2774     /*---------------------------------------------------------------*/
2775         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
2776            Locate Record, Read IPL, or Recalibrate command */
2777         if (dev->ckd3990
2778             && dev->ckdseek == 0 && dev->ckdskcyl == 0
2779             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
2780             && dev->ckdrecal == 0)
2781         {
2782             ckd_build_sense (dev, SENSE_CR, 0, 0,
2783                             FORMAT_0, MESSAGE_2);
2784             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2785             break;
2786         }
2787 
2788         /* Check operation code if within domain of a Locate Record */
2789         if (dev->ckdlcount > 0)
2790         {
2791             if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA
2792                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDANY
2793                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ))
2794             {
2795                 ckd_build_sense (dev, SENSE_CR, 0, 0,
2796                                 FORMAT_0, MESSAGE_2);
2797                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
2798                 break;
2799             }
2800         }
2801 
2802         /* Read next count field */
2803         rc = ckd_read_count (dev, code, &rechdr, unitstat);
2804         if (rc < 0) break;
2805 
2806         /* Calculate number of bytes to read and set residual count */
2807         size = CKDDASD_RECHDR_SIZE + dev->ckdcurkl + dev->ckdcurdl;
2808         num = (count < size) ? count : size;
2809         *residual = count - num;
2810         if (count < size) *more = 1;
2811         offset = CKDDASD_RECHDR_SIZE + dev->ckdcurkl;
2812 
2813         /* Copy count field to I/O buffer */
2814         memcpy (iobuf, &rechdr, CKDDASD_RECHDR_SIZE);
2815 
2816         /* Turn off track overflow flag in read record header */
2817         if(dev->ckdcyls < 32768)
2818             *iobuf &= 0x7F;
2819 
2820         /* Read key field */
2821         rc = ckd_read_key (dev, code,
2822                             iobuf + CKDDASD_RECHDR_SIZE, unitstat);
2823         if (rc < 0) break;
2824 
2825         /* Read data field */
2826         rc = ckd_read_data (dev, code,
2827                             iobuf + CKDDASD_RECHDR_SIZE + dev->ckdcurkl,
2828                             unitstat);
2829         if (rc < 0) break;
2830 
2831         /* If track overflow, keep reading */
2832         while (dev->ckdtrkof)
2833         {
2834             /* Advance to next track */
2835             rc = mt_advance (dev, unitstat, 1);
2836             if (rc < 0) break;
2837 
2838             /* Read the first count field */
2839             rc = ckd_read_count (dev, code, &rechdr, unitstat);
2840             if (rc < 0) break;
2841 
2842             /* Skip the key field if present */
2843             if (dev->ckdcurkl > 0)
2844                 dev->bufoff += dev->ckdcurkl;
2845 
2846             /* Set offset into buffer for this read */
2847             offset += num;
2848 
2849             /* Account for size of this overflow record */
2850             size = dev->ckdcurdl;
2851             num = (*residual < size) ? *residual : size;
2852             if (*residual < size) *more = 1;
2853             else *more = 0;
2854             *residual -= num;
2855 
2856             /* Read the next data field */
2857             rc = ckd_read_data (dev, code, iobuf+offset, unitstat);
2858             if (rc < 0) break;
2859         }
2860 
2861         /* Bail out if track overflow produced I/O error */
2862         if (rc < 0) break;
2863 
2864         /* Save size and offset of data not used by this CCW */
2865         dev->ckdrem = size - num;
2866         dev->ckdpos = num;
2867 
2868         /* Return unit exception if data length is zero */
2869         if (dev->ckdcurdl == 0)
2870             *unitstat = CSW_CE | CSW_DE | CSW_UX;
2871         else
2872             *unitstat = CSW_CE | CSW_DE;
2873 
2874         break;
2875 
2876     case 0x5E:
2877     /*---------------------------------------------------------------*/
2878     /* READ MULTIPLE COUNT KEY AND DATA                              */
2879     /*---------------------------------------------------------------*/
2880         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
2881            Locate Record, Read IPL, or Recalibrate */
2882         if (dev->ckd3990
2883             && dev->ckdseek == 0 && dev->ckdskcyl == 0
2884             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
2885             && dev->ckdrecal == 0)
2886         {
2887             ckd_build_sense (dev, SENSE_CR, 0, 0,
2888                             FORMAT_0, MESSAGE_2);
2889             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2890             break;
2891         }
2892 
2893         /* Command reject if within the domain of a Locate Record */
2894         if (dev->ckdlcount > 0)
2895         {
2896             ckd_build_sense (dev, SENSE_CR, 0, 0,
2897                             FORMAT_0, MESSAGE_2);
2898             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2899             break;
2900         }
2901 
2902         /* Read records into the I/O buffer until end of track */
2903         for (size = 0; ; )
2904         {
2905             /* Read next count field */
2906             rc = ckd_read_count (dev, code, &rechdr, unitstat);
2907             if (rc < 0) break;
2908 
2909             /* Exit if end of track marker was read */
2910             if (memcmp (&rechdr, eighthexFF, 8) == 0)
2911                 break;
2912 
2913             /* Copy count field to I/O buffer */
2914             memcpy (iobuf + size, &rechdr, CKDDASD_RECHDR_SIZE);
2915             size += CKDDASD_RECHDR_SIZE;
2916 
2917             /* Turn off track overflow flag */
2918             if(dev->ckdcyls < 32768)
2919                 *(iobuf + size) &= 0x7F;
2920 
2921             /* Read key field */
2922             rc = ckd_read_key (dev, code, iobuf + size, unitstat);
2923             if (rc < 0) break;
2924             size += dev->ckdcurkl;
2925 
2926             /* Read data field */
2927             rc = ckd_read_data (dev, code, iobuf + size, unitstat);
2928             if (rc < 0) break;
2929             size += dev->ckdcurdl;
2930 
2931         } /* end for(size) */
2932 
2933         /* Set the residual count */
2934         num = (count < size) ? count : size;
2935         *residual = count - num;
2936         if (count < size) *more = 1;
2937 
2938         /* Save size and offset of data not used by this CCW */
2939         dev->ckdrem = size - num;
2940         dev->ckdpos = num;
2941 
2942         /* Return normal status */
2943         *unitstat = CSW_CE | CSW_DE;
2944 
2945         break;
2946 
2947     case 0xDE:
2948     /*---------------------------------------------------------------*/
2949     /* READ TRACK                                                    */
2950     /*---------------------------------------------------------------*/
2951         /* Command reject if not within the domain of a Locate Record
2952            that specifies a read tracks operation */
2953         if (dev->ckdlcount == 0
2954          || (((dev->ckdloper & CKDOPER_CODE) != CKDOPER_RDTRKS)
2955           && ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_RDTSET)))
2956         {
2957             ckd_build_sense (dev, SENSE_CR, 0, 0,
2958                             FORMAT_0, MESSAGE_2);
2959             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2960             break;
2961         }
2962 
2963         /* Command reject if not chained from a Locate Record
2964            command or from another Read Track command */
2965         if (chained == 0
2966          || (prevcode != 0x47 && prevcode != 0x4B && prevcode != 0xDE))
2967         {
2968             ckd_build_sense (dev, SENSE_CR, 0, 0,
2969                             FORMAT_0, MESSAGE_2);
2970             *unitstat = CSW_CE | CSW_DE | CSW_UC;
2971             break;
2972         }
2973 
2974         /* Advance to next track if chained from previous read track */
2975         if (prevcode == 0xDE)
2976         {
2977             j = 1;
2978             /* Skip tracks while hi bit off in ckdlmask */
2979             if (dev->ckdlmask)
2980             {
2981                 while (!(dev->ckdlmask & 0x8000))
2982                 {
2983                     j++;
2984                     dev->ckdlmask <<= 1;
2985                 }
2986             }
2987             rc = mt_advance (dev, unitstat, j);
2988             if (rc < 0) break;
2989         }
2990 
2991         /* Shift read track set mask left a bit */
2992         dev->ckdlmask <<= 1;
2993 
2994         /* Read each record on the track into the I/O buffer */
2995         for (size = 0; ; )
2996         {
2997             /* Read next count field */
2998             rc = ckd_read_count (dev, code, &rechdr, unitstat);
2999             if (rc < 0) break;
3000 
3001             /* Copy count field to I/O buffer */
3002             memcpy (iobuf + size, &rechdr, CKDDASD_RECHDR_SIZE);
3003             size += CKDDASD_RECHDR_SIZE;
3004 
3005             /* Turn off track overflow flag */
3006             if(dev->ckdcyls < 32768)
3007                 *(iobuf+size) &= 0x7F;
3008 
3009             /* Exit if end of track marker was read */
3010             if (memcmp (&rechdr, eighthexFF, 8) == 0)
3011                 break;
3012 
3013             /* Read key field */
3014             rc = ckd_read_key (dev, code, iobuf + size, unitstat);
3015             if (rc < 0) break;
3016             size += dev->ckdcurkl;
3017 
3018             /* Read data field */
3019             rc = ckd_read_data (dev, code, iobuf + size, unitstat);
3020             if (rc < 0) break;
3021             size += dev->ckdcurdl;
3022 
3023         } /* end for(size) */
3024 
3025         /* Set the residual count */
3026         num = (count < size) ? count : size;
3027         *residual = count - num;
3028         if (count < size) *more = 1;
3029 
3030         /* Save size and offset of data not used by this CCW */
3031         dev->ckdrem = size - num;
3032         dev->ckdpos = num;
3033 
3034         /* Return normal status */
3035         *unitstat = CSW_CE | CSW_DE;
3036 
3037         break;
3038 
3039     case 0x27:
3040     /*---------------------------------------------------------------*/
3041     /* PERFORM SUBSYSTEM FUNCTION                                    */
3042     /*---------------------------------------------------------------*/
3043         /* If the control unit is not a 3990 then CCW code 0x27 is
3044            treated as a SEEK AND SET SECTOR (Itel 7330 controller) */
3045         if (dev->ckd3990 == 0)
3046             goto seek_0x27;
3047 
3048         /* Command reject if within the domain of a Locate Record */
3049         if (dev->ckdlcount > 0)
3050         {
3051             ckd_build_sense (dev, SENSE_CR, 0, 0,
3052                             FORMAT_0, MESSAGE_2);
3053             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3054             break;
3055         }
3056 
3057         /* Use the order code to determine the required count */
3058         num = (count < 2) ? 2 :
3059               (iobuf[0] == 0x10) ? 14 :
3060               (iobuf[0] == 0x11 || iobuf[0] == 0x18) ? 12 :
3061               (iobuf[0] == 0x12) ? 5 :
3062               (iobuf[0] == 0x13 || iobuf[0] == 0x14) ? 4 :
3063               (iobuf[0] == 0x16) ? 4 :
3064               (iobuf[0] == 0x1D) ? 66 :
3065               (iobuf[0] == 0xB0) ? 4 :
3066               2;
3067 
3068         /* Command reject if count is less than required */
3069         if (count < num)
3070         {
3071             ckd_build_sense (dev, SENSE_CR, 0, 0,
3072                             FORMAT_0, MESSAGE_3);
3073             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3074             break;
3075         }
3076 
3077         /* Set residual count */
3078         *residual = count - num;
3079 
3080 #if 0
3081         /* Command reject if SSI active */
3082         if(dev->ckdssi)
3083         {
3084             /* Reset SSI condition */
3085             dev->ckdssi = 0;
3086             ckd_build_sense (dev, SENSE_CR, 0, 0,
3087                             FORMAT_0, MESSAGE_F);
3088             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3089             break;
3090         }
3091 #endif
3092 
3093         /* Process depending on order code in byte 0 of data */
3094         switch (iobuf[0]) {
3095 
3096         case 0x18: /* Prepare for Read Subsystem Data */
3097 
3098             /* Command reject if bytes 1-5 not zero */
3099             if (memcmp(&iobuf[1], "\x00\x00\x00\x00\x00", 5) != 0)
3100             {
3101                 ckd_build_sense (dev, SENSE_CR, 0, 0,
3102                                 FORMAT_0, MESSAGE_4);
3103                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3104                 break;
3105             }
3106 
3107             /* Process suborder code in byte 6 of data */
3108             switch (iobuf[6]) {
3109 
3110             case 0x00: /* Storage path status */
3111                 /* Prepare storage path status record */
3112                 memset (iobuf, 0x00, 16);
3113                 iobuf[0] = 0xC0; /* Storage path valid and attached */
3114                 iobuf[1] = 0x80; /* Logical paths configured bitmap */
3115                 iobuf[2] = 0x00; /* Channels enabled bitmap */
3116                 iobuf[3] = 0x00; /* Channels fenced bitmap */
3117                 iobuf[16] = 1;   /* #logical paths thru cluster 0 */
3118 
3119                 /* Indicate the length of subsystem data prepared */
3120                 dev->ckdssdlen = (dev->ckdcu->code==0x15) ? 24 : 16;
3121                 break;
3122 
3123             case 0x01: /* Subsystem statistics */
3124                 /* Indicate the length of subsystem data prepared */
3125                 dev->ckdssdlen = (iobuf[8]==0x00) ? 96 : 192;
3126 
3127                 /* Prepare subsystem statistics record */
3128                 memset (iobuf, 0x00, dev->ckdssdlen);
3129                 iobuf[1] = dev->devnum & 0xFF;
3130                 iobuf[94] = (myssid >> 8) & 0xff;
3131                 iobuf[95] = myssid & 0xff;
3132                 break;
3133             case 0x03:  /* Read attention message for this path-group for
3134                           the addressed device Return a "no message"
3135                            message */
3136                 iobuf[0] = 0x00;                     // Message length
3137                 iobuf[1] = 0x09;                    // ...
3138                 iobuf[2] = 0x00;                    // No message
3139                 iobuf[3] = 0x00;                    // Message code
3140                 memcpy (iobuf+4, iobuf+8, 4);       // Copy message identifier from bytes 8-11
3141                 iobuf[8] = 0x00;                    // Flags
3142                 dev->ckdssdlen = 9;                 // Indicate length of subsystem data prepared
3143                 break;
3144             case 0x0E: /* Unit address configuration */
3145                 /* Prepare unit address configuration record */
3146                 memset (iobuf, 0x00, 512);
3147                 /* 256 pairs (UA type, base UA) */
3148 
3149                 /* Indicate the length of subsystem data prepared */
3150                 dev->ckdssdlen = 512;
3151                 break;
3152 
3153             case 0x41: /* Feature codes */
3154                 /* Prepare feature codes record */
3155                 memset (iobuf, 0x00, 256);
3156 
3157                 /* Indicate the length of subsystem data prepared */
3158                 dev->ckdssdlen = 256;
3159                 break;
3160 
3161             default: /* Unknown suborder code */
3162                 ckd_build_sense (dev, SENSE_CR, 0, 0,
3163                                 FORMAT_0, MESSAGE_4);
3164                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3165 
3166             } /* end switch(iobuf[6]) */
3167 
3168             break;
3169 
3170         case 0x1B: /* Set Special Intercept Condition */
3171 
3172             /* Command reject if not the first command in the chain
3173                or indeed if preceded by any command at all apart from
3174                Suspend Multipath Reconnection */
3175             if (ccwseq > 1
3176                 || (chained && prevcode != 0x5B))
3177             {
3178                 ckd_build_sense (dev, SENSE_CR, 0, 0,
3179                                 FORMAT_0, MESSAGE_2);
3180                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3181                 break;
3182             }
3183 
3184             /* Command reject if flag byte is not zero */
3185             if (iobuf[1] != 0x00)
3186             {
3187                 ckd_build_sense (dev, SENSE_CR, 0, 0,
3188                                 FORMAT_0, MESSAGE_4);
3189                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3190                 break;
3191             }
3192 
3193             /* Command reject if any command is chained from this command */
3194             if (flags & CCW_FLAGS_CC)
3195             {
3196                 ckd_build_sense (dev, SENSE_CR, 0, 0,
3197                                 FORMAT_0, MESSAGE_2);
3198                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3199                 break;
3200             }
3201 
3202             /* Mark Set Special Intercept inactive */
3203             dev->ckdssi = 1;
3204 
3205             break;
3206 
3207         case 0x1D: /* Set Subsystem Characteristics */
3208 
3209             /* Command reject if flag byte is not zero */
3210             if (iobuf[1] != 0x00)
3211             {
3212                 ckd_build_sense (dev, SENSE_CR, 0, 0,
3213                                 FORMAT_0, MESSAGE_4);
3214                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3215                 break;
3216             }
3217 
3218             break;
3219 
3220         case 0xB0: /* Set Interface Identifier */
3221 
3222             /* Command reject if flag byte bits 0-5 are not zero
3223                or bits 6-7 are 11 or 10 */
3224             if ((iobuf[1] & 0xFE) != 0x00)
3225             {
3226                 ckd_build_sense (dev, SENSE_CR, 0, 0,
3227                                 FORMAT_0, MESSAGE_4);
3228                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3229                 break;
3230             }
3231 
3232             /* Prepare subsystem data (node descriptor record) */
3233             memset (iobuf, 0x00, 96);
3234 
3235             /* Bytes 0-31 contain the subsystem node descriptor */
3236             store_fw(&iobuf[0], 0x00000100);
3237             sprintf ((char *)&iobuf[4], "00%4.4X   HRCZZ000000000001",
3238                                 dev->ckdcu->devt);
3239             for (i = 4; i < 30; i++)
3240                 iobuf[i] = host_to_guest(iobuf[i]);
3241 
3242             /* Bytes 32-63 contain node qualifier data */
3243             store_fw(&iobuf[32],0x00000000); // flags+zeros
3244             store_fw(&iobuf[40],0x00000000);
3245             store_fw(&iobuf[40],0x41010000); // start range
3246             store_fw(&iobuf[44],0x41010001); // end range
3247             store_fw(&iobuf[48],0x41010010); // start range
3248             store_fw(&iobuf[52],0x41010011); // end range
3249 
3250             /* Bytes 64-95 contain a 2nd subsystem node descriptor */
3251             iobuf[64] = 0x00;
3252 
3253             /* Indicate the length of subsystem data prepared */
3254             dev->ckdssdlen = (iobuf[1] & 0x03) ? 32 : 96;
3255 
3256             break;
3257 
3258         default: /* Unknown order code */
3259 
3260             ckd_build_sense (dev, SENSE_CR, 0, 0,
3261                             FORMAT_0, MESSAGE_4);
3262             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3263 
3264         } /* end switch(iobuf[0]) */
3265 
3266         /* Exit if unit check has already been set */
3267         if (*unitstat & CSW_UC)
3268             break;
3269 
3270         /* Return normal status */
3271         *unitstat = CSW_CE | CSW_DE;
3272 
3273         break;
3274 
3275     seek_0x27: /* SEEK AND SET SECTOR (Itel 7330 controller only) */
3276     case 0x07: /* SEEK */
3277     case 0x0B: /* SEEK CYLINDER */
3278     case 0x1B: /* SEEK HEAD */
3279     /*---------------------------------------------------------------*/
3280     /* SEEK                                                          */
3281     /*---------------------------------------------------------------*/
3282         /* Command reject if within the domain of a Locate Record */
3283         if (dev->ckdlcount > 0)
3284         {
3285             ckd_build_sense (dev, SENSE_CR, 0, 0,
3286                             FORMAT_0, MESSAGE_2);
3287             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3288             break;
3289         }
3290 
3291         /* For 3990, command reject if Seek Head not preceded by Seek,
3292            Seek Cylinder, Locate Record, Read IPL, or Recalibrate */
3293         if (code == 0x1B && dev->ckd3990
3294             && dev->ckdseek == 0 && dev->ckdskcyl == 0
3295             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
3296             && dev->ckdrecal == 0)
3297         {
3298             ckd_build_sense (dev, SENSE_CR, 0, 0,
3299                             FORMAT_0, MESSAGE_2);
3300             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3301             break;
3302         }
3303 
3304         /* File protected if file mask does not allow requested seek */
3305         if (((code == 0x07 || code == 0x27)
3306             && (dev->ckdfmask & CKDMASK_SKCTL) != CKDMASK_SKCTL_ALLSKR)
3307            || (code == 0x0B
3308             && (dev->ckdfmask & CKDMASK_SKCTL) != CKDMASK_SKCTL_ALLSKR
3309             && (dev->ckdfmask & CKDMASK_SKCTL) != CKDMASK_SKCTL_CYLHD)
3310            || (code == 0x1B
3311             && (dev->ckdfmask & CKDMASK_SKCTL) == CKDMASK_SKCTL_INHSMT))
3312         {
3313             ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0);
3314             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3315             break;
3316         }
3317 
3318         /* Set residual count */
3319         num = (count < 6) ? count : 6;
3320         *residual = count - num;
3321 
3322         /* Command reject if count is less than 6 */
3323         if (count < 6)
3324         {
3325             ckd_build_sense (dev, SENSE_CR, 0, 0,
3326                             FORMAT_0, MESSAGE_3);
3327             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3328             break;
3329         }
3330 
3331         /* Extract the BBCCHH seek address from the I/O buffer */
3332         bin = (iobuf[0] << 8) | iobuf[1];
3333         cyl = (iobuf[2] << 8) | iobuf[3];
3334         head = (iobuf[4] << 8) | iobuf[5];
3335 
3336         /* For Seek Head, use the current cylinder number */
3337         if (code == 0x1B)
3338             cyl = dev->ckdcurcyl;
3339 
3340         /* Command reject if seek address is invalid */
3341         if (bin != 0 || cyl >= dev->ckdcyls || head >= dev->ckdheads)
3342         {
3343             ckd_build_sense (dev, SENSE_CR, 0, 0,
3344                             FORMAT_0, MESSAGE_4);
3345             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3346             break;
3347         }
3348 
3349         /* File protected if outside defined extent */
3350         if ( EXTENT_CHECK(dev, cyl, head) )
3351         {
3352             ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0);
3353             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3354             break;
3355         }
3356 
3357         /* Seek to specified cylinder and head */
3358         rc = ckd_seek (dev, cyl, head, &trkhdr, unitstat);
3359         if (rc < 0) break;
3360 
3361         /* Set command processed flag */
3362         dev->ckdseek = 1;
3363 
3364         /* Return normal status */
3365         *unitstat = CSW_CE | CSW_DE;
3366         break;
3367 
3368     case 0x13:
3369     /*---------------------------------------------------------------*/
3370     /* RECALIBRATE                                                   */
3371     /*---------------------------------------------------------------*/
3372         /* Command reject if recalibrate is issued to a 3390 */
3373         if (dev->devtype == 0x3390)
3374         {
3375             ckd_build_sense (dev, SENSE_CR, 0, 0,
3376                             FORMAT_0, MESSAGE_1);
3377             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3378             break;
3379         }
3380 
3381         /* Command reject if within the domain of a Locate Record */
3382         if (dev->ckdlcount > 0)
3383         {
3384             ckd_build_sense (dev, SENSE_CR, 0, 0,
3385                             FORMAT_0, MESSAGE_2);
3386             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3387             break;
3388         }
3389 
3390         /* File protected if the file mask does not allow recalibrate,
3391            or if the file mask specifies diagnostic authorization */
3392         if ((dev->ckdfmask & CKDMASK_SKCTL) != CKDMASK_SKCTL_ALLSKR
3393             || (dev->ckdfmask & CKDMASK_AAUTH) == CKDMASK_AAUTH_DIAG)
3394         {
3395             ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0);
3396             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3397             break;
3398         }
3399 
3400         /* File protected if cyl 0 head 0 is outside defined extent */
3401         if ( EXTENT_CHECK0(dev) )
3402         {
3403             ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0);
3404             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3405             break;
3406         }
3407 
3408         /* Seek to cylinder 0 head 0 */
3409         rc = ckd_seek (dev, 0, 0, &trkhdr, unitstat);
3410         if (rc < 0) break;
3411 
3412         /* Set command processed flag */
3413         dev->ckdrecal = 1;
3414 
3415         /* Return normal status */
3416         *unitstat = CSW_CE | CSW_DE;
3417         break;
3418 
3419     case 0x1F:
3420     /*---------------------------------------------------------------*/
3421     /* SET FILE MASK                                                 */
3422     /*---------------------------------------------------------------*/
3423         /* Command reject if preceded by a Define Extent or
3424            Set File Mask, or within the domain of a Locate Record */
3425         if (dev->ckdxtdef || dev->ckdsetfm || dev->ckdlcount > 0)
3426         {
3427             ckd_build_sense (dev, SENSE_CR, 0, 0,
3428                             FORMAT_0, MESSAGE_2);
3429             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3430             break;
3431         }
3432 
3433         /* Set residual count */
3434         num = (count < 1) ? count : 1;
3435         *residual = count - num;
3436 
3437         /* Command reject if count is less than 1 */
3438         if (count < 1)
3439         {
3440             ckd_build_sense (dev, SENSE_CR, 0, 0,
3441                             FORMAT_0, MESSAGE_3);
3442             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3443             break;
3444         }
3445 
3446         /* Extract the file mask from the I/O buffer */
3447         dev->ckdfmask = iobuf[0];
3448         logdevtr (dev, _("HHCDA054I set file mask %2.2X\n"), dev->ckdfmask);
3449 
3450         /* Command reject if file mask is invalid */
3451         if ((dev->ckdfmask & CKDMASK_RESV) != 0)
3452         {
3453             ckd_build_sense (dev, SENSE_CR, 0, 0,
3454                             FORMAT_0, MESSAGE_4);
3455             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3456             break;
3457         }
3458 
3459         /* Set command processed flag */
3460         dev->ckdsetfm = 1;
3461 
3462         /* Return normal status */
3463         *unitstat = CSW_CE | CSW_DE;
3464         break;
3465 
3466     case 0x22:
3467     /*---------------------------------------------------------------*/
3468     /* READ SECTOR                                                   */
3469     /*---------------------------------------------------------------*/
3470         /* Command reject if non-RPS device */
3471         if (dev->ckdtab->sectors == 0)
3472         {
3473             ckd_build_sense (dev, SENSE_CR, 0, 0,
3474                             FORMAT_0, MESSAGE_1);
3475             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3476             break;
3477         }
3478 
3479         /* Command reject if within the domain of a Locate Record */
3480         if (dev->ckdlcount > 0)
3481         {
3482             ckd_build_sense (dev, SENSE_CR, 0, 0,
3483                             FORMAT_0, MESSAGE_2);
3484             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3485             break;
3486         }
3487 
3488         /* Set residual count */
3489         num = (count < 1) ? count : 1;
3490         *residual = count - num;
3491         if (count < 1) *more = 1;
3492 
3493         /* Return sector number in I/O buffer */
3494         iobuf[0] = 0;
3495 
3496         /* Return normal status */
3497         *unitstat = CSW_CE | CSW_DE;
3498         break;
3499 
3500     case 0x23:
3501     /*---------------------------------------------------------------*/
3502     /* SET SECTOR                                                    */
3503     /*---------------------------------------------------------------*/
3504         /* Command reject if non-RPS device */
3505         if (dev->ckdtab->sectors == 0)
3506         {
3507             ckd_build_sense (dev, SENSE_CR, 0, 0,
3508                             FORMAT_0, MESSAGE_1);
3509             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3510             break;
3511         }
3512 
3513         /* Command reject if within the domain of a Locate Record */
3514         if (dev->ckdlcount > 0)
3515         {
3516             ckd_build_sense (dev, SENSE_CR, 0, 0,
3517                             FORMAT_0, MESSAGE_2);
3518             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3519             break;
3520         }
3521 
3522         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
3523            Locate Record, Read IPL, or Recalibrate command */
3524         if (dev->ckd3990
3525             && dev->ckdseek == 0 && dev->ckdskcyl == 0
3526             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
3527             && dev->ckdrecal == 0)
3528         {
3529             ckd_build_sense (dev, SENSE_CR, 0, 0,
3530                             FORMAT_0, MESSAGE_2);
3531             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3532             break;
3533         }
3534 
3535         /* Set residual count */
3536         num = (count < 1) ? count : 1;
3537         *residual = count - num;
3538 
3539         /* Command reject if count is less than 1 */
3540         if (count < 1)
3541         {
3542             ckd_build_sense (dev, SENSE_CR, 0, 0,
3543                             FORMAT_0, MESSAGE_3);
3544             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3545             break;
3546         }
3547 
3548         /* Return normal status */
3549         *unitstat = CSW_CE | CSW_DE;
3550         break;
3551 
3552     case 0x29: case 0xA9: /* SEARCH KEY EQUAL */
3553     case 0x49: case 0xC9: /* SEARCH KEY HIGH */
3554     case 0x69: case 0xE9: /* SEARCH KEY EQUAL OR HIGH */
3555     /*---------------------------------------------------------------*/
3556     /* SEARCH KEY                                                    */
3557     /*---------------------------------------------------------------*/
3558         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
3559            Locate Record, Read IPL, or Recalibrate command */
3560         if (dev->ckd3990
3561             && dev->ckdseek == 0 && dev->ckdskcyl == 0
3562             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
3563             && dev->ckdrecal == 0)
3564         {
3565             ckd_build_sense (dev, SENSE_CR, 0, 0,
3566                             FORMAT_0, MESSAGE_2);
3567             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3568             break;
3569         }
3570 
3571         /* Command reject if within the domain of a Locate Record */
3572         if (dev->ckdlcount > 0)
3573         {
3574             ckd_build_sense (dev, SENSE_CR, 0, 0,
3575                             FORMAT_0, MESSAGE_2);
3576             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3577             break;
3578         }
3579 
3580         /* Read next key */
3581         rc = ckd_read_key (dev, code, key, unitstat);
3582         if (rc < 0) break;
3583 
3584         /* Calculate number of compare bytes and set residual count */
3585         num = (count < dev->ckdcurkl) ? count : dev->ckdcurkl;
3586         *residual = count - num;
3587 
3588         /* Nothing to compare if key length is zero */
3589         if (dev->ckdcurkl == 0)
3590         {
3591             *unitstat = CSW_CE | CSW_DE;
3592             break;
3593         }
3594 
3595         /* Compare key with search argument */
3596         rc = memcmp(key, iobuf, num);
3597 
3598         /* Return status modifier if compare result matches */
3599         if (((code & 0x20) && (rc == 0))
3600             || ((code & 0x40) && (rc > 0)))
3601             *unitstat = CSW_SM | CSW_CE | CSW_DE;
3602         else
3603             *unitstat = CSW_CE | CSW_DE;
3604 
3605 #ifdef OPTION_CKD_KEY_TRACING
3606         /* If the search was successful, trace the first 8 bytes of
3607            the key, which will usually be a dataset name or member
3608            name and can provide useful debugging information */
3609         if ((*unitstat & CSW_SM) && dev->ckdkeytrace
3610             && isprint(guest_to_host(iobuf[0])))
3611         {
3612             BYTE module[45]; int i;
3613             for (i=0; i < (ssize_t)sizeof(module)-1 && i < num; i++)
3614                 module[i] = guest_to_host(iobuf[i]);
3615             module[i] = '\0';
3616             logmsg (_("HHCDA055I search key %s\n"), module);
3617         }
3618 #endif /*OPTION_CKD_KEY_TRACING*/
3619 
3620         /* Set flag if entire key was equal for SEARCH KEY EQUAL */
3621         if (rc == 0 && num == dev->ckdcurkl && (code & 0x7F) == 0x29)
3622             dev->ckdkyeq = 1;
3623         else
3624             dev->ckdkyeq = 0;
3625 
3626         break;
3627 
3628     case 0x31: case 0xB1: /* SEARCH ID EQUAL */
3629     case 0x51: case 0xD1: /* SEARCH ID HIGH */
3630     case 0x71: case 0xF1: /* SEARCH ID EQUAL OR HIGH */
3631     /*---------------------------------------------------------------*/
3632     /* SEARCH ID                                                     */
3633     /*---------------------------------------------------------------*/
3634         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
3635            Locate Record, Read IPL, or Recalibrate command */
3636         if (dev->ckd3990
3637             && dev->ckdseek == 0 && dev->ckdskcyl == 0
3638             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
3639             && dev->ckdrecal == 0)
3640         {
3641             ckd_build_sense (dev, SENSE_CR, 0, 0,
3642                             FORMAT_0, MESSAGE_2);
3643             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3644             break;
3645         }
3646 
3647         /* Command reject if within the domain of a Locate Record */
3648         if (dev->ckdlcount > 0)
3649         {
3650             ckd_build_sense (dev, SENSE_CR, 0, 0,
3651                             FORMAT_0, MESSAGE_2);
3652             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3653             break;
3654         }
3655 
3656         /* Read next count field */
3657         rc = ckd_read_count (dev, code, &rechdr, unitstat);
3658         if (rc < 0) break;
3659 
3660         /* Calculate number of compare bytes and set residual count */
3661         num = (count < 5) ? count : 5;
3662         *residual = count - num;
3663 
3664         /* Turn off track overflow flag in record header if present */
3665         if(dev->ckdcyls < 32768)
3666             rechdr.cyl[0] &= 0x7F;
3667 
3668         /* Compare count with search argument */
3669         rc = memcmp(&rechdr, iobuf, num);
3670 
3671         /* Return status modifier if compare result matches */
3672         if (((code & 0x20) && (rc == 0))
3673             || ((code & 0x40) && (rc > 0)))
3674             *unitstat = CSW_SM | CSW_CE | CSW_DE;
3675         else
3676             *unitstat = CSW_CE | CSW_DE;
3677 
3678         /* Set flag if entire id compared equal for SEARCH ID EQUAL */
3679         if (rc == 0 && num == 5 && (code & 0x7F) == 0x31)
3680             dev->ckdideq = 1;
3681         else
3682             dev->ckdideq = 0;
3683 
3684         break;
3685 
3686     case 0x39:
3687     case 0xB9:
3688     /*---------------------------------------------------------------*/
3689     /* SEARCH HOME ADDRESS EQUAL                                     */
3690     /*---------------------------------------------------------------*/
3691         /* For 3990, command reject if not preceded by Seek, Seek Cyl,
3692            Locate Record, Read IPL, or Recalibrate command */
3693         if (dev->ckd3990
3694             && dev->ckdseek == 0 && dev->ckdskcyl == 0
3695             && dev->ckdlocat == 0 && dev->ckdrdipl == 0
3696             && dev->ckdrecal == 0)
3697         {
3698             ckd_build_sense (dev, SENSE_CR, 0, 0,
3699                             FORMAT_0, MESSAGE_2);
3700             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3701             break;
3702         }
3703 
3704         /* Command reject if within the domain of a Locate Record */
3705         if (dev->ckdlcount > 0)
3706         {
3707             ckd_build_sense (dev, SENSE_CR, 0, 0,
3708                             FORMAT_0, MESSAGE_2);
3709             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3710             break;
3711         }
3712 
3713         /* For multitrack operation, advance to next track */
3714         if (code & 0x80)
3715         {
3716             rc = mt_advance (dev, unitstat, 1);
3717             if (rc < 0) break;
3718         }
3719 
3720         /* Seek to beginning of track */
3721         rc = ckd_seek (dev, dev->ckdcurcyl, dev->ckdcurhead, &trkhdr, unitstat);
3722         if (rc < 0) break;
3723 
3724         /* Calculate number of compare bytes and set residual count */
3725         num = (count < 4) ? count : 4;
3726         *residual = count - num;
3727 
3728         /* Compare CCHH portion of track header with search argument */
3729         rc = memcmp(&(trkhdr.cyl), iobuf, num);
3730 
3731         /* Return status modifier if compare result matches */
3732         if (rc == 0)
3733             *unitstat = CSW_SM | CSW_CE | CSW_DE;
3734         else
3735             *unitstat = CSW_CE | CSW_DE;
3736 
3737         /* Set flag if entire home address compared equal */
3738         if (rc == 0 && num == 4)
3739             dev->ckdhaeq = 1;
3740         else
3741             dev->ckdhaeq = 0;
3742 
3743         break;
3744 
3745     case 0x05:
3746     /*---------------------------------------------------------------*/
3747     /* WRITE DATA                                                    */
3748     /*---------------------------------------------------------------*/
3749         /* Command reject if the current track is in the DSF area */
3750         if (dev->ckdcurcyl >= dev->ckdcyls)
3751         {
3752             ckd_build_sense (dev, SENSE_CR, 0, 0,
3753                             FORMAT_0, MESSAGE_2);
3754             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3755             break;
3756         }
3757 
3758         /* Command reject if not within the domain of a Locate Record
3759            and not preceded by either a Search ID Equal or Search Key
3760            Equal that compared equal on all bytes */
3761            /*INCOMPLETE*/ /*Write CKD allows intervening Read/Write
3762              key and data commands, Write Data does not!!! Rethink
3763              the handling of these flags*/
3764         if (dev->ckdlcount == 0 && dev->ckdideq == 0
3765             && dev->ckdkyeq == 0)
3766         {
3767             ckd_build_sense (dev, SENSE_CR, 0, 0,
3768                             FORMAT_0, MESSAGE_2);
3769             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3770             break;
3771         }
3772 
3773         /* Command reject if file mask inhibits all write commands */
3774         if ((dev->ckdfmask & CKDMASK_WRCTL) == CKDMASK_WRCTL_INHWRT)
3775         {
3776             ckd_build_sense (dev, SENSE_CR, 0, 0,
3777                             FORMAT_0, MESSAGE_2);
3778             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3779             break;
3780         }
3781 
3782         /* Check operation code if within domain of a Locate Record */
3783         if (dev->ckdlcount > 0)
3784         {
3785             if (!(((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE
3786                        && dev->ckdlcount ==
3787                             (dev->ckdlaux & CKDLAUX_RDCNTSUF) ? 2 : 1)
3788                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK))
3789             {
3790                 ckd_build_sense (dev, SENSE_CR, 0, 0,
3791                                 FORMAT_0, MESSAGE_2);
3792                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3793                 break;
3794             }
3795 
3796             /* If not operating in CKD conversion mode, check that the
3797                data length is equal to the transfer length factor,
3798                except when writing a R0 data area under the control
3799                of a Locate Record Write Track operation, in which
3800                case a transfer length factor of 8 is used instead */
3801             if ((dev->ckdxgattr & CKDGATR_CKDCONV) == 0)
3802             {
3803                 if ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK
3804                     && dev->ckdcurrec == 0)
3805                     num = 8;
3806                 else
3807                     num = dev->ckdltranlf;
3808 
3809                 if (dev->ckdcurdl != num)
3810                 {
3811                     /* Unit check with invalid track format */
3812                     ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0);
3813                     *unitstat = CSW_CE | CSW_DE | CSW_UC;
3814                     break;
3815                 }
3816             }
3817         } /* end if(ckdlcount) */
3818 
3819         /* If data length is zero, terminate with unit exception */
3820         if (dev->ckdcurdl == 0)
3821         {
3822             *unitstat = CSW_CE | CSW_DE | CSW_UX;
3823             break;
3824         }
3825 
3826         /* Calculate number of bytes written and set residual count */
3827         size = dev->ckdcurdl;
3828         num = (count < size) ? count : size;
3829         *residual = count - num;
3830 
3831         /* Write data */
3832         rc = ckd_write_data (dev, iobuf, num, unitstat);
3833         if (rc < 0) break;
3834 
3835         /* If track overflow, keep writing */
3836         offset = 0;
3837         while (dev->ckdtrkof)
3838         {
3839             /* Advance to next track */
3840             rc = mt_advance (dev, unitstat, 1);
3841             if (rc < 0) break;
3842 
3843             /* Read the first count field */
3844             rc = ckd_read_count (dev, code, &rechdr, unitstat);
3845             if (rc < 0) break;
3846 
3847             /* Set offset into buffer for this write */
3848             offset += size;
3849 
3850             /* Account for size of this overflow record */
3851             size = dev->ckdcurdl;
3852             num = (*residual < size) ? *residual : size;
3853             *residual -= num;
3854 
3855             /* Write the next data field */
3856             rc = ckd_write_data (dev, iobuf+offset, num, unitstat);
3857             if (rc < 0) break;
3858         }
3859 
3860         /* Bail out if track overflow produced I/O error */
3861         if (rc < 0) break;
3862 
3863         /* Return normal status */
3864         *unitstat = CSW_CE | CSW_DE;
3865 
3866         break;
3867 
3868     case 0xA5:
3869 //FIXME: 0xA5 ccw is undoc'd.  We are treating it as 0x85 except
3870 //       we will allow a DX ccw to follow.
3871     case 0x85:
3872     /*---------------------------------------------------------------*/
3873     /* WRITE UPDATE DATA                                             */
3874     /*---------------------------------------------------------------*/
3875         /* Command reject if not within the domain of a Locate Record
3876            that specifies the Write Data operation code */
3877         if (dev->ckdlcount == 0
3878          || ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRITE
3879           && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRTANY))
3880         {
3881             ckd_build_sense (dev, SENSE_CR, 0, 0,
3882                             FORMAT_0, MESSAGE_2);
3883             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3884             break;
3885         }
3886 
3887         /* Orient to next user record count field */
3888         if (dev->ckdorient != CKDORIENT_COUNT
3889             || dev->ckdcurrec == 0)
3890         {
3891             /* Read next count field */
3892             rc = ckd_read_count (dev, code, &rechdr, unitstat);
3893             if (rc < 0) break;
3894         }
3895 
3896         /* If not operating in CKD conversion mode, check that the
3897            data length is equal to the transfer length factor */
3898         if ((dev->ckdxgattr & CKDGATR_CKDCONV) == 0)
3899         {
3900             if (dev->ckdcurdl != dev->ckdltranlf)
3901             {
3902                 /* Unit check with invalid track format */
3903                 ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0);
3904                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3905                 break;
3906             }
3907         }
3908 
3909         /* If data length is zero, terminate with unit exception */
3910         if (dev->ckdcurdl == 0)
3911         {
3912             *unitstat = CSW_CE | CSW_DE | CSW_UX;
3913             break;
3914         }
3915 
3916         /* Calculate number of bytes written and set residual count */
3917         size = dev->ckdcurdl;
3918         num = (count < size) ? count : size;
3919         *residual = count - num;
3920 
3921         /* Write data */
3922         rc = ckd_write_data (dev, iobuf, num, unitstat);
3923         if (rc < 0) break;
3924 
3925         /* If track overflow, keep writing */
3926         offset = 0;
3927         while (dev->ckdtrkof)
3928         {
3929             /* Advance to next track */
3930             rc = mt_advance (dev, unitstat, 1);
3931             if (rc < 0) break;
3932 
3933             /* Read the first count field */
3934             rc = ckd_read_count (dev, code, &rechdr, unitstat);
3935             if (rc < 0) break;
3936 
3937             /* Set offset into buffer for this write */
3938             offset += size;
3939 
3940             /* Account for size of this overflow record */
3941             size = dev->ckdcurdl;
3942             num = (*residual < size) ? *residual : size;
3943             *residual -= num;
3944 
3945             /* Write the next data field */
3946             rc = ckd_write_data (dev, iobuf+offset, num, unitstat);
3947             if (rc < 0) break;
3948         }
3949 
3950         /* Bail out if track overflow produced I/O error */
3951         if (rc < 0) break;
3952 
3953         /* Return normal status */
3954         *unitstat = CSW_CE | CSW_DE;
3955 
3956         break;
3957 
3958     case 0x0D:
3959     /*---------------------------------------------------------------*/
3960     /* WRITE KEY AND DATA                                            */
3961     /*---------------------------------------------------------------*/
3962         /* Command reject if the current track is in the DSF area */
3963         if (dev->ckdcurcyl >= dev->ckdcyls)
3964         {
3965             ckd_build_sense (dev, SENSE_CR, 0, 0,
3966                             FORMAT_0, MESSAGE_2);
3967             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3968             break;
3969         }
3970 
3971         /* Command reject if not within the domain of a Locate Record
3972            and not preceded by a Search ID Equal that compared equal
3973            on all bytes */
3974            /*INCOMPLETE*/ /*Write CKD allows intervening Read/Write
3975              key and data commands, Write Key Data does not!!! Rethink
3976              the handling of these flags*/
3977         if (dev->ckdlcount == 0 && dev->ckdideq == 0)
3978         {
3979             ckd_build_sense (dev, SENSE_CR, 0, 0,
3980                             FORMAT_0, MESSAGE_2);
3981             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3982             break;
3983         }
3984 
3985         /* Command reject if file mask inhibits all write commands */
3986         if ((dev->ckdfmask & CKDMASK_WRCTL) == CKDMASK_WRCTL_INHWRT)
3987         {
3988             ckd_build_sense (dev, SENSE_CR, 0, 0,
3989                             FORMAT_0, MESSAGE_2);
3990             *unitstat = CSW_CE | CSW_DE | CSW_UC;
3991             break;
3992         }
3993 
3994         /* Check operation code if within domain of a Locate Record */
3995         if (dev->ckdlcount > 0)
3996         {
3997             if (!(((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE
3998                        && dev->ckdlcount ==
3999                             (dev->ckdlaux & CKDLAUX_RDCNTSUF) ? 2 : 1)
4000                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK))
4001             {
4002                 ckd_build_sense (dev, SENSE_CR, 0, 0,
4003                                 FORMAT_0, MESSAGE_2);
4004                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
4005                 break;
4006             }
4007 
4008             /* If not operating in CKD conversion mode, check that the
4009                key + data length equals the transfer length factor */
4010             if ((dev->ckdxgattr & CKDGATR_CKDCONV) == 0
4011                 && dev->ckdcurkl + dev->ckdcurdl != dev->ckdltranlf)
4012             {
4013                 /* Unit check with invalid track format */
4014                 ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0);
4015                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
4016                 break;
4017             }
4018         } /* end if(ckdlcount) */
4019 
4020         /* If data length is zero, terminate with unit exception */
4021         if (dev->ckdcurdl == 0)
4022         {
4023             *unitstat = CSW_CE | CSW_DE | CSW_UX;
4024             break;
4025         }
4026 
4027         /* Calculate number of bytes written and set residual count */
4028         size = dev->ckdcurkl + dev->ckdcurdl;
4029         num = (count < size) ? count : size;
4030         *residual = count - num;
4031 
4032         /* Write key and data */
4033         rc = ckd_write_kd (dev, iobuf, num, unitstat);
4034         if (rc < 0) break;
4035 
4036         /* If track overflow, keep writing */
4037         offset = dev->ckdcurkl;
4038         while (dev->ckdtrkof)
4039         {
4040             /* Advance to next track */
4041             rc = mt_advance (dev, unitstat, 1);
4042             if (rc < 0) break;
4043 
4044             /* Read the first count field */
4045             rc = ckd_read_count (dev, code, &rechdr, unitstat);
4046             if (rc < 0) break;
4047 
4048             /* Set offset into buffer for this write */
4049             offset += size;
4050 
4051             /* Account for size of this overflow record */
4052             size = dev->ckdcurdl;
4053             num = (*residual < size) ? *residual : size;
4054             *residual -= num;
4055 
4056             /* Write the next data field */
4057             rc = ckd_write_data (dev, iobuf+offset, num, unitstat);
4058             if (rc < 0) break;
4059         }
4060 
4061         /* Bail out if track overflow produced I/O error */
4062         if (rc < 0) break;
4063 
4064         /* Return normal status */
4065         *unitstat = CSW_CE | CSW_DE;
4066 
4067         break;
4068 
4069     case 0x8D:
4070     /*---------------------------------------------------------------*/
4071     /* WRITE UPDATE KEY AND DATA                                     */
4072     /*---------------------------------------------------------------*/
4073         /* Command reject if not within the domain of a Locate Record
4074            that specifies the Write Data operation code */
4075         if (dev->ckdlcount == 0
4076             || (dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRITE)
4077         {
4078             ckd_build_sense (dev, SENSE_CR, 0, 0,
4079                             FORMAT_0, MESSAGE_2);
4080             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4081             break;
4082         }
4083 
4084         /* Orient to next user record count field */
4085         if (dev->ckdorient != CKDORIENT_COUNT
4086             || dev->ckdcurrec == 0)
4087         {
4088             /* Read next count field */
4089             rc = ckd_read_count (dev, code, &rechdr, unitstat);
4090             if (rc < 0) break;
4091         }
4092 
4093         /* If not operating in CKD conversion mode, check that the
4094            data length is equal to the transfer length factor */
4095         if ((dev->ckdxgattr & CKDGATR_CKDCONV) == 0)
4096         {
4097             if ((dev->ckdcurkl + dev->ckdcurdl) != dev->ckdltranlf)
4098             {
4099                 /* Unit check with invalid track format */
4100                 ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0);
4101                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
4102                 break;
4103             }
4104         }
4105 
4106         /* If data length is zero, terminate with unit exception */
4107         if (dev->ckdcurdl == 0)
4108         {
4109             *unitstat = CSW_CE | CSW_DE | CSW_UX;
4110             break;
4111         }
4112 
4113         /* Calculate number of bytes written and set residual count */
4114         size = dev->ckdcurkl + dev->ckdcurdl;
4115         num = (count < size) ? count : size;
4116         *residual = count - num;
4117 
4118         /* Write key and data */
4119         rc = ckd_write_kd (dev, iobuf, num, unitstat);
4120         if (rc < 0) break;
4121 
4122         /* If track overflow, keep writing */
4123         offset = dev->ckdcurkl;
4124         while (dev->ckdtrkof)
4125         {
4126             /* Advance to next track */
4127             rc = mt_advance (dev, unitstat, 1);
4128             if (rc < 0) break;
4129 
4130             /* Read the first count field */
4131             rc = ckd_read_count (dev, code, &rechdr, unitstat);
4132             if (rc < 0) break;
4133 
4134             /* Set offset into buffer for this write */
4135             offset += size;
4136 
4137             /* Account for size of this overflow record */
4138             size = dev->ckdcurdl;
4139             num = (*residual < size) ? *residual : size;
4140             *residual -= num;
4141 
4142             /* Write the next data field */
4143             rc = ckd_write_data (dev, iobuf+offset, num, unitstat);
4144             if (rc < 0) break;
4145         }
4146 
4147         /* Bail out if track overflow produced I/O error */
4148         if (rc < 0) break;
4149 
4150         /* Return normal status */
4151         *unitstat = CSW_CE | CSW_DE;
4152 
4153         break;
4154 
4155     case 0x11:
4156     /*---------------------------------------------------------------*/
4157     /* ERASE                                                         */
4158     /*---------------------------------------------------------------*/
4159         /* Command reject if the current track is in the DSF area */
4160         if (dev->ckdcurcyl >= dev->ckdcyls)
4161         {
4162             ckd_build_sense (dev, SENSE_CR, 0, 0,
4163                             FORMAT_0, MESSAGE_2);
4164             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4165             break;
4166         }
4167 
4168         /* Command reject if not within the domain of a Locate Record
4169            and not preceded by either a Search ID Equal or Search Key
4170            Equal that compared equal on all bytes, or a Write R0 or
4171            Write CKD not within the domain of a Locate Record */
4172         if (dev->ckdlcount == 0 && dev->ckdideq == 0
4173             && dev->ckdkyeq == 0 && dev->ckdwckd == 0)
4174         {
4175             ckd_build_sense (dev, SENSE_CR, 0, 0,
4176                             FORMAT_0, MESSAGE_2);
4177             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4178             break;
4179         }
4180 
4181         /* Command reject if file mask does not permit Write CKD */
4182         if ((dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_ALLWRT
4183             && (dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_INHWR0)
4184         {
4185             ckd_build_sense (dev, SENSE_CR, 0, 0,
4186                             FORMAT_0, MESSAGE_2);
4187             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4188             break;
4189         }
4190 
4191         /* Check operation code if within domain of a Locate Record */
4192         if (dev->ckdlcount > 0)
4193         {
4194             if ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRTTRK)
4195             {
4196                 ckd_build_sense (dev, SENSE_CR, 0, 0,
4197                                 FORMAT_0, MESSAGE_2);
4198                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
4199                 break;
4200             }
4201         }
4202 
4203         /* Write end of track marker */
4204         rc = ckd_erase (dev, iobuf, count, &size, unitstat);
4205         if (rc < 0) break;
4206 
4207         /* Calculate number of bytes used and set residual count */
4208         num = (count < size) ? count : size;
4209         *residual = count - num;
4210 
4211         /* Return normal status */
4212         *unitstat = CSW_CE | CSW_DE;
4213 
4214         break;
4215 
4216     case 0x15:
4217     /*---------------------------------------------------------------*/
4218     /* WRITE RECORD ZERO                                             */
4219     /*---------------------------------------------------------------*/
4220         /* Command reject if the current track is in the DSF area */
4221         if (dev->ckdcurcyl >= dev->ckdcyls)
4222         {
4223             ckd_build_sense (dev, SENSE_CR, 0, 0,
4224                             FORMAT_0, MESSAGE_2);
4225             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4226             logmsg("DEBUG : WR0 OUTSIDE PACK\n");
4227             break;
4228         }
4229 
4230         /* Command reject if not within the domain of a Locate Record
4231            and not preceded by either a Search Home Address that
4232            compared equal on all 4 bytes, or a Write Home Address not
4233            within the domain of a Locate Record */
4234         /* ISW20030819-1 : Added check for previously issued WRHA */
4235         if (dev->ckdlcount == 0 && dev->ckdhaeq == 0 && dev->ckdwrha==0)
4236         {
4237             ckd_build_sense (dev, SENSE_CR, 0, 0,
4238                             FORMAT_0, MESSAGE_2);
4239             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4240             logmsg("DEBUG : WR0 CASE 2\n");
4241             break;
4242         }
4243 
4244         /* Command reject if file mask does not permit Write R0 */
4245         if ((dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_ALLWRT)
4246         {
4247             ckd_build_sense (dev, SENSE_CR, 0, 0,
4248                             FORMAT_0, MESSAGE_2);
4249             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4250             logmsg("DEBUG : WR0 BAD FM\n");
4251             break;
4252         }
4253 
4254         /* Check operation code if within domain of a Locate Record */
4255         if (dev->ckdlcount > 0)
4256         {
4257             if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT
4258                     && ((dev->ckdloper & CKDOPER_ORIENTATION)
4259                                 == CKDOPER_ORIENT_HOME
4260                           || (dev->ckdloper & CKDOPER_ORIENTATION)
4261                                 == CKDOPER_ORIENT_INDEX
4262                        )))
4263             {
4264                 ckd_build_sense (dev, SENSE_CR, 0, 0,
4265                                 FORMAT_0, MESSAGE_2);
4266                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
4267                 logmsg("DEBUG : LOC REC 2\n");
4268                 break;
4269             }
4270         }
4271 
4272         /* Write R0 count key and data */
4273         rc = ckd_write_ckd (dev, iobuf, count, unitstat, 0);
4274         if (rc < 0) break;
4275 
4276         /* Calculate number of bytes written and set residual count */
4277         size = CKDDASD_RECHDR_SIZE + dev->ckdcurkl + dev->ckdcurdl;
4278         num = (count < size) ? count : size;
4279         *residual = count - num;
4280 
4281         /* Return normal status */
4282         *unitstat = CSW_CE | CSW_DE;
4283 
4284         /* Set flag if Write R0 outside domain of a locate record */
4285         if (dev->ckdlcount == 0)
4286             dev->ckdwckd = 1;
4287         else
4288             dev->ckdwckd = 0;
4289 
4290         break;
4291 
4292     case 0x1D: /* WRITE CKD */
4293     case 0x01: /* WRITE SPECIAL CKD */
4294     /*---------------------------------------------------------------*/
4295     /* WRITE COUNT KEY AND DATA                                      */
4296     /*---------------------------------------------------------------*/
4297         /* Command reject if the current track is in the DSF area */
4298         if (dev->ckdcurcyl >= dev->ckdcyls)
4299         {
4300             ckd_build_sense (dev, SENSE_CR, 0, 0,
4301                             FORMAT_0, MESSAGE_2);
4302             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4303             break;
4304         }
4305 
4306         /* Command reject if previous command was a Write R0 that
4307            assigned an alternate track - not implemented */
4308 
4309         /* Command reject if not within the domain of a Locate Record
4310            and not preceded by either a Search ID Equal or Search Key
4311            Equal that compared equal on all bytes, or a Write R0 or
4312            Write CKD not within the domain of a Locate Record */
4313         if (dev->ckdlcount == 0 && dev->ckdideq == 0
4314             && dev->ckdkyeq == 0 && dev->ckdwckd == 0)
4315         {
4316             ckd_build_sense (dev, SENSE_CR, 0, 0,
4317                             FORMAT_0, MESSAGE_2);
4318             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4319             break;
4320         }
4321 
4322         /* Command reject if file mask does not permit Write CKD */
4323         if ((dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_ALLWRT
4324             && (dev->ckdfmask & CKDMASK_WRCTL) != CKDMASK_WRCTL_INHWR0)
4325         {
4326             ckd_build_sense (dev, SENSE_CR, 0, 0,
4327                             FORMAT_0, MESSAGE_2);
4328             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4329             break;
4330         }
4331 
4332         /* Command reject if WRITE SPECIAL CKD to a 3380 or 3390 */
4333         if ((code == 0x01)
4334             && ((dev->devtype == 0x3380) || (dev->devtype == 0x3390)))
4335         {
4336             ckd_build_sense (dev, SENSE_CR, 0, 0,
4337                             FORMAT_0, MESSAGE_2);
4338             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4339             break;
4340         }
4341 
4342         /* Check operation code if within domain of a Locate Record */
4343         if (dev->ckdlcount > 0)
4344         {
4345             if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT
4346                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK))
4347             {
4348                 ckd_build_sense (dev, SENSE_CR, 0, 0,
4349                                 FORMAT_0, MESSAGE_2);
4350                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
4351                 break;
4352             }
4353         }
4354 
4355         /* Set track overflow flag if WRITE SPECIAL CKD */
4356         trk_ovfl = (dev->ckdcyls < 32768 && code==0x01) ? 1 : 0;
4357 
4358         /* Write count key and data */
4359         rc = ckd_write_ckd (dev, iobuf, count, unitstat, trk_ovfl);
4360         if (rc < 0) break;
4361 
4362         /* Calculate number of bytes written and set residual count */
4363         size = CKDDASD_RECHDR_SIZE + dev->ckdcurkl + dev->ckdcurdl;
4364         num = (count < size) ? count : size;
4365         *residual = count - num;
4366 
4367         /* Return normal status */
4368         *unitstat = CSW_CE | CSW_DE;
4369 
4370         /* Set flag if Write CKD outside domain of a locate record */
4371         if (dev->ckdlcount == 0)
4372             dev->ckdwckd = 1;
4373         else
4374             dev->ckdwckd = 0;
4375 
4376         break;
4377 
4378     case 0x9D:
4379     /*---------------------------------------------------------------*/
4380     /* WRITE COUNT KEY AND DATA NEXT TRACK                           */
4381     /*---------------------------------------------------------------*/
4382         /* Command reject if not within the domain of a Locate Record
4383            that specifies a format write operation */
4384         if (dev->ckdlcount == 0
4385             || (dev->ckdloper & CKDOPER_CODE) != CKDOPER_FORMAT)
4386         {
4387             ckd_build_sense (dev, SENSE_CR, 0, 0,
4388                             FORMAT_0, MESSAGE_2);
4389             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4390             break;
4391         }
4392 
4393         /* Command reject if not chained from a Write CKD or
4394            another Write CKD Next Track command */
4395         if (chained == 0
4396             || (prevcode != 0x1D && prevcode != 0x9D))
4397         {
4398             ckd_build_sense (dev, SENSE_CR, 0, 0,
4399                             FORMAT_0, MESSAGE_2);
4400             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4401             break;
4402         }
4403 
4404         /* Advance to next track */
4405         rc = mt_advance (dev, unitstat, 1);
4406         if (rc < 0) break;
4407 
4408         /* Read the count field for record zero */
4409         rc = ckd_read_count (dev, code, &rechdr, unitstat);
4410         if (rc < 0) break;
4411 
4412         /* Write count key and data */
4413         rc = ckd_write_ckd (dev, iobuf, count, unitstat, 0);
4414         if (rc < 0) break;
4415 
4416         /* Calculate number of bytes written and set residual count */
4417         size = CKDDASD_RECHDR_SIZE + dev->ckdcurkl + dev->ckdcurdl;
4418         num = (count < size) ? count : size;
4419         *residual = count - num;
4420 
4421         /* Return normal status */
4422         *unitstat = CSW_CE | CSW_DE;
4423 
4424         break;
4425 
4426     case 0x47:
4427     /*---------------------------------------------------------------*/
4428     /* LOCATE RECORD                                                 */
4429     /*---------------------------------------------------------------*/
4430         /* Calculate residual byte count */
4431         num = (count < 16) ? count : 16;
4432         *residual = count - num;
4433 
4434         /* Control information length must be at least 16 bytes */
4435         if (count < 16)
4436         {
4437             ckd_build_sense (dev, SENSE_CR, 0, 0,
4438                             FORMAT_0, MESSAGE_3);
4439             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4440             break;
4441         }
4442 
4443         /* Command reject if within the domain of a Locate Record,
4444            or not preceded by a Define Extent or Read IPL command */
4445         if (dev->ckdlcount > 0
4446             || (dev->ckdxtdef == 0 && dev->ckdrdipl == 0))
4447         {
4448             ckd_build_sense (dev, SENSE_CR, 0, 0,
4449                             FORMAT_0, MESSAGE_2);
4450             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4451             break;
4452         }
4453 
4454         /* Byte 0 contains the locate record operation byte */
4455         dev->ckdloper = iobuf[0];
4456 
4457         /* Validate the locate record operation code (bits 2-7) */
4458         if (!((dev->ckdloper & CKDOPER_CODE) == CKDOPER_ORIENT
4459               || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE
4460               || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT
4461               || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA
4462               || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK
4463               || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDTRKS
4464               || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ))
4465         {
4466             ckd_build_sense (dev, SENSE_CR, 0, 0,
4467                             FORMAT_0, MESSAGE_4);
4468             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4469             break;
4470         }
4471 
4472         /* Check for valid combination of orientation and opcode */
4473         if (   ((dev->ckdloper & CKDOPER_ORIENTATION)
4474                                         == CKDOPER_ORIENT_HOME
4475                 && !((dev->ckdloper & CKDOPER_CODE) == CKDOPER_ORIENT
4476                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT
4477                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA
4478                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDTRKS
4479                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ))
4480             ||
4481                ((dev->ckdloper & CKDOPER_ORIENTATION)
4482                                         == CKDOPER_ORIENT_DATA
4483                 && !((dev->ckdloper & CKDOPER_CODE) == CKDOPER_ORIENT
4484                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE
4485                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_RDDATA
4486                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ))
4487             ||
4488                ((dev->ckdloper & CKDOPER_ORIENTATION)
4489                                         == CKDOPER_ORIENT_INDEX
4490                 && !((dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT
4491                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ))
4492             )
4493         {
4494             ckd_build_sense (dev, SENSE_CR, 0, 0,
4495                             FORMAT_0, MESSAGE_4);
4496             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4497             break;
4498         }
4499 
4500         /* Check for write operation on a read only disk */
4501         if ( (dev->ckdrdonly && !dev->ckdfakewr && !dev->dasdsfn)
4502              &&  ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE
4503                || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT
4504                || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK)
4505            )
4506         {
4507             ckd_build_sense (dev, SENSE_EC, SENSE1_WRI, 0,
4508                             FORMAT_0, MESSAGE_4);
4509             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4510             break;
4511         }
4512 
4513         /* Byte 1 contains the locate record auxiliary byte */
4514         dev->ckdlaux = iobuf[1];
4515 
4516         /* Validate the auxiliary byte */
4517         if ((dev->ckdlaux & CKDLAUX_RESV) != 0
4518             || ((dev->ckdlaux & CKDLAUX_RDCNTSUF)
4519                 && !((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE
4520                   || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_READ))
4521             )
4522         {
4523             ckd_build_sense (dev, SENSE_CR, 0, 0,
4524                             FORMAT_0, MESSAGE_4);
4525             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4526             break;
4527         }
4528 
4529         /* Byte 2 must contain zeroes */
4530         if (iobuf[2] != 0)
4531         {
4532             ckd_build_sense (dev, SENSE_CR, 0, 0,
4533                             FORMAT_0, MESSAGE_4);
4534             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4535             break;
4536         }
4537 
4538         /* Byte 3 contains the locate record domain count */
4539         dev->ckdlcount = iobuf[3];
4540 
4541         /* Validate the locate record domain count */
4542         if (   ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_ORIENT
4543                 && dev->ckdlcount != 0)
4544             || ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_ORIENT
4545                 && dev->ckdlcount == 0)
4546             || ((dev->ckdlaux & CKDLAUX_RDCNTSUF)
4547                 && dev->ckdlcount < 2)
4548             )
4549         {
4550             ckd_build_sense (dev, SENSE_CR, 0, 0,
4551                             FORMAT_0, MESSAGE_4);
4552             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4553             break;
4554         }
4555 
4556         /* Bytes 4-7 contain the seek address */
4557         cyl = (iobuf[4] << 8) | iobuf[5];
4558         head = (iobuf[6] << 8) | iobuf[7];
4559 
4560         /* Command reject if seek address is not valid */
4561         if (cyl >= dev->ckdcyls || head >= dev->ckdheads)
4562         {
4563             ckd_build_sense (dev, SENSE_CR, 0, 0,
4564                             FORMAT_0, MESSAGE_4);
4565             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4566             break;
4567         }
4568 
4569         /* File protect error if seek address is outside extent */
4570         if ( EXTENT_CHECK(dev, cyl, head) )
4571         {
4572             ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0);
4573             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4574             break;
4575         }
4576 
4577         /* Bytes 8-12 contain the search argument */
4578         memcpy (cchhr, iobuf+8, 5);
4579 
4580         /* Byte 13 contains the sector number */
4581         sector = iobuf[13];
4582 
4583         /* Command reject if sector number is not valid */
4584         if (sector != 0xFF && sector >= dev->ckdtab->sectors)
4585         {
4586             ckd_build_sense (dev, SENSE_CR, 0, 0,
4587                             FORMAT_0, MESSAGE_4);
4588             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4589             break;
4590         }
4591 
4592         /* Bytes 14-15 contain the transfer length factor */
4593         dev->ckdltranlf = (iobuf[14] << 8) | iobuf[15];
4594 
4595         /* Validate the transfer length factor */
4596         if (   ((dev->ckdlaux & CKDLAUX_TLFVALID) == 0
4597                 && dev->ckdltranlf != 0)
4598             || ((dev->ckdlaux & CKDLAUX_TLFVALID)
4599                 && dev->ckdltranlf == 0)
4600             || dev->ckdltranlf > dev->ckdxblksz)
4601         {
4602             ckd_build_sense (dev, SENSE_CR, 0, 0,
4603                             FORMAT_0, MESSAGE_4);
4604             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4605             break;
4606         }
4607 
4608         /* If transfer length factor is not supplied then use
4609            the blocksize from the define extent command */
4610         if ((dev->ckdlaux & CKDLAUX_TLFVALID) == 0)
4611             dev->ckdltranlf = dev->ckdxblksz;
4612 
4613         /* Seek to the required track */
4614         rc = ckd_seek (dev, cyl, head, &trkhdr, unitstat);
4615         if (rc < 0)
4616         {
4617             if (dev->syncio_retry) dev->ckdlcount = 0;
4618             break;
4619         }
4620 
4621         /* Set normal status */
4622         *unitstat = CSW_CE | CSW_DE;
4623 
4624         /* Perform search according to specified orientation */
4625         switch ((dev->ckdloper & CKDOPER_ORIENTATION)) {
4626 
4627         case CKDOPER_ORIENT_HOME:
4628             /* For home orientation, compare the search CCHH
4629                with the CCHH in the track header */
4630             if (memcmp (&(trkhdr.cyl), cchhr, 4) != 0)
4631             {
4632                 ckd_build_sense (dev, 0, SENSE1_NRF, 0, 0, 0);
4633                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
4634             }
4635             break;
4636 
4637         case CKDOPER_ORIENT_COUNT:
4638         case CKDOPER_ORIENT_DATA:
4639             /* For count or data orientation, search the track
4640                for a count field matching the specified CCHHR */
4641             while (1)
4642             {
4643                 /* Read next count field and exit at end of track
4644                    with sense data indicating no record found */
4645                 rc = ckd_read_count (dev, code, &rechdr, unitstat);
4646                 if (rc < 0) break;
4647 
4648                 /* Turn off track overflow flag */
4649                 if(dev->ckdcyls < 32768)
4650                     rechdr.cyl[0] &= 0x7F;
4651 
4652                 /* Compare the count field with the search CCHHR */
4653                 if (memcmp (&rechdr, cchhr, 5) == 0)
4654                     break;
4655 
4656 // NOTE: Code like this breaks VM mini-disks !!!
4657 #if 0
4658                 if (memcmp (&rechdr, cchhr, 4) != 0)
4659                 {
4660                     logmsg ("HHCDA999E wrong recordheader: cc hh r=%d %d %d,"
4661                             "should be:cc hh r=%d %d %d\n",
4662                             (rechdr.cyl[0] << 8) | rechdr.cyl[1],
4663                             (rechdr.head[0] << 8) | rechdr.head[1],
4664                             rechdr.rec,
4665                             (cchhr[0] << 8) | cchhr[1],
4666                             (cchhr[2] << 8) | cchhr[3],
4667                             cchhr[4]);
4668                     break;
4669                 }
4670 #endif
4671             } /* end while */
4672 
4673         } /* end switch(CKDOPER_ORIENTATION) */
4674 
4675         /* Exit if search ended with error status */
4676         if (*unitstat != (CSW_CE | CSW_DE))
4677             break;
4678 
4679         /* Reorient past data if data orientation is specified */
4680         if ((dev->ckdloper & CKDOPER_ORIENTATION)
4681                         == CKDOPER_ORIENT_DATA)
4682         {
4683             /* Skip past key and data fields */
4684             dev->bufoff += dev->ckdcurkl + dev->ckdcurdl;
4685 
4686             /* Set the device orientation fields */
4687             dev->ckdrem = 0;
4688             dev->ckdorient = CKDORIENT_DATA;
4689         }
4690 
4691         /* Set locate record flag and return normal status */
4692         dev->ckdlocat = 1;
4693         break;
4694 
4695     case 0x4B:
4696     /*---------------------------------------------------------------*/
4697     /* LOCATE RECORD EXTENDED                                        */
4698     /*---------------------------------------------------------------*/
4699 
4700     /* LRE only valid for 3990-3 or 3990-6 */
4701     if (dev->ckdcu->devt != 0x3990 ||
4702         (dev->ckdcu->model != 0xec && dev->ckdcu->model != 0xe9))
4703     {
4704         /* Set command reject sense byte, and unit check status */
4705         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_1);
4706         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4707         break;
4708     }
4709     /*
4710      * The Storage Director initially requests 20 bytes of parameters
4711      * from the channel; if the channel provides fewer than 20 bytes,
4712      * execution is terminated with status that includes unit check
4713      * (Command Reject, format X'03', CCW byte count less than required).
4714      */
4715     num = (count < 20) ? count : 20;
4716     *residual = count - num;
4717     if (count < 20)
4718     {
4719         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3);
4720         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4721         break;
4722     }
4723     /*
4724      * If Locate Record Extended is received within a Locate Record
4725      * domain, execution is terminated with status that includes unit
4726      * check (Command Reject, format X'02', Invalid Command Sequence).
4727      */
4728     if (dev->ckdlcount > 0)
4729     {
4730         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2);
4731         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4732         break;
4733     }
4734     /*
4735      * If Locate Record Extended was not preceded by a Define Extent
4736      * or Read IPL command in the same channel program, execution is
4737      * terminated with status that includes unit check (Command Reject,
4738      * format X'02', Invalid Command Sequence). If any other operation
4739      * is specified, the command is terminated with status that
4740      * includes unit check (Command Reject, format X'02', Invalid
4741      * Command Sequence).
4742      */
4743     //FIXME not sure what that last sentence means
4744     if (dev->ckdxtdef == 0 && dev->ckdrdipl == 0)
4745     {
4746         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_2);
4747         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4748         break;
4749     }
4750 
4751     /* Byte 0 contains the locate record operation byte */
4752     dev->ckdloper = iobuf[0];
4753 
4754     /* Validate the locate record operation code (byte 0 bits 2-7) */
4755     if ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRITE
4756      && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_FORMAT
4757      && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRTTRK
4758      && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_RDTRKS
4759      && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_READ
4760      && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_EXTOP)
4761     {
4762         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4763         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4764         break;
4765     }
4766     /* Validate the locate record extended operation code (byte 17) */
4767     if ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_EXTOP)
4768     {
4769         if (iobuf[17] != CKDOPER_WRTANY
4770          && iobuf[17] != CKDOPER_RDANY
4771          && iobuf[17] != CKDOPER_RDTSET)
4772         {
4773             ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4774             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4775             break;
4776         }
4777         dev->ckdloper &= CKDOPER_ORIENTATION;
4778         dev->ckdloper |= iobuf[17];
4779     }
4780     else if (iobuf[17] != 0)
4781     {
4782         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4783         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4784         break;
4785     }
4786 
4787     /* Check for write operation on a read only disk */
4788 //FIXME Not sure if this is right here
4789     if ( (dev->ckdrdonly && !dev->ckdfakewr && !dev->dasdsfn)
4790          &&  ((dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRITE
4791            || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTANY
4792            || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_FORMAT
4793            || (dev->ckdloper & CKDOPER_CODE) == CKDOPER_WRTTRK)
4794            )
4795         {
4796             ckd_build_sense (dev, SENSE_EC, SENSE1_WRI, 0,
4797                             FORMAT_0, MESSAGE_4);
4798             *unitstat = CSW_CE | CSW_DE | CSW_UC;
4799             break;
4800         }
4801     /*
4802      * Check for valid combination of orientation and opcode
4803      *
4804      * +------------------------------------------------+
4805      * | Operation Code          Orientation      Byte  |
4806      * |                      Cnt  HA Data Index    17  |
4807      * +------------------------------------------------+
4808      * | Write Data            01   x   81     x    00  |
4809      * | Format Write          03  43    x    C3    00  |
4810      * | Write Track           0B   x    x     x    00  |
4811      * | Read Tracks           0C  4C    x     x    00  |
4812      * | Read                  16  56   96    D6    00  |
4813      * | Write Any             3F   x    x     x    09  |
4814      * | Read Any              3F   x    x     x    0A  |
4815      * | Read Trackset         3F  7F    x     x    0E  |
4816      * +------------------------------------------------+
4817      * | Note:  x - Combination is not valid.           |
4818      * +------------------------------------------------+
4819      * Table: valid orientation + operation code values
4820      */
4821     if (dev->ckdloper != 0x01 && dev->ckdloper != 0x81
4822      && dev->ckdloper != 0x03 && dev->ckdloper != 0x43 &&
4823         dev->ckdloper != 0xC3
4824      && dev->ckdloper != 0x0B
4825      && dev->ckdloper != 0x0C && dev->ckdloper != 0x4C
4826      && dev->ckdloper != 0x16 && dev->ckdloper != 0x56 &&
4827         dev->ckdloper != 0x96 && dev->ckdloper != 0xD6
4828      && dev->ckdloper != 0x09
4829      && dev->ckdloper != 0x0A
4830      && dev->ckdloper != 0x0E && dev->ckdloper != 0x4E)
4831     {
4832         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4833         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4834         break;
4835     }
4836     /*
4837      * Byte 1 is the Auxiliary Byte
4838      * bit 0 = 0 : Bytes 14-15 are unused
4839      *         1 : Bytes 14-15 contain a TLF that overrides the
4840      *             blocksize specified by the DX parameter.
4841      * bits 1-6  : Must be zero
4842      *             If any of these bits are '1', the LRE is terminated
4843      *             with status that includes unit check (Command Reject,
4844      *             format X'04', Invalid Parameter).
4845      * bit 7 = 0 : No Read Count CCW is suffixed to the LR domain
4846      *         1 : A Read Count CCW is suffixed to the LR domain
4847      */
4848     if ((iobuf[1] & CKDLAUX_RESV) != 0)
4849     {
4850         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4851         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4852         break;
4853     }
4854     /*
4855      * A Read Count command may only be suffixed to the domain of a LRE
4856      * that specifies a Write Data (01), Write Any (09), Read Any (0A),
4857      * or Read (16) operation code; if bit 7 = '1' when any other
4858      * Operation code is specified, Locate Record Extended is terminated
4859      * with status that includes unit check (Command Reject, format
4860      * X'04', Invalid Parameter).
4861      */
4862     if ((iobuf[1] & CKDLAUX_RDCNTSUF)
4863      && ((dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRITE
4864       && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_WRTANY
4865       && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_RDANY
4866       && (dev->ckdloper & CKDOPER_CODE) != CKDOPER_READ))
4867     {
4868         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4869         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4870         break;
4871     }
4872     dev->ckdlaux = iobuf[1];
4873 
4874     /* Byte 2 must contain zeroes */
4875     if (iobuf[2] != 0)
4876     {
4877         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4878         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4879         break;
4880     }
4881     /*
4882      * Byte 3 is the Count parameter. In general, the count parameter
4883      * specifies the number of records, or tracks to be operated on by
4884      * data transfer commands that follow Locate Record Extended.
4885      * Specific interpretation of the Count parameter depends upon the
4886      * operation code in byte 0.
4887      *
4888      * The Count must be nonzero. If Read Count Suffixing is specified
4889      * in a Locate Record, the count must be greater than 1. If the
4890      * Count is invalid, Locate Record Extended is terminated with
4891      * status that includes unit check (Command Reject, format X'04',
4892      * Invalid Parameter).
4893      */
4894     if (iobuf[3] == 0
4895      || ((dev->ckdlaux & CKDLAUX_RDCNTSUF) && iobuf[3] < 2))
4896     {
4897         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4898         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4899         break;
4900     }
4901     dev->ckdlcount = iobuf[3];
4902     /*
4903      * The value in bytes 4-7 must be a valid track address for the
4904      * device and must be within the extent boundaries specified by the
4905      * preceding Define Extent command.
4906      *
4907      * If the Seek Address is not valid for the device or if the Extended
4908      * Operation code is Write Any or Read Any and the seek address does
4909      * not specify a primary track, Locate Record Extended is terminated
4910      * with status that includes unit check (Command Reject, format X'04',
4911      * Invalid Parameter). If the Seek Address is not within the defined
4912      * extent, Locate Record Extended is terminated with status that
4913      * includes unit check (File Protected).
4914      */
4915     cyl = fetch_hw(iobuf+4);
4916     head = fetch_hw(iobuf+6);
4917     if (cyl >= dev->ckdcyls || head >= dev->ckdheads)
4918     {
4919         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4920         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4921         break;
4922     }
4923     if ( EXTENT_CHECK(dev, cyl, head) )
4924     {
4925         ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0);
4926         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4927         break;
4928     }
4929     /*
4930      * Bytes 8-12 specify a value to be used as a search argument for
4931      * the Locate Record Extended search operation.
4932      *
4933      * When the operation specified in byte 0 does not require
4934      * orientation to a specific record, no search operation is
4935      * performed and bytes 8-12 are ignored. When Home Address
4936      * orientation is specified, byte 12 is ignored.
4937      */
4938     memcpy (cchhr, iobuf+8, 5);
4939     /*
4940      * Byte 13 contains a sector number to which the device is to be
4941      * positioned before the Storage Director establishes orientation.
4942      *
4943      * The sector number must be within the range of valid sector
4944      * numbers for the device. If the sector number is invalid, Locate
4945      * Record Extended is terminated with status that includes unit
4946      * check (Command Reject, format X'04', Invalid Parameter).
4947      *
4948      * A value of X'FF' is valid and specifies that sector positioning
4949      * is not to be performed prior to establishing orientation.
4950      */
4951     if (iobuf[13] != 0xFF && iobuf[13] >= dev->ckdtab->sectors)
4952     {
4953         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4954         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4955         break;
4956     }
4957     sector = iobuf[13];
4958     /*
4959      * When byte 1, bit 0 is '0', bytes 14-15 must contain zeros; if
4960      * bytes 14-15 are not zero, Locate Record Extended is terminated
4961      * with status that includes unit check (Command Reject, format
4962      * X'04', Invalid Parameter).
4963      *
4964      * When byte 1 bit 0 is '1', bytes 14-15 contain a Transfer Length
4965      * Factor (TLF). The Transfer Length Factor must be non-zero; if it
4966      * is zero, Locate Record Extended is terminated with status that
4967      * includes unit check (Command Reject, format X'04', Invalid
4968      * Parameter).
4969      *
4970      * If the Transfer Length Factor value is greater than the value
4971      * specified (or implied) in the Define Extent Blocksize parameter,
4972      * Locate Record Extended is terminated with status that includes
4973      * unit check (Command Reject, format X'04', Invalid Parameter).
4974      *
4975      * The Storage Director uses the TLF to determine the number of
4976      * data bytes to be requested from the channel for each write
4977      * command that follows a Locate Record Extended that specified the
4978      * Write Data (01) Operation code. The product of the value in
4979      * bytes 14-15 and the count parameter is used to determine the
4980      * total number of bytes to be transferred by data transfer commands
4981      * that are executed within the domain of a Locate Record Extended
4982      * that specified the Format Write (03), Write Track (0B), or
4983      * Read (16) Operation codes.
4984      *
4985      * The TLF value is not retained by the Storage Director after the
4986      * expiration of the Locate Record domain.
4987      *
4988      * If Locate Record Extended does not specify a Transfer Length
4989      * Factor, the Storage Director will use the value from the Define
4990      * Extent Blocksize parameter for any required data transfer length
4991      * calculation.
4992      */
4993     if ((!(dev->ckdlaux & CKDLAUX_TLFVALID) &&  fetch_hw(iobuf+14))
4994      || ( (dev->ckdlaux & CKDLAUX_TLFVALID) && !fetch_hw(iobuf+14))
4995      || fetch_hw(iobuf+14) > dev->ckdxblksz)
4996     {
4997         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
4998         *unitstat = CSW_CE | CSW_DE | CSW_UC;
4999         break;
5000     }
5001     if ((dev->ckdlaux & CKDLAUX_TLFVALID) == 0)
5002         dev->ckdltranlf = dev->ckdxblksz;
5003     else
5004         dev->ckdltranlf = fetch_hw(iobuf+14);
5005     /*
5006      * Bytes 18-19 contain an unsigned 16-bit binary value that
5007      * specifies the total number of extended parameter bytes. The
5008      * format and content of the Extended Parameters are defined by
5009      * the Extended Operation code.
5010      *
5011      * The length for 3990 Mod 6 or 9390 for the Extended Operation
5012      * codes must be consistent with the Extended Operation code in
5013      * byte 17 as follows:
5014      *   09  0001
5015      *   0A  0001
5016      *   0E  0001 or 0002
5017      *
5018      * If the operation code is any code other than those defined, the
5019      * extended parameter length count must be zero. If these conditions
5020      * are not met the Locate Record Extended is terminated with status
5021      * that includes unit check (Command Reject, format X'04', Invalid
5022      * Parameter).
5023      */
5024     num = fetch_hw(iobuf+18);
5025     if ((iobuf[17] == CKDOPER_WRTANY &&  num != 1)
5026      || (iobuf[17] == CKDOPER_RDANY  &&  num != 1)
5027      || (iobuf[17] == CKDOPER_RDTSET && (num != 1 && num != 2))
5028      || (iobuf[17] != CKDOPER_WRTANY &&  iobuf[17] != CKDOPER_RDANY
5029       && iobuf[17] != CKDOPER_RDTSET &&  num))
5030     {
5031         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
5032         *unitstat = CSW_CE | CSW_DE | CSW_UC;
5033         break;
5034     }
5035     /*
5036      * Request the extended parameter bytes from the channel. If the
5037      * channel provides fewer bytes, execution is terminated with status
5038      * that includes unit check (Command Reject, format X'03', CCW byte
5039      * count less than required).
5040      */
5041     if (count < 20 + num)
5042     {
5043         *residual = 0;
5044         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_3);
5045         *unitstat = CSW_CE | CSW_DE | CSW_UC;
5046         break;
5047     }
5048     *residual -= num;
5049     /*
5050      * For `Read Any' (0x0A) or `Write Any' (0x09) the extended
5051      * length must be one and the extended parameter value (set size)
5052      * must be one.  Otherwise the Locate Record Extended command is
5053      * terminated with status that includes unit check (Command Reject,
5054      * format X'04', Invalid Parameter).
5055      */
5056     if ((iobuf[17] == CKDOPER_WRTANY && iobuf[20] != 1)
5057      || (iobuf[17] == CKDOPER_RDANY  && iobuf[20] != 1))
5058     {
5059         ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
5060         *unitstat = CSW_CE | CSW_DE | CSW_UC;
5061         break;
5062     }
5063     /*
5064      * Read Trackset - X'0E': The Read Trackset Operation Code prepares
5065      * the Storage Director to transfer all records from one or more
5066      * tracks to the channel. The tracks to be transferred are
5067      * specified by the Extended Parameter and the number of tracks to
5068      * be transferred is specified by the Count Parameter (byte 3).
5069      *
5070      * The maximum length of the Extended Parameter is specified in byte
5071      * 43 of the Device Characteristics Information.
5072      *
5073      * The Extended Parameter contains a bit map that represents a set
5074      * of sequentially addressed tracks within the defined extent. Each
5075      * bit in the parameter represent one track. A '1' bit indicates the
5076      * data associated with the corresponding track is to be read. A '0'
5077      * bit indicates the track is to be skipped.
5078      *
5079      * The first bit must be a '1' and represents the track whose
5080      * address is specified in the Seek Address parameter (bytes 4-7).
5081      * Subsequent bits represent consecutively addressed tracks in
5082      * ascending order. If the first bit is not a '1', the Locate Record
5083      * Extended command is terminated with status that includes unit
5084      * check (Command Reject, format X'04', Invalid Parameter).
5085      *
5086      * The number of '1' bits in the bit map must be equal to the value
5087      * in the count parameter (byte 3); otherwise Locate Record Extended
5088      * is terminated with status that includes unit check (Command
5089      * Reject, format X'04', Invalid Parameter).
5090      *
5091      * All tracks in the bit map represented by the '1' bits must be
5092      * contained within the defined extent; otherwise the Locate Record
5093      * Extended command is terminated with status that includes unit
5094      * check (File Protected).
5095      *
5096      * Track access is initiated using the Seek Address and Sector
5097      * Number parameters.
5098      *
5099      * When track access is completed, the search operation specified by
5100      * the Search Argument and the orientation modifiers (byte 0, bits
5101      * 0-1) is performed.
5102      *
5103      * Locate Record Extended must be followed by the number of Read
5104      * Track commands specified in the count parameter (byte 3). If any
5105      * other command sequence is detected within the Locate Record
5106      * domain, the non-conforming command will be rejected with status
5107      * that includes Unit Check (Command Reject, format X'02', Invalid
5108      * Command Sequence).
5109      */
5110     if (iobuf[17] == CKDOPER_RDTSET)
5111     {
5112         U16 lastcyl, lasthead;
5113         U16 mask = iobuf[20] << 8;
5114         if (num > 1)
5115             mask |= iobuf[21];
5116         if (!(mask & 0x8000))
5117         {
5118             ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
5119             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5120             break;
5121         }
5122         dev->ckdlmask = mask;
5123         /*
5124          * Count the one bits in mask.  There are elegant but obscure
5125          * ways to do this but just keeping it simple here.  Plus we
5126          * also figure out the last track we will read.
5127          */
5128         for (i = j = 0; mask; mask <<= 1)
5129         {
5130             j++;
5131             if (mask & 0x8000)
5132                 i++;
5133         }
5134         /* Number of one bits must match count */
5135         if (i != dev->ckdlcount)
5136         {
5137             ckd_build_sense (dev, SENSE_CR, 0, 0, FORMAT_0, MESSAGE_4);
5138             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5139             break;
5140         }
5141         /* Check extent of last track to be read */
5142         lastcyl = cyl;
5143         lasthead = head + j - 1;
5144         while (lasthead >= dev->ckdheads)
5145         {
5146             lastcyl++;
5147             lasthead -= dev->ckdheads;
5148         }
5149         if ( EXTENT_CHECK(dev, lastcyl, lasthead) )
5150         {
5151             ckd_build_sense (dev, 0, SENSE1_FP, 0, 0, 0);
5152             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5153             break;
5154         }
5155     }
5156 
5157     /* Seek to the required track */
5158     rc = ckd_seek (dev, cyl, head, &trkhdr, unitstat);
5159     if (rc < 0)
5160     {
5161         if (dev->syncio_retry) dev->ckdlcount = 0;
5162         break;
5163     }
5164 
5165     /* Set normal status */
5166     *unitstat = CSW_CE | CSW_DE;
5167 
5168     /* Perform search according to specified orientation */
5169     switch ((dev->ckdloper & CKDOPER_ORIENTATION)) {
5170 
5171     case CKDOPER_ORIENT_HOME:
5172         /* For home orientation, compare the search CCHH
5173            with the CCHH in the track header */
5174         if (memcmp (&(trkhdr.cyl), cchhr, 4) != 0)
5175         {
5176             ckd_build_sense (dev, 0, SENSE1_NRF, 0, 0, 0);
5177             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5178         }
5179         break;
5180 
5181     case CKDOPER_ORIENT_COUNT:
5182     case CKDOPER_ORIENT_DATA:
5183         /* For count or data orientation, search the track
5184            for a count field matching the specified CCHHR */
5185         while (1)
5186         {
5187             /* Read next count field and exit at end of track
5188                with sense data indicating no record found */
5189             rc = ckd_read_count (dev, code, &rechdr, unitstat);
5190             if (rc < 0) break;
5191 
5192             /* Turn off track overflow flag */
5193             if(dev->ckdcyls < 32768)
5194                 rechdr.cyl[0] &= 0x7F;
5195 
5196             /* For extended op code skip r0 */
5197             if ((iobuf[0] & CKDOPER_CODE) == CKDOPER_EXTOP)
5198             {
5199                 if (rechdr.rec != 0)
5200                     break;
5201             }
5202             /* Compare the count field with the search CCHHR */
5203             else if (memcmp (&rechdr, cchhr, 5) == 0)
5204                 break;
5205         } /* end while */
5206     } /* end switch(CKDOPER_ORIENTATION) */
5207 
5208     /* Exit if search ended with error status */
5209     if (*unitstat != (CSW_CE | CSW_DE))
5210         break;
5211 
5212     /* Reorient past data if data orientation is specified */
5213     if ((dev->ckdloper & CKDOPER_ORIENTATION)
5214                         == CKDOPER_ORIENT_DATA)
5215     {
5216         /* Skip past key and data fields */
5217         dev->bufoff += dev->ckdcurkl + dev->ckdcurdl;
5218 
5219         /* Set the device orientation fields */
5220         dev->ckdrem = 0;
5221         dev->ckdorient = CKDORIENT_DATA;
5222     }
5223 
5224     /* Set locate record flag and return normal status */
5225     dev->ckdlocat = 1;
5226     break;
5227 
5228     case 0x63:
5229     /*---------------------------------------------------------------*/
5230     /* DEFINE EXTENT                                                 */
5231     /*---------------------------------------------------------------*/
5232     {
5233     U16 bcyl, bhead, ecyl, ehead, xblksz;
5234     BYTE fmask, xgattr;
5235 
5236         /* Calculate residual byte count */
5237         num = (count < 16) ? count : 16;
5238         *residual = count - num;
5239 
5240         /* Control information length must be at least 16 bytes */
5241         if (count < 16)
5242         {
5243             ckd_build_sense (dev, SENSE_CR, 0, 0,
5244                             FORMAT_0, MESSAGE_3);
5245             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5246             break;
5247         }
5248 
5249         /* Command reject if within the domain of a Locate Record, or
5250            preceded by Define Extent, Space Count, or Set File Mask,
5251            or (for 3390 only) preceded by Read IPL */
5252         if (dev->ckdlcount > 0
5253 #if 0
5254             || dev->ckdxtdef
5255 #endif
5256             || dev->ckdsetfm || dev->ckdspcnt
5257             || (dev->ckdrdipl && dev->devtype == 0x3390))
5258         {
5259             ckd_build_sense (dev, SENSE_CR, 0, 0,
5260                             FORMAT_0, MESSAGE_2);
5261             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5262             break;
5263         }
5264 
5265         /* Bytes 0-1 contain the file mask and global attributes */
5266         fmask = iobuf[0];
5267         xgattr = iobuf[1];
5268 
5269         if(dev->ckdxtdef
5270          && (dev->ckdfmask != fmask || dev->ckdxgattr != xgattr) )
5271         {
5272             ckd_build_sense (dev, SENSE_CR, 0, 0,
5273                             FORMAT_0, MESSAGE_2);
5274             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5275             break;
5276         }
5277 
5278         dev->ckdfmask = fmask;
5279         dev->ckdxgattr = xgattr;
5280 
5281         /* Validate the global attributes byte bits 0-1 */
5282         if ((dev->ckdxgattr & CKDGATR_ARCH) != CKDGATR_ARCH_ECKD)
5283         {
5284             ckd_build_sense (dev, SENSE_CR, 0, 0,
5285                             FORMAT_0, MESSAGE_4);
5286             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5287             break;
5288         }
5289 
5290         /* Validate the file mask */
5291         if ((dev->ckdfmask & CKDMASK_RESV) != 0)
5292         {
5293             ckd_build_sense (dev, SENSE_CR, 0, 0,
5294                             FORMAT_0, MESSAGE_4);
5295             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5296             break;
5297         }
5298 
5299         /* Bytes 2-3 contain the extent block size */
5300         xblksz = (iobuf[2] << 8) | iobuf[3];
5301 
5302         /* If extent block size is zero then use the maximum R0
5303            record length (as returned in device characteristics
5304            bytes 44 and 45) plus 8 */
5305         if (xblksz == 0)
5306             xblksz = dev->ckdtab->r0 + 8;
5307 
5308         if(dev->ckdxtdef
5309          && dev->ckdxblksz != xblksz )
5310         {
5311             ckd_build_sense (dev, SENSE_CR, 0, 0,
5312                             FORMAT_0, MESSAGE_2);
5313             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5314             break;
5315         }
5316 
5317         dev->ckdxblksz = xblksz;
5318 
5319         /* Validate the extent block */
5320         if (dev->ckdxblksz > dev->ckdtab->r0 + 8)
5321         {
5322             ckd_build_sense (dev, SENSE_CR, 0, 0,
5323                             FORMAT_0, MESSAGE_4);
5324             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5325             break;
5326         }
5327 
5328         /* Bytes 4-6 must contain zeroes */
5329         if (iobuf[4] != 0 || iobuf[5] != 0 || iobuf[6] != 0)
5330         {
5331             ckd_build_sense (dev, SENSE_CR, 0, 0,
5332                             FORMAT_0, MESSAGE_4);
5333             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5334             break;
5335         }
5336 
5337         /* Bytes 8-11 contain the extent begin cylinder and head */
5338         bcyl = (iobuf[8] << 8) | iobuf[9];
5339         bhead = (iobuf[10] << 8) | iobuf[11];
5340 
5341         /* Bytes 12-15 contain the extent end cylinder and head */
5342         ecyl = (iobuf[12] << 8) | iobuf[13];
5343         ehead = (iobuf[14] << 8) | iobuf[15];
5344 
5345         /* Validate the extent description by checking that the
5346            ending track is not less than the starting track and
5347            that the extent does not exceed the already defined extent */
5348         if ( bcyl > ecyl
5349             || (bcyl == ecyl && bhead > ehead)
5350             || EXTENT_CHECK(dev, bcyl, bhead)
5351             || EXTENT_CHECK(dev, ecyl, ehead) )
5352         {
5353             ckd_build_sense (dev, SENSE_CR, 0, 0,
5354                             FORMAT_0, dev->ckdxtdef ? MESSAGE_2 : MESSAGE_4);
5355             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5356             break;
5357         }
5358 
5359         /* Define the new extent */
5360         dev->ckdxbcyl = bcyl;
5361         dev->ckdxbhead = bhead;
5362         dev->ckdxecyl = ecyl;
5363         dev->ckdxehead = ehead;
5364 
5365         /* Set extent defined flag and return normal status */
5366         dev->ckdxtdef = 1;
5367         *unitstat = CSW_CE | CSW_DE;
5368         break;
5369     }
5370 
5371     case 0x64:
5372     /*---------------------------------------------------------------*/
5373     /* READ DEVICE CHARACTERISTICS                                   */
5374     /*---------------------------------------------------------------*/
5375         /* Command reject if within the domain of a Locate Record */
5376         if (dev->ckdlcount > 0)
5377         {
5378             ckd_build_sense (dev, SENSE_CR, 0, 0,
5379                             FORMAT_0, MESSAGE_2);
5380             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5381             break;
5382         }
5383 
5384         /* Command reject if not 3380 or 3390 or 9345 */
5385         if ((dev->devtype != 0x3380)
5386          && (dev->devtype != 0x3390)
5387          && (dev->devtype != 0x9345))
5388         {
5389             ckd_build_sense (dev, SENSE_CR, 0, 0,
5390                             FORMAT_0, MESSAGE_2);
5391             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5392             break;
5393         }
5394 
5395         /* Calculate residual byte count */
5396         num = (count < dev->numdevchar) ? count : dev->numdevchar;
5397         *residual = count - num;
5398         if (count < dev->numdevchar) *more = 1;
5399 
5400         /* Copy device characteristics bytes to channel buffer */
5401         memcpy (iobuf, dev->devchar, num);
5402 
5403         *unitstat = CSW_CE | CSW_DE;
5404         break;
5405 
5406     case 0x3E:
5407     /*---------------------------------------------------------------*/
5408     /* READ SUBSYSTEM DATA                                           */
5409     /*---------------------------------------------------------------*/
5410         /* Command reject if within the domain of a Locate Record,
5411            or if subsystem data has not been prepared in the channel
5412            buffer by a previous Perform Subsystem Function command */
5413         if (dev->ckdlcount > 0 || dev->ckdssdlen == 0)
5414         {
5415             ckd_build_sense (dev, SENSE_CR, 0, 0,
5416                             FORMAT_0, MESSAGE_2);
5417             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5418             break;
5419         }
5420 
5421         /* Calculate residual byte count */
5422         num = (count < dev->ckdssdlen) ? count : dev->ckdssdlen;
5423         *residual = count - num;
5424         if (count < dev->ckdssdlen) *more = 1;
5425 
5426         /* Subsystem data is already in the channel buffer, so
5427            just return channel end and device end */
5428         *unitstat = CSW_CE | CSW_DE;
5429         break;
5430 
5431     case 0x5B:
5432     /*---------------------------------------------------------------*/
5433     /* SUSPEND MULTIPATH RECONNECTION                                */
5434     /*---------------------------------------------------------------*/
5435         /* Command reject if within the domain of a Locate Record */
5436         if (dev->ckdlcount > 0)
5437         {
5438             ckd_build_sense (dev, SENSE_CR, 0, 0,
5439                             FORMAT_0, MESSAGE_2);
5440             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5441             break;
5442         }
5443 
5444         /* Return normal status */
5445         *unitstat = CSW_CE | CSW_DE;
5446         break;
5447 
5448     case 0xF3:
5449     /*---------------------------------------------------------------*/
5450     /* DIAGNOSTIC CONTROL                                            */
5451     /*---------------------------------------------------------------*/
5452         /* Command reject if SSI active */
5453         if(dev->ckdssi)
5454         {
5455             /* Mark Set Special Intercept inactive */
5456             dev->ckdssi = 0;
5457             ckd_build_sense (dev, SENSE_CR, 0, 0,
5458                             FORMAT_0, MESSAGE_F);
5459             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5460             break;
5461         }
5462 
5463         /* Calculate residual byte count */
5464         num = (count < 4) ? count : 4;
5465         *residual = count - num;
5466 
5467         /* Control information length must be at least 4 bytes */
5468         if (count < 4)
5469         {
5470             ckd_build_sense (dev, SENSE_CR, 0, 0,
5471                             FORMAT_0, MESSAGE_3);
5472             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5473             break;
5474         }
5475 
5476         /* Command reject if within the domain of a Locate Record */
5477         if (dev->ckdlcount > 0)
5478         {
5479             ckd_build_sense (dev, SENSE_CR, 0, 0,
5480                             FORMAT_0, MESSAGE_2);
5481             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5482             break;
5483         }
5484 
5485         /* Command reject if byte 0 does not contain a valid
5486            subcommand code, or if bytes 2-3 are not zero */
5487         if (!(iobuf[0] == DIAGCTL_MAINT_QUERY
5488 //            || iobuf[0] == DIAGCTL_MAINT_RESERVE
5489 //            || iobuf[0] == DIAGCTL_MAINT_RELEASE
5490 //            || iobuf[0] == DIAGCTL_INHIBIT_WRITE
5491 //            || iobuf[0] == DIAGCTL_SET_GUAR_PATH
5492 //            || iobuf[0] == DIAGCTL_ENABLE_WRITE
5493 //            || iobuf[0] == DIAGCTL_3380_TC_MODE
5494 //            || iobuf[0] == DIAGCTL_INIT_SUBSYS
5495 //            || iobuf[0] == DIAGCTL_UNFENCE
5496 //            || iobuf[0] == DIAGCTL_ACCDEV_UNKCOND
5497              ) || iobuf[2] != 0 || iobuf[3] != 0)
5498         {
5499             ckd_build_sense (dev, SENSE_CR, 0, 0,
5500                             FORMAT_0, MESSAGE_4);
5501             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5502             break;
5503         }
5504 
5505         /* Command reject if file mask does not specify
5506            diagnostic or device support authorization */
5507         if ((dev->ckdfmask & CKDMASK_AAUTH) == CKDMASK_AAUTH_NORMAL)
5508         {
5509             ckd_build_sense (dev, SENSE_CR, 0, 0,
5510                             FORMAT_0, MESSAGE_5);
5511             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5512             break;
5513         }
5514 
5515         /* Return normal status */
5516         *unitstat = CSW_CE | CSW_DE;
5517         break;
5518 
5519     case 0x94:
5520     /*---------------------------------------------------------------*/
5521     /* DEVICE RELEASE                                                */
5522     /*---------------------------------------------------------------*/
5523         /* Command reject if within the domain of a Locate Record, or
5524            preceded by Define Extent, Space Count, or Set File Mask,
5525            or (for 3390 only) preceded by Read IPL */
5526         if (dev->ckdlcount > 0
5527             || dev->ckdxtdef || dev->ckdspcnt || dev->ckdsetfm
5528             || (dev->ckdrdipl && dev->devtype == 0x3390))
5529         {
5530             ckd_build_sense (dev, SENSE_CR, 0, 0,
5531                             FORMAT_0, MESSAGE_2);
5532             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5533             break;
5534         }
5535 
5536         /* Call the release exit and mark the device not reserved */
5537         if (dev->hnd->release) (dev->hnd->release) (dev);
5538 
5539         obtain_lock (&dev->lock);
5540         dev->reserved = 0;
5541         release_lock (&dev->lock);
5542 
5543         /* Perform the operation of a sense command */
5544         goto sense;
5545 
5546     case 0x14: /* UNCONDITIONAL RESERVE */
5547     case 0xB4: /* DEVICE RESERVE */
5548     /*---------------------------------------------------------------*/
5549     /* DEVICE RESERVE                                                */
5550     /*---------------------------------------------------------------*/
5551         /* Command reject if within the domain of a Locate Record,
5552            or indeed if preceded by any command at all apart from
5553            Suspend Multipath Reconnection */
5554         if (dev->ckdlcount > 0
5555             || ccwseq > 1
5556             || (chained && prevcode != 0x5B))
5557         {
5558             ckd_build_sense (dev, SENSE_CR, 0, 0,
5559                             FORMAT_0, MESSAGE_2);
5560             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5561             break;
5562         }
5563 
5564         /* Mark the device reserved and call the reserve exit */
5565 
5566         obtain_lock (&dev->lock);
5567         dev->reserved = 1;
5568         release_lock (&dev->lock);
5569 
5570         if (dev->hnd->reserve) (dev->hnd->reserve) (dev);
5571 
5572         /* Perform the operation of a sense command */
5573         goto sense;
5574 
5575     case 0x04:
5576     /*---------------------------------------------------------------*/
5577     /* SENSE                                                         */
5578     /*---------------------------------------------------------------*/
5579         /* Command reject if within the domain of a Locate Record */
5580         if (dev->ckdlcount > 0)
5581         {
5582             ckd_build_sense (dev, SENSE_CR, 0, 0,
5583                             FORMAT_0, MESSAGE_2);
5584             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5585             break;
5586         }
5587 
5588     sense:
5589         /* If sense bytes are cleared then build sense */
5590         if ((dev->sense[0] == 0) & (dev->sense[1] == 0))
5591             ckd_build_sense (dev, 0, 0, 0, 0, 0);
5592 
5593         /* Calculate residual byte count */
5594         num = (count < dev->numsense) ? count : dev->numsense;
5595         *residual = count - num;
5596         if (count < dev->numsense) *more = 1;
5597 
5598         /* Copy device sense bytes to channel I/O buffer */
5599         memcpy (iobuf, dev->sense, num);
5600 
5601         /* Clear the device sense bytes */
5602         memset (dev->sense, 0, sizeof(dev->sense));
5603 
5604         *unitstat = CSW_CE | CSW_DE;
5605         break;
5606 
5607     case 0xE4:
5608     /*---------------------------------------------------------------*/
5609     /* SENSE ID                                                      */
5610     /*---------------------------------------------------------------*/
5611 
5612         /* If numdevid is 0, then 0xE4 Sense ID is not supported */
5613         if (dev->numdevid == 0)
5614         {
5615             ckd_build_sense (dev, SENSE_CR, 0, 0,
5616                             FORMAT_0, MESSAGE_1);
5617             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5618             break;
5619         }
5620 
5621         /* Command reject if within the domain of a Locate Record */
5622         if (dev->ckdlcount > 0)
5623         {
5624             ckd_build_sense (dev, SENSE_CR, 0, 0,
5625                             FORMAT_0, MESSAGE_2);
5626             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5627             break;
5628         }
5629 
5630         /* Calculate residual byte count */
5631         num = (count < dev->numdevid) ? count : dev->numdevid;
5632         *residual = count - num;
5633         if (count < dev->numdevid) *more = 1;
5634 
5635         /* Copy device identifier bytes to channel I/O buffer */
5636         memcpy (iobuf, dev->devid, num);
5637 
5638         /* Return unit status */
5639         *unitstat = CSW_CE | CSW_DE;
5640         break;
5641 
5642     case 0x34:
5643     /*---------------------------------------------------------------*/
5644     /* SENSE PATH GROUP ID                                           */
5645     /*---------------------------------------------------------------*/
5646 
5647         /* Calculate residual byte count */
5648         num = (count < 12) ? count : 12;
5649         *residual = count - num;
5650         if (count < 12) *more = 1;
5651 
5652         /* Byte 0 is the path group state byte */
5653         iobuf[0] = SPG_PATHSTAT_RESET
5654                 | SPG_PARTSTAT_IENABLED
5655                 | SPG_PATHMODE_SINGLE;
5656 
5657         /* Bytes 1-11 contain the path group identifier */
5658         memcpy (iobuf+1, dev->pgid, 11);
5659 
5660         /* Return unit status */
5661         *unitstat = CSW_CE | CSW_DE;
5662         break;
5663 
5664     case 0xAF:
5665     /*---------------------------------------------------------------*/
5666     /* SET PATH GROUP ID                                             */
5667     /*---------------------------------------------------------------*/
5668 
5669         /* Calculate residual byte count */
5670         num = (count < 12) ? count : 12;
5671         *residual = count - num;
5672 
5673         /* Control information length must be at least 12 bytes */
5674         if (count < 12)
5675         {
5676             dev->sense[0] = SENSE_CR;
5677             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5678             break;
5679         }
5680 
5681         /* Byte 0 is the path group state byte */
5682         if ((iobuf[0] & SPG_SET_COMMAND) == SPG_SET_ESTABLISH)
5683         {
5684             /* Only accept the new pathgroup id when
5685                1) it has not yet been set (ie contains zeros) or
5686                2) It is set, but we are setting the same value */
5687             if(memcmp(dev->pgid,
5688                  "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 11)
5689               && memcmp(dev->pgid, iobuf+1, 11))
5690             {
5691                 dev->sense[0] = SENSE_CR;
5692                 *unitstat = CSW_CE | CSW_DE | CSW_UC;
5693                 break;
5694             }
5695 
5696             /* Bytes 1-11 contain the path group identifier */
5697             memcpy (dev->pgid, iobuf+1, 11);
5698         }
5699 
5700         /* Return unit status */
5701         *unitstat = CSW_CE | CSW_DE;
5702         break;
5703 
5704     case 0x54:
5705     /*---------------------------------------------------------------*/
5706     /* SENSE SUBSYSTEM STATUS                                        */
5707     /*---------------------------------------------------------------*/
5708         /* Command reject if within the domain of a Locate Record,
5709            or if chained from any command unless the preceding command
5710            is Read Device Characteristics, Read Configuration Data, or
5711            a Suspend Multipath Reconnection command that was the first
5712            command in the chain */
5713         if (dev->ckdlcount > 0
5714             || (chained && prevcode != 0x64 && prevcode != 0xFA
5715                 && prevcode != 0x5B)
5716             || (chained && prevcode == 0x5B && ccwseq > 1))
5717         {
5718             ckd_build_sense (dev, SENSE_CR, 0, 0,
5719                             FORMAT_0, MESSAGE_2);
5720             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5721             break;
5722         }
5723 
5724         /* Build the basic subsystem status data in the I/O area */
5725         num = dasd_build_ckd_subsys_status (dev, iobuf, count);
5726 
5727         /* Calculate residual byte count */
5728         *residual = count < num ? 0 : count - num;
5729         *more = count < num;
5730 
5731         /* Return unit status */
5732         *unitstat = CSW_CE | CSW_DE;
5733         break;
5734 
5735     case 0xA4:
5736     /*---------------------------------------------------------------*/
5737     /* READ AND RESET BUFFERED LOG                                   */
5738     /*---------------------------------------------------------------*/
5739         /* Command reject if within the domain of a Locate Record,
5740            or if chained from any command unless the preceding command
5741            is Read Device Characteristics, Read Configuration Data, or
5742            a Suspend Multipath Reconnection command that was the first
5743            command in the chain */
5744         if (dev->ckdlcount > 0
5745             || (chained && prevcode != 0x64 && prevcode != 0xFA
5746                 && prevcode != 0x5B)
5747             || (chained && prevcode == 0x5B && ccwseq > 1))
5748         {
5749             ckd_build_sense (dev, SENSE_CR, 0, 0,
5750                             FORMAT_0, MESSAGE_2);
5751             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5752             break;
5753         }
5754 
5755         /* Calculate residual byte count */
5756         num = (count < 32) ? count : 32;
5757         *residual = count - num;
5758         if (count < 32) *more = 1;
5759 
5760         /* Build the buffered error log in the I/O area */
5761         memset (iobuf, 0x00, 32);
5762 
5763         /* Return unit status */
5764         *unitstat = CSW_CE | CSW_DE;
5765         break;
5766 
5767     case 0x87:
5768     /*---------------------------------------------------------------*/
5769     /* Set Subsystem Mode                                            */
5770     /*---------------------------------------------------------------*/
5771 
5772         /* Command reject if within the domain of a Locate Record */
5773         if (dev->ckdlcount > 0)
5774         {
5775             ckd_build_sense (dev, SENSE_CR, 0, 0,
5776                             FORMAT_0, MESSAGE_2);
5777             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5778             break;
5779         }
5780 
5781         /* Command reject if not a cached device, first in chain, or */
5782         /* immediately preceded by Suspend Multipath Connection      */
5783         /*                                                           */
5784         /* TBD: Add first in chain and Suspend Multipath check       */
5785         /*                                                           */
5786         if ((dev->ckdcu->devt != 0x3990 && dev->ckdcu->devt != 0x2105)
5787             || (dev->ckdcu->model & 0x07) == 0x02)      /* 3990-1/2  */
5788         {
5789             ckd_build_sense (dev, SENSE_CR, 0, 0,
5790                             FORMAT_0, MESSAGE_2);
5791             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5792             break;
5793         }
5794 
5795         /* Calculate residual byte count */
5796         num = (count < 2) ? count : 2;
5797         *residual = count - num;
5798 
5799         /* Control information length must be at least 2 bytes */
5800         if (count < 2)
5801         {
5802             ckd_build_sense (dev, SENSE_CR, 0, 0,
5803                             FORMAT_0, MESSAGE_3);
5804             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5805             break;
5806         }
5807 
5808         /* TBD / MGD:   Complete checks for Set Subsystem Mode      */
5809         /*              covering message required flag and read     */
5810         /*              message id check                            */
5811 
5812         /* Validate operands -- Refer to 2105 validation sequence   */
5813         if (((iobuf[0] & 0x02) != 0) || ((iobuf[1] & 0x07) != 0)    ||
5814             ((iobuf[1] & 0x18) != 0) /* zero unless in TPF mode */  ||
5815             ((iobuf[0] & 0xE0) > 0xA0)                              ||
5816             ((iobuf[0] & 0x1C) > 0x14)                              ||
5817             ((iobuf[1] & 0xE0) > 0xA0)                              ||
5818             ((iobuf[1] & 0x18) == 0x18) /* TPF reserved */          ||
5819             (((iobuf[0] & 0x10) != 0) && (
5820                ((iobuf[0] & 0xE0) >  0x80) ||
5821                ((iobuf[0] & 0xE0) <  0x40) ||
5822                ((iobuf[0] & 0x1C) != 0x10) ||
5823                ((iobuf[1] & 0xE0) >  0xA0) ||
5824                ((iobuf[1] & 0xE0) <  0x40) ||
5825                ((iobuf[1] & 0xE0) == 0x60)))                        ||
5826             (((iobuf[0] & 0xE0) != 0) && (
5827                ((iobuf[0] & 0x1C) != 0) || (iobuf[1] != 0)))        ||
5828             (((iobuf[0] & 0x1C) != 0) && (iobuf[1] != 0)))
5829         {
5830 
5831             ckd_build_sense (dev, SENSE_CR, 0, 0,
5832                             FORMAT_0, MESSAGE_4);
5833             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5834             break;
5835         }
5836 
5837         /* TBD / Future:        Cache Fast Write Data Control        */
5838 
5839         /* Treat as NOP and Return unit status */
5840         *unitstat = CSW_CE | CSW_DE;
5841         break;
5842 
5843     case 0xFA:
5844     /*---------------------------------------------------------------*/
5845     /* READ CONFIGURATION DATA                                       */
5846     /*---------------------------------------------------------------*/
5847         /* Command reject if within the domain of a Locate Record */
5848         if (dev->ckdlcount > 0)
5849         {
5850             ckd_build_sense (dev, SENSE_CR, 0, 0,
5851                             FORMAT_0, MESSAGE_2);
5852             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5853             break;
5854         }
5855 
5856         /* Build the configuration data area */
5857         num = dasd_build_ckd_config_data (dev, iobuf, count);
5858 
5859         /* Calculate residual byte count */
5860         *residual = count < num ? 0 : count - num;
5861         *more = count < num;
5862 
5863         /* Return unit status */
5864         *unitstat = CSW_CE | CSW_DE;
5865         break;
5866 
5867     default:
5868     /*---------------------------------------------------------------*/
5869     /* INVALID OPERATION                                             */
5870     /*---------------------------------------------------------------*/
5871         /* Set command reject sense byte, and unit check status */
5872         ckd_build_sense (dev, SENSE_CR, 0, 0,
5873                         FORMAT_0, MESSAGE_1);
5874         *unitstat = CSW_CE | CSW_DE | CSW_UC;
5875 
5876     } /* end switch(code) */
5877 
5878     /* Return if synchronous I/O needs to be retried asynchronously */
5879     if (dev->syncio_retry) return;
5880 
5881     /* Reset the flags which ensure correct positioning for write
5882        commands */
5883 
5884     /* Reset search HA flag if command was not SEARCH HA EQUAL
5885        or WRITE HA */
5886     if ((code & 0x7F) != 0x39 && (code & 0x7F) != 0x19)
5887         dev->ckdhaeq = 0;
5888 
5889     /* Reset search id flag if command was not SEARCH ID EQUAL,
5890        READ/WRITE KEY AND DATA, or READ/WRITE DATA */
5891     if ((code & 0x7F) != 0x31
5892         && (code & 0x7F) != 0x0E && (code & 0x7F) != 0x0D
5893         && (code & 0x7F) != 0x06 && (code & 0x7F) != 0x05)
5894         dev->ckdideq = 0;
5895 
5896     /* Reset search key flag if command was not SEARCH KEY EQUAL
5897        or READ/WRITE DATA */
5898     if ((code & 0x7F) != 0x29
5899         && (code & 0x7F) != 0x06 && (code & 0x7F) != 0x05)
5900         dev->ckdkyeq = 0;
5901 
5902     /* Reset write CKD flag if command was not WRITE R0 or WRITE CKD */
5903     if (code != 0x15 && code != 0x1D)
5904         dev->ckdwckd = 0;
5905 
5906     /* If within the domain of a locate record then decrement the
5907        count of CCWs remaining to be processed within the domain */
5908     if (dev->ckdlcount > 0 && code != 0x047 && code != 0x4B)
5909     {
5910         /* Decrement the count of CCWs remaining in the domain */
5911         dev->ckdlcount--;
5912 
5913         /* Command reject with incomplete domain if CCWs remain
5914            but command chaining is not specified */
5915         if (dev->ckdlcount > 0 && (flags & CCW_FLAGS_CC) == 0 &&
5916             code != 0x02)
5917         {
5918             ckd_build_sense (dev, SENSE_CR | SENSE_OC, 0, 0, 0, 0);
5919             *unitstat = CSW_CE | CSW_DE | CSW_UC;
5920         }
5921     } /* end if(ckdlcount) */
5922 
5923 } /* end function ckddasd_execute_ccw */
5924 
5925 DLL_EXPORT DEVHND ckddasd_device_hndinfo = {
5926         &ckddasd_init_handler,          /* Device Initialisation      */
5927         &ckddasd_execute_ccw,           /* Device CCW execute         */
5928         &ckddasd_close_device,          /* Device Close               */
5929         &ckddasd_query_device,          /* Device Query               */
5930         &ckddasd_start,                 /* Device Start channel pgm   */
5931         &ckddasd_end,                   /* Device End channel pgm     */
5932         &ckddasd_start,                 /* Device Resume channel pgm  */
5933         &ckddasd_end,                   /* Device Suspend channel pgm */
5934         &ckddasd_read_track,            /* Device Read                */
5935         &ckddasd_update_track,          /* Device Write               */
5936         &ckddasd_used,                  /* Device Query used          */
5937         NULL,                           /* Device Reserve             */
5938         NULL,                           /* Device Release             */
5939         NULL,                           /* Device Attention           */
5940         NULL,                           /* Immediate CCW Codes        */
5941         NULL,                           /* Signal Adapter Input       */
5942         NULL,                           /* Signal Adapter Ouput       */
5943         &ckddasd_hsuspend,              /* Hercules suspend           */
5944         &ckddasd_hresume                /* Hercules resume            */
5945 };
5946