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