1 /* CCKDDIAG.C (c) Copyright Greg Smith, 2000-2009 */
2 /* (c) Copyright James M. Morrison, 2003 */
3 /* CCKD diagnostic tool */
4
5 /* 2003-02-07 James M. Morrison initial implementation */
6 /* portions borrowed from cckdcdsk & other CCKD code */
7
8 /*-------------------------------------------------------------------*/
9 /* Diagnostic tool to display various CCKD data */
10 /*-------------------------------------------------------------------*/
11
12 #include "hstdinc.h"
13
14 /* TODO: add FBA support or write cfbadiag */
15
16 #include "hercules.h"
17 #include "dasdblks.h" /* data_dump */
18
19 typedef struct _CKD_RECSTAT { /* CKD DASD record stats */
20 int cc; /* CC cylinder # (relative zero) */
21 int hh; /* HH head # (relative zero) */
22 int r; /* Record # (relative zero) */
23 int kl; /* key length */
24 int dl; /* data length */
25 } CKD_RECSTAT;
26
27 /*-------------------------------------------------------------------*/
28 /* Global data areas */
29 /*-------------------------------------------------------------------*/
30 CCKD_L1ENT *l1 = NULL; /* L1TAB */
31 CCKD_L2ENT *l2 = NULL; /* L2TAB */
32 void *tbuf = NULL; /* track header & data */
33 void *bulk = NULL; /* bulk data buffer */
34 int fd = 0; /* File descriptor */
35 static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
36
37 #ifdef DEBUG
38 int debug = 1; // enable debug code
39 #else
40 int debug = 0; // disable debug code
41 #endif
42 int pausesnap = 0; // 1 = pause after snap (getc)
43
44 /*-------------------------------------------------------------------*/
45 /* print syntax */
46 /*-------------------------------------------------------------------*/
syntax()47 int syntax()
48 {
49 fprintf (stdout, "\n"
50 "cckddiag [options] file-name\n"
51 "Valid options are one or more of the following:\n"
52 " -v display version and exit\n"
53 " -d display DEVHDR\n"
54 " -c display CDEVHDR\n"
55 " -1 display L1TAB (numeric one)\n"
56 " -g enable debug output\n"
57 "CKD track related options:\n"
58 " -a cc hh display absolute CCHH data\n"
59 " -r tt display relative TT data\n"
60 " -2 display L2TAB related to -a or -r\n"
61 " -t display track data\n"
62 " -x hex display track key/data\n"
63 "Offset option:\n"
64 " -o oo ll hex display data at offset oo of length ll\n"
65 "Further information: man 1 cckddiag\n"
66 );
67 return -1;
68 }
69
70 /*-------------------------------------------------------------------*/
71 /* snap - display msg, dump data */
72 /*-------------------------------------------------------------------*/
73 /* Newline appended to message */
snap(char * msg,void * data,int len)74 void snap(char *msg, void *data, int len) {
75 int x;
76
77 if (msg != NULL)
78 fprintf(stdout, "%s\n", msg);
79 data_dump(data, len);
80 if (pausesnap) {
81 fprintf(stdout, "Press enter to continue\n");
82 x = getc(stdin);
83 }
84 }
85
86 /*-------------------------------------------------------------------*/
87 /* clean - cleanup before exit */
88 /*-------------------------------------------------------------------*/
clean(void)89 void clean(void) {
90 close(fd);
91 free(l1); /* L1TAB buffer */
92 free(l2); /* L2TAB buffer */
93 free(tbuf); /* track and header buffer */
94 free(bulk); /* offset data buffer */
95 }
96
97 /*-------------------------------------------------------------------*/
98 /* makbuf - allocate buffer, handle errors (exit if any) */
99 /*-------------------------------------------------------------------*/
makbuf(int len,char * label)100 void *makbuf(int len, char *label) {
101 void *p;
102
103 p = malloc(len);
104 if (p == NULL) {
105 fprintf(stdout, "malloc %s of length %d failed\n",
106 label, len);
107 clean();
108 exit(4);
109 }
110 if (debug) fprintf(stdout, "\n"
111 "MAKBUF malloc %s buffer of %d bytes at %p\n",
112 label, len, p);
113 return p;
114 }
115
116 /*-------------------------------------------------------------------*/
117 /* readpos - common lseek and read invocation with error handling */
118 /*-------------------------------------------------------------------*/
119 /* This code exits on error rather than return to caller. */
readpos(int fd,void * buf,off_t offset,size_t len)120 int readpos(
121 int fd, /* opened CCKD image file */
122 void *buf, /* buffer of size len */
123 off_t offset, /* offset into CCKD image to read */
124 size_t len /* length of data to read */
125 ) {
126 if (debug)
127 fprintf(stdout, "\nREADPOS seeking %d (0x%8.8X)\n",
128 (int)offset, (unsigned int)offset);
129 if (lseek(fd, offset, SEEK_SET) < 0) {
130 fprintf(stdout, _("lseek to pos 0x%8.8x error: %s\n"),
131 (unsigned int) offset, strerror(errno));
132 clean();
133 exit (1);
134 }
135 if (debug)
136 fprintf(stdout,
137 "READPOS reading buf addr "PTR_FMTx" length %"SIZE_T_FMT"d (0x"SIZE_T_FMTX")\n",
138 (uintptr_t)buf, len, len);
139 if (read(fd, buf, len) < (ssize_t)len) {
140 fprintf(stdout, _("cckddiag: read error: %s\n"),
141 strerror(errno));
142 clean();
143 exit (2);
144 }
145 return 0;
146 }
147
148 /*-------------------------------------------------------------------*/
149 /* decomptrk - decompress track data */
150 /*-------------------------------------------------------------------*/
decomptrk(BYTE * ibuf,int ibuflen,BYTE * obuf,int obuflen,int heads,int trk,char * msg)151 int decomptrk(
152 BYTE *ibuf, /* input buffer address */
153 int ibuflen, /* input buffer length */
154 BYTE *obuf, /* output buffer address */
155 int obuflen, /* output buffer length */
156 int heads, /* >=0 means CKD, else FBA */
157 int trk, /* relative track or block number */
158 char *msg /* addr of 80 byte msg buf or NULL */
159 )
160 /* ibuf points at CKDDASD_TRKHDR header followed by track data */
161 /* ibuflen specifies length of TRKHDR and data */
162 /* This code based on decompression logic in cdsk_valid_trk. */
163 /* Returns length of decompressed data or -1 on error. */
164 {
165 #if defined( HAVE_LIBZ ) || defined( CCKD_BZIP2 )
166 int rc; /* Return code */
167 BYTE *bufp; /* Buffer pointer */
168 #endif
169 size_t bufl; /* Buffer length */
170 #ifdef CCKD_BZIP2
171 unsigned int ubufl; /* when size_t != unsigned int */
172 #endif
173
174 #if !defined( HAVE_LIBZ ) && !defined( CCKD_BZIP2 )
175 UNREFERENCED(heads);
176 UNREFERENCED(trk);
177 UNREFERENCED(msg);
178 #endif
179
180 memset(obuf, 0x00, obuflen); /* clear output buffer */
181
182 /* Uncompress the track/block image */
183 switch (ibuf[0] & CCKD_COMPRESS_MASK) {
184
185 case CCKD_COMPRESS_NONE:
186 bufl = (ibuflen < obuflen) ? ibuflen : obuflen;
187 memcpy (obuf, ibuf, bufl);
188 break;
189
190 #ifdef HAVE_LIBZ
191 case CCKD_COMPRESS_ZLIB:
192 bufp = (BYTE *)obuf;
193 memcpy (obuf, ibuf, CKDDASD_TRKHDR_SIZE);
194 bufl = obuflen - CKDDASD_TRKHDR_SIZE;
195 rc = uncompress(&obuf[CKDDASD_TRKHDR_SIZE],
196 (void *)&bufl,
197 &ibuf[CKDDASD_TRKHDR_SIZE],
198 ibuflen);
199 if (rc != Z_OK) {
200 if (msg)
201 snprintf(msg, 80, "%s %d uncompress error, rc=%d;"
202 "%2.2x%2.2x%2.2x%2.2x%2.2x",
203 heads >= 0 ? "trk" : "blk", trk, rc,
204 ibuf[0], ibuf[1], ibuf[2], ibuf[3], ibuf[4]);
205 return -1;
206 }
207 bufl += CKDDASD_TRKHDR_SIZE;
208 break;
209 #endif
210
211 #ifdef CCKD_BZIP2
212 case CCKD_COMPRESS_BZIP2:
213 bufp = obuf;
214 memcpy(obuf, ibuf, CKDDASD_TRKHDR_SIZE);
215 ubufl = obuflen - CKDDASD_TRKHDR_SIZE;
216 rc = BZ2_bzBuffToBuffDecompress (
217 (char *)&obuf[CKDDASD_TRKHDR_SIZE],
218 &ubufl,
219 (char *)&ibuf[CKDDASD_TRKHDR_SIZE],
220 ibuflen, 0, 0);
221 if (rc != BZ_OK) {
222 if (msg)
223 snprintf(msg, 80, "%s %d decompress error, rc=%d;"
224 "%2.2x%2.2x%2.2x%2.2x%2.2x",
225 heads >= 0 ? "trk" : "blk", trk, rc,
226 ibuf[0], ibuf[1], ibuf[2], ibuf[3], ibuf[4]);
227 return -1;
228 }
229 bufl=ubufl;
230 bufl += CKDDASD_TRKHDR_SIZE;
231 break;
232 #endif
233
234 default:
235 return -1;
236
237 } /* switch (buf[0] & CCKD_COMPRESS_MASK) */
238 return bufl;
239 }
240
241 /*-------------------------------------------------------------------*/
242 /* show_ckd_count - display CKD dasd record COUNT field */
243 /*-------------------------------------------------------------------*/
244 /* RECHDR is stored in big-endian byte order. */
show_ckd_count(CKDDASD_RECHDR * rh,int trk)245 BYTE *show_ckd_count(CKDDASD_RECHDR *rh, int trk) {
246 int cc, hh, r, kl, dl;
247 BYTE *past;
248
249 cc = (rh->cyl[0] << 8) | (rh->cyl[1]);
250 hh = (rh->head[0] << 8) | (rh->head[1]);
251 r = rh->rec;
252 kl = rh->klen;
253 dl = (rh->dlen[0] << 8) | (rh->dlen[1]);
254 fprintf(stdout, "\n"
255 "Track %d COUNT "
256 "CC=%d HH=%d R=%d KL=%d DL=%d\n",
257 trk, cc, hh, r, kl, dl);
258 past = (BYTE *)rh + sizeof(CKDDASD_RECHDR);
259 return past;
260 }
261
262 /*-------------------------------------------------------------------*/
263 /* show_ckd_key - display CKD dasd record KEY field */
264 /*-------------------------------------------------------------------*/
show_ckd_key(CKDDASD_RECHDR * rh,BYTE * buf,int trk,int xop)265 BYTE *show_ckd_key(CKDDASD_RECHDR *rh, BYTE *buf, int trk, int xop) {
266
267 if (rh->klen && xop) {
268 fprintf(stdout,
269 "\nTrack %d R%d KEY (%d bytes)\n",
270 trk, rh->rec, rh->klen);
271 data_dump(buf, rh->klen);
272 }
273 return (BYTE *)buf + rh->klen; /* skip past KEY field */
274 }
275
276 /*-------------------------------------------------------------------*/
277 /* show_ckd_data - display CKD dasd record DATA field */
278 /*-------------------------------------------------------------------*/
show_ckd_data(CKDDASD_RECHDR * rh,BYTE * buf,int trk,int xop)279 BYTE *show_ckd_data(CKDDASD_RECHDR *rh, BYTE *buf, int trk, int xop) {
280 int dl;
281
282 dl = (rh->dlen[0] << 8) | (rh->dlen[1]);
283 if (dl && xop) {
284 fprintf(stdout,
285 "\nTrack %d R%d DATA (%d bytes)\n",
286 trk, rh->rec, dl);
287 data_dump(buf, dl);
288 }
289 return buf + dl; /* skip past DATA field */
290 }
291
292 /*-------------------------------------------------------------------*/
293 /* showtrk - display track data */
294 /*-------------------------------------------------------------------*/
295 /* This code mimics selected logic in cdsk_valid_trk. */
showtrk(CKDDASD_TRKHDR * buf,int imglen,int trk,int xop)296 void showtrk(
297 CKDDASD_TRKHDR *buf, /* track header ptr */
298 int imglen, /* TRKHDR + track user data length */
299 int trk, /* relative track number */
300 int xop /* 1=dump key & data blks; 0=don't */
301 ) {
302 BYTE buf2[64*1024]; /* max uncompressed buffer */
303 char msg[81]; /* error message buffer */
304 CKDDASD_RECHDR *rh; /* CCKD COUNT field */
305 BYTE *bufp;
306 int len;
307
308 if (debug)
309 snap("\nSHOWTRK Compressed track header and data", buf, imglen);
310 len = decomptrk(
311 (BYTE *)buf, /* input buffer address */
312 imglen, /* input buffer length */
313 buf2, /* output buffer address */
314 sizeof(buf2), /* output buffer length */
315 1, /* >=0 means CKD, else FBA */
316 trk, /* relative track or block number */
317 msg /* addr of message buffer */
318 );
319 if (debug)
320 snap("\nSHOWTRK Decompressed track header and data", buf2, len);
321 bufp = &buf2[sizeof(CKDDASD_TRKHDR)];
322 while (bufp < &buf2[sizeof(buf2)]) {
323 rh = (CKDDASD_RECHDR *)bufp;
324 if (memcmp((BYTE *)rh, &eighthexFF, 8) == 0) {
325 fprintf(stdout, "\nEnd of Track\n");
326 break;
327 }
328 bufp = show_ckd_count(rh, trk);
329 bufp = show_ckd_key(rh, bufp, trk, xop);
330 bufp = show_ckd_data(rh, bufp, trk, xop);
331 }
332 }
333
334 /*-------------------------------------------------------------------*/
335 /* offtify - given decimal or hex input string, return off_t */
336 /* Locale independent, does not check for overflow */
337 /* References <ctype.h> and <string.h> */
338 /*-------------------------------------------------------------------*/
339 /* Based on code in P. J. Plauger's "The Standard C Library" */
340 /* See page 34, in Chapter 2 (ctype.h) */
offtify(char * s)341 off_t offtify(char *s) {
342
343 static const char xd[] = {"0123456789abcdefABCDEF"};
344 static const char xv[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
345 10, 11, 12, 13, 14, 15,
346 10, 11, 12, 13, 14, 15};
347 off_t v;
348 char *p;
349
350 p = s;
351 if ( (*s == '0') && (*(s+1) == 'x') ) {
352 s = s + 2;
353 for (v = 0; isxdigit(*s); ++s)
354 v = (v << 4) + xv[strchr(xd, *s) - xd];
355 if (debug)
356 fprintf(stdout,
357 "OFFTIFY string %s hex %8.8" I64_FMT "X decimal %" I64_FMT "d\n",
358 p, (U64)v, (U64)v);
359 return v;
360 } else { /* decimal input */
361 v = (off_t) atoll(s);
362 if (debug)
363 fprintf(stdout,
364 "OFFTIFY string %s decimal %" I64_FMT "X %" I64_FMT "d\n",
365 p, (U64)v, (U64)v);
366 return v;
367 }
368 }
369
370 /*-------------------------------------------------------------------*/
371 /* Main function for CCKD diagnostics */
372 /*-------------------------------------------------------------------*/
main(int argc,char * argv[])373 int main (int argc, char *argv[])
374 {
375 int cckd_diag_rc = 0; /* Program return code */
376 char *fn; /* File name */
377
378 CKDDASD_DEVHDR devhdr; /* [C]CKD device hdr */
379 CCKDDASD_DEVHDR cdevhdr; /* Compressed CKD device hdr */
380 CKDDEV *ckd=0; /* CKD DASD table entry */
381 FBADEV *fba=0; /* FBA DASD table entry */
382
383 int cmd_devhdr = 0; /* display DEVHDR */
384 int cmd_cdevhdr = 0; /* display CDEVHDR */
385 int cmd_l1tab = 0; /* display L1TAB */
386 int cmd_l2tab = 0; /* display L2TAB */
387 int cmd_trkdata = 0; /* display track data */
388 int cmd_hexdump = 0; /* display track data (hex) */
389
390 int cmd_offset = 0; /* 1 = display data at */
391 int op_offset = 0; /* op_offset of length */
392 int op_length = 0; /* op_length */
393
394 int cmd_cchh = 0; /* 1 = display CCHH data */
395 int op_cc = 0; /* CC = cylinder */
396 int op_hh = 0; /* HH = head */
397
398 int cmd_tt = 0; /* 1 = display TT data */
399 int op_tt = 0; /* relative track # */
400
401 int swapend; /* 1 = New endianess doesn't
402 match machine endianess */
403 int n, trk=0, l1ndx=0, l2ndx=0;
404 off_t l2taboff=0; /* offset to assoc. L2 table */
405 int ckddasd; /* 1=CKD dasd 0=FBA dasd */
406 int heads=0; /* Heads per cylinder */
407 int blks; /* Number fba blocks */
408 off_t trkhdroff=0; /* offset to assoc. trk hdr */
409 int imglen=0; /* track length */
410 char pathname[MAX_PATH]; /* file path in host format */
411
412 INITIALIZE_UTILITY("cckddiag");
413
414 /* parse the arguments */
415 argc--;
416 argv++ ;
417 while (argc > 0) {
418 if(**argv != '-') break;
419
420 switch(argv[0][1]) {
421 case 'v': if (argv[0][2] != '\0') return syntax ();
422 display_version (stdout,
423 "Hercules CCKD diagnostic program\n", FALSE);
424 return 0;
425 case 'd': if (argv[0][2] != '\0') return syntax ();
426 cmd_devhdr = 1;
427 break;
428 case 'c': if (argv[0][2] != '\0') return syntax ();
429 cmd_cdevhdr = 1;
430 break;
431 case '1': if (argv[0][2] != '\0') return syntax ();
432 cmd_l1tab = 1;
433 break;
434 case '2': if (argv[0][2] != '\0') return syntax ();
435 cmd_l2tab = 1;
436 break;
437 case 'a': if (argv[0][2] != '\0') return syntax ();
438 cmd_cchh = 1;
439 argc--; argv++;
440 op_cc = offtify(*argv);
441 argc--; argv++;
442 op_hh = offtify(*argv);
443 break;
444 case 'r': if (argv[0][2] != '\0') return syntax ();
445 cmd_tt = 1;
446 argc--; argv++;
447 op_tt = offtify(*argv);
448 break;
449 case 'o': if (argv[0][2] != '\0') return syntax ();
450 cmd_offset = 1;
451 argc--;
452 argv++;
453 op_offset = offtify(*argv);
454 argc--;
455 argv++;
456 op_length = offtify(*argv);
457 break;
458 case 't': if (argv[0][2] != '\0') return syntax ();
459 cmd_trkdata = 1;
460 break;
461 case 'x': if (argv[0][2] != '\0') return syntax ();
462 cmd_hexdump = 1;
463 cmd_trkdata = 1;
464 break;
465 case 'g': if (argv[0][2] != '\0') return syntax ();
466 debug = 1;
467 break;
468 default: return syntax ();
469 }
470 argc--;
471 argv++;
472 }
473 if (argc != 1) return syntax ();
474 fn = argv[0];
475
476 /* open the file */
477 hostpath(pathname, fn, sizeof(pathname));
478 fd = hopen(pathname, O_RDONLY | O_BINARY);
479 if (fd < 0) {
480 fprintf(stdout,
481 _("cckddiag: error opening file %s: %s\n"),
482 fn, strerror(errno));
483 return -1;
484 }
485
486 /*---------------------------------------------------------------*/
487 /* display DEVHDR - first 512 bytes of dasd image */
488 /*---------------------------------------------------------------*/
489 readpos(fd, &devhdr, 0, sizeof(devhdr));
490 if (cmd_devhdr) {
491 fprintf(stdout, "\nDEVHDR - %"SIZE_T_FMT"d (decimal) bytes:\n",
492 sizeof(devhdr));
493 data_dump(&devhdr, sizeof(devhdr));
494 }
495
496 /*---------------------------------------------------------------*/
497 /* Determine CKD or FBA device type */
498 /*---------------------------------------------------------------*/
499 if (memcmp(devhdr.devid, "CKD_C370", 8) == 0
500 || memcmp(devhdr.devid, "CKD_S370", 8) == 0) {
501 ckddasd = 1;
502 ckd = dasd_lookup(DASD_CKDDEV, NULL, devhdr.devtype, 0);
503 if (ckd == NULL) {
504 fprintf(stdout,
505 "DASD table entry not found for devtype 0x%2.2X\n",
506 devhdr.devtype);
507 clean();
508 exit(5);
509 }
510 }
511 else
512 if (memcmp(devhdr.devid, "FBA_C370", 8) == 0
513 || memcmp(devhdr.devid, "FBA_S370", 8) == 0) {
514 ckddasd = 0;
515 fba = dasd_lookup(DASD_FBADEV, NULL, devhdr.devtype, 0);
516 if (fba == NULL) {
517 fprintf(stdout,
518 "DASD table entry not found for "
519 "devtype 0x%2.2X\n",
520 DEFAULT_FBA_TYPE);
521 clean();
522 exit(6);
523 }
524 }
525 else {
526 fprintf(stdout, "incorrect header id\n");
527 clean();
528 return -1;
529 }
530
531 /*---------------------------------------------------------------*/
532 /* Set up device characteristics */
533 /*---------------------------------------------------------------*/
534 if (ckddasd) {
535 heads = ((U32)(devhdr.heads[3]) << 24)
536 | ((U32)(devhdr.heads[2]) << 16)
537 | ((U32)(devhdr.heads[1]) << 8)
538 | (U32)(devhdr.heads[0]);
539 if (debug)
540 fprintf(stdout,
541 "\n%s device has %d heads/cylinder\n",
542 ckd->name, heads);
543 } else {
544 blks = 0;
545 #if 0 /* cdevhdr is uninitialized and blks is never referenced... */
546 blks = ((U32)(cdevhdr.cyls[0]) << 24)
547 | ((U32)(cdevhdr.cyls[2]) << 16)
548 | ((U32)(cdevhdr.cyls[1]) << 8)
549 | (U32)(cdevhdr.cyls[0]);
550 #endif
551 }
552
553 /*---------------------------------------------------------------*/
554 /* display CDEVHDR - follows DEVHDR */
555 /*---------------------------------------------------------------*/
556 readpos(fd, &cdevhdr, CKDDASD_DEVHDR_SIZE, sizeof(cdevhdr));
557 if (cmd_cdevhdr) {
558 fprintf(stdout, "\nCDEVHDR - %"SIZE_T_FMT"d (decimal) bytes:\n",
559 sizeof(cdevhdr));
560 data_dump(&cdevhdr, sizeof(cdevhdr));
561 }
562
563 /*---------------------------------------------------------------*/
564 /* Find machine endian-ness */
565 /*---------------------------------------------------------------*/
566 /* cckd_endian() returns 1 for big-endian machines */
567 swapend = (cckd_endian() !=
568 ((cdevhdr.options & CCKD_BIGENDIAN) != 0));
569
570 /*---------------------------------------------------------------*/
571 /* display L1TAB - follows CDEVHDR */
572 /*---------------------------------------------------------------*/
573 /* swap numl1tab if needed */
574 n = cdevhdr.numl1tab;
575 if (swapend) cckd_swapend4((char *)&n);
576
577 l1 = makbuf(n * CCKD_L1ENT_SIZE, "L1TAB");
578 readpos(fd, l1, CCKD_L1TAB_POS, n * CCKD_L1ENT_SIZE);
579 /* L1TAB itself is not adjusted for endian-ness */
580 if (cmd_l1tab) {
581 fprintf(stdout, "\nL1TAB - %"SIZE_T_FMT"d (0x"SIZE_T_FMTX") bytes:\n",
582 (n * CCKD_L1ENT_SIZE), (n * CCKD_L1ENT_SIZE));
583 data_dump(l1, n * CCKD_L1ENT_SIZE);
584 }
585
586 /*---------------------------------------------------------------*/
587 /* display OFFSET, LENGTH data */
588 /*---------------------------------------------------------------*/
589 if (cmd_offset) {
590 bulk = makbuf(op_length, "BULK");
591 readpos(fd, bulk, op_offset, op_length);
592 fprintf(stdout,
593 "\nIMAGE OFFSET %d (0x%8.8X) "
594 "of length %d (0x%8.8X) bytes:\n",
595 op_offset, op_offset, op_length, op_length);
596 data_dump(bulk, op_length);
597 free(bulk);
598 bulk = NULL;
599 }
600
601 /*---------------------------------------------------------------*/
602 /* FBA isn't supported here because I don't know much about FBA */
603 /*---------------------------------------------------------------*/
604 if ( (!ckddasd) && ((cmd_cchh) || (cmd_tt)) ) {
605 fprintf(stdout, "CCHH/reltrk not supported for FBA\n");
606 clean();
607 exit(3);
608 }
609
610 /*---------------------------------------------------------------*/
611 /* Setup CCHH or relative track request */
612 /*---------------------------------------------------------------*/
613 if (ckddasd) {
614 if (cmd_tt) {
615 trk = op_tt;
616 op_cc = trk / heads;
617 op_hh = trk % heads;
618 } else {
619 trk = (op_cc * heads) + op_hh;
620 }
621 l1ndx = trk / cdevhdr.numl2tab;
622 l2ndx = trk % cdevhdr.numl2tab;
623 l2taboff = l1[l1ndx];
624 if (swapend) cckd_swapend4((char *)&l2taboff);
625 }
626
627 /*---------------------------------------------------------------*/
628 /* display CKD CCHH or relative track data */
629 /*---------------------------------------------------------------*/
630 if ((cmd_cchh) || (cmd_tt)) {
631 fprintf(stdout,
632 "CC %d HH %d = reltrk %d; "
633 "L1 index = %d, L2 index = %d\n"
634 "L1 index %d = L2TAB offset %d (0x%8.8X)\n",
635 op_cc, op_hh, trk,
636 l1ndx, l2ndx,
637 l1ndx, (int)l2taboff, (int)l2taboff);
638 l2 = makbuf(cdevhdr.numl2tab * sizeof(CCKD_L2ENT), "L2TAB");
639 readpos(fd, l2, l2taboff,
640 cdevhdr.numl2tab * sizeof(CCKD_L2ENT));
641 if (cmd_l2tab) {
642 fprintf(stdout,
643 "\nL2TAB - %"SIZE_T_FMT"d (decimal) bytes\n",
644 (cdevhdr.numl2tab * sizeof(CCKD_L2ENT)));
645 data_dump(l2, (cdevhdr.numl2tab * sizeof(CCKD_L2ENT)) );
646 }
647 fprintf(stdout, "\nL2 index %d = L2TAB entry %"SIZE_T_FMT"d bytes\n",
648 l2ndx, sizeof(CCKD_L2ENT) );
649 data_dump(&l2[l2ndx], sizeof(CCKD_L2ENT) );
650 trkhdroff = l2[l2ndx].pos;
651 imglen = l2[l2ndx].len;
652 if (swapend) {
653 cckd_swapend4((char *)&trkhdroff);
654 cckd_swapend4((char *)&imglen);
655 }
656 fprintf(stdout, "\nTRKHDR offset %d (0x%8.8X); "
657 "length %d (0x%4.4X)\n",
658 (int)trkhdroff, (int)trkhdroff, imglen, imglen);
659 tbuf = makbuf(imglen, "TRKHDR+DATA");
660 readpos(fd, tbuf, trkhdroff, imglen);
661 fprintf(stdout, "\nTRKHDR track %d\n", trk);
662 data_dump(tbuf, sizeof(CKDDASD_TRKHDR) );
663 if (cmd_trkdata) showtrk(tbuf, imglen, trk, cmd_hexdump);
664 free(l2); free(tbuf);
665 l2 = NULL; tbuf = NULL;
666 }
667
668 /* Close file, exit */
669 fprintf(stdout, "\n");
670 clean();
671 return cckd_diag_rc;
672 }
673
674