1 /* CCKDDASD.C (c) Copyright Greg Smith, 2000-2009 */
2 /* Compressed CKD Direct Access Storage Device Handler */
3
4 /*-------------------------------------------------------------------*/
5 /* This module contains device functions for compressed emulated */
6 /* count-key-data direct access storage devices. */
7 /*-------------------------------------------------------------------*/
8
9 #include "hstdinc.h"
10
11 #define _CCKDDASD_C_
12 #define _HDASD_DLL_
13 #include "hercules.h"
14 #include "devtype.h"
15 #include "opcode.h"
16
17 /*-------------------------------------------------------------------*/
18 /* Internal functions */
19 /*-------------------------------------------------------------------*/
20 int cckddasd_init(int argc, BYTE *argv[]);
21 int cckddasd_term();
22 int cckddasd_init_handler( DEVBLK *dev, int argc, char *argv[] );
23 int cckddasd_close_device(DEVBLK *dev);
24 void cckddasd_start(DEVBLK *dev);
25 void cckddasd_end(DEVBLK *dev);
26
27 int cckd_open (DEVBLK *dev, int sfx, int flags, mode_t mode);
28 int cckd_close (DEVBLK *dev, int sfx);
29 int cckd_read (DEVBLK *dev, int sfx, off_t off, void *buf, size_t len);
30 int cckd_write (DEVBLK *dev, int sfx, off_t off, void *buf, size_t len);
31 int cckd_ftruncate(DEVBLK *dev, int sfx, off_t off);
32 void *cckd_malloc(DEVBLK *dev, char *id, size_t size);
33 void *cckd_calloc(DEVBLK *dev, char *id, size_t n, size_t size);
34 void *cckd_free(DEVBLK *dev, char *id,void *p);
35
36 int cckd_read_track(DEVBLK *dev, int trk, BYTE *unitstat);
37 int cckd_update_track(DEVBLK *dev, int trk, int off,
38 BYTE *buf, int len, BYTE *unitstat);
39 int cckd_used(DEVBLK *dev);
40 int cfba_read_block(DEVBLK *dev, int blkgrp, BYTE *unitstat);
41 int cfba_write_block(DEVBLK *dev, int blkgrp, int off,
42 BYTE *buf, int wrlen, BYTE *unitstat);
43 int cfba_used(DEVBLK *dev);
44 int cckd_read_trk(DEVBLK *dev, int trk, int ra, BYTE *unitstat);
45 void cckd_readahead(DEVBLK *dev, int trk);
46 int cckd_readahead_scan(int *answer, int ix, int i, void *data);
47 void cckd_ra();
48 void cckd_flush_cache(DEVBLK *dev);
49 int cckd_flush_cache_scan(int *answer, int ix, int i, void *data);
50 void cckd_flush_cache_all();
51 void cckd_purge_cache(DEVBLK *dev);
52 int cckd_purge_cache_scan(int *answer, int ix, int i, void *data);
53 void cckd_writer(void *arg);
54 int cckd_writer_scan(int *o, int ix, int i, void *data);
55 off_t cckd_get_space(DEVBLK *dev, int *size, int flags);
56 void cckd_rel_space(DEVBLK *dev, off_t pos, int len, int size);
57 void cckd_flush_space(DEVBLK *dev);
58 int cckd_read_chdr(DEVBLK *dev);
59 int cckd_write_chdr(DEVBLK *dev);
60 int cckd_read_l1(DEVBLK *dev);
61 int cckd_write_l1(DEVBLK *dev);
62 int cckd_write_l1ent(DEVBLK *dev, int l1x);
63 int cckd_read_init(DEVBLK *dev);
64 int cckd_read_fsp(DEVBLK *dev);
65 int cckd_write_fsp(DEVBLK *dev);
66 int cckd_read_l2(DEVBLK *dev, int sfx, int l1x);
67 void cckd_purge_l2(DEVBLK *dev);
68 int cckd_purge_l2_scan(int *answer, int ix, int i, void *data);
69 int cckd_steal_l2();
70 int cckd_steal_l2_scan(int *answer, int ix, int i, void *data);
71 int cckd_write_l2(DEVBLK *dev);
72 int cckd_read_l2ent(DEVBLK *dev, CCKD_L2ENT *l2, int trk);
73 int cckd_write_l2ent(DEVBLK *dev, CCKD_L2ENT *l2, int trk);
74 int cckd_read_trkimg(DEVBLK *dev, BYTE *buf, int trk, BYTE *unitstat);
75 int cckd_write_trkimg(DEVBLK *dev, BYTE *buf, int len, int trk, int flags);
76 int cckd_harden(DEVBLK *dev);
77 int cckd_trklen(DEVBLK *dev, BYTE *buf);
78 int cckd_null_trk(DEVBLK *dev, BYTE *buf, int trk, int nullfmt);
79 int cckd_check_null_trk (DEVBLK *dev, BYTE *buf, int trk, int len);
80 int cckd_cchh(DEVBLK *dev, BYTE *buf, int trk);
81 int cckd_validate(DEVBLK *dev, BYTE *buf, int trk, int len);
82 char *cckd_sf_name(DEVBLK *dev, int sfx);
83 int cckd_sf_init(DEVBLK *dev);
84 int cckd_sf_new(DEVBLK *dev);
85 DLL_EXPORT void *cckd_sf_add(void *data);
86 DLL_EXPORT void *cckd_sf_remove(void *data);
87 DLL_EXPORT void *cckd_sf_comp(void *data);
88 DLL_EXPORT void *cckd_sf_chk(void *data);
89 DLL_EXPORT void *cckd_sf_stats(void *data);
90 int cckd_disable_syncio(DEVBLK *dev);
91 void cckd_lock_devchain(int flag);
92 void cckd_unlock_devchain();
93 void cckd_gcol();
94 int cckd_gc_percolate(DEVBLK *dev, unsigned int size);
95 int cckd_gc_l2(DEVBLK *dev, BYTE *buf);
96 DEVBLK *cckd_find_device_by_devnum (U16 devnum);
97 BYTE *cckd_uncompress(DEVBLK *dev, BYTE *from, int len, int maxlen, int trk);
98 int cckd_uncompress_zlib(DEVBLK *dev, BYTE *to, BYTE *from, int len, int maxlen);
99 int cckd_uncompress_bzip2(DEVBLK *dev, BYTE *to, BYTE *from, int len, int maxlen);
100 int cckd_compress(DEVBLK *dev, BYTE **to, BYTE *from, int len, int comp, int parm);
101 int cckd_compress_none(DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm);
102 int cckd_compress_zlib(DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm);
103 int cckd_compress_bzip2(DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm);
104 void cckd_command_help();
105 void cckd_command_opts();
106 void cckd_command_stats();
107 void cckd_command_debug();
108 int cckd_command(char *op, int cmd);
109 DLL_EXPORT void cckd_print_itrace();
110 void cckd_trace(DEVBLK *dev, char *msg, ...);
111
112 /*-------------------------------------------------------------------*/
113 /* Definitions for sense data format codes and message codes */
114 /*-------------------------------------------------------------------*/
115 #define FORMAT_0 0 /* Program or System Checks */
116 #define FORMAT_1 1 /* Device Equipment Checks */
117 #define FORMAT_2 2 /* 3990 Equipment Checks */
118 #define FORMAT_3 3 /* 3990 Control Checks */
119 #define FORMAT_4 4 /* Data Checks */
120 #define FORMAT_5 5 /* Data Check + Displacement */
121 #define FORMAT_6 6 /* Usage Stats/Overrun Errors*/
122 #define FORMAT_7 7 /* Device Control Checks */
123 #define FORMAT_8 8 /* Device Equipment Checks */
124 #define FORMAT_9 9 /* Device Rd/Wrt/Seek Checks */
125 #define FORMAT_F 15 /* Cache Storage Checks */
126 #define MESSAGE_0 0 /* Message 0 */
127 #define MESSAGE_1 1 /* Message 1 */
128 #define MESSAGE_2 2 /* Message 2 */
129 #define MESSAGE_3 3 /* Message 3 */
130 #define MESSAGE_4 4 /* Message 4 */
131 #define MESSAGE_5 5 /* Message 5 */
132 #define MESSAGE_6 6 /* Message 6 */
133 #define MESSAGE_7 7 /* Message 7 */
134 #define MESSAGE_8 8 /* Message 8 */
135 #define MESSAGE_9 9 /* Message 9 */
136 #define MESSAGE_A 10 /* Message A */
137 #define MESSAGE_B 11 /* Message B */
138 #define MESSAGE_C 12 /* Message C */
139 #define MESSAGE_D 13 /* Message D */
140 #define MESSAGE_E 14 /* Message E */
141 #define MESSAGE_F 15 /* Message F */
142
143 /*-------------------------------------------------------------------*/
144 /* Data areas */
145 /*-------------------------------------------------------------------*/
146 static CCKD_L2ENT empty_l2[CKDDASD_NULLTRK_FMTMAX+1][256];
147 static BYTE eighthexFF[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
148 DEVHND cckddasd_device_hndinfo;
149 DEVHND cfbadasd_device_hndinfo;
150 DLL_EXPORT CCKDBLK cckdblk; /* cckd global area */
151
152 /*-------------------------------------------------------------------*/
153 /* CCKD global initialization */
154 /*-------------------------------------------------------------------*/
cckddasd_init(int argc,BYTE * argv[])155 int cckddasd_init (int argc, BYTE *argv[])
156 {
157 int i, j; /* Loop indexes */
158
159 UNREFERENCED(argc);
160 UNREFERENCED(argv);
161
162 if (memcmp (&cckdblk.id, "CCKDBLK ", sizeof(cckdblk.id)) == 0)
163 return 0;
164
165 /* Clear the cckdblk */
166 memset(&cckdblk, 0, sizeof(CCKDBLK));
167
168 /* Initialize locks and conditions */
169 memcpy (&cckdblk.id, "CCKDBLK ", sizeof(cckdblk.id));
170 initialize_lock (&cckdblk.gclock);
171 initialize_lock (&cckdblk.ralock);
172 initialize_lock (&cckdblk.wrlock);
173 initialize_lock (&cckdblk.devlock);
174 initialize_condition (&cckdblk.gccond);
175 initialize_condition (&cckdblk.racond);
176 initialize_condition (&cckdblk.wrcond);
177 initialize_condition (&cckdblk.devcond);
178 initialize_condition (&cckdblk.termcond);
179
180 /* Initialize some variables */
181 cckdblk.wrprio = 16;
182 cckdblk.ranbr = CCKD_DEFAULT_RA_SIZE;
183 cckdblk.ramax = CCKD_DEFAULT_RA;
184 cckdblk.wrmax = CCKD_DEFAULT_WRITER;
185 cckdblk.gcmax = CCKD_DEFAULT_GCOL;
186 cckdblk.gcwait = CCKD_DEFAULT_GCOLWAIT;
187 cckdblk.gcparm = CCKD_DEFAULT_GCOLPARM;
188 cckdblk.readaheads = CCKD_DEFAULT_READAHEADS;
189 cckdblk.freepend = CCKD_DEFAULT_FREEPEND;
190 #ifdef HAVE_LIBZ
191 cckdblk.comps |= CCKD_COMPRESS_ZLIB;
192 #endif
193 #ifdef CCKD_BZIP2
194 cckdblk.comps |= CCKD_COMPRESS_BZIP2;
195 #endif
196 cckdblk.comp = 0xff;
197 cckdblk.compparm = -1;
198
199 /* Initialize the readahead queue */
200 cckdblk.ra1st = cckdblk.ralast = -1;
201 cckdblk.rafree = 0;
202 for (i = 0; i < cckdblk.ranbr; i++) cckdblk.ra[i].next = i + 1;
203 cckdblk.ra[cckdblk.ranbr - 1].next = -1;
204
205 /* Clear the empty L2 tables */
206 for (i = 0; i <= CKDDASD_NULLTRK_FMTMAX; i++)
207 for (j = 0; j < 256; j++)
208 {
209 empty_l2[i][j].pos = 0;
210 empty_l2[i][j].len = empty_l2[i][j].size = i;
211 }
212
213 return 0;
214
215 } /* end function cckddasd_init */
216
217 /*-------------------------------------------------------------------*/
218 /* CCKD dasd global termination */
219 /*-------------------------------------------------------------------*/
cckddasd_term()220 int cckddasd_term ()
221 {
222 /* Terminate the readahead threads */
223 obtain_lock (&cckdblk.ralock);
224 cckdblk.ramax = 0;
225 if (cckdblk.ras)
226 {
227 broadcast_condition (&cckdblk.racond);
228 wait_condition (&cckdblk.termcond, &cckdblk.ralock);
229 }
230 release_lock (&cckdblk.ralock);
231
232 /* Terminate the garbage collection threads */
233 obtain_lock (&cckdblk.gclock);
234 cckdblk.gcmax = 0;
235 if (cckdblk.gcs)
236 {
237 broadcast_condition (&cckdblk.gccond);
238 wait_condition (&cckdblk.termcond, &cckdblk.gclock);
239 }
240 release_lock (&cckdblk.gclock);
241
242 /* Terminate the writer threads */
243 obtain_lock (&cckdblk.wrlock);
244 cckdblk.wrmax = 0;
245 if (cckdblk.wrs)
246 {
247 broadcast_condition (&cckdblk.wrcond);
248 wait_condition (&cckdblk.termcond, &cckdblk.wrlock);
249 }
250 release_lock (&cckdblk.wrlock);
251
252 memset(&cckdblk, 0, sizeof(CCKDBLK));
253
254 return 0;
255
256 } /* end function cckddasd_term */
257
258 /*-------------------------------------------------------------------*/
259 /* CKD dasd initialization */
260 /*-------------------------------------------------------------------*/
cckddasd_init_handler(DEVBLK * dev,int argc,char * argv[])261 int cckddasd_init_handler ( DEVBLK *dev, int argc, char *argv[] )
262 {
263 CCKDDASD_EXT *cckd; /* -> cckd extension */
264 DEVBLK *dev2; /* -> device in cckd queue */
265 int i; /* Counter */
266 int fdflags; /* File flags */
267
268 UNREFERENCED(argc);
269 UNREFERENCED(argv);
270
271 /* Initialize the global cckd block if necessary */
272 if (memcmp (&cckdblk.id, "CCKDBLK ", sizeof(cckdblk.id)))
273 cckddasd_init (0, NULL);
274
275 /* Obtain area for cckd extension */
276 dev->cckd_ext = cckd = cckd_calloc (dev, "ext", 1, sizeof(CCKDDASD_EXT));
277 if (cckd == NULL)
278 return -1;
279
280 /* Initialize locks and conditions */
281 initialize_lock (&cckd->iolock);
282 initialize_lock (&cckd->filelock);
283 initialize_condition (&cckd->iocond);
284
285 /* Initialize some variables */
286 obtain_lock (&cckd->filelock);
287 cckd->l1x = cckd->sfx = cckd->l2active = -1;
288 dev->cache = cckd->free1st = -1;
289 cckd->fd[0] = dev->fd;
290 fdflags = get_file_accmode_flags( dev->fd );
291 cckd->open[0] = (fdflags & O_RDWR) ? CCKD_OPEN_RW : CCKD_OPEN_RO;
292 for (i = 1; i <= CCKD_MAX_SF; i++)
293 {
294 cckd->fd[i] = -1;
295 cckd->open[i] = CCKD_OPEN_NONE;
296 }
297 cckd->maxsize = sizeof(off_t) > 4 ? 0xffffffffll : 0x7fffffffll;
298
299 /* call the chkdsk function */
300 if (cckd_chkdsk (dev, 0) < 0)
301 return -1;
302
303 /* Perform initial read */
304 if (cckd_read_init (dev) < 0)
305 return -1;
306 if (cckd->fbadasd) dev->ckdtrksz = CFBA_BLOCK_SIZE;
307
308 /* open the shadow files */
309 if (cckd_sf_init (dev) < 0)
310 {
311 logmsg (_("HHCCD101E %4.4X error initializing shadow files\n"), dev->devnum);
312 return -1;
313 }
314
315 /* Update the device handler routines */
316 if (cckd->ckddasd)
317 dev->hnd = &cckddasd_device_hndinfo;
318 else
319 dev->hnd = &cfbadasd_device_hndinfo;
320 release_lock (&cckd->filelock);
321
322 /* Insert the device into the cckd device queue */
323 cckd_lock_devchain(1);
324 for (cckd = NULL, dev2 = cckdblk.dev1st; dev2; dev2 = cckd->devnext)
325 cckd = dev2->cckd_ext;
326 if (cckd) cckd->devnext = dev;
327 else cckdblk.dev1st = dev;
328 cckd_unlock_devchain();
329
330 cckdblk.batch = dev->batch;
331 if (cckdblk.batch)
332 {
333 cckdblk.nostress = 1;
334 cckdblk.freepend = 0;
335 cckdblk.linuxnull = 1;
336 }
337
338 return 0;
339 } /* end function cckddasd_init_handler */
340
341 /*-------------------------------------------------------------------*/
342 /* Close a Compressed CKD Device */
343 /*-------------------------------------------------------------------*/
cckddasd_close_device(DEVBLK * dev)344 int cckddasd_close_device (DEVBLK *dev)
345 {
346 CCKDDASD_EXT *cckd; /* -> cckd extension */
347 int i; /* Index */
348
349 cckd = dev->cckd_ext;
350
351 /* Wait for readaheads to finish */
352 obtain_lock(&cckdblk.ralock);
353 cckd->stopping = 1;
354 while (cckd->ras)
355 {
356 release_lock(&cckdblk.ralock);
357 usleep(1);
358 obtain_lock(&cckdblk.ralock);
359 }
360 release_lock(&cckdblk.ralock);
361
362 /* Flush the cache and wait for the writes to complete */
363 obtain_lock (&cckd->iolock);
364 cckd->stopping = 1;
365 cckd_flush_cache (dev);
366 while (cckd->wrpending || cckd->ioactive)
367 {
368 cckd->iowaiters++;
369 wait_condition (&cckd->iocond, &cckd->iolock);
370 cckd->iowaiters--;
371 cckd_flush_cache (dev);
372 }
373 broadcast_condition (&cckd->iocond);
374 cckd_purge_cache (dev); cckd_purge_l2 (dev);
375 dev->bufcur = dev->cache = -1;
376 if (cckd->newbuf) cckd_free (dev, "newbuf", cckd->newbuf);
377 release_lock (&cckd->iolock);
378
379 /* Remove the device from the cckd queue */
380 cckd_lock_devchain(1);
381 if (dev == cckdblk.dev1st) cckdblk.dev1st = cckd->devnext;
382 else
383 {
384 DEVBLK *dev2 = cckdblk.dev1st;
385 CCKDDASD_EXT *cckd2 = dev2->cckd_ext;
386 while (cckd2->devnext != dev)
387 {
388 dev2 = cckd2->devnext; cckd2 = dev2->cckd_ext;
389 }
390 cckd2->devnext = cckd->devnext;
391 }
392 cckd_unlock_devchain();
393
394 /* harden the file */
395 obtain_lock (&cckd->filelock);
396 cckd_harden (dev);
397
398 /* close the shadow files */
399 for (i = 1; i <= cckd->sfn; i++)
400 {
401 cckd_close (dev, i);
402 cckd->open[i] = 0;
403 }
404
405 /* free the level 1 tables */
406 for (i = 0; i <= cckd->sfn; i++)
407 cckd->l1[i] = cckd_free (dev, "l1", cckd->l1[i]);
408
409 /* reset the device handler */
410 if (cckd->ckddasd)
411 dev->hnd = &ckddasd_device_hndinfo;
412 else
413 dev->hnd = &fbadasd_device_hndinfo;
414
415 /* write some statistics */
416 if (!dev->batch)
417 cckd_sf_stats (dev);
418 release_lock (&cckd->filelock);
419
420 /* free the cckd extension */
421 dev->cckd_ext= cckd_free (dev, "ext", cckd);
422
423 if (dev->dasdsfn) free (dev->dasdsfn);
424 dev->dasdsfn = NULL;
425
426 close (dev->fd);
427 dev->fd = -1;
428
429 /* If no more devices then perform global termination */
430 if (cckdblk.dev1st == NULL) cckddasd_term ();
431
432 return 0;
433 } /* end function cckddasd_close_device */
434
435 /*-------------------------------------------------------------------*/
436 /* Compressed ckd start/resume channel program */
437 /*-------------------------------------------------------------------*/
cckddasd_start(DEVBLK * dev)438 void cckddasd_start (DEVBLK *dev)
439 {
440 CCKDDASD_EXT *cckd; /* -> cckd extension */
441 U16 devnum = 0; /* Last active device number */
442 int trk = 0; /* Last active track */
443
444 cckd = dev->cckd_ext;
445
446 cckd_trace (dev, "start i/o file[%d] bufcur %d cache[%d]\n",
447 cckd->sfn, dev->bufcur, dev->cache);
448
449 /* Reset buffer offsets */
450 dev->bufoff = 0;
451 dev->bufoffhi = cckd->ckddasd ? dev->ckdtrksz : CFBA_BLOCK_SIZE;
452
453 /* Check for merge - synchronous i/o should be disabled */
454 obtain_lock(&cckd->iolock);
455 if (cckd->merging)
456 {
457 cckd_trace (dev, "start i/o waiting for merge%s\n","");
458 while (cckd->merging)
459 {
460 cckd->iowaiters++;
461 wait_condition (&cckd->iocond, &cckd->iolock);
462 cckd->iowaiters--;
463 }
464 dev->bufcur = dev->cache = -1;
465 }
466 cckd->ioactive = 1;
467
468 cache_lock(CACHE_DEVBUF);
469
470 if (dev->cache >= 0)
471 CCKD_CACHE_GETKEY(dev->cache, devnum, trk);
472
473 /* Check if previous active entry is still valid and not busy */
474 if (dev->cache >= 0 && dev->devnum == devnum && dev->bufcur == trk
475 && !(cache_getflag(CACHE_DEVBUF, dev->cache) & CCKD_CACHE_IOBUSY))
476 {
477 /* Make the entry active again */
478 cache_setflag (CACHE_DEVBUF, dev->cache, ~0, CCKD_CACHE_ACTIVE);
479
480 /* If the entry is pending write then change it to `updated' */
481 if (cache_getflag(CACHE_DEVBUF, dev->cache) & CCKD_CACHE_WRITE)
482 {
483 cache_setflag (CACHE_DEVBUF, dev->cache, ~CCKD_CACHE_WRITE, CCKD_CACHE_UPDATED);
484 cckd->wrpending--;
485 if (cckd->iowaiters && !cckd->wrpending)
486 broadcast_condition (&cckd->iocond);
487 }
488 }
489 else
490 dev->bufcur = dev->cache = -1;
491
492 cache_unlock (CACHE_DEVBUF);
493
494 release_lock (&cckd->iolock);
495
496 return;
497
498 } /* end function cckddasd_start */
499
500 /*-------------------------------------------------------------------*/
501 /* Compressed ckd end/suspend channel program */
502 /*-------------------------------------------------------------------*/
cckddasd_end(DEVBLK * dev)503 void cckddasd_end (DEVBLK *dev)
504 {
505 CCKDDASD_EXT *cckd; /* -> cckd extension */
506
507 cckd = dev->cckd_ext;
508
509 /* Update length if previous image was updated */
510 if (dev->bufupd && dev->bufcur >= 0 && dev->cache >= 0)
511 {
512 dev->buflen = cckd_trklen (dev, dev->buf);
513 cache_setval (CACHE_DEVBUF, dev->cache, dev->buflen);
514 }
515
516 dev->bufupd = 0;
517
518 cckd_trace (dev, "end i/o bufcur %d cache[%d] waiters %d\n",
519 dev->bufcur, dev->cache, cckd->iowaiters);
520
521 obtain_lock (&cckd->iolock);
522
523 cckd->ioactive = 0;
524
525 /* Make the current entry inactive */
526 if (dev->cache >= 0)
527 {
528 cache_lock (CACHE_DEVBUF);
529 cache_setflag (CACHE_DEVBUF, dev->cache, ~CCKD_CACHE_ACTIVE, 0);
530 cache_unlock (CACHE_DEVBUF);
531 }
532
533 /* Cause writers to start after first update */
534 if (cckd->updated && (cckdblk.wrs == 0 || cckd->iowaiters != 0))
535 cckd_flush_cache (dev);
536 else if (cckd->iowaiters)
537 broadcast_condition (&cckd->iocond);
538
539 release_lock (&cckd->iolock);
540
541 } /* end function cckddasd_end */
542
543 /*-------------------------------------------------------------------*/
544 /* Open a cckd file */
545 /* */
546 /* If O_CREAT is not set and mode is non-zero then the error message */
547 /* will be supressed. */
548 /*-------------------------------------------------------------------*/
cckd_open(DEVBLK * dev,int sfx,int flags,mode_t mode)549 int cckd_open (DEVBLK *dev, int sfx, int flags, mode_t mode)
550 {
551 CCKDDASD_EXT *cckd; /* -> cckd extension */
552 int err; /* 1 = issue error message */
553 char pathname[MAX_PATH]; /* file path in host format */
554
555 cckd = dev->cckd_ext;
556
557 err = !((flags & O_CREAT) == 0 && mode != 0);
558
559 if (cckd->fd[sfx] >= 0)
560 cckd_close (dev, sfx);
561
562 hostpath(pathname, cckd_sf_name (dev, sfx), sizeof(pathname));
563 cckd->fd[sfx] = hopen(pathname, flags, mode);
564 if (sfx == 0) dev->fd = cckd->fd[sfx];
565
566 if (cckd->fd[sfx] >= 0)
567 cckd->open[sfx] = flags & O_RDWR ? CCKD_OPEN_RW :
568 cckd->open[sfx] == CCKD_OPEN_RW ?
569 CCKD_OPEN_RD : CCKD_OPEN_RO;
570 else
571 {
572 if (err)
573 {
574 logmsg (_("HHCCD130E %4.4X file[%d] %s open error: %s\n"),
575 dev->devnum, sfx, cckd_sf_name (dev, sfx),
576 strerror(errno));
577 cckd_trace (dev, "file[%d] fd[%d] open %s error flags %8.8x mode %8.8x\n",
578 sfx, cckd->fd[sfx], cckd_sf_name (dev, sfx), flags, mode);
579 cckd_print_itrace ();
580 }
581 cckd->open[sfx] = CCKD_OPEN_NONE;
582 }
583
584 cckd_trace (dev, "file[%d] fd[%d] open %s, flags %8.8x mode %8.8x\n",
585 sfx, cckd->fd[sfx], cckd_sf_name (dev, sfx), flags, mode);
586
587 return cckd->fd[sfx];
588
589 } /* end function cckd_open */
590
591 /*-------------------------------------------------------------------*/
592 /* Close a cckd file */
593 /*-------------------------------------------------------------------*/
cckd_close(DEVBLK * dev,int sfx)594 int cckd_close (DEVBLK *dev, int sfx)
595 {
596 CCKDDASD_EXT *cckd; /* -> cckd extension */
597 int rc = 0; /* Return code */
598
599 cckd = dev->cckd_ext;
600
601 cckd_trace (dev, "file[%d] fd[%d] close %s\n",
602 sfx, cckd->fd[sfx], cckd_sf_name(dev, sfx));
603
604 if (cckd->fd[sfx] >= 0)
605 rc = close (cckd->fd[sfx]);
606
607 if (rc < 0)
608 {
609 logmsg (_("HHCCD130E %4.4X file[%d] close error: %s\n"),
610 dev->devnum, sfx, strerror(errno));
611 cckd_print_itrace ();
612 }
613
614 cckd->fd[sfx] = -1;
615 if (sfx == 0) dev->fd = -1;
616
617 return rc;
618
619 } /* end function cckd_close */
620
621 /*-------------------------------------------------------------------*/
622 /* Read from a cckd file */
623 /*-------------------------------------------------------------------*/
cckd_read(DEVBLK * dev,int sfx,off_t off,void * buf,size_t len)624 int cckd_read (DEVBLK *dev, int sfx, off_t off, void *buf, size_t len)
625 {
626 CCKDDASD_EXT *cckd; /* -> cckd extension */
627 int rc; /* Return code */
628
629 cckd = dev->cckd_ext;
630
631 cckd_trace (dev, "file[%d] fd[%d] read, off 0x%" I64_FMT "x len %ld\n",
632 sfx, cckd->fd[sfx], (long long)off, (long)len);
633
634 /* Seek to specified offset */
635 if (lseek (cckd->fd[sfx], off, SEEK_SET) < 0)
636 {
637 logmsg (_("HHCCD130E %4.4X file[%d] lseek error, offset 0x%" I64_FMT "x: %s\n"),
638 dev->devnum, sfx, (long long)off, strerror(errno));
639 cckd_print_itrace ();
640 return -1;
641 }
642
643 /* Read the data */
644 rc = read (cckd->fd[sfx], buf, len);
645 if (rc < (int)len)
646 {
647 if (rc < 0)
648 logmsg (_("HHCCD130E %4.4X file[%d] read error, offset 0x%" I64_FMT "x: %s\n"),
649 dev->devnum, sfx, (long long)off, strerror(errno));
650 else
651 logmsg (_("HHCCD130E %4.4X file[%d] read incomplete, offset 0x%" I64_FMT "x: "
652 "read %d expected %d\n"),
653 dev->devnum, sfx, (long long)off, rc, len);
654 cckd_print_itrace ();
655 return -1;
656 }
657
658 return rc;
659
660 } /* end function cckd_read */
661
662 /*-------------------------------------------------------------------*/
663 /* Write to a cckd file */
664 /*-------------------------------------------------------------------*/
cckd_write(DEVBLK * dev,int sfx,off_t off,void * buf,size_t len)665 int cckd_write (DEVBLK *dev, int sfx, off_t off, void *buf, size_t len)
666 {
667 CCKDDASD_EXT *cckd; /* -> cckd extension */
668 int rc = 0; /* Return code */
669
670 cckd = dev->cckd_ext;
671
672 cckd_trace (dev, "file[%d] fd[%d] write, off 0x%" I64_FMT "x len %ld\n",
673 sfx, cckd->fd[sfx], (long long)off, (long)len);
674
675 /* Seek to specified offset */
676 if (lseek (cckd->fd[sfx], off, SEEK_SET) < 0)
677 {
678 logmsg (_("HHCCD130E %4.4X file[%d] lseek error, offset 0x%" I64_FMT "x: %s\n"),
679 dev->devnum, sfx, (long long)off, strerror(errno));
680 return -1;
681 }
682
683 /* Write the data */
684 rc = write (cckd->fd[sfx], buf, len);
685 if (rc < (int)len)
686 {
687 if (rc < 0)
688 logmsg (_("HHCCD130E %4.4X file[%d] write error, offset 0x%" I64_FMT "x: %s\n"),
689 dev->devnum, sfx, (long long)off, strerror(errno));
690 else
691 logmsg (_("HHCCD130E %4.4X file[%d] write incomplete, offset 0x%" I64_FMT "x: "
692 "wrote %d expected %d\n"),
693 dev->devnum, sfx, (long long)off, rc, len);
694 cckd_print_itrace ();
695 return -1;
696 }
697
698 return rc;
699
700 } /* end function cckd_write */
701
702 /*-------------------------------------------------------------------*/
703 /* Truncate a cckd file */
704 /*-------------------------------------------------------------------*/
cckd_ftruncate(DEVBLK * dev,int sfx,off_t off)705 int cckd_ftruncate(DEVBLK *dev, int sfx, off_t off)
706 {
707 CCKDDASD_EXT *cckd; /* -> cckd extension */
708
709 cckd = dev->cckd_ext;
710
711 cckd_trace (dev, "file[%d] fd[%d] ftruncate, off 0x%" I64_FMT "x\n",
712 sfx, cckd->fd[sfx], (long long)off);
713
714 /* Truncate the file */
715 if (ftruncate (cckd->fd[sfx], off) < 0)
716 {
717 logmsg (_("HHCCD130E %4.4X file[%d] ftruncate error, offset 0x%" I64_FMT "x: %s\n"),
718 dev->devnum, sfx, (long long)off, strerror(errno));
719 cckd_print_itrace ();
720 return -1;
721 }
722
723 return 0;
724
725 } /* end function cckd_ftruncate */
726
727 /*-------------------------------------------------------------------*/
728 /* malloc */
729 /*-------------------------------------------------------------------*/
cckd_malloc(DEVBLK * dev,char * id,size_t size)730 void *cckd_malloc (DEVBLK *dev, char *id, size_t size)
731 {
732 void *p; /* Pointer */
733
734 p = malloc (size);
735 cckd_trace (dev, "%s malloc %p len %ld\n", id, p, (long)size);
736
737 if (p == NULL)
738 {
739 logmsg (_("HHCCD130E %4.4X malloc error, size %d: %s\n"),
740 dev ? dev->devnum : 0, size, strerror(errno));
741 cckd_print_itrace ();
742 }
743
744 return p;
745
746 } /* end function cckd_malloc */
747
748 /*-------------------------------------------------------------------*/
749 /* calloc */
750 /*-------------------------------------------------------------------*/
cckd_calloc(DEVBLK * dev,char * id,size_t n,size_t size)751 void *cckd_calloc (DEVBLK *dev, char *id, size_t n, size_t size)
752 {
753 void *p; /* Pointer */
754
755 p = calloc (n, size);
756 cckd_trace (dev, "%s calloc %p len %ld\n", id, p, n*(long)size);
757
758 if (p == NULL)
759 {
760 logmsg (_("HHCCD130E %4.4X calloc error, size %d: %s\n"),
761 dev ? dev->devnum : 0, n*size, strerror(errno));
762 cckd_print_itrace ();
763 }
764
765 return p;
766
767 } /* end function cckd_calloc */
768
769 /*-------------------------------------------------------------------*/
770 /* free */
771 /*-------------------------------------------------------------------*/
cckd_free(DEVBLK * dev,char * id,void * p)772 void *cckd_free (DEVBLK *dev, char *id, void *p)
773 {
774 cckd_trace (dev, "%s free %p\n", id, p);
775 if (p) free (p);
776 return NULL;
777 } /* end function cckd_free */
778
779 /*-------------------------------------------------------------------*/
780 /* Compressed ckd read track image */
781 /*-------------------------------------------------------------------*/
cckd_read_track(DEVBLK * dev,int trk,BYTE * unitstat)782 int cckd_read_track (DEVBLK *dev, int trk, BYTE *unitstat)
783 {
784 CCKDDASD_EXT *cckd; /* -> cckd extension */
785 int rc; /* Return code */
786 int len; /* Compressed length */
787 BYTE *newbuf; /* Uncompressed buffer */
788 int cache; /* New active cache entry */
789 int syncio; /* Syncio indicator */
790
791 cckd = dev->cckd_ext;
792
793 /* Update length if previous image was updated */
794 if (dev->bufupd && dev->bufcur >= 0 && dev->cache >= 0)
795 {
796 dev->buflen = cckd_trklen (dev, dev->buf);
797 cache_setval (CACHE_DEVBUF, dev->cache, dev->buflen);
798 }
799
800 /* Turn off the synchronous I/O bit if trk overflow or trk 0 */
801 syncio = dev->syncio_active;
802 if (dev->ckdtrkof || trk == 0)
803 dev->syncio_active = 0;
804
805 /* Reset buffer offsets */
806 dev->bufoff = 0;
807 dev->bufoffhi = dev->ckdtrksz;
808
809 /* Check if reading the same track image */
810 if (trk == dev->bufcur && dev->cache >= 0)
811 {
812 /* Track image may be compressed */
813 if ((dev->buf[0] & CCKD_COMPRESS_MASK) != 0
814 && (dev->buf[0] & dev->comps) == 0)
815 {
816 #if 0
817 /* Return if synchronous i/o */
818 if (dev->syncio_active)
819 {
820 cckd_trace (dev, "read trk %d syncio compressed\n", trk);
821 cckdblk.stats_synciomisses++;
822 dev->syncio_retry = 1;
823 return -1;
824 }
825 #endif
826 len = cache_getval(CACHE_DEVBUF, dev->cache);
827 newbuf = cckd_uncompress (dev, dev->buf, len, dev->ckdtrksz, trk);
828 if (newbuf == NULL) {
829 ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0);
830 *unitstat = CSW_CE | CSW_DE | CSW_UC;
831 dev->bufcur = dev->cache = -1;
832 dev->syncio_active = syncio;
833 return -1;
834 }
835 cache_setbuf (CACHE_DEVBUF, dev->cache, newbuf, dev->ckdtrksz);
836 dev->buf = newbuf;
837 dev->buflen = cckd_trklen (dev, newbuf);
838 cache_setval (CACHE_DEVBUF, dev->cache, dev->buflen);
839 dev->bufsize = cache_getlen (CACHE_DEVBUF, dev->cache);
840 dev->bufupd = 0;
841 cckd_trace (dev, "read trk %d uncompressed len %d\n",
842 trk, dev->buflen);
843 }
844
845 dev->comp = dev->buf[0] & CCKD_COMPRESS_MASK;
846 if (dev->comp != 0) dev->compoff = CKDDASD_TRKHDR_SIZE;
847
848 return 0;
849 }
850
851 cckd_trace (dev, "read trk %d (%s)\n", trk,
852 dev->syncio_active ? "synchronous" : "asynchronous");
853
854 /* read the new track */
855 dev->bufupd = 0;
856 *unitstat = 0;
857 cache = cckd_read_trk (dev, trk, 0, unitstat);
858 if (cache < 0)
859 {
860 dev->bufcur = dev->cache = -1;
861 return -1;
862 }
863
864 dev->cache = cache;
865 dev->buf = cache_getbuf (CACHE_DEVBUF, dev->cache, 0);
866 dev->bufcur = trk;
867 dev->bufoff = 0;
868 dev->bufoffhi = dev->ckdtrksz;
869 dev->buflen = cache_getval (CACHE_DEVBUF, dev->cache);
870 dev->bufsize = cache_getlen (CACHE_DEVBUF, dev->cache);
871
872 dev->comp = dev->buf[0] & CCKD_COMPRESS_MASK;
873 if (dev->comp != 0) dev->compoff = CKDDASD_TRKHDR_SIZE;
874
875 /* If the image is compressed then call ourself recursively
876 to cause the image to get uncompressed */
877 if (dev->comp != 0 && (dev->comp & dev->comps) == 0)
878 rc = cckd_read_track (dev, trk, unitstat);
879 else
880 rc = 0;
881
882 dev->syncio_active = syncio;
883 return rc;
884 } /* end function cckd_read_track */
885
886 /*-------------------------------------------------------------------*/
887 /* Compressed ckd update track image */
888 /*-------------------------------------------------------------------*/
cckd_update_track(DEVBLK * dev,int trk,int off,BYTE * buf,int len,BYTE * unitstat)889 int cckd_update_track (DEVBLK *dev, int trk, int off,
890 BYTE *buf, int len, BYTE *unitstat)
891 {
892 CCKDDASD_EXT *cckd; /* -> cckd extension */
893 int rc; /* Return code */
894
895 cckd = dev->cckd_ext;
896
897 /* Error if opened read-only */
898 if (dev->ckdrdonly && cckd->sfn == 0)
899 {
900 ckd_build_sense (dev, SENSE_EC, SENSE1_WRI, 0,FORMAT_1, MESSAGE_0);
901 *unitstat = CSW_CE | CSW_DE | CSW_UC;
902 dev->bufcur = dev->cache = -1;
903 return -1;
904 }
905
906 /* If the track is not current or compressed then read it.
907 `dev->comps' is set to zero forcing the read routine to
908 uncompress the image. */
909 if (trk != dev->bufcur || (dev->buf[0] & CCKD_COMPRESS_MASK) != 0)
910 {
911 dev->comps = 0;
912 rc = (dev->hnd->read) (dev, trk, unitstat);
913 if (rc < 0)
914 {
915 dev->bufcur = dev->cache = -1;
916 return -1;
917 }
918 }
919
920 /* Invalid track format if going past buffer end */
921 if (off + len > dev->ckdtrksz)
922 {
923 ckd_build_sense (dev, 0, SENSE1_ITF, 0, 0, 0);
924 *unitstat = CSW_CE | CSW_DE | CSW_UC;
925 dev->bufcur = dev->cache = -1;
926 return -1;
927 }
928
929 /* Copy the data into the buffer */
930 if (buf && len > 0) memcpy (dev->buf + off, buf, len);
931
932 cckd_trace (dev, "updt trk %d offset %d length %d\n",
933 trk, off, len);
934
935 /* Update the cache entry */
936 cache_setflag (CACHE_DEVBUF, dev->cache, ~0, CCKD_CACHE_UPDATED | CCKD_CACHE_USED);
937 cckd->updated = 1;
938
939 /* Notify the shared server of the update */
940 if (!dev->bufupd)
941 {
942 dev->bufupd = 1;
943 shared_update_notify (dev, trk);
944 }
945
946 return len;
947
948 } /* end function cckd_update_track */
949
950 /*-------------------------------------------------------------------*/
951 /* Return used cylinders */
952 /*-------------------------------------------------------------------*/
cckd_used(DEVBLK * dev)953 int cckd_used (DEVBLK *dev)
954 {
955 CCKDDASD_EXT *cckd; /* -> cckd extension */
956 int rc; /* Return code */
957 int l1x, l2x; /* Lookup table indexes */
958 int sfx; /* Shadow file suffix */
959 CCKD_L2ENT l2; /* Copied level 2 entry */
960
961 cckd = dev->cckd_ext;
962 obtain_lock (&cckd->filelock);
963
964 /* Find the last used level 1 table entry */
965 for (l1x = cckd->cdevhdr[0].numl1tab - 1; l1x > 0; l1x--)
966 {
967 sfx = cckd->sfn;
968 while (cckd->l1[sfx][l1x] == 0xffffffff && sfx > 0) sfx--;
969 if (cckd->l1[sfx][l1x]) break;
970 }
971
972 /* Find the last used level 2 table entry */
973 for (l2x = 255; l2x >= 0; l2x--)
974 {
975 rc = cckd_read_l2ent (dev, &l2, l1x * 256 + l2x);
976 if (rc < 0 || l2.pos != 0) break;
977 }
978
979 release_lock (&cckd->filelock);
980 return (l1x * 256 + l2x + dev->ckdheads) / dev->ckdheads;
981 }
982
983 /*-------------------------------------------------------------------*/
984 /* Compressed fba read block(s) */
985 /*-------------------------------------------------------------------*/
cfba_read_block(DEVBLK * dev,int blkgrp,BYTE * unitstat)986 int cfba_read_block (DEVBLK *dev, int blkgrp, BYTE *unitstat)
987 {
988 CCKDDASD_EXT *cckd; /* -> cckd extension */
989 int rc; /* Return code */
990 int cache; /* New active cache entry */
991 BYTE *cbuf; /* -> cache buffer */
992 BYTE *newbuf; /* Uncompressed buffer */
993 int len; /* Compressed length */
994 int maxlen; /* Size for cache entry */
995
996 cckd = dev->cckd_ext;
997
998 if (dev->cache >= 0)
999 cbuf = cache_getbuf (CACHE_DEVBUF, dev->cache, 0);
1000 else
1001 cbuf = NULL;
1002 maxlen = CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE;
1003
1004 /* Return if reading the same track image */
1005 if (blkgrp == dev->bufcur && dev->cache >= 0)
1006 {
1007 /* Block group image may be compressed */
1008 if ((cbuf[0] & CCKD_COMPRESS_MASK) != 0
1009 && (cbuf[0] & dev->comps) == 0)
1010 {
1011 #if 0
1012 /* Return if synchronous i/o */
1013 if (dev->syncio_active)
1014 {
1015 cckd_trace (dev, "read blkgrp %d syncio compressed\n",
1016 blkgrp);
1017 cckdblk.stats_synciomisses++;
1018 dev->syncio_retry = 1;
1019 return -1;
1020 }
1021 #endif
1022 len = cache_getval(CACHE_DEVBUF, dev->cache) + CKDDASD_TRKHDR_SIZE;
1023 newbuf = cckd_uncompress (dev, cbuf, len, maxlen, blkgrp);
1024 if (newbuf == NULL) {
1025 dev->sense[0] = SENSE_EC;
1026 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1027 dev->bufcur = dev->cache = -1;
1028 return -1;
1029 }
1030 cache_setbuf (CACHE_DEVBUF, dev->cache, newbuf, maxlen);
1031 cbuf = newbuf;
1032 dev->buf = newbuf + CKDDASD_TRKHDR_SIZE;
1033 dev->buflen = CFBA_BLOCK_SIZE;
1034 cache_setval (CACHE_DEVBUF, dev->cache, dev->buflen);
1035 dev->bufsize = cache_getlen (CACHE_DEVBUF, dev->cache);
1036 dev->bufupd = 0;
1037 cckd_trace (dev, "read bkgrp %d uncompressed len %d\n",
1038 blkgrp, dev->buflen);
1039 }
1040
1041 dev->comp = cbuf[0] & CCKD_COMPRESS_MASK;
1042
1043 return 0;
1044 }
1045
1046 cckd_trace (dev, "read blkgrp %d (%s)\n", blkgrp,
1047 dev->syncio_active ? "synchronous" : "asynchronous");
1048
1049 /* Read the new blkgrp */
1050 dev->bufupd = 0;
1051 *unitstat = 0;
1052 cache = cckd_read_trk (dev, blkgrp, 0, unitstat);
1053 if (cache < 0)
1054 {
1055 dev->bufcur = dev->cache = -1;
1056 return -1;
1057 }
1058 dev->cache = cache;
1059 cbuf = cache_getbuf (CACHE_DEVBUF, dev->cache, 0);
1060 dev->buf = cbuf + CKDDASD_TRKHDR_SIZE;
1061 dev->bufcur = blkgrp;
1062 dev->bufoff = 0;
1063 dev->bufoffhi = CFBA_BLOCK_SIZE;
1064 dev->buflen = CFBA_BLOCK_SIZE;
1065 cache_setval (CACHE_DEVBUF, dev->cache, dev->buflen);
1066 dev->bufsize = cache_getlen (CACHE_DEVBUF, dev->cache);
1067 dev->comp = cbuf[0] & CCKD_COMPRESS_MASK;
1068
1069 /* If the image is compressed then call ourself recursively
1070 to cause the image to get uncompressed. This is because
1071 `bufcur' will match blkgrp and `comps' won't match `comp' */
1072 if (dev->comp != 0 && (dev->comp & dev->comps) == 0)
1073 rc = cfba_read_block (dev, blkgrp, unitstat);
1074 else
1075 rc = 0;
1076
1077 return rc;
1078 } /* end function cfba_read_block */
1079
1080 /*-------------------------------------------------------------------*/
1081 /* Compressed fba write block(s) */
1082 /*-------------------------------------------------------------------*/
cfba_write_block(DEVBLK * dev,int blkgrp,int off,BYTE * buf,int len,BYTE * unitstat)1083 int cfba_write_block (DEVBLK *dev, int blkgrp, int off,
1084 BYTE *buf, int len, BYTE *unitstat)
1085 {
1086 CCKDDASD_EXT *cckd; /* -> cckd extension */
1087 int rc; /* Return code */
1088 BYTE *cbuf; /* -> cache buffer */
1089
1090 cckd = dev->cckd_ext;
1091
1092 if (dev->cache >= 0)
1093 cbuf = cache_getbuf (CACHE_DEVBUF, dev->cache, 0);
1094 else
1095 cbuf = NULL;
1096
1097 /* Read the block group if it's not current or compressed.
1098 `dev->comps' is set to zero forcing the read routine to
1099 uncompress the image. */
1100 if (blkgrp != dev->bufcur || (cbuf[0] & CCKD_COMPRESS_MASK) != 0)
1101 {
1102 dev->comps = 0;
1103 rc = (dev->hnd->read) (dev, blkgrp, unitstat);
1104 if (rc < 0)
1105 {
1106 dev->bufcur = dev->cache = -1;
1107 return -1;
1108 }
1109 }
1110
1111 /* Copy the data into the buffer */
1112 if (buf) memcpy (dev->buf + off, buf, len);
1113
1114 /* Update the cache entry */
1115 cache_setflag (CACHE_DEVBUF, dev->cache, ~0, CCKD_CACHE_UPDATED|CCKD_CACHE_USED);
1116 cckd->updated = 1;
1117
1118 /* Notify the shared server of the update */
1119 if (!dev->bufupd)
1120 {
1121 dev->bufupd = 1;
1122 shared_update_notify (dev, blkgrp);
1123 }
1124
1125 return len;
1126
1127 } /* end function cfba_write_block */
1128
1129 /*-------------------------------------------------------------------*/
1130 /* Return used blocks */
1131 /*-------------------------------------------------------------------*/
cfba_used(DEVBLK * dev)1132 int cfba_used (DEVBLK *dev)
1133 {
1134 CCKDDASD_EXT *cckd; /* -> cckd extension */
1135 int rc; /* Return code */
1136 int l1x, l2x; /* Lookup table indexes */
1137 int sfx; /* Shadow file suffix */
1138 CCKD_L2ENT l2; /* Copied level 2 entry */
1139
1140 cckd = dev->cckd_ext;
1141 obtain_lock (&cckd->filelock);
1142
1143 /* Find the last used level 1 table entry */
1144 for (l1x = cckd->cdevhdr[0].numl1tab - 1; l1x > 0; l1x--)
1145 {
1146 sfx = cckd->sfn;
1147 while (cckd->l1[sfx][l1x] == 0xffffffff && sfx > 0) sfx--;
1148 if (cckd->l1[sfx][l1x]) break;
1149 }
1150
1151 /* Find the last used level 2 table entry */
1152 for (l2x = 255; l2x >= 0; l2x--)
1153 {
1154 rc = cckd_read_l2ent (dev, &l2, l1x * 256 + l2x);
1155 if (rc < 0 || l2.pos != 0) break;
1156 }
1157
1158 release_lock (&cckd->filelock);
1159 return (l1x * 256 + l2x + CFBA_BLOCK_NUM) / CFBA_BLOCK_NUM;
1160 }
1161
1162 /*-------------------------------------------------------------------*/
1163 /* Read a track image */
1164 /* */
1165 /* This routine can be called by the i/o thread (`ra' == 0) or */
1166 /* by readahead threads (0 < `ra' <= cckdblk.ramax). */
1167 /* */
1168 /*-------------------------------------------------------------------*/
cckd_read_trk(DEVBLK * dev,int trk,int ra,BYTE * unitstat)1169 int cckd_read_trk(DEVBLK *dev, int trk, int ra, BYTE *unitstat)
1170 {
1171 CCKDDASD_EXT *cckd; /* -> cckd extension */
1172 int fnd; /* Cache index for hit */
1173 int lru; /* Oldest unused cache index */
1174 int len; /* Length of track image */
1175 int maxlen; /* Length for buffer */
1176 int curtrk = -1; /* Current track (at entry) */
1177 U16 devnum; /* Device number */
1178 U32 oldtrk; /* Stolen track number */
1179 U32 flag; /* Cache flag */
1180 BYTE *buf; /* Read buffer */
1181
1182 cckd = dev->cckd_ext;
1183
1184 cckd_trace (dev, "%d rdtrk %d\n", ra, trk);
1185
1186 maxlen = cckd->ckddasd ? dev->ckdtrksz
1187 : CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE;
1188
1189 if (!ra) obtain_lock (&cckd->iolock);
1190
1191 cache_lock (CACHE_DEVBUF);
1192
1193 /* Inactivate the old entry */
1194 if (!ra)
1195 {
1196 curtrk = dev->bufcur;
1197 if (dev->cache >= 0)
1198 cache_setflag(CACHE_DEVBUF, dev->cache, ~CCKD_CACHE_ACTIVE, 0);
1199 dev->bufcur = dev->cache = -1;
1200 }
1201
1202 cckd_read_trk_retry:
1203
1204 /* scan the cache array for the track */
1205 fnd = cache_lookup (CACHE_DEVBUF, CCKD_CACHE_SETKEY(dev->devnum, trk), &lru);
1206
1207 /* check for cache hit */
1208 if (fnd >= 0)
1209 {
1210 if (ra) /* readahead doesn't care about a cache hit */
1211 { cache_unlock (CACHE_DEVBUF);
1212 return fnd;
1213 }
1214
1215 /* If synchronous I/O and I/O is active then return
1216 with syncio_retry bit on */
1217 if (dev->syncio_active)
1218 {
1219 if (cache_getflag(CACHE_DEVBUF, fnd) & CCKD_CACHE_IOBUSY)
1220 {
1221 cckd_trace (dev, "%d rdtrk[%d] %d syncio %s\n", ra, fnd, trk,
1222 cache_getflag(CACHE_DEVBUF, fnd) & CCKD_CACHE_READING ?
1223 "reading" : "writing");
1224 cckdblk.stats_synciomisses++;
1225 dev->syncio_retry = 1;
1226 cache_unlock (CACHE_DEVBUF);
1227 release_lock (&cckd->iolock);
1228 return -1;
1229 }
1230 else cckdblk.stats_syncios++;
1231 }
1232
1233 /* Mark the new entry active */
1234 cache_setflag(CACHE_DEVBUF, fnd, ~0, CCKD_CACHE_ACTIVE | CCKD_CACHE_USED);
1235 cache_setage(CACHE_DEVBUF, fnd);
1236
1237 /* If the entry is pending write then change it to `updated' */
1238 if (cache_getflag(CACHE_DEVBUF, fnd) & CCKD_CACHE_WRITE)
1239 {
1240 cache_setflag(CACHE_DEVBUF, fnd, ~CCKD_CACHE_WRITE, CCKD_CACHE_UPDATED);
1241 cckd->wrpending--;
1242 if (cckd->iowaiters && !cckd->wrpending)
1243 broadcast_condition (&cckd->iocond);
1244 }
1245 buf = cache_getbuf(CACHE_DEVBUF, fnd, 0);
1246
1247 cache_unlock (CACHE_DEVBUF);
1248
1249 cckd_trace (dev, "%d rdtrk[%d] %d cache hit buf %p:%2.2x%2.2x%2.2x%2.2x%2.2x\n",
1250 ra, fnd, trk, buf, buf[0], buf[1], buf[2], buf[3], buf[4]);
1251
1252 cckdblk.stats_switches++; cckd->switches++;
1253 cckdblk.stats_cachehits++; cckd->cachehits++;
1254
1255 /* if read/write is in progress then wait for it to finish */
1256 while (cache_getflag(CACHE_DEVBUF, fnd) & CCKD_CACHE_IOBUSY)
1257 {
1258 cckdblk.stats_iowaits++;
1259 cckd_trace (dev, "%d rdtrk[%d] %d waiting for %s\n", ra, fnd, trk,
1260 cache_getflag(CACHE_DEVBUF, fnd) & CCKD_CACHE_READING ?
1261 "read" : "write");
1262 cache_setflag (CACHE_DEVBUF, fnd, ~0, CCKD_CACHE_IOWAIT);
1263 cckd->iowaiters++;
1264 wait_condition (&cckd->iocond, &cckd->iolock);
1265 cckd->iowaiters--;
1266 cache_setflag (CACHE_DEVBUF, fnd, ~CCKD_CACHE_IOWAIT, 0);
1267 cckd_trace (dev, "%d rdtrk[%d] %d io wait complete\n",
1268 ra, fnd, trk);
1269 }
1270
1271 release_lock (&cckd->iolock);
1272
1273 /* Asynchrously schedule readaheads */
1274 if (curtrk > 0 && trk > curtrk && trk <= curtrk + 2)
1275 cckd_readahead (dev, trk);
1276
1277 return fnd;
1278
1279 } /* cache hit */
1280
1281 /* If not readahead and synchronous I/O then retry */
1282 if (!ra && dev->syncio_active)
1283 {
1284 cache_unlock(CACHE_DEVBUF);
1285 release_lock (&cckd->iolock);
1286 cckd_trace (dev, "%d rdtrk[%d] %d syncio cache miss\n", ra, lru, trk);
1287 cckdblk.stats_synciomisses++;
1288 dev->syncio_retry = 1;
1289 return -1;
1290 }
1291
1292 cckd_trace (dev, "%d rdtrk[%d] %d cache miss\n", ra, lru, trk);
1293
1294 /* If no cache entry was stolen, then flush all outstanding writes.
1295 This requires us to release our locks. cache_wait should be
1296 called with only the cache_lock held. Fortunately, cache waits
1297 occur very rarely. */
1298 if (lru < 0) /* No available entry to be stolen */
1299 {
1300 cckd_trace (dev, "%d rdtrk[%d] %d no available cache entry\n",
1301 ra, lru, trk);
1302 cache_unlock (CACHE_DEVBUF);
1303 if (!ra) release_lock (&cckd->iolock);
1304 cckd_flush_cache_all();
1305 cache_lock (CACHE_DEVBUF);
1306 cckdblk.stats_cachewaits++;
1307 cache_wait (CACHE_DEVBUF);
1308 if (!ra)
1309 {
1310 cache_unlock (CACHE_DEVBUF);
1311 obtain_lock (&cckd->iolock);
1312 cache_lock (CACHE_DEVBUF);
1313 }
1314 goto cckd_read_trk_retry;
1315 }
1316
1317 CCKD_CACHE_GETKEY(lru, devnum, oldtrk);
1318 if (devnum != 0)
1319 {
1320 cckd_trace (dev, "%d rdtrk[%d] %d dropping %4.4X:%d from cache\n",
1321 ra, lru, trk, devnum, oldtrk);
1322 if (!(cache_getflag(CACHE_DEVBUF, lru) & CCKD_CACHE_USED))
1323 {
1324 cckdblk.stats_readaheadmisses++; cckd->misses++;
1325 }
1326 }
1327
1328 /* Initialize the entry */
1329 cache_setkey(CACHE_DEVBUF, lru, CCKD_CACHE_SETKEY(dev->devnum, trk));
1330 cache_setflag(CACHE_DEVBUF, lru, 0, CCKD_CACHE_READING);
1331 cache_setage(CACHE_DEVBUF, lru);
1332 cache_setval(CACHE_DEVBUF, lru, 0);
1333 if (!ra)
1334 {
1335 cckdblk.stats_switches++; cckd->switches++;
1336 cckdblk.stats_cachemisses++;
1337 cache_setflag(CACHE_DEVBUF, lru, ~0, CCKD_CACHE_ACTIVE|CCKD_CACHE_USED);
1338 }
1339 cache_setflag(CACHE_DEVBUF, lru, ~CACHE_TYPE,
1340 cckd->ckddasd ? DEVBUF_TYPE_CCKD : DEVBUF_TYPE_CFBA);
1341 buf = cache_getbuf(CACHE_DEVBUF, lru, maxlen);
1342
1343 cckd_trace (dev, "%d rdtrk[%d] %d buf %p len %d\n",
1344 ra, lru, trk, buf, cache_getlen(CACHE_DEVBUF, lru));
1345
1346 cache_unlock (CACHE_DEVBUF);
1347
1348 if (!ra) release_lock (&cckd->iolock);
1349
1350 /* Asynchronously schedule readaheads */
1351 if (!ra && curtrk > 0 && trk > curtrk && trk <= curtrk + 2)
1352 cckd_readahead (dev, trk);
1353
1354 /* Clear the buffer if batch mode */
1355 if (dev->batch) memset(buf, 0, maxlen);
1356
1357 /* Read the track image */
1358 obtain_lock (&cckd->filelock);
1359 len = cckd_read_trkimg (dev, buf, trk, unitstat);
1360 release_lock (&cckd->filelock);
1361 cache_setval (CACHE_DEVBUF, lru, len);
1362
1363 obtain_lock (&cckd->iolock);
1364
1365 /* Turn off the READING bit */
1366 cache_lock (CACHE_DEVBUF);
1367 flag = cache_setflag(CACHE_DEVBUF, lru, ~CCKD_CACHE_READING, 0);
1368 cache_unlock (CACHE_DEVBUF);
1369
1370 /* Wakeup other thread waiting for this read */
1371 if (cckd->iowaiters && (flag & CCKD_CACHE_IOWAIT))
1372 { cckd_trace (dev, "%d rdtrk[%d] %d signalling read complete\n",
1373 ra, lru, trk);
1374 broadcast_condition (&cckd->iocond);
1375 }
1376
1377 release_lock (&cckd->iolock);
1378
1379 if (ra)
1380 {
1381 cckdblk.stats_readaheads++; cckd->readaheads++;
1382 }
1383
1384 cckd_trace (dev, "%d rdtrk[%d] %d complete buf %p:%2.2x%2.2x%2.2x%2.2x%2.2x\n",
1385 ra, lru, trk, buf, buf[0], buf[1], buf[2], buf[3], buf[4]);
1386
1387 if (cache_busy_percent(CACHE_DEVBUF) > 80) cckd_flush_cache_all();
1388
1389 return lru;
1390
1391 } /* end function cckd_read_trk */
1392
1393 /*-------------------------------------------------------------------*/
1394 /* Schedule asynchronous readaheads */
1395 /*-------------------------------------------------------------------*/
cckd_readahead(DEVBLK * dev,int trk)1396 void cckd_readahead (DEVBLK *dev, int trk)
1397 {
1398 CCKDDASD_EXT *cckd; /* -> cckd extension */
1399 int i, r; /* Indexes */
1400 TID tid; /* Readahead thread id */
1401
1402 cckd = dev->cckd_ext;
1403
1404 if (cckdblk.ramax < 1 || cckdblk.readaheads < 1)
1405 return;
1406
1407 obtain_lock (&cckdblk.ralock);
1408
1409 /* Scan the cache to see if the tracks are already there */
1410 memset(cckd->ralkup, 0, sizeof(cckd->ralkup));
1411 cckd->ratrk = trk;
1412 cache_lock(CACHE_DEVBUF);
1413 cache_scan(CACHE_DEVBUF, cckd_readahead_scan, dev);
1414 cache_unlock(CACHE_DEVBUF);
1415
1416 /* Scan the queue to see if the tracks are already there */
1417 for (r = cckdblk.ra1st; r >= 0; r = cckdblk.ra[r].next)
1418 if (cckdblk.ra[r].dev == dev)
1419 {
1420 i = cckdblk.ra[r].trk - trk;
1421 if (i > 0 && i <= cckdblk.readaheads)
1422 cckd->ralkup[i-1] = 1;
1423 }
1424
1425 /* Queue the tracks to the readahead queue */
1426 for (i = 1; i <= cckdblk.readaheads && cckdblk.rafree >= 0; i++)
1427 {
1428 if (cckd->ralkup[i-1]) continue;
1429 if (trk + i >= dev->ckdtrks) break;
1430 r = cckdblk.rafree;
1431 cckdblk.rafree = cckdblk.ra[r].next;
1432 if (cckdblk.ralast < 0)
1433 {
1434 cckdblk.ra1st = cckdblk.ralast = r;
1435 cckdblk.ra[r].prev = cckdblk.ra[r].next = -1;
1436 }
1437 else
1438 {
1439 cckdblk.ra[cckdblk.ralast].next = r;
1440 cckdblk.ra[r].prev = cckdblk.ralast;
1441 cckdblk.ra[r].next = -1;
1442 cckdblk.ralast = r;
1443 }
1444 cckdblk.ra[r].trk = trk + i;
1445 cckdblk.ra[r].dev = dev;
1446 }
1447
1448 /* Schedule the readahead if any are pending */
1449 if (cckdblk.ra1st >= 0)
1450 {
1451 if (cckdblk.rawaiting)
1452 signal_condition (&cckdblk.racond);
1453 else if (cckdblk.ras < cckdblk.ramax)
1454 create_thread (&tid, JOINABLE, cckd_ra, NULL, "cckd_ra");
1455 }
1456
1457 release_lock (&cckdblk.ralock);
1458
1459 } /* end function cckd_readahead */
1460
cckd_readahead_scan(int * answer,int ix,int i,void * data)1461 int cckd_readahead_scan (int *answer, int ix, int i, void *data)
1462 {
1463 CCKDDASD_EXT *cckd; /* -> cckd extension */
1464 U16 devnum; /* Cached device number */
1465 U32 trk; /* Cached track */
1466 DEVBLK *dev = data; /* -> device block */
1467 int k; /* Index */
1468
1469 UNREFERENCED(answer);
1470 UNREFERENCED(ix);
1471 cckd = dev->cckd_ext;
1472 CCKD_CACHE_GETKEY(i, devnum, trk);
1473 if (devnum == dev->devnum)
1474 {
1475 k = (int)trk - cckd->ratrk;
1476 if (k > 0 && k <= cckdblk.readaheads)
1477 cckd->ralkup[k-1] = 1;
1478 }
1479 return 0;
1480 }
1481
1482 /*-------------------------------------------------------------------*/
1483 /* Asynchronous readahead thread */
1484 /*-------------------------------------------------------------------*/
cckd_ra()1485 void cckd_ra ()
1486 {
1487 CCKDDASD_EXT *cckd; /* -> cckd extension */
1488 DEVBLK *dev; /* Readahead devblk */
1489 int trk; /* Readahead track */
1490 int ra; /* Readahead index */
1491 int r; /* Readahead queue index */
1492 TID tid; /* Readahead thread id */
1493
1494 obtain_lock (&cckdblk.ralock);
1495 ra = ++cckdblk.ras;
1496
1497 /* Return without messages if too many already started */
1498 if (ra > cckdblk.ramax)
1499 {
1500 --cckdblk.ras;
1501 release_lock (&cckdblk.ralock);
1502 return;
1503 }
1504
1505 if (!cckdblk.batch)
1506 {
1507 logmsg (_("HHCCD001I Readahead thread %d started: tid="TIDPAT", pid=%d\n"),
1508 ra, thread_id(), getpid());
1509 }
1510
1511 while (ra <= cckdblk.ramax)
1512 {
1513 if (cckdblk.ra1st < 0)
1514 {
1515 cckdblk.rawaiting++;
1516 wait_condition (&cckdblk.racond, &cckdblk.ralock);
1517 cckdblk.rawaiting--;
1518 }
1519
1520 /* Possibly shutting down if no writes pending */
1521 if (cckdblk.ra1st < 0) continue;
1522
1523 r = cckdblk.ra1st;
1524 trk = cckdblk.ra[r].trk;
1525 dev = cckdblk.ra[r].dev;
1526 cckd = dev->cckd_ext;
1527
1528 /* Requeue the 1st entry to the readahead free queue */
1529 cckdblk.ra1st = cckdblk.ra[r].next;
1530 if (cckdblk.ra[r].next > -1)
1531 cckdblk.ra[cckdblk.ra[r].next].prev = -1;
1532 else cckdblk.ralast = -1;
1533 cckdblk.ra[r].next = cckdblk.rafree;
1534 cckdblk.rafree = r;
1535
1536 /* Schedule the other readaheads if any are still pending */
1537 if (cckdblk.ra1st)
1538 {
1539 if (cckdblk.rawaiting)
1540 signal_condition (&cckdblk.racond);
1541 else if (cckdblk.ras < cckdblk.ramax)
1542 create_thread (&tid, JOINABLE, cckd_ra, dev, "cckd_ra");
1543 }
1544
1545 if (!cckd || cckd->stopping || cckd->merging) continue;
1546
1547 cckd->ras++;
1548 release_lock (&cckdblk.ralock);
1549
1550 /* Read the readahead track */
1551 cckd_read_trk (dev, trk, ra, NULL);
1552
1553 obtain_lock (&cckdblk.ralock);
1554 cckd->ras--;
1555 }
1556
1557 if (!cckdblk.batch)
1558 logmsg (_("HHCCD011I Readahead thread %d stopping: tid="TIDPAT", pid=%d\n"),
1559 ra, thread_id(), getpid());
1560 --cckdblk.ras;
1561 if (!cckdblk.ras) signal_condition(&cckdblk.termcond);
1562 release_lock(&cckdblk.ralock);
1563
1564 } /* end thread cckd_ra_thread */
1565
1566 /*-------------------------------------------------------------------*/
1567 /* Flush updated cache entries for a device */
1568 /* */
1569 /* Caller holds the cckd->iolock */
1570 /* cckdblk.wrlock then cache_lock is obtained and released */
1571 /*-------------------------------------------------------------------*/
cckd_flush_cache(DEVBLK * dev)1572 void cckd_flush_cache(DEVBLK *dev)
1573 {
1574 int rc; /* Return code */
1575 TID tid; /* Writer thread id */
1576
1577 /* Scan cache for updated cache entries */
1578 obtain_lock (&cckdblk.wrlock);
1579 cache_lock (CACHE_DEVBUF);
1580 rc = cache_scan (CACHE_DEVBUF, cckd_flush_cache_scan, dev);
1581 cache_unlock (CACHE_DEVBUF);
1582
1583 /* Schedule the writer if any writes are pending */
1584 if (cckdblk.wrpending)
1585 {
1586 if (cckdblk.wrwaiting)
1587 signal_condition (&cckdblk.wrcond);
1588 else if (cckdblk.wrs < cckdblk.wrmax)
1589 {
1590 create_thread (&tid, JOINABLE, cckd_writer, NULL, "cckd_writer");
1591 }
1592 }
1593 release_lock (&cckdblk.wrlock);
1594 }
cckd_flush_cache_scan(int * answer,int ix,int i,void * data)1595 int cckd_flush_cache_scan (int *answer, int ix, int i, void *data)
1596 {
1597 CCKDDASD_EXT *cckd; /* -> cckd extension */
1598 U16 devnum; /* Cached device number */
1599 U32 trk; /* Cached track */
1600 DEVBLK *dev = data; /* -> device block */
1601
1602 UNREFERENCED(answer);
1603 cckd = dev->cckd_ext;
1604 CCKD_CACHE_GETKEY(i, devnum, trk);
1605 if ((cache_getflag(ix,i) & CACHE_BUSY) == CCKD_CACHE_UPDATED
1606 && dev->devnum == devnum)
1607 {
1608 cache_setflag (ix, i, ~CCKD_CACHE_UPDATED, CCKD_CACHE_WRITE);
1609 ++cckd->wrpending;
1610 ++cckdblk.wrpending;
1611 cckd_trace (dev, "flush file[%d] cache[%d] %4.4X trk %d\n",
1612 cckd->sfn, i, devnum, trk);
1613 }
1614 return 0;
1615 }
cckd_flush_cache_all()1616 void cckd_flush_cache_all()
1617 {
1618 CCKDDASD_EXT *cckd; /* -> cckd extension */
1619 DEVBLK *dev = NULL; /* -> device block */
1620
1621 cckd_lock_devchain(0);
1622 for (dev = cckdblk.dev1st; dev; dev = cckd->devnext)
1623 {
1624 cckd = dev->cckd_ext;
1625 obtain_lock (&cckd->iolock);
1626 if (!cckd->merging && !cckd->stopping)
1627 cckd_flush_cache(dev);
1628 release_lock (&cckd->iolock);
1629 }
1630 cckd_unlock_devchain();
1631 }
1632
1633 /*-------------------------------------------------------------------*/
1634 /* Purge cache entries for a device */
1635 /* */
1636 /* Caller holds the iolock */
1637 /* cache_lock is obtained and released */
1638 /*-------------------------------------------------------------------*/
cckd_purge_cache(DEVBLK * dev)1639 void cckd_purge_cache(DEVBLK *dev)
1640 {
1641
1642 /* Scan cache and purge entries */
1643 cache_lock (CACHE_DEVBUF);
1644 cache_scan (CACHE_DEVBUF, cckd_purge_cache_scan, dev);
1645 cache_unlock (CACHE_DEVBUF);
1646 }
cckd_purge_cache_scan(int * answer,int ix,int i,void * data)1647 int cckd_purge_cache_scan (int *answer, int ix, int i, void *data)
1648 {
1649 U16 devnum; /* Cached device number */
1650 U32 trk; /* Cached track */
1651 DEVBLK *dev = data; /* -> device block */
1652
1653 UNREFERENCED(answer);
1654 CCKD_CACHE_GETKEY(i, devnum, trk);
1655 if (dev->devnum == devnum)
1656 {
1657 cache_release (ix, i, 0);
1658 cckd_trace (dev, "purge cache[%d] %4.4X trk %d purged\n",
1659 i, devnum, trk);
1660 }
1661 return 0;
1662 }
1663
1664 /*-------------------------------------------------------------------*/
1665 /* Writer thread */
1666 /*-------------------------------------------------------------------*/
cckd_writer(void * arg)1667 void cckd_writer(void *arg)
1668 {
1669 DEVBLK *dev; /* Device block */
1670 CCKDDASD_EXT *cckd; /* -> cckd extension */
1671 int writer; /* Writer identifier */
1672 int o; /* Cache entry found */
1673 U16 devnum; /* Device number */
1674 BYTE *buf; /* Buffer */
1675 BYTE *bufp; /* Buffer to be written */
1676 int len, bufl; /* Buffer lengths */
1677 int trk; /* Track number */
1678 int comp; /* Compression algorithm */
1679 int parm; /* Compression parameter */
1680 TID tid; /* Writer thead id */
1681 U32 flag; /* Cache flag */
1682 static char *compress[] = {"none", "zlib", "bzip2"};
1683 BYTE buf2[65536]; /* Compress buffer */
1684
1685 UNREFERENCED(arg);
1686
1687 #ifndef WIN32
1688 /* Set writer priority just below cpu priority to mimimize the
1689 compression effect */
1690 if(cckdblk.wrprio >= 0)
1691 setpriority (PRIO_PROCESS, 0, cckdblk.wrprio);
1692 #endif
1693
1694 obtain_lock (&cckdblk.wrlock);
1695
1696 writer = ++cckdblk.wrs;
1697
1698 /* Return without messages if too many already started */
1699 if (writer > cckdblk.wrmax)
1700 {
1701 --cckdblk.wrs;
1702 release_lock (&cckdblk.wrlock);
1703 return;
1704 }
1705
1706 if (!cckdblk.batch)
1707 {
1708 logmsg (_("HHCCD002I Writer thread %d started: tid="TIDPAT", pid=%d\n"),
1709 writer, thread_id(), getpid());
1710 }
1711
1712 while (writer <= cckdblk.wrmax || cckdblk.wrpending)
1713 {
1714 /* Wait for work */
1715 if (cckdblk.wrpending == 0)
1716 {
1717 cckdblk.wrwaiting++;
1718 wait_condition (&cckdblk.wrcond, &cckdblk.wrlock);
1719 cckdblk.wrwaiting--;
1720 }
1721
1722 /* Scan the cache for the oldest pending write */
1723 cache_lock (CACHE_DEVBUF);
1724 o = cache_scan (CACHE_DEVBUF, cckd_writer_scan, NULL);
1725
1726 /* Possibly shutting down if no writes pending */
1727 if (o < 0)
1728 {
1729 cache_unlock (CACHE_DEVBUF);
1730 cckdblk.wrpending = 0;
1731 continue;
1732 }
1733 cache_setflag (CACHE_DEVBUF, o, ~CCKD_CACHE_WRITE, CCKD_CACHE_WRITING);
1734 cache_unlock (CACHE_DEVBUF);
1735
1736 /* Schedule the other writers if any writes are still pending */
1737 cckdblk.wrpending--;
1738 if (cckdblk.wrpending)
1739 {
1740 if (cckdblk.wrwaiting)
1741 signal_condition (&cckdblk.wrcond);
1742 else if (cckdblk.wrs < cckdblk.wrmax)
1743 {
1744 create_thread (&tid, JOINABLE, cckd_writer, NULL, "cckd_writer");
1745 }
1746 }
1747 release_lock (&cckdblk.wrlock);
1748
1749 /* Prepare to compress */
1750 CCKD_CACHE_GETKEY(o, devnum, trk);
1751 dev = cckd_find_device_by_devnum (devnum);
1752 cckd = dev->cckd_ext;
1753 buf = cache_getbuf(CACHE_DEVBUF, o, 0);
1754 len = cckd_trklen (dev, buf);
1755 comp = len < CCKD_COMPRESS_MIN ? CCKD_COMPRESS_NONE
1756 : cckdblk.comp == 0xff ? cckd->cdevhdr[cckd->sfn].compress
1757 : cckdblk.comp;
1758 parm = cckdblk.compparm < 0
1759 ? cckd->cdevhdr[cckd->sfn].compress_parm
1760 : cckdblk.compparm;
1761
1762 cckd_trace (dev, "%d wrtrk[%d] %d len %d buf %p:%2.2x%2.2x%2.2x%2.2x%2.2x\n",
1763 writer, o, trk, len, buf, buf[0], buf[1],buf[2],buf[3],buf[4]);
1764
1765 /* Compress the image if not null */
1766 if ((len = cckd_check_null_trk (dev, buf, trk, len)) > CKDDASD_NULLTRK_FMTMAX)
1767 {
1768 /* Stress adjustments */
1769 if ((cache_waiters(CACHE_DEVBUF) || cache_busy(CACHE_DEVBUF) > 90)
1770 && !cckdblk.nostress)
1771 {
1772 cckdblk.stats_stresswrites++;
1773 comp = len < CCKD_STRESS_MINLEN ?
1774 CCKD_COMPRESS_NONE : CCKD_STRESS_COMP;
1775 parm = cache_busy(CACHE_DEVBUF) <= 95 ?
1776 CCKD_STRESS_PARM1 : CCKD_STRESS_PARM2;
1777 }
1778
1779 /* Compress the track image */
1780 cckd_trace (dev, "%d wrtrk[%d] %d comp %s parm %d\n",
1781 writer, o, trk, compress[comp], parm);
1782 bufp = (BYTE *)&buf2;
1783 bufl = cckd_compress(dev, &bufp, buf, len, comp, parm);
1784 cckd_trace (dev, "%d wrtrk[%d] %d compressed length %d\n",
1785 writer, o, trk, bufl);
1786 }
1787 else
1788 {
1789 bufp = buf;
1790 bufl = len;
1791 }
1792
1793 obtain_lock (&cckd->filelock);
1794
1795 /* Turn on read-write header bits if not already on */
1796 if (!(cckd->cdevhdr[cckd->sfn].options & CCKD_OPENED))
1797 {
1798 cckd->cdevhdr[cckd->sfn].options |= (CCKD_OPENED | CCKD_ORDWR);
1799 cckd_write_chdr (dev);
1800 }
1801
1802 /* Write the track image */
1803 cckd_write_trkimg (dev, bufp, bufl, trk, CCKD_SIZE_ANY);
1804
1805 release_lock (&cckd->filelock);
1806
1807 /* Schedule the garbage collector */
1808 if (cckdblk.gcs < cckdblk.gcmax)
1809 create_thread (&tid, JOINABLE, cckd_gcol, NULL, "cckd_gcol");
1810
1811 obtain_lock (&cckd->iolock);
1812 cache_lock (CACHE_DEVBUF);
1813 flag = cache_setflag (CACHE_DEVBUF, o, ~CCKD_CACHE_WRITING, 0);
1814 cache_unlock (CACHE_DEVBUF);
1815 cckd->wrpending--;
1816 if (cckd->iowaiters && ((flag & CCKD_CACHE_IOWAIT) || !cckd->wrpending))
1817 { cckd_trace (dev, "writer[%d] cache[%2.2d] %d signalling write complete\n",
1818 writer, o, trk);
1819 broadcast_condition (&cckd->iocond);
1820 }
1821 release_lock(&cckd->iolock);
1822
1823 cckd_trace (dev, "%d wrtrk[%2.2d] %d complete flags:%8.8x\n",
1824 writer, o, trk, cache_getflag(CACHE_DEVBUF,o));
1825
1826 obtain_lock(&cckdblk.wrlock);
1827 }
1828
1829 if (!cckdblk.batch)
1830 logmsg (_("HHCCD012I Writer thread %d stopping: tid="TIDPAT", pid=%d\n"),
1831 writer, thread_id(), getpid());
1832 cckdblk.wrs--;
1833 if (cckdblk.wrs == 0) signal_condition(&cckdblk.termcond);
1834 release_lock(&cckdblk.wrlock);
1835 } /* end thread cckd_writer */
1836
cckd_writer_scan(int * o,int ix,int i,void * data)1837 int cckd_writer_scan (int *o, int ix, int i, void *data)
1838 {
1839 UNREFERENCED(data);
1840 if ((cache_getflag(ix,i) & DEVBUF_TYPE_COMP)
1841 && (cache_getflag(ix,i) & CCKD_CACHE_WRITE)
1842 && (*o == -1 || cache_getage(ix, i) < cache_getage(ix, *o)))
1843 *o = i;
1844 return 0;
1845 }
1846
1847 /*-------------------------------------------------------------------*/
1848 /* Debug routine for checking the free space array */
1849 /*-------------------------------------------------------------------*/
1850
cckd_chk_space(DEVBLK * dev)1851 void cckd_chk_space(DEVBLK *dev)
1852 {
1853 #if 1
1854 CCKDDASD_EXT *cckd; /* -> cckd extension */
1855 int sfx; /* Shadow file index */
1856 int err = 0, n = 0, i, p;
1857 size_t largest=0;
1858 size_t total=0;
1859 off_t fpos;
1860
1861 cckd = dev->cckd_ext;
1862 sfx = cckd->sfn;
1863
1864 p = -1;
1865 fpos = cckd->cdevhdr[sfx].free;
1866 for (i = cckd->free1st; i >= 0; i = cckd->free[i].next)
1867 {
1868 n++; total += cckd->free[i].len;
1869 if (n > cckd->freenbr) break;
1870 if (cckd->free[i].prev != p)
1871 err = 1;
1872 if (cckd->free[i].next >= 0)
1873 {
1874 if (fpos + cckd->free[i].len > cckd->free[i].pos)
1875 err = 1;
1876 }
1877 else
1878 {
1879 if (fpos + cckd->free[i].len > cckd->cdevhdr[sfx].size)
1880 err = 1;
1881 }
1882 if (cckd->free[i].pending == 0 && cckd->free[i].len > largest)
1883 largest = cckd->free[i].len;
1884 fpos = cckd->free[i].pos;
1885 p = i;
1886 }
1887
1888 if (err
1889 || (cckd->cdevhdr[sfx].free != 0 && cckd->cdevhdr[sfx].free_number == 0)
1890 || (cckd->cdevhdr[sfx].free == 0 && cckd->cdevhdr[sfx].free_number != 0)
1891 || (n != cckd->cdevhdr[sfx].free_number)
1892 || (total != cckd->cdevhdr[sfx].free_total - cckd->cdevhdr[sfx].free_imbed)
1893 || (cckd->freelast != p)
1894 || (largest != cckd->cdevhdr[sfx].free_largest)
1895 )
1896 {
1897 cckd_trace (dev, "cdevhdr[%d] size %10d used %10d free 0x%8.8x\n",
1898 sfx,cckd->cdevhdr[sfx].size,cckd->cdevhdr[sfx].used,
1899 cckd->cdevhdr[sfx].free);
1900 cckd_trace (dev, " nbr %10d total %10d imbed %10d largest %10d\n",
1901 cckd->cdevhdr[sfx].free_number,
1902 cckd->cdevhdr[sfx].free_total,cckd->cdevhdr[sfx].free_imbed,
1903 cckd->cdevhdr[sfx].free_largest);
1904 cckd_trace (dev, "free %p nbr %d 1st %d last %d avail %d\n",
1905 cckd->free,cckd->freenbr,cckd->free1st,
1906 cckd->freelast,cckd->freeavail);
1907 cckd_trace (dev, "found nbr %d total %ld largest %ld\n",n,(long)total,(long)largest);
1908 fpos = cckd->cdevhdr[sfx].free;
1909 for (n = 0, i = cckd->free1st; i >= 0; i = cckd->free[i].next)
1910 {
1911 if (++n > cckd->freenbr) break;
1912 cckd_trace (dev, "%4d: [%4d] prev[%4d] next[%4d] pos %8.8" I64_FMT "x len %8d %8.8" I64_FMT "x pend %d\n",
1913 n, i, cckd->free[i].prev, cckd->free[i].next,
1914 (long long)fpos, cckd->free[i].len,
1915 (long long)fpos + cckd->free[i].len, cckd->free[i].pending);
1916 fpos = cckd->free[i].pos;
1917 }
1918 cckd_print_itrace();
1919 }
1920 #endif
1921 } /* end function cckd_chk_space */
1922
1923 /*-------------------------------------------------------------------*/
1924 /* Get file space */
1925 /*-------------------------------------------------------------------*/
cckd_get_space(DEVBLK * dev,int * size,int flags)1926 off_t cckd_get_space(DEVBLK *dev, int *size, int flags)
1927 {
1928 CCKDDASD_EXT *cckd; /* -> cckd extension */
1929 int i,p,n; /* Free space indexes */
1930 int len2; /* Other lengths */
1931 off_t fpos; /* Free space offset */
1932 unsigned int flen; /* Free space size */
1933 int sfx; /* Shadow file index */
1934 int len; /* Requested length */
1935
1936 cckd = dev->cckd_ext;
1937 sfx = cckd->sfn;
1938
1939 len = *size;
1940
1941 if (flags & CCKD_L2SPACE)
1942 {
1943 flags |= CCKD_SIZE_EXACT;
1944 len = *size = CCKD_L2TAB_SIZE;
1945 }
1946
1947 cckd_trace (dev, "get_space len %d largest %d flags 0x%2.2x\n",
1948 len, cckd->cdevhdr[sfx].free_largest, flags);
1949
1950 if (len <= CKDDASD_NULLTRK_FMTMAX)
1951 return 0;
1952
1953 if (!cckd->free)
1954 cckd_read_fsp (dev);
1955
1956 len2 = len + CCKD_FREEBLK_SIZE;
1957
1958 /* Get space at the end if no space is large enough */
1959 if (len2 > (int)cckd->cdevhdr[sfx].free_largest
1960 && len != (int)cckd->cdevhdr[sfx].free_largest)
1961 {
1962
1963 cckd_get_space_atend:
1964
1965 fpos = (off_t)cckd->cdevhdr[sfx].size;
1966 if ((long long)(fpos + len) > cckd->maxsize)
1967 {
1968 logmsg (_("HHCCD102E %4.4X file[%d] get space error, size exceeds %lldM\n"),
1969 dev->devnum, sfx, (cckd->maxsize >> 20) + 1);
1970 return -1;
1971 }
1972 cckd->cdevhdr[sfx].size += len;
1973 cckd->cdevhdr[sfx].used += len;
1974
1975 cckd_trace (dev, "get_space atend 0x%" I64_FMT "x len %d\n",(long long)fpos, len);
1976
1977 return fpos;
1978 }
1979
1980 /* Scan free space chain */
1981 fpos = (off_t)cckd->cdevhdr[sfx].free;
1982 for (i = cckd->free1st; i >= 0; i = cckd->free[i].next)
1983 {
1984 if (cckd->free[i].pending == 0
1985 && (len2 <= (int)cckd->free[i].len || len == (int)cckd->free[i].len)
1986 && ((flags & CCKD_L2SPACE) || fpos >= cckd->l2bounds))
1987 break;
1988 fpos = (off_t)cckd->free[i].pos;
1989 }
1990
1991 /* This can happen if largest comes before l2bounds */
1992 if (i < 0) goto cckd_get_space_atend;
1993
1994 flen = cckd->free[i].len;
1995 p = cckd->free[i].prev;
1996 n = cckd->free[i].next;
1997
1998 /*
1999 * If `CCKD_SIZE_ANY' bit is set and the left over space is small
2000 * enough, then use the entire free space
2001 */
2002 if ((flags & CCKD_SIZE_ANY) && flen <= cckd->freemin)
2003 *size = (int)flen;
2004
2005 /* Remove the new space from free space */
2006 if (*size < (int)flen)
2007 {
2008 cckd->free[i].len -= *size;
2009 if (p >= 0)
2010 cckd->free[p].pos += *size;
2011 else
2012 cckd->cdevhdr[sfx].free += *size;
2013 }
2014 else
2015 {
2016 cckd->cdevhdr[sfx].free_number--;
2017
2018 /* Remove the free space entry from the chain */
2019 if (p >= 0)
2020 {
2021 cckd->free[p].pos = cckd->free[i].pos;
2022 cckd->free[p].next = n;
2023 }
2024 else
2025 {
2026 cckd->cdevhdr[sfx].free = cckd->free[i].pos;
2027 cckd->free1st = n;
2028 }
2029
2030 if (n >= 0)
2031 cckd->free[n].prev = p;
2032 else
2033 cckd->freelast = p;
2034
2035 /* Add entry to the available queue */
2036 cckd->free[i].next = cckd->freeavail;
2037 cckd->freeavail = i;
2038 }
2039
2040 /* Find the largest free space if we got the largest */
2041 if (flen >= cckd->cdevhdr[sfx].free_largest)
2042 {
2043 int i;
2044 cckd->cdevhdr[sfx].free_largest = 0;
2045 for (i = cckd->free1st; i >= 0; i = cckd->free[i].next)
2046 if (cckd->free[i].len > cckd->cdevhdr[sfx].free_largest
2047 && cckd->free[i].pending == 0)
2048 cckd->cdevhdr[sfx].free_largest = cckd->free[i].len;
2049 }
2050
2051 /* Update free space stats */
2052 cckd->cdevhdr[sfx].used += len;
2053 cckd->cdevhdr[sfx].free_total -= len;
2054
2055 cckd->cdevhdr[sfx].free_imbed += *size - len;
2056
2057 cckd_trace (dev, "get_space found 0x%" I64_FMT "x len %d size %d\n",
2058 (long long)fpos, len, *size);
2059
2060 return fpos;
2061
2062 } /* end function cckd_get_space */
2063
2064 /*-------------------------------------------------------------------*/
2065 /* Release file space */
2066 /*-------------------------------------------------------------------*/
cckd_rel_space(DEVBLK * dev,off_t pos,int len,int size)2067 void cckd_rel_space(DEVBLK *dev, off_t pos, int len, int size)
2068 {
2069 CCKDDASD_EXT *cckd; /* -> cckd extension */
2070 int sfx; /* Shadow file index */
2071 off_t ppos, npos; /* Prev/next free offsets */
2072 int i, p, n; /* Free space indexes */
2073 int pending; /* Calculated pending value */
2074 int fsize = size; /* Free space size */
2075
2076 if (len <= CKDDASD_NULLTRK_FMTMAX || pos == 0 || pos == 0xffffffff)
2077 return;
2078
2079 cckd = dev->cckd_ext;
2080 sfx = cckd->sfn;
2081
2082 cckd_trace (dev, "rel_space offset %" I64_FMT "x len %d size %d\n",
2083 (long long)pos, len, size);
2084
2085 if (!cckd->free) cckd_read_fsp (dev);
2086
2087 // cckd_chk_space(dev);
2088
2089 /* Scan free space chain */
2090 ppos = -1;
2091 npos = cckd->cdevhdr[sfx].free;
2092 for (p = -1, n = cckd->free1st; n >= 0; n = cckd->free[n].next)
2093 {
2094 if (pos < npos) break;
2095 ppos = npos;
2096 npos = cckd->free[n].pos;
2097 p = n;
2098 }
2099
2100 /* Calculate the `pending' value */
2101 pending = cckdblk.freepend >= 0 ? cckdblk.freepend : 1 + (1 - cckdblk.fsync);
2102
2103 /* If possible use previous adjacent free space otherwise get an available one */
2104 if (p >= 0 && ppos + cckd->free[p].len == pos && cckd->free[p].pending == pending)
2105 {
2106 cckd->free[p].len += size;
2107 fsize = cckd->free[p].len;
2108 }
2109 else
2110 {
2111 /* Increase the size of the free space array if necessary */
2112 if (cckd->freeavail < 0)
2113 {
2114 cckd->freeavail = cckd->freenbr;
2115 cckd->freenbr += 1024;
2116 cckd->free = realloc ( cckd->free, cckd->freenbr * CCKD_FREEBLK_ISIZE);
2117 for (i = cckd->freeavail; i < cckd->freenbr; i++)
2118 cckd->free[i].next = i + 1;
2119 cckd->free[i-1].next = -1;
2120 cckd->freemin = CCKD_FREE_MIN_SIZE + ((cckd->freenbr >> 10) * CCKD_FREE_MIN_INCR);
2121 }
2122
2123 /* Get an available free space entry */
2124 i = cckd->freeavail;
2125 cckd->freeavail = cckd->free[i].next;
2126 cckd->cdevhdr[sfx].free_number++;
2127
2128 /* Update the new entry */
2129 cckd->free[i].prev = p;
2130 cckd->free[i].next = n;
2131 cckd->free[i].len = size;
2132 cckd->free[i].pending = pending;
2133
2134 /* Update the previous entry */
2135 if (p >= 0)
2136 {
2137 cckd->free[i].pos = cckd->free[p].pos;
2138 cckd->free[p].pos = pos;
2139 cckd->free[p].next = i;
2140 }
2141 else
2142 {
2143 cckd->free[i].pos = cckd->cdevhdr[sfx].free;
2144 cckd->cdevhdr[sfx].free = pos;
2145 cckd->free1st = i;
2146 }
2147
2148 /* Update the next entry */
2149 if (n >= 0)
2150 cckd->free[n].prev = i;
2151 else
2152 cckd->freelast = i;
2153 }
2154
2155 /* Update the free space statistics */
2156 cckd->cdevhdr[sfx].used -= len;
2157 cckd->cdevhdr[sfx].free_total += len;
2158 cckd->cdevhdr[sfx].free_imbed -= size - len;
2159 if (!pending && (U32)fsize > cckd->cdevhdr[sfx].free_largest)
2160 cckd->cdevhdr[sfx].free_largest = (U32)fsize;
2161
2162 // cckd_chk_space(dev);
2163
2164 } /* end function cckd_rel_space */
2165
2166 /*-------------------------------------------------------------------*/
2167 /* Flush pending free space */
2168 /*-------------------------------------------------------------------*/
cckd_flush_space(DEVBLK * dev)2169 void cckd_flush_space(DEVBLK *dev)
2170 {
2171 CCKDDASD_EXT *cckd; /* -> cckd extension */
2172 int p,i,n; /* Free free space indexes */
2173 int sfx; /* Shadow file index */
2174 U32 ppos, pos; /* Free space offsets */
2175
2176 cckd = dev->cckd_ext;
2177 sfx = cckd->sfn;
2178
2179 cckd_trace (dev, "flush_space nbr %d\n",cckd->cdevhdr[sfx].free_number);
2180
2181 /* Make sure the free space chain is built */
2182 if (!cckd->free) cckd_read_fsp (dev);
2183
2184 // cckd_chk_space(dev);
2185
2186 if (cckd->cdevhdr[sfx].free_number == 0 || cckd->cdevhdr[sfx].free == 0)
2187 {
2188 cckd->cdevhdr[sfx].free_number = cckd->cdevhdr[sfx].free = 0;
2189 cckd->free1st = cckd->freelast = cckd->freeavail = -1;
2190 }
2191
2192 pos = cckd->cdevhdr[sfx].free;
2193 ppos = p = -1;
2194 cckd->cdevhdr[sfx].free_number = cckd->cdevhdr[sfx].free_largest = 0;
2195 for (i = cckd->free1st; i >= 0; i = cckd->free[i].next)
2196 {
2197 /* Decrement the pending count */
2198 if (cckd->free[i].pending)
2199 --cckd->free[i].pending;
2200
2201 /* Combine adjacent free spaces */
2202 while (pos + cckd->free[i].len == cckd->free[i].pos)
2203 {
2204 n = cckd->free[i].next;
2205 if (cckd->free[n].pending > cckd->free[i].pending + 1
2206 || cckd->free[n].pending < cckd->free[i].pending)
2207 break;
2208 cckd->free[i].pos = cckd->free[n].pos;
2209 cckd->free[i].len += cckd->free[n].len;
2210 cckd->free[i].next = cckd->free[n].next;
2211 cckd->free[n].next = cckd->freeavail;
2212 cckd->freeavail = n;
2213 n = cckd->free[i].next;
2214 if (n >= 0)
2215 cckd->free[n].prev = i;
2216
2217 }
2218 ppos = pos;
2219 pos = cckd->free[i].pos;
2220 cckd->cdevhdr[sfx].free_number++;
2221 if (cckd->free[i].len > cckd->cdevhdr[sfx].free_largest
2222 && !cckd->free[i].pending)
2223 cckd->cdevhdr[sfx].free_largest = cckd->free[i].len;
2224 p = i;
2225 }
2226 cckd->freelast = p;
2227
2228 cckd_trace (dev, "rel_flush_space nbr %d (after merge)\n",
2229 cckd->cdevhdr[sfx].free_number);
2230
2231 /* If the last free space is at the end of the file then release it */
2232 if (p >= 0 && ppos + cckd->free[p].len == cckd->cdevhdr[sfx].size
2233 && !cckd->free[p].pending)
2234 {
2235 i = p;
2236 p = cckd->free[i].prev;
2237
2238 cckd_trace (dev, "file[%d] rel_flush_space atend 0x%" I64_FMT "x len %d\n",
2239 sfx, (long long)ppos, cckd->free[i].len);
2240
2241 /* Remove the entry from the chain */
2242 if (p >= 0)
2243 {
2244 cckd->free[p].pos = 0;
2245 cckd->free[p].next = -1;
2246 }
2247 else
2248 {
2249 cckd->cdevhdr[sfx].free = 0;
2250 cckd->free1st = -1;
2251 }
2252 cckd->freelast = p;
2253
2254 /* Add the entry to the available chain */
2255 cckd->free[i].next = cckd->freeavail;
2256 cckd->freeavail = i;
2257
2258 /* Update the device header */
2259 cckd->cdevhdr[sfx].size -= cckd->free[i].len;
2260 cckd->cdevhdr[sfx].free_total -= cckd->free[i].len;
2261 cckd->cdevhdr[sfx].free_number--;
2262 if (cckd->free[i].len >= cckd->cdevhdr[sfx].free_largest)
2263 {
2264 cckd->cdevhdr[sfx].free_largest = 0;
2265 for (i = cckd->free1st; i >= 0; i = cckd->free[i].next)
2266 if (cckd->free[i].len > cckd->cdevhdr[sfx].free_largest
2267 && cckd->free[i].pending == 0)
2268 cckd->cdevhdr[sfx].free_largest = cckd->free[i].len;
2269 }
2270
2271 /* Truncate the file */
2272 cckd_ftruncate (dev, sfx, (off_t)cckd->cdevhdr[sfx].size);
2273
2274 } /* Release space at end of the file */
2275
2276 // cckd_chk_space(dev);
2277
2278 } /* end function cckd_flush_space */
2279
2280 /*-------------------------------------------------------------------*/
2281 /* Read compressed dasd header */
2282 /*-------------------------------------------------------------------*/
cckd_read_chdr(DEVBLK * dev)2283 int cckd_read_chdr (DEVBLK *dev)
2284 {
2285 CCKDDASD_EXT *cckd; /* -> cckd extension */
2286 int sfx; /* File index */
2287
2288 cckd = dev->cckd_ext;
2289 sfx = cckd->sfn;
2290
2291 cckd_trace (dev, "file[%d] read_chdr\n", sfx);
2292
2293 memset (&cckd->cdevhdr[sfx], 0, CCKDDASD_DEVHDR_SIZE);
2294
2295 /* Read the device header */
2296 if (cckd_read (dev, sfx, CKDDASD_DEVHDR_SIZE, &cckd->cdevhdr[sfx], CCKDDASD_DEVHDR_SIZE) < 0)
2297 return -1;
2298
2299 /* Check endian format */
2300 cckd->swapend[sfx] = 0;
2301 if ((cckd->cdevhdr[sfx].options & CCKD_BIGENDIAN) != cckd_endian())
2302 {
2303 if (cckd->open[sfx] == CCKD_OPEN_RW)
2304 {
2305 if (cckd_swapend (dev) < 0)
2306 return -1;
2307 cckd_swapend_chdr (&cckd->cdevhdr[sfx]);
2308 }
2309 else
2310 {
2311 cckd->swapend[sfx] = 1;
2312 cckd_swapend_chdr (&cckd->cdevhdr[sfx]);
2313 }
2314 }
2315
2316 /* Set default null format */
2317 if (cckd->cdevhdr[sfx].nullfmt > CKDDASD_NULLTRK_FMTMAX)
2318 cckd->cdevhdr[sfx].nullfmt = 0;
2319
2320 if (cckd->cdevhdr[sfx].nullfmt == 0 && dev->oslinux && dev->devtype == 0x3390)
2321 cckd->cdevhdr[sfx].nullfmt = CKDDASD_NULLTRK_FMT2;
2322
2323 if (cckd->cdevhdr[sfx].nullfmt == CKDDASD_NULLTRK_FMT2)
2324 dev->oslinux = 1;
2325
2326 return 0;
2327
2328 } /* end function cckd_read_chdr */
2329
2330 /*-------------------------------------------------------------------*/
2331 /* Write compressed dasd header */
2332 /*-------------------------------------------------------------------*/
cckd_write_chdr(DEVBLK * dev)2333 int cckd_write_chdr (DEVBLK *dev)
2334 {
2335 CCKDDASD_EXT *cckd; /* -> cckd extension */
2336 int sfx; /* File index */
2337
2338 cckd = dev->cckd_ext;
2339 sfx = cckd->sfn;
2340
2341 cckd_trace (dev, "file[%d] write_chdr\n", sfx);
2342
2343 /* Set version.release.modlvl */
2344 cckd->cdevhdr[sfx].vrm[0] = CCKD_VERSION;
2345 cckd->cdevhdr[sfx].vrm[1] = CCKD_RELEASE;
2346 cckd->cdevhdr[sfx].vrm[2] = CCKD_MODLVL;
2347
2348 if (cckd_write (dev, sfx, CCKD_DEVHDR_POS, &cckd->cdevhdr[sfx], CCKD_DEVHDR_SIZE) < 0)
2349 return -1;
2350
2351 return 0;
2352
2353 } /* end function cckd_write_chdr */
2354
2355 /*-------------------------------------------------------------------*/
2356 /* Read the level 1 table */
2357 /*-------------------------------------------------------------------*/
cckd_read_l1(DEVBLK * dev)2358 int cckd_read_l1 (DEVBLK *dev)
2359 {
2360 CCKDDASD_EXT *cckd; /* -> cckd extension */
2361 int sfx; /* File index */
2362 int len; /* Length of level 1 table */
2363 int i; /* Work integer */
2364
2365 cckd = dev->cckd_ext;
2366 sfx = cckd->sfn;
2367
2368 cckd_trace (dev, "file[%d] read_l1 offset 0x%"I64_FMT"x\n",
2369 sfx, (U64)CCKD_L1TAB_POS);
2370
2371 /* Free the old level 1 table if it exists */
2372 cckd->l1[sfx] = cckd_free (dev, "l1", cckd->l1[sfx]);
2373
2374 /* Allocate the level 1 table */
2375 len = cckd->cdevhdr[sfx].numl1tab * CCKD_L1ENT_SIZE;
2376 if ((cckd->l1[sfx] = cckd_malloc (dev, "l1", len)) == NULL)
2377 return -1;
2378 memset(cckd->l1[sfx], sfx ? 0xFF : 0, len);
2379
2380 /* Read the level 1 table */
2381 if (cckd_read (dev, sfx, CCKD_L1TAB_POS, cckd->l1[sfx], len) < 0)
2382 return -1;
2383
2384 /* Fix endianess */
2385 if (cckd->swapend[sfx])
2386 cckd_swapend_l1 (cckd->l1[sfx], cckd->cdevhdr[sfx].numl1tab);
2387
2388 /* Determine bounds */
2389 cckd->l2bounds = CCKD_L1TAB_POS + len;
2390 for (i = 0; i < cckd->cdevhdr[sfx].numl1tab; i++)
2391 if (cckd->l1[sfx][i] != 0 && cckd->l1[sfx][i] != 0xffffffff)
2392 cckd->l2bounds += CCKD_L2TAB_SIZE;
2393
2394 /* Check if all l2 tables are within bounds */
2395 cckd->l2ok = 1;
2396 for (i = 0; i < cckd->cdevhdr[sfx].numl1tab && cckd->l2ok; i++)
2397 if (cckd->l1[sfx][i] != 0 && cckd->l1[sfx][i] != 0xffffffff)
2398 if (cckd->l1[sfx][i] > cckd->l2bounds - CCKD_L2TAB_SIZE)
2399 cckd->l2ok = 0;
2400
2401 return 0;
2402
2403 } /* end function cckd_read_l1 */
2404
2405 /*-------------------------------------------------------------------*/
2406 /* Write the level 1 table */
2407 /*-------------------------------------------------------------------*/
cckd_write_l1(DEVBLK * dev)2408 int cckd_write_l1 (DEVBLK *dev)
2409 {
2410 CCKDDASD_EXT *cckd; /* -> cckd extension */
2411 int sfx; /* File index */
2412 int len; /* Length of level 1 table */
2413
2414 cckd = dev->cckd_ext;
2415 sfx = cckd->sfn;
2416 len = cckd->cdevhdr[sfx].numl1tab * CCKD_L1ENT_SIZE;
2417
2418 cckd_trace (dev, "file[%d] write_l1 0x%"I64_FMT"x len %d\n",
2419 sfx, (U64)CCKD_L1TAB_POS, len);
2420
2421 if (cckd_write (dev, sfx, CCKD_L1TAB_POS, cckd->l1[sfx], len) < 0)
2422 return -1;
2423
2424 return 0;
2425
2426 } /* end function cckd_write_l1 */
2427
2428 /*-------------------------------------------------------------------*/
2429 /* Update a level 1 table entry */
2430 /*-------------------------------------------------------------------*/
cckd_write_l1ent(DEVBLK * dev,int l1x)2431 int cckd_write_l1ent (DEVBLK *dev, int l1x)
2432 {
2433 CCKDDASD_EXT *cckd; /* -> cckd extension */
2434 int sfx; /* File index */
2435 off_t off; /* Offset to l1 entry */
2436
2437 cckd = dev->cckd_ext;
2438 sfx = cckd->sfn;
2439 off = (off_t)(CCKD_L1TAB_POS + l1x * CCKD_L1ENT_SIZE);
2440
2441 cckd_trace (dev, "file[%d] write_l1ent[%d] , 0x%" I64_FMT "x\n",
2442 sfx, l1x, (long long)off);
2443
2444 if (cckd_write (dev, sfx, off, &cckd->l1[sfx][l1x], CCKD_L1ENT_SIZE) < 0)
2445 return -1;
2446
2447 return 0;
2448
2449 } /* end function cckd_write_l1ent */
2450
2451 /*-------------------------------------------------------------------*/
2452 /* Initial read */
2453 /*-------------------------------------------------------------------*/
cckd_read_init(DEVBLK * dev)2454 int cckd_read_init (DEVBLK *dev)
2455 {
2456 CCKDDASD_EXT *cckd; /* -> cckd extension */
2457 int sfx; /* File index */
2458 CKDDASD_DEVHDR devhdr; /* Device header */
2459
2460 cckd = dev->cckd_ext;
2461 sfx = cckd->sfn;
2462
2463 cckd_trace (dev, "file[%d] read_init\n", sfx);
2464
2465 /* Read the device header */
2466 if (cckd_read (dev, sfx, 0, &devhdr, CKDDASD_DEVHDR_SIZE) < 0)
2467 return -1;
2468
2469 /* Check the device hdr */
2470 if (sfx == 0 && memcmp (&devhdr.devid, "CKD_C370", 8) == 0)
2471 cckd->ckddasd = 1;
2472 else if (sfx == 0 && memcmp (&devhdr.devid, "FBA_C370", 8) == 0)
2473 cckd->fbadasd = 1;
2474 else if (!(sfx && memcmp (&devhdr.devid, "CKD_S370", 8) == 0 && cckd->ckddasd)
2475 && !(sfx && memcmp (&devhdr.devid, "FBA_S370", 8) == 0 && cckd->fbadasd))
2476 {
2477 logmsg (_("HHCCD110E %4.4X file[%d] devhdr id error\n"),
2478 dev->devnum, sfx);
2479 return -1;
2480 }
2481
2482 /* Read the compressed header */
2483 if (cckd_read_chdr (dev) < 0)
2484 return -1;
2485
2486 /* Read the level 1 table */
2487 if (cckd_read_l1 (dev) < 0)
2488 return -1;
2489
2490 return 0;
2491 } /* end function cckd_read_init */
2492
2493 /*-------------------------------------------------------------------*/
2494 /* Read free space */
2495 /*-------------------------------------------------------------------*/
cckd_read_fsp(DEVBLK * dev)2496 int cckd_read_fsp (DEVBLK *dev)
2497 {
2498 CCKDDASD_EXT *cckd; /* -> cckd extension */
2499 off_t fpos; /* Free space offset */
2500 int sfx; /* File index */
2501 int i; /* Index */
2502 CCKD_FREEBLK freeblk; /* First freeblk read */
2503
2504 cckd = dev->cckd_ext;
2505 sfx = cckd->sfn;
2506
2507 cckd_trace (dev, "file[%d] read_fsp number %d\n",
2508 sfx, cckd->cdevhdr[sfx].free_number);
2509
2510 cckd->free = cckd_free (dev, "free", cckd->free);
2511 cckd->free1st = cckd->freelast = cckd->freeavail = -1;
2512
2513 /* Get storage for the internal free space chain
2514 * in a multiple of 1024 entries
2515 */
2516 cckd->freenbr = (cckd->cdevhdr[sfx].free_number + 1023) & ~0x3FF;
2517 if (cckd->freenbr)
2518 if ((cckd->free = cckd_calloc (dev, "free", cckd->freenbr, CCKD_FREEBLK_ISIZE)) == NULL)
2519 return -1;
2520
2521 /* Build the doubly linked internal free space chain */
2522 if (cckd->cdevhdr[sfx].free_number)
2523 {
2524 cckd->free1st = 0;
2525
2526 /* Read the first freeblk to determine old/new format */
2527 fpos = (off_t)cckd->cdevhdr[sfx].free;
2528 if (cckd_read (dev, sfx, fpos, &freeblk, CCKD_FREEBLK_SIZE) < 0)
2529 return -1;
2530
2531 if (memcmp(&freeblk, "FREE_BLK", 8) == 0)
2532 {
2533 /* new format free space */
2534 CCKD_FREEBLK *fsp;
2535 U32 ofree = cckd->cdevhdr[sfx].free;
2536 int n = cckd->cdevhdr[sfx].free_number * CCKD_FREEBLK_SIZE;
2537 if ((fsp = cckd_malloc (dev, "fsp", n)) == NULL)
2538 return -1;
2539 fpos += CCKD_FREEBLK_SIZE;
2540 if (cckd_read (dev, sfx, fpos, fsp, n) < 0)
2541 return -1;
2542 for (i = 0; i < cckd->cdevhdr[sfx].free_number; i++)
2543 {
2544 if (i == 0)
2545 cckd->cdevhdr[sfx].free = fsp[i].pos;
2546 else
2547 cckd->free[i-1].pos = fsp[i].pos;
2548 cckd->free[i].pos = 0;
2549 cckd->free[i].len = fsp[i].len;
2550 cckd->free[i].prev = i - 1;
2551 cckd->free[i].next = i + 1;
2552 }
2553 cckd->free[i-1].next = -1;
2554 cckd->freelast = i-1;
2555 fsp = cckd_free (dev, "fsp", fsp);
2556
2557 /* truncate if new format free space was at the end */
2558 if (ofree == cckd->cdevhdr[sfx].size)
2559 {
2560 fpos = (off_t)cckd->cdevhdr[sfx].size;
2561 cckd_ftruncate(dev, sfx, fpos);
2562 }
2563 } /* new format free space */
2564 else
2565 {
2566 /* old format free space */
2567 fpos = (off_t)cckd->cdevhdr[sfx].free;
2568 for (i = 0; i < cckd->cdevhdr[sfx].free_number; i++)
2569 {
2570 if (cckd_read (dev, sfx, fpos, &cckd->free[i], CCKD_FREEBLK_SIZE) < 0)
2571 return -1;
2572 cckd->free[i].prev = i - 1;
2573 cckd->free[i].next = i + 1;
2574 fpos = (off_t)cckd->free[i].pos;
2575 }
2576 cckd->free[i-1].next = -1;
2577 cckd->freelast = i-1;
2578 } /* old format free space */
2579 } /* if (cckd->cdevhdr[sfx].free_number) */
2580
2581 /* Build singly linked chain of available free space entries */
2582 if (cckd->cdevhdr[sfx].free_number < cckd->freenbr)
2583 {
2584 cckd->freeavail = cckd->cdevhdr[sfx].free_number;
2585 for (i = cckd->freeavail; i < cckd->freenbr; i++)
2586 cckd->free[i].next = i + 1;
2587 cckd->free[i-1].next = -1;
2588 }
2589
2590 /* Set minimum free space size */
2591 cckd->freemin = CCKD_FREE_MIN_SIZE + ((cckd->freenbr >> 10) * CCKD_FREE_MIN_INCR);
2592 return 0;
2593
2594 } /* end function cckd_read_fsp */
2595
2596 /*-------------------------------------------------------------------*/
2597 /* Write the free space */
2598 /*-------------------------------------------------------------------*/
cckd_write_fsp(DEVBLK * dev)2599 int cckd_write_fsp (DEVBLK *dev)
2600 {
2601 CCKDDASD_EXT *cckd; /* -> cckd extension */
2602 off_t fpos; /* Free space offset */
2603 U32 ppos; /* Previous free space offset*/
2604 int sfx; /* File index */
2605 int i, j, n; /* Work variables */
2606 int rc; /* Return code */
2607 CCKD_FREEBLK *fsp = NULL; /* -> new format free space */
2608
2609 cckd = dev->cckd_ext;
2610 sfx = cckd->sfn;
2611
2612 if (cckd->free == NULL)
2613 return 0;
2614
2615 cckd_trace (dev, "file[%d] write_fsp number %d\n",
2616 sfx, cckd->cdevhdr[sfx].free_number);
2617
2618 /* get rid of pending free space */
2619 for (i = 0; i < CCKD_MAX_FREEPEND; i++)
2620 cckd_flush_space(dev);
2621
2622 /* sanity checks */
2623 if (cckd->cdevhdr[sfx].free_number == 0 || cckd->cdevhdr[sfx].free == 0)
2624 {
2625 cckd->cdevhdr[sfx].free_number = cckd->cdevhdr[sfx].free = 0;
2626 cckd->free1st = cckd->freelast = cckd->freeavail = -1;
2627 }
2628
2629 /* Write any free spaces */
2630 if (cckd->cdevhdr[sfx].free)
2631 {
2632 /* size needed for new format free space */
2633 n = (cckd->cdevhdr[sfx].free_number+1) * CCKD_FREEBLK_SIZE;
2634
2635 /* look for existing free space to fit new format free space */
2636 fpos = 0;
2637 for (i = cckd->free1st; i >= 0; i = cckd->free[i].next)
2638 if (n <= (int)cckd->free[i].len)
2639 break;
2640 if (i >= 0)
2641 fpos = cckd->free[i].prev < 0
2642 ? (off_t)cckd->cdevhdr[sfx].free
2643 : (off_t)cckd->free[cckd->free[i].prev].pos;
2644
2645 /* if no applicable space see if we can append to the file */
2646 if (fpos == 0 && cckd->maxsize - cckd->cdevhdr[sfx].size >= n)
2647 fpos = (off_t)cckd->cdevhdr[sfx].size;
2648
2649 if (fpos && (fsp = cckd_malloc (dev, "fsp", n)) == NULL)
2650 fpos = 0;
2651
2652 if (fpos)
2653 {
2654 /* New format free space */
2655 memcpy (&fsp[0], "FREE_BLK", 8);
2656 ppos = cckd->cdevhdr[sfx].free;
2657 for (i = cckd->free1st, j = 1; i >= 0; i = cckd->free[i].next)
2658 {
2659 fsp[j].pos = ppos;
2660 fsp[j++].len = cckd->free[i].len;
2661 ppos = cckd->free[i].pos;
2662 }
2663 rc = cckd_write (dev, sfx, fpos, fsp, n);
2664 fsp = cckd_free (dev, "fsp", fsp);
2665 if (rc < 0)
2666 return -1;
2667 cckd->cdevhdr[sfx].free = (U32)fpos;
2668 } /* new format free space */
2669 else
2670 {
2671 /* Old format free space */
2672 for (i = cckd->free1st; i >= 0; i = cckd->free[i].next)
2673 {
2674 if (cckd_write (dev, sfx, fpos, &cckd->free[i], CCKD_FREEBLK_SIZE) < 0)
2675 return -1;
2676 fpos = (off_t)cckd->free[i].pos;
2677 }
2678 } /* old format free space */
2679 } /* if (cckd->cdevhdr[sfx].free) */
2680
2681 /* Free the free space array */
2682 cckd->free = cckd_free (dev, "free", cckd->free);
2683 cckd->freenbr = 0;
2684 cckd->free1st = cckd->freelast = cckd->freeavail = -1;
2685
2686 return 0;
2687
2688 } /* end function cckd_write_fsp */
2689
2690 /*-------------------------------------------------------------------*/
2691 /* Read a new level 2 table */
2692 /*-------------------------------------------------------------------*/
cckd_read_l2(DEVBLK * dev,int sfx,int l1x)2693 int cckd_read_l2 (DEVBLK *dev, int sfx, int l1x)
2694 {
2695 CCKDDASD_EXT *cckd; /* -> cckd extension */
2696 off_t off; /* L2 file offset */
2697 int fnd; /* Found cache */
2698 int lru; /* Oldest available cache */
2699 CCKD_L2ENT *buf; /* -> Cache buffer */
2700 int i; /* Loop index */
2701 int nullfmt; /* Null track format */
2702
2703 cckd = dev->cckd_ext;
2704 nullfmt = cckd->cdevhdr[cckd->sfn].nullfmt;
2705
2706 cckd_trace (dev, "file[%d] read_l2 %d active %d %d %d\n",
2707 sfx, l1x, cckd->sfx, cckd->l1x, cckd->l2active);
2708
2709 /* Return if table is already active */
2710 if (sfx == cckd->sfx && l1x == cckd->l1x) return 0;
2711
2712 cache_lock(CACHE_L2);
2713
2714 /* Inactivate the previous entry */
2715 if (cckd->l2active >= 0)
2716 cache_setflag(CACHE_L2, cckd->l2active, ~L2_CACHE_ACTIVE, 0);
2717 cckd->l2 = NULL;
2718 cckd->l2active = cckd->sfx = cckd->l1x = -1;
2719
2720 /* scan the cache array for the l2tab */
2721 fnd = cache_lookup (CACHE_L2, L2_CACHE_SETKEY(sfx, dev->devnum, l1x), &lru);
2722
2723 /* check for level 2 cache hit */
2724 if (fnd >= 0)
2725 {
2726 cckd_trace (dev, "l2[%d,%d] cache[%d] hit\n", sfx, l1x, fnd);
2727 cache_setflag (CACHE_L2, fnd, 0, L2_CACHE_ACTIVE);
2728 cache_setage (CACHE_L2, fnd);
2729 cckdblk.stats_l2cachehits++;
2730 cache_unlock (CACHE_L2);
2731 cckd->sfx = sfx;
2732 cckd->l1x = l1x;
2733 cckd->l2 = cache_getbuf(CACHE_L2, fnd, 0);
2734 cckd->l2active = fnd;
2735 return 1;
2736 }
2737
2738 cckd_trace (dev, "l2[%d,%d] cache[%d] miss\n", sfx, l1x, lru);
2739
2740 /* Steal an entry if all are busy */
2741 if (lru < 0) lru = cckd_steal_l2();
2742
2743 /* Make the entry active */
2744 cache_setkey (CACHE_L2, lru, L2_CACHE_SETKEY(sfx, dev->devnum, l1x));
2745 cache_setflag (CACHE_L2, lru, 0, L2_CACHE_ACTIVE);
2746 cache_setage (CACHE_L2, lru);
2747 buf = cache_getbuf(CACHE_L2, lru, CCKD_L2TAB_SIZE);
2748 cckdblk.stats_l2cachemisses++;
2749 cache_unlock (CACHE_L2);
2750 if (buf == NULL) return -1;
2751
2752 /* Check for null table */
2753 if (cckd->l1[sfx][l1x] == 0)
2754 {
2755 memset(buf, 0, CCKD_L2TAB_SIZE);
2756 if (nullfmt)
2757 for (i = 0; i < 256; i++)
2758 buf[i].len = buf[i].size = nullfmt;
2759 cckd_trace (dev, "l2[%d,%d] cache[%d] null fmt[%d]\n", sfx, l1x, lru, nullfmt);
2760 }
2761 else if (cckd->l1[sfx][l1x] == 0xffffffff)
2762 {
2763 memset(buf, 0xff, CCKD_L2TAB_SIZE);
2764 cckd_trace (dev, "l2[%d,%d] cache[%d] null 0xff\n", sfx, l1x, lru);
2765 }
2766 /* Read the new level 2 table */
2767 else
2768 {
2769 off = (off_t)cckd->l1[sfx][l1x];
2770 if (cckd_read (dev, sfx, off, buf, CCKD_L2TAB_SIZE) < 0)
2771 {
2772 cache_lock(CACHE_L2);
2773 cache_setflag(CACHE_L2, lru, 0, 0);
2774 cache_unlock(CACHE_L2);
2775 return -1;
2776 }
2777
2778 if (cckd->swapend[sfx])
2779 cckd_swapend_l2 (buf);
2780
2781 cckd_trace (dev, "file[%d] cache[%d] l2[%d] read offset 0x%" I64_FMT "x\n",
2782 sfx, lru, l1x, (long long)cckd->l1[sfx][l1x]);
2783
2784 cckd->l2reads[sfx]++;
2785 cckd->totl2reads++;
2786 cckdblk.stats_l2reads++;
2787 }
2788
2789 cckd->sfx = sfx;
2790 cckd->l1x = l1x;
2791 cckd->l2 = buf;
2792 cckd->l2active = lru;
2793
2794 return 0;
2795
2796 } /* end function cckd_read_l2 */
2797
2798 /*-------------------------------------------------------------------*/
2799 /* Purge all l2tab cache entries for a given device */
2800 /*-------------------------------------------------------------------*/
cckd_purge_l2(DEVBLK * dev)2801 void cckd_purge_l2 (DEVBLK *dev)
2802 {
2803 CCKDDASD_EXT *cckd; /* -> cckd extension */
2804
2805 cckd = dev->cckd_ext;
2806
2807 cckd_trace (dev, "purge_l2%s\n", "");
2808
2809 cache_lock (CACHE_L2);
2810 cckd->l2active = cckd->sfx = cckd->l1x = -1;
2811 cckd->l2 = NULL;
2812 cache_scan (CACHE_L2, cckd_purge_l2_scan, dev);
2813 cache_unlock (CACHE_L2);
2814 }
cckd_purge_l2_scan(int * answer,int ix,int i,void * data)2815 int cckd_purge_l2_scan (int *answer, int ix, int i, void *data)
2816 {
2817 U16 sfx; /* Cached suffix */
2818 U16 devnum; /* Cached device number */
2819 U32 l1x; /* Cached level 1 index */
2820 DEVBLK *dev = data; /* -> device block */
2821
2822 UNREFERENCED(answer);
2823 L2_CACHE_GETKEY(i, sfx, devnum, l1x);
2824 if (dev == NULL || devnum == dev->devnum)
2825 {
2826 cckd_trace (dev, "purge l2cache[%d] %4.4X sfx %d ix %d purged\n",
2827 i, devnum, sfx, l1x);
2828 cache_release(ix, i, 0);
2829 }
2830 return 0;
2831 }
2832
2833 /*-------------------------------------------------------------------*/
2834 /* Steal an l2tab cache entry */
2835 /*-------------------------------------------------------------------*/
cckd_steal_l2()2836 int cckd_steal_l2 ()
2837 {
2838 DEVBLK *dev; /* -> device block */
2839 CCKDDASD_EXT *cckd; /* -> cckd extension */
2840 int i; /* Stolen cache index */
2841 U16 sfx; /* Cached suffix */
2842 U16 devnum; /* Cached device number */
2843 U32 l1x; /* Cached level 1 index */
2844
2845 i = cache_scan (CACHE_L2, cckd_steal_l2_scan, NULL);
2846 L2_CACHE_GETKEY(i, sfx, devnum, l1x);
2847 dev = cckd_find_device_by_devnum(devnum);
2848 cckd = dev->cckd_ext;
2849 cckd->l2active = cckd->sfx = cckd->l1x = -1;
2850 cckd->l2 = NULL;
2851 cache_release(CACHE_L2, i, 0);
2852 return i;
2853 }
cckd_steal_l2_scan(int * answer,int ix,int i,void * data)2854 int cckd_steal_l2_scan (int *answer, int ix, int i, void *data)
2855 {
2856 UNREFERENCED(data);
2857 if (*answer < 0) *answer = i;
2858 else if (cache_getage(ix, i) < cache_getage(ix, *answer))
2859 *answer = i;
2860 return 0;
2861 }
2862
2863 /*-------------------------------------------------------------------*/
2864 /* Write the current level 2 table */
2865 /*-------------------------------------------------------------------*/
cckd_write_l2(DEVBLK * dev)2866 int cckd_write_l2 (DEVBLK *dev)
2867 {
2868 CCKDDASD_EXT *cckd; /* -> cckd extension */
2869 int sfx,l1x; /* Lookup table indices */
2870 off_t off, old_off; /* New/old L2 file offsets */
2871 int size = CCKD_L2TAB_SIZE; /* L2 table size */
2872 int fix; /* Null format type */
2873
2874 cckd = dev->cckd_ext;
2875 sfx = cckd->sfn;
2876 l1x = cckd->l1x;
2877 fix = cckd->cdevhdr[sfx].nullfmt;
2878 cckd->l2ok = 0;
2879
2880 cckd_trace (dev, "file[%d] write_l2 %d\n", sfx, l1x);
2881
2882 if (sfx < 0 || l1x < 0) return -1;
2883
2884 old_off = (off_t)cckd->l1[sfx][l1x];
2885
2886 if (cckd->l1[sfx][l1x] == 0 || cckd->l1[sfx][l1x] == 0xffffffff)
2887 cckd->l2bounds += CCKD_L2TAB_SIZE;
2888
2889 /* Write the L2 table if it's not empty */
2890 if (memcmp(cckd->l2, &empty_l2[fix], CCKD_L2TAB_SIZE))
2891 {
2892 if ((off = cckd_get_space (dev, &size, CCKD_L2SPACE)) < 0)
2893 return -1;
2894 if (cckd_write (dev, sfx, off, cckd->l2, CCKD_L2TAB_SIZE) < 0)
2895 return -1;
2896 }
2897 else
2898 {
2899 off = 0;
2900 cckd->l2bounds -= CCKD_L2TAB_SIZE;
2901 }
2902
2903 /* Free the old L2 space */
2904 cckd_rel_space (dev, old_off, CCKD_L2TAB_SIZE, CCKD_L2TAB_SIZE);
2905
2906 /* Update level 1 table */
2907 cckd->l1[sfx][l1x] = (U32)off;
2908 if (cckd_write_l1ent (dev, l1x) < 0)
2909 return -1;
2910
2911 return 0;
2912
2913 } /* end function cckd_write_l2 */
2914
2915 /*-------------------------------------------------------------------*/
2916 /* Return a level 2 entry */
2917 /*-------------------------------------------------------------------*/
cckd_read_l2ent(DEVBLK * dev,CCKD_L2ENT * l2,int trk)2918 int cckd_read_l2ent (DEVBLK *dev, CCKD_L2ENT *l2, int trk)
2919 {
2920 CCKDDASD_EXT *cckd; /* -> cckd extension */
2921 int sfx,l1x,l2x; /* Lookup table indices */
2922
2923 cckd = dev->cckd_ext;
2924
2925 l1x = trk >> 8;
2926 l2x = trk & 0xff;
2927
2928 if (l2 != NULL) l2->pos = l2->len = l2->size = 0;
2929
2930 for (sfx = cckd->sfn; sfx >= 0; sfx--)
2931 {
2932 cckd_trace (dev, "file[%d] l2[%d,%d] trk[%d] read_l2ent 0x%x\n",
2933 sfx, l1x, l2x, trk, cckd->l1[sfx][l1x]);
2934
2935 /* Continue if l2 table not in this file */
2936 if (cckd->l1[sfx][l1x] == 0xffffffff)
2937 continue;
2938
2939 /* Read l2 table from this file */
2940 if (cckd_read_l2 (dev, sfx, l1x) < 0)
2941 return -1;
2942
2943 /* Exit loop if track is in this file */
2944 if (cckd->l2[l2x].pos != 0xffffffff)
2945 break;
2946 }
2947
2948 cckd_trace (dev, "file[%d] l2[%d,%d] trk[%d] read_l2ent 0x%x %d %d\n",
2949 sfx, l1x, l2x, trk, sfx >= 0 ? cckd->l2[l2x].pos : 0,
2950 sfx >= 0 ? cckd->l2[l2x].len : 0,
2951 sfx >= 0 ? cckd->l2[l2x].size : 0);
2952
2953 if (l2 != NULL && sfx >= 0)
2954 {
2955 l2->pos = cckd->l2[l2x].pos;
2956 l2->len = cckd->l2[l2x].len;
2957 l2->size = cckd->l2[l2x].size;
2958 }
2959
2960 return sfx;
2961
2962 } /* end function cckd_read_l2ent */
2963
2964 /*-------------------------------------------------------------------*/
2965 /* Update a level 2 entry */
2966 /*-------------------------------------------------------------------*/
cckd_write_l2ent(DEVBLK * dev,CCKD_L2ENT * l2,int trk)2967 int cckd_write_l2ent (DEVBLK *dev, CCKD_L2ENT *l2, int trk)
2968 {
2969 CCKDDASD_EXT *cckd; /* -> cckd extension */
2970 int sfx,l1x,l2x; /* Lookup table indices */
2971 off_t off; /* L2 entry offset */
2972
2973 cckd = dev->cckd_ext;
2974
2975 /* Error return if no available level 2 table */
2976 if (!cckd->l2) return -1;
2977
2978 sfx = cckd->sfn;
2979 l1x = trk >> 8;
2980 l2x = trk & 0xff;
2981
2982 /* Copy the new entry if passed */
2983 if (l2) memcpy (&cckd->l2[l2x], l2, CCKD_L2ENT_SIZE);
2984
2985 cckd_trace (dev, "file[%d] l2[%d,%d] trk[%d] write_l2ent 0x%x %d %d\n",
2986 sfx, l1x, l2x, trk,
2987 cckd->l2[l2x].pos, cckd->l2[l2x].len, cckd->l2[l2x].size);
2988
2989 /* If no level 2 table for this file, then write a new one */
2990 if (cckd->l1[sfx][l1x] == 0 || cckd->l1[sfx][l1x] == 0xffffffff)
2991 return cckd_write_l2 (dev);
2992
2993 /* Write the level 2 table entry */
2994 off = (off_t)(cckd->l1[sfx][l1x] + l2x * CCKD_L2ENT_SIZE);
2995 if (cckd_write (dev, sfx, off, &cckd->l2[l2x], CCKD_L2ENT_SIZE) < 0)
2996 return -1;
2997
2998 return 0;
2999 } /* end function cckd_write_l2ent */
3000
3001 /*-------------------------------------------------------------------*/
3002 /* Read a track image */
3003 /*-------------------------------------------------------------------*/
cckd_read_trkimg(DEVBLK * dev,BYTE * buf,int trk,BYTE * unitstat)3004 int cckd_read_trkimg (DEVBLK *dev, BYTE *buf, int trk, BYTE *unitstat)
3005 {
3006 CCKDDASD_EXT *cckd; /* -> cckd extension */
3007 int rc; /* Return code */
3008 int sfx; /* File index */
3009 CCKD_L2ENT l2; /* Level 2 entry */
3010
3011 cckd = dev->cckd_ext;
3012
3013 cckd_trace (dev, "trk[%d] read_trkimg\n", trk);
3014
3015 /* Read level 2 entry for the track */
3016 if ((sfx = cckd_read_l2ent (dev, &l2, trk)) < 0)
3017 goto cckd_read_trkimg_error;
3018
3019 /* Read the track image or build a null track image */
3020 if (l2.pos != 0)
3021 {
3022 rc = cckd_read (dev, sfx, (off_t)l2.pos, buf, (size_t)l2.len);
3023 if (rc < 0)
3024 goto cckd_read_trkimg_error;
3025
3026 cckd->reads[sfx]++;
3027 cckd->totreads++;
3028 cckdblk.stats_reads++;
3029 cckdblk.stats_readbytes += rc;
3030 if (cckd->notnull == 0 && trk > 1) cckd->notnull = 1;
3031 }
3032 else
3033 rc = cckd_null_trk (dev, buf, trk, l2.len);
3034
3035 /* Validate the track image */
3036 if (cckd_cchh (dev, buf, trk) < 0)
3037 goto cckd_read_trkimg_error;
3038
3039 return rc;
3040
3041 cckd_read_trkimg_error:
3042
3043 if (unitstat)
3044 {
3045 ckd_build_sense (dev, SENSE_EC, 0, 0, FORMAT_1, MESSAGE_0);
3046 *unitstat = CSW_CE | CSW_DE | CSW_UC;
3047 }
3048
3049 return cckd_null_trk (dev, buf, trk, 0);
3050
3051 } /* end function cckd_read_trkimg */
3052
3053 /*-------------------------------------------------------------------*/
3054 /* Write a track image */
3055 /*-------------------------------------------------------------------*/
cckd_write_trkimg(DEVBLK * dev,BYTE * buf,int len,int trk,int flags)3056 int cckd_write_trkimg (DEVBLK *dev, BYTE *buf, int len, int trk, int flags)
3057 {
3058 CCKDDASD_EXT *cckd; /* -> cckd extension */
3059 int rc; /* Return code */
3060 off_t off; /* File offset */
3061 CCKD_L2ENT l2, oldl2; /* Level 2 entries */
3062 int sfx,l1x,l2x; /* Lookup table indices */
3063 int after = 0; /* 1=New track after old */
3064 int size; /* Size of new track */
3065
3066 cckd = dev->cckd_ext;
3067
3068 sfx = cckd->sfn;
3069 l1x = trk >> 8;
3070 l2x = trk & 0xff;
3071
3072 cckd_trace (dev, "file[%d] trk[%d] write_trkimg len %d buf %p:%2.2x%2.2x%2.2x%2.2x%2.2x\n",
3073 sfx, trk, len, buf, buf[0], buf[1], buf[2], buf[3], buf[4]);
3074
3075 /* Validate the new track image */
3076 if (cckd_cchh (dev, buf, trk) < 0)
3077 return -1;
3078
3079 /* Get the level 2 table for the track in the active file */
3080 if (cckd_read_l2 (dev, sfx, l1x) < 0)
3081 return -1;
3082
3083 /* Save the level 2 entry for the track */
3084 oldl2.pos = cckd->l2[l2x].pos;
3085 oldl2.len = cckd->l2[l2x].len;
3086 oldl2.size = cckd->l2[l2x].size;
3087 cckd_trace (dev, "file[%d] trk[%d] write_trkimg oldl2 0x%x %d %d\n",
3088 sfx, trk, oldl2.pos,oldl2.len,oldl2.size);
3089
3090 /* Check if writing a null track */
3091 len = cckd_check_null_trk(dev, buf, trk, len);
3092
3093 if (len > CKDDASD_NULLTRK_FMTMAX)
3094 {
3095 /* Get space for the track image */
3096 size = len;
3097 if ((off = cckd_get_space (dev, &size, flags)) < 0)
3098 return -1;
3099
3100 l2.pos = (U32)off;
3101 l2.len = (U16)len;
3102 l2.size = (U16)size;
3103
3104 if (oldl2.pos != 0 && oldl2.pos != 0xffffffff && oldl2.pos < l2.pos)
3105 after = 1;
3106
3107 /* Write the track image */
3108 if ((rc = cckd_write (dev, sfx, off, buf, len)) < 0)
3109 return -1;
3110
3111 cckd->writes[sfx]++;
3112 cckd->totwrites++;
3113 cckdblk.stats_writes++;
3114 cckdblk.stats_writebytes += rc;
3115 }
3116 else
3117 {
3118 l2.pos = 0;
3119 l2.len = l2.size = (U16)len;
3120 }
3121
3122 /* Update the level 2 entry */
3123 if (cckd_write_l2ent (dev, &l2, trk) < 0)
3124 return -1;
3125
3126 /* Release the previous space */
3127 cckd_rel_space (dev, (off_t)oldl2.pos, (int)oldl2.len, (int)oldl2.size);
3128
3129 /* `after' is 1 if the new offset is after the old offset */
3130 return after;
3131
3132 } /* end function cckd_write_trkimg */
3133
3134 /*-------------------------------------------------------------------*/
3135 /* Harden the file */
3136 /*-------------------------------------------------------------------*/
cckd_harden(DEVBLK * dev)3137 int cckd_harden(DEVBLK *dev)
3138 {
3139 CCKDDASD_EXT *cckd; /* -> cckd extension */
3140 int rc=0; /* Return code */
3141
3142 cckd = dev->cckd_ext;
3143
3144 if ((dev->ckdrdonly && cckd->sfn == 0)
3145 || cckd->open[cckd->sfn] != CCKD_OPEN_RW)
3146 return 0;
3147
3148 cckd_trace (dev, "file[%d] harden\n", cckd->sfn);
3149
3150 /* Write the compressed device header */
3151 if (cckd_write_chdr (dev) < 0)
3152 rc = -1;
3153
3154 /* Write the level 1 table */
3155 if (cckd_write_l1 (dev) < 0)
3156 rc = -1;
3157
3158 /* Write the free space chain */
3159 if (cckd_write_fsp (dev) < 0)
3160 rc = -1;
3161
3162 /* Re-write the compressed device header */
3163 cckd->cdevhdr[cckd->sfn].options &= ~CCKD_OPENED;
3164 if (cckd_write_chdr (dev) < 0)
3165 rc = -1;
3166
3167 if (cckdblk.fsync)
3168 fdatasync (cckd->fd[cckd->sfn]);
3169
3170 return rc;
3171 } /* cckd_harden */
3172
3173 /*-------------------------------------------------------------------*/
3174 /* Return length of an uncompressed track image */
3175 /*-------------------------------------------------------------------*/
cckd_trklen(DEVBLK * dev,BYTE * buf)3176 int cckd_trklen (DEVBLK *dev, BYTE *buf)
3177 {
3178 CCKDDASD_EXT *cckd; /* -> cckd extension */
3179 int size; /* Track size */
3180
3181 cckd = dev->cckd_ext;
3182
3183 if (cckd->fbadasd)
3184 return CKDDASD_TRKHDR_SIZE + CFBA_BLOCK_SIZE;
3185
3186 for (size = CKDDASD_TRKHDR_SIZE;
3187 memcmp (&buf[size], &eighthexFF, 8) != 0; )
3188 {
3189 if (size > dev->ckdtrksz) break;
3190
3191 /* add length of count, key, and data fields */
3192 size += CKDDASD_RECHDR_SIZE +
3193 buf[size+5] +
3194 (buf[size+6] << 8) + buf[size+7];
3195 }
3196
3197 /* add length for end-of-track indicator */
3198 size += CKDDASD_RECHDR_SIZE;
3199
3200 /* check for missing end-of-track indicator */
3201 if (size > dev->ckdtrksz ||
3202 memcmp (&buf[size-CKDDASD_RECHDR_SIZE], &eighthexFF, 8) != 0)
3203 {
3204 logmsg (_("HHCCD121E %4.4X file[%d] trklen err for %2.2x%2.2x%2.2x%2.2x%2.2x\n"),
3205 dev->devnum, cckd->sfn, buf[0], buf[1], buf[2], buf[3], buf[4]);
3206 size = -1;
3207 }
3208
3209 return size;
3210 }
3211
3212 /*-------------------------------------------------------------------*/
3213 /* Build a null track */
3214 /*-------------------------------------------------------------------*/
cckd_null_trk(DEVBLK * dev,BYTE * buf,int trk,int nullfmt)3215 int cckd_null_trk(DEVBLK *dev, BYTE *buf, int trk, int nullfmt)
3216 {
3217 CCKDDASD_EXT *cckd; /* -> cckd extension */
3218 int i; /* Loop counter */
3219 CKDDASD_TRKHDR *trkhdr; /* -> Track header */
3220 CKDDASD_RECHDR *rechdr; /* -> Record header */
3221 U32 cyl; /* Cylinder number */
3222 U32 head; /* Head number */
3223 BYTE r; /* Record number */
3224 BYTE *pos; /* -> Next position in buffer*/
3225 int len; /* Length of null track */
3226
3227 cckd = dev->cckd_ext;
3228
3229 if (nullfmt < 0 || nullfmt > CKDDASD_NULLTRK_FMTMAX)
3230 nullfmt = cckd->cdevhdr[cckd->sfn].nullfmt;
3231
3232 // FIXME
3233 // Compatibility check for nullfmt bug and linux -- 18 May 2005
3234 // Remove at some reasonable date in the future
3235 else if (nullfmt == 0
3236 && cckd->cdevhdr[cckd->sfn].nullfmt == CKDDASD_NULLTRK_FMT2)
3237 nullfmt = CKDDASD_NULLTRK_FMT2;
3238
3239 if (cckd->ckddasd)
3240 {
3241
3242 /* cylinder and head calculations */
3243 cyl = trk / dev->ckdheads;
3244 head = trk % dev->ckdheads;
3245
3246 /* Build the track header */
3247 trkhdr = (CKDDASD_TRKHDR*)buf;
3248 trkhdr->bin = 0;
3249 store_hw(&trkhdr->cyl, cyl);
3250 store_hw(&trkhdr->head, head);
3251 pos = buf + CKDDASD_TRKHDR_SIZE;
3252
3253 /* Build record zero */
3254 r = 0;
3255 rechdr = (CKDDASD_RECHDR*)pos;
3256 pos += CKDDASD_RECHDR_SIZE;
3257 store_hw(&rechdr->cyl, cyl);
3258 store_hw(&rechdr->head, head);
3259 rechdr->rec = r;
3260 rechdr->klen = 0;
3261 store_hw(&rechdr->dlen, 8);
3262 memset (pos, 0, 8);
3263 pos += 8;
3264 r++;
3265
3266 /* Specific null track formatting */
3267 if (nullfmt == CKDDASD_NULLTRK_FMT0)
3268 {
3269 rechdr = (CKDDASD_RECHDR*)pos;
3270 pos += CKDDASD_RECHDR_SIZE;
3271
3272 store_hw(&rechdr->cyl, cyl);
3273 store_hw(&rechdr->head, head);
3274 rechdr->rec = r;
3275 rechdr->klen = 0;
3276 store_hw(&rechdr->dlen, 0);
3277 r++;
3278 }
3279 else if (nullfmt == CKDDASD_NULLTRK_FMT2)
3280 {
3281 for (i = 0; i < 12; i++)
3282 {
3283 rechdr = (CKDDASD_RECHDR*)pos;
3284 pos += CKDDASD_RECHDR_SIZE;
3285
3286 store_hw(&rechdr->cyl, cyl);
3287 store_hw(&rechdr->head, head);
3288 rechdr->rec = r;
3289 rechdr->klen = 0;
3290 store_hw(&rechdr->dlen, 4096);
3291 r++;
3292 memset(pos, 0, 4096);
3293 pos += 4096;
3294 }
3295 }
3296
3297 /* Build the end of track marker */
3298 memcpy (pos, eighthexFF, 8);
3299 pos += 8;
3300 len = (int)(pos - buf);
3301 }
3302 else
3303 {
3304 memset (buf, 0, CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE);
3305 store_fw(buf+1, trk);
3306 len = CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE;
3307 }
3308
3309 cckd_trace (dev, "null_trk %s %d format %d size %d\n",
3310 cckd->ckddasd ? "trk" : "blkgrp", trk, nullfmt, len);
3311
3312 return len;
3313
3314 } /* end function cckd_null_trk */
3315
3316 /*-------------------------------------------------------------------*/
3317 /* Return a number 0 .. CKDDASD_NULLTRK_FMTMAX if track is null */
3318 /* else return the original length */
3319 /*-------------------------------------------------------------------*/
cckd_check_null_trk(DEVBLK * dev,BYTE * buf,int trk,int len)3320 int cckd_check_null_trk (DEVBLK *dev, BYTE *buf, int trk, int len)
3321 {
3322 CCKDDASD_EXT *cckd; /* -> cckd extension */
3323 int rc; /* Return code */
3324 BYTE buf2[65536]; /* Null track buffer */
3325
3326 cckd = dev->cckd_ext;
3327 rc = len;
3328
3329 if (len == CKDDASD_NULLTRK_SIZE0)
3330 rc = CKDDASD_NULLTRK_FMT0;
3331 else if (len == CKDDASD_NULLTRK_SIZE1)
3332 rc = CKDDASD_NULLTRK_FMT1;
3333 else if (len == CKDDASD_NULLTRK_SIZE2 && dev->oslinux
3334 && (!cckd->notnull || cckdblk.linuxnull))
3335 {
3336 cckd_null_trk (dev, buf2, trk, 0);
3337 if (memcmp(buf, buf2, len) == 0)
3338 rc = CKDDASD_NULLTRK_FMT2;
3339 }
3340
3341 return rc;
3342 }
3343
3344 /*-------------------------------------------------------------------*/
3345 /* Verify a track/block header and return track/block number */
3346 /*-------------------------------------------------------------------*/
cckd_cchh(DEVBLK * dev,BYTE * buf,int trk)3347 int cckd_cchh (DEVBLK *dev, BYTE *buf, int trk)
3348 {
3349 CCKDDASD_EXT *cckd; /* -> cckd extension */
3350 U16 cyl; /* Cylinder */
3351 U16 head; /* Head */
3352 int t; /* Calculated track */
3353 BYTE badcomp=0; /* 1=Unsupported compression */
3354 static char *comp[] = {"none", "zlib", "bzip2"};
3355
3356 cckd = dev->cckd_ext;
3357
3358 /* CKD dasd header verification */
3359 if (cckd->ckddasd)
3360 {
3361 cyl = fetch_hw (buf + 1);
3362 head = fetch_hw (buf + 3);
3363 t = cyl * dev->ckdheads + head;
3364
3365 if (cyl < dev->ckdcyls && head < dev->ckdheads
3366 && (trk == -1 || t == trk))
3367 {
3368 if (buf[0] & ~cckdblk.comps)
3369 {
3370 if (buf[0] & ~CCKD_COMPRESS_MASK)
3371 {
3372 if (cckdblk.bytemsgs++ < 10)
3373 logmsg (_("HHCCD122E %4.4X file[%d] invalid byte 0 trk %d: "
3374 "buf %2.2x%2.2x%2.2x%2.2x%2.2x\n"), dev->devnum, cckd->sfn,
3375 t, buf[0],buf[1],buf[2],buf[3],buf[4]);
3376 buf[0] &= CCKD_COMPRESS_MASK;
3377 }
3378 }
3379 if (buf[0] & ~cckdblk.comps)
3380 badcomp = 1;
3381 else
3382 return t;
3383 }
3384 }
3385 /* FBA dasd header verification */
3386 else
3387 {
3388 t = fetch_fw (buf + 1);
3389 if (t < dev->fbanumblk && (trk == -1 || t == trk))
3390 {
3391 if (buf[0] & ~cckdblk.comps)
3392 {
3393 if (buf[0] & ~CCKD_COMPRESS_MASK)
3394 {
3395 logmsg (_("HHCCD123E %4.4X file[%d] invalid byte 0 blkgrp %d: "
3396 "buf %2.2x%2.2x%2.2x%2.2x%2.2x\n"), dev->devnum, cckd->sfn,
3397 t, buf[0],buf[1],buf[2],buf[3],buf[4]);
3398 buf[0] &= CCKD_COMPRESS_MASK;
3399 }
3400 }
3401 if (buf[0] & ~cckdblk.comps)
3402 badcomp = 1;
3403 else
3404 return t;
3405 }
3406 }
3407
3408 if (badcomp)
3409 {
3410 logmsg (_("HHCCD124E %4.4X file[%d] invalid %s hdr %s %d: "
3411 "%s compression unsupported\n"),
3412 dev->devnum, cckd->sfn,
3413 cckd->ckddasd ? "trk" : "blk",
3414 cckd->ckddasd ? "trk" : "blk", t, comp[buf[0]]);
3415 }
3416 else
3417 {
3418 logmsg (_("HHCCD125E %4.4X file[%d] invalid %s hdr %s %d "
3419 "buf %p:%2.2x%2.2x%2.2x%2.2x%2.2x\n"),
3420 dev->devnum, cckd->sfn,
3421 cckd->ckddasd ? "trk" : "blk",
3422 cckd->ckddasd ? "trk" : "blk", trk,
3423 buf, buf[0], buf[1], buf[2], buf[3], buf[4]);
3424 cckd_print_itrace ();
3425 }
3426
3427 return -1;
3428 } /* end function cckd_cchh */
3429
3430 /*-------------------------------------------------------------------*/
3431 /* Validate a track image */
3432 /*-------------------------------------------------------------------*/
cckd_validate(DEVBLK * dev,BYTE * buf,int trk,int len)3433 int cckd_validate (DEVBLK *dev, BYTE *buf, int trk, int len)
3434 {
3435 CCKDDASD_EXT *cckd; /* -> cckd extension */
3436 int cyl; /* Cylinder */
3437 int head; /* Head */
3438 char cchh[4],cchh2[4]; /* Cyl, head big-endian */
3439 int r; /* Record number */
3440 int sz; /* Track size */
3441 int vlen; /* Validation length */
3442 int kl,dl; /* Key/Data lengths */
3443
3444 cckd = dev->cckd_ext;
3445
3446 if (buf == NULL || len < 0) return -1;
3447
3448 cckd_trace (dev, "validating %s %d len %d %2.2x%2.2x%2.2x%2.2x%2.2x "
3449 "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
3450 cckd->ckddasd ? "trk" : "blkgrp", trk, len,
3451 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
3452 buf[7], buf[8], buf[9], buf[10], buf[11], buf[12]);
3453
3454 /* FBA dasd check */
3455 if (cckd->fbadasd)
3456 {
3457 if (len == CFBA_BLOCK_SIZE + CKDDASD_TRKHDR_SIZE || len == 0)
3458 return len;
3459 cckd_trace (dev, "validation failed: bad length%s\n","");
3460 return -1;
3461 }
3462
3463 /* cylinder and head calculations */
3464 cyl = trk / dev->ckdheads;
3465 head = trk % dev->ckdheads;
3466 cchh[0] = cyl >> 8;
3467 cchh[1] = cyl & 0xFF;
3468 cchh[2] = head >> 8;
3469 cchh[3] = head & 0xFF;
3470
3471 /* validate record 0 */
3472 memcpy (cchh2, &buf[5], 4); cchh2[0] &= 0x7f; /* fix for ovflow */
3473 if (/* memcmp (cchh, cchh2, 4) != 0 || */ buf[9] != 0 ||
3474 buf[10] != 0 || buf[11] != 0 || buf[12] != 8)
3475 {
3476 cckd_trace (dev, "validation failed: bad r0%s\n","");
3477 return -1;
3478 }
3479
3480 /* validate records 1 thru n */
3481 vlen = len > 0 ? len : dev->ckdtrksz;
3482 for (r = 1, sz = 21; sz + 8 <= vlen; sz += 8 + kl + dl, r++)
3483 {
3484 if (memcmp (&buf[sz], eighthexFF, 8) == 0) break;
3485 kl = buf[sz+5];
3486 dl = buf[sz+6] * 256 + buf[sz+7];
3487 /* fix for track overflow bit */
3488 memcpy (cchh2, &buf[sz], 4); cchh2[0] &= 0x7f;
3489
3490 /* fix for funny formatted vm disks */
3491 /*
3492 if (r == 1) memcpy (cchh, cchh2, 4);
3493 */
3494
3495 if (/*memcmp (cchh, cchh2, 4) != 0 ||*/ buf[sz+4] == 0 ||
3496 sz + 8 + kl + dl >= vlen)
3497 {
3498 cckd_trace (dev, "validation failed: bad r%d "
3499 "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
3500 r, buf[sz], buf[sz+1], buf[sz+2], buf[sz+3],
3501 buf[sz+4], buf[sz+5], buf[sz+6], buf[sz+7]);
3502 return -1;
3503 }
3504 }
3505 sz += 8;
3506
3507 if ((sz != len && len > 0) || sz > vlen)
3508 {
3509 cckd_trace (dev, "validation failed: no eot%s\n","");
3510 return -1;
3511 }
3512
3513 return sz;
3514
3515 } /* end function cckd_validate */
3516
3517 /*-------------------------------------------------------------------*/
3518 /* Return shadow file name */
3519 /*-------------------------------------------------------------------*/
cckd_sf_name(DEVBLK * dev,int sfx)3520 char *cckd_sf_name (DEVBLK *dev, int sfx)
3521 {
3522 /* Return base file name if index is 0 */
3523 if (sfx == 0)
3524 return dev->filename;
3525
3526 /* Error if no shadow file name specified or number exceeded */
3527 if (dev->dasdsfn == NULL || sfx > CCKD_MAX_SF)
3528 return NULL;
3529
3530 /* Set the suffix character in the shadow file name */
3531 if (sfx > 0)
3532 *dev->dasdsfx = '0' + sfx;
3533 else
3534 *dev->dasdsfx = '*';
3535
3536 return dev->dasdsfn;
3537
3538 } /* end function cckd_sf_name */
3539
3540 /*-------------------------------------------------------------------*/
3541 /* Initialize shadow files */
3542 /*-------------------------------------------------------------------*/
cckd_sf_init(DEVBLK * dev)3543 int cckd_sf_init (DEVBLK *dev)
3544 {
3545 CCKDDASD_EXT *cckd; /* -> cckd extension */
3546 int rc; /* Return code */
3547 int i; /* Index */
3548 struct stat st; /* stat() buffer */
3549 char pathname[MAX_PATH]; /* file path in host format */
3550
3551 cckd = dev->cckd_ext;
3552
3553 /* return if no shadow files */
3554 if (dev->dasdsfn == NULL) return 0;
3555
3556 #if 1
3557 /* Check for shadow file name collision */
3558 for (i = 1; i <= CCKD_MAX_SF && dev->dasdsfn != NULL; i++)
3559 {
3560 DEVBLK *dev2;
3561 CCKDDASD_EXT *cckd2;
3562 int j;
3563
3564 for (dev2 = cckdblk.dev1st; dev2; dev2 = cckd2->devnext)
3565 {
3566 cckd2 = dev2->cckd_ext;
3567 if (dev2 == dev) continue;
3568 for (j = 0; j <= CCKD_MAX_SF && dev2->dasdsfn != NULL; j++)
3569 {
3570 if (strcmp (cckd_sf_name(dev, i),cckd_sf_name(dev2, j)) == 0)
3571 {
3572 logmsg (_("HHCCD142E %4.4X file[%d] shadow file name %s\n"
3573 " collides with %4.4X file[%d] name %s\n"),
3574 dev->devnum, i, cckd_sf_name(dev, i),
3575 dev2->devnum, j, cckd_sf_name(dev2, j));
3576 return -1;
3577 }
3578 }
3579 }
3580 }
3581 #endif
3582
3583 /* open all existing shadow files */
3584 for (cckd->sfn = 1; cckd->sfn <= CCKD_MAX_SF; cckd->sfn++)
3585 {
3586 hostpath(pathname, cckd_sf_name (dev, cckd->sfn), sizeof(pathname));
3587 if (stat (pathname, &st) < 0)
3588 break;
3589
3590 /* Try to open the shadow file read-write then read-only */
3591 if (cckd_open (dev, cckd->sfn, O_RDWR|O_BINARY, 1) < 0)
3592 if (cckd_open (dev, cckd->sfn, O_RDONLY|O_BINARY, 0) < 0)
3593 break;
3594
3595 /* Call the chkdsk function */
3596 rc = cckd_chkdsk (dev, 0);
3597 if (rc < 0) return -1;
3598
3599 /* Perform initial read */
3600 rc = cckd_read_init (dev);
3601 }
3602
3603 /* Backup to the last opened file number */
3604 cckd->sfn--;
3605
3606 /* If the last file was opened read-only then create a new one */
3607 if (cckd->open[cckd->sfn] == CCKD_OPEN_RO)
3608 if (cckd_sf_new(dev) < 0)
3609 return -1;
3610
3611 /* Re-open previous rdwr files rdonly */
3612 for (i = 0; i < cckd->sfn; i++)
3613 {
3614 if (cckd->open[i] == CCKD_OPEN_RO) continue;
3615 if (cckd_open (dev, i, O_RDONLY|O_BINARY, 0) < 0)
3616 {
3617 logmsg (_("HHCCD151E %4.4X file[%d] error re-opening %s readonly\n %s\n"),
3618 dev->devnum, i, cckd_sf_name(dev, i), strerror(errno));
3619 return -1;
3620 }
3621 }
3622
3623 return 0;
3624
3625 } /* end function cckd_sf_init */
3626
3627 /*-------------------------------------------------------------------*/
3628 /* Create a new shadow file */
3629 /*-------------------------------------------------------------------*/
cckd_sf_new(DEVBLK * dev)3630 int cckd_sf_new (DEVBLK *dev)
3631 {
3632 CCKDDASD_EXT *cckd; /* -> cckd extension */
3633 int l1size; /* Size of level 1 table */
3634 CKDDASD_DEVHDR devhdr; /* Device header */
3635
3636 cckd = dev->cckd_ext;
3637
3638 cckd_trace (dev, "file[%d] sf_new %s\n", cckd->sfn+1,
3639 cckd_sf_name(dev, cckd->sfn+1) ?
3640 (char *)cckd_sf_name(dev, cckd->sfn+1) : "(none)");
3641
3642 /* Error if no shadow file name */
3643 if (dev->dasdsfn == NULL)
3644 {
3645 logmsg (_("HHCCD161E %4.4X file[%d] no shadow file name\n"),
3646 dev->devnum, cckd->sfn+1);
3647 return -1;
3648 }
3649
3650 /* Error if max number of shadow files exceeded */
3651 if (cckd->sfn+1 == CCKD_MAX_SF)
3652 {
3653 logmsg (_("HHCCD161E %4.4X file[%d] max shadow files exceeded\n"),
3654 dev->devnum, cckd->sfn+1);
3655 return -1;
3656 }
3657
3658 /* Harden the current file */
3659 cckd_harden (dev);
3660
3661 /* Open the new shadow file */
3662 if (cckd_open(dev, cckd->sfn+1, O_RDWR|O_CREAT|O_EXCL|O_BINARY,
3663 S_IRUSR | S_IWUSR | S_IRGRP) < 0)
3664 return -1;
3665
3666 /* Read previous file's device header */
3667 if (cckd_read (dev, cckd->sfn, 0, &devhdr, CKDDASD_DEVHDR_SIZE) < 0)
3668 goto sf_new_error;
3669
3670 /* Make sure identifier is CKD_S370 or FBA_S370 */
3671 devhdr.devid[4] = 'S';
3672
3673 /* Write new file's device header */
3674 if (cckd_write (dev, cckd->sfn+1, 0, &devhdr, CKDDASD_DEVHDR_SIZE) < 0)
3675 goto sf_new_error;
3676
3677 /* Build the compressed device header */
3678 memcpy (&cckd->cdevhdr[cckd->sfn+1], &cckd->cdevhdr[cckd->sfn], CCKDDASD_DEVHDR_SIZE);
3679 l1size = cckd->cdevhdr[cckd->sfn+1].numl1tab * CCKD_L1ENT_SIZE;
3680 cckd->cdevhdr[cckd->sfn+1].size =
3681 cckd->cdevhdr[cckd->sfn+1].used = CKDDASD_DEVHDR_SIZE + CCKDDASD_DEVHDR_SIZE + l1size;
3682 cckd->cdevhdr[cckd->sfn+1].free =
3683 cckd->cdevhdr[cckd->sfn+1].free_total =
3684 cckd->cdevhdr[cckd->sfn+1].free_largest =
3685 cckd->cdevhdr[cckd->sfn+1].free_number =
3686 cckd->cdevhdr[cckd->sfn+1].free_imbed = 0;
3687
3688 /* Init the level 1 table */
3689 if ((cckd->l1[cckd->sfn+1] = cckd_malloc (dev, "l1", l1size)) == NULL)
3690 goto sf_new_error;
3691 memset (cckd->l1[cckd->sfn+1], 0xff, l1size);
3692
3693 /* Make the new file active */
3694 cckd->sfn++;
3695
3696 /* Harden the new file */
3697 if (cckd_harden (dev) < 0)
3698 {
3699 cckd->sfn--;
3700 goto sf_new_error;
3701 }
3702
3703 /* Re-read the l1 to set l2bounds, l2ok */
3704 cckd_read_l1 (dev);
3705
3706 return 0;
3707
3708 sf_new_error:
3709 cckd->l1[cckd->sfn+1] = cckd_free(dev, "l1", cckd->l1[cckd->sfn+1]);
3710 cckd_close (dev, cckd->sfn+1);
3711 cckd->open[cckd->sfn+1] = CCKD_OPEN_NONE;
3712 unlink (cckd_sf_name (dev, cckd->sfn+1));
3713
3714 /* Re-read the l1 to set l2bounds, l2ok */
3715 cckd_read_l1 (dev);
3716
3717 return -1;
3718
3719 } /* end function cckd_sf_new */
3720
3721 /*-------------------------------------------------------------------*/
3722 /* Add a shadow file (sf+) */
3723 /*-------------------------------------------------------------------*/
cckd_sf_add(void * data)3724 void *cckd_sf_add (void *data)
3725 {
3726 DEVBLK *dev = data; /* -> DEVBLK */
3727 CCKDDASD_EXT *cckd; /* -> cckd extension */
3728 int syncio; /* Saved syncio bit */
3729
3730 if (dev == NULL)
3731 {
3732 int n = 0;
3733 for (dev=sysblk.firstdev; dev; dev=dev->nextdev)
3734 if (dev->cckd_ext)
3735 {
3736 logmsg( _("HHCCD207I Adding device %d:%4.4X\n"),
3737 SSID_TO_LCSS(dev->ssid), dev->devnum );
3738 cckd_sf_add (dev);
3739 n++;
3740 }
3741 logmsg( _("HHCCD092I %d devices processed\n"), n );
3742 return NULL;
3743 }
3744
3745 cckd = dev->cckd_ext;
3746 if (!cckd)
3747 {
3748 logmsg (_("HHCCD160E %4.4X not a cckd device\n"), dev->devnum);
3749 return NULL;
3750 }
3751
3752 /* Disable synchronous I/O for the device */
3753 syncio = cckd_disable_syncio(dev);
3754
3755 /* Schedule updated track entries to be written */
3756 obtain_lock (&cckd->iolock);
3757 if (cckd->merging)
3758 {
3759 dev->syncio = syncio;
3760 release_lock (&cckd->iolock);
3761 logmsg (_("HHCCD165W %4.4X error adding shadow file, "
3762 "sf command busy on device\n"),
3763 dev->devnum,cckd->sfn);
3764 return NULL;
3765 }
3766 cckd->merging = 1;
3767 cckd_flush_cache (dev);
3768 while (cckd->wrpending || cckd->ioactive)
3769 {
3770 cckd->iowaiters++;
3771 wait_condition (&cckd->iocond, &cckd->iolock);
3772 cckd->iowaiters--;
3773 cckd_flush_cache (dev);
3774 }
3775 cckd_purge_cache (dev); cckd_purge_l2 (dev);
3776 dev->bufcur = dev->cache = -1;
3777 release_lock (&cckd->iolock);
3778
3779 /* Obtain control of the file */
3780 obtain_lock (&cckd->filelock);
3781
3782 /* Harden the current file */
3783 cckd_harden (dev);
3784
3785 /* Create a new shadow file */
3786 if (cckd_sf_new (dev) < 0) {
3787 logmsg (_("HHCCD161E %4.4X file[%d] error adding shadow file\n"),
3788 dev->devnum, cckd->sfn+1);
3789 goto cckd_sf_add_exit;
3790 }
3791
3792 /* Re-open the previous file if opened read-write */
3793 if (cckd->open[cckd->sfn-1] == CCKD_OPEN_RW)
3794 cckd_open (dev, cckd->sfn-1, O_RDONLY|O_BINARY, 0);
3795
3796 logmsg (_("HHCCD162I %4.4X file[%d] %s added\n"),
3797 dev->devnum, cckd->sfn, cckd_sf_name (dev, cckd->sfn));
3798
3799 cckd_sf_add_exit:
3800
3801 /* Re-read the l1 to set l2bounds, l2ok */
3802 cckd_read_l1 (dev);
3803
3804 release_lock (&cckd->filelock);
3805
3806 obtain_lock (&cckd->iolock);
3807 cckd->merging = 0;
3808 if (cckd->iowaiters)
3809 broadcast_condition (&cckd->iocond);
3810 dev->syncio = syncio;
3811 release_lock (&cckd->iolock);
3812
3813 cckd_sf_stats (dev);
3814 return NULL;
3815 } /* end function cckd_sf_add */
3816
3817 /*-------------------------------------------------------------------*/
3818 /* Remove a shadow file (sf-) */
3819 /*-------------------------------------------------------------------*/
cckd_sf_remove(void * data)3820 void *cckd_sf_remove (void *data)
3821 {
3822 DEVBLK *dev = data; /* -> DEVBLK */
3823 CCKDDASD_EXT *cckd; /* -> cckd extension */
3824 int syncio; /* Saved syncio bit */
3825 int rc; /* Return code */
3826 int from_sfx, to_sfx; /* From/to file index */
3827 int fix; /* nullfmt index */
3828 int add = 0; /* 1=Add shadow file back */
3829 int l2updated = 0; /* 1=L2 table was updated */
3830 int i,j; /* Loop indexes */
3831 int merge, force; /* Flags */
3832 off_t pos; /* File offset */
3833 size_t len; /* Length to read/write */
3834 int size; /* Image size */
3835 int trk = -1; /* Track being read/written */
3836 CCKD_L2ENT from_l2[256], /* Level 2 tables */
3837 to_l2[256];
3838 CCKD_L2ENT new_l2; /* New level 2 table entry */
3839 BYTE buf[65536]; /* Buffer */
3840
3841 if (dev == NULL)
3842 {
3843 int n = 0;
3844 merge = cckdblk.sfmerge;
3845 force = cckdblk.sfforce;
3846 cckdblk.sfmerge = cckdblk.sfforce = 0;
3847 for (dev=sysblk.firstdev; dev; dev=dev->nextdev)
3848 if ((cckd = dev->cckd_ext))
3849 {
3850 logmsg( _("HHCCD179I Merging device %d:%4.4X\n"),
3851 SSID_TO_LCSS(dev->ssid), dev->devnum );
3852 cckd->sfmerge = merge;
3853 cckd->sfforce = force;
3854 cckd_sf_remove (dev);
3855 n++;
3856 }
3857 logmsg( _("HHCCD092I %d devices processed\n"), n );
3858 return NULL;
3859 }
3860
3861 cckd = dev->cckd_ext;
3862 if (!cckd)
3863 {
3864 logmsg (_("HHCCD170E %4.4X not a cckd device\n"),
3865 dev ? dev->devnum : 0);
3866 return NULL;
3867 }
3868
3869 /* Set flags */
3870 merge = cckd->sfmerge || cckd->sfforce;
3871 force = cckd->sfforce;
3872 cckd->sfmerge = cckd->sfforce = 0;
3873
3874 cckd_trace (dev, "merge starting: %s %s\n",
3875 merge ? "merge" : "nomerge", force ? "force" : "");
3876
3877 /* Disable synchronous I/O for the device */
3878 syncio = cckd_disable_syncio(dev);
3879
3880 /* Schedule updated track entries to be written */
3881 obtain_lock (&cckd->iolock);
3882 if (cckd->merging)
3883 {
3884 dev->syncio = syncio;
3885 release_lock (&cckd->iolock);
3886 logmsg (_("HHCCD175W %4.4X file[%d] merge failed, "
3887 "sf command busy on device\n"),
3888 dev->devnum,cckd->sfn);
3889 return NULL;
3890 }
3891 cckd->merging = 1;
3892 cckd_flush_cache (dev);
3893 while (cckd->wrpending || cckd->ioactive)
3894 {
3895 cckd->iowaiters++;
3896 wait_condition (&cckd->iocond, &cckd->iolock);
3897 cckd->iowaiters--;
3898 cckd_flush_cache (dev);
3899 }
3900 cckd_purge_cache (dev); cckd_purge_l2 (dev);
3901 dev->bufcur = dev->cache = -1;
3902 release_lock (&cckd->iolock);
3903
3904 obtain_lock (&cckd->filelock);
3905
3906 if (cckd->sfn == 0)
3907 {
3908 dev->syncio = syncio;
3909 release_lock (&cckd->filelock);
3910 logmsg (_("HHCCD171E %4.4X file[%d] cannot remove base file\n"),
3911 dev->devnum,cckd->sfn);
3912 cckd->merging = 0;
3913 return NULL;
3914 }
3915
3916 from_sfx = cckd->sfn;
3917 to_sfx = cckd->sfn - 1;
3918 fix = cckd->cdevhdr[to_sfx].nullfmt;
3919
3920 /* Harden the `from' file */
3921 if (cckd_harden (dev) < 0)
3922 {
3923 logmsg (_("HHCCD174E %4.4X file[%d] not merged, "
3924 "file[%d] not hardened\n"),
3925 dev->devnum, from_sfx, from_sfx);
3926 goto sf_remove_exit;
3927 }
3928
3929 /* Attempt to re-open the `to' file read-write */
3930 cckd_close (dev, to_sfx);
3931 if (to_sfx > 0 || !dev->ckdrdonly || force)
3932 cckd_open (dev, to_sfx, O_RDWR|O_BINARY, 1);
3933 if (cckd->fd[to_sfx] < 0)
3934 {
3935 /* `from' file can't be opened read-write */
3936 cckd_open (dev, to_sfx, O_RDONLY|O_BINARY, 0);
3937 if (merge)
3938 {
3939 logmsg (_("HHCCD172E %4.4X file[%d] not merged, "
3940 "file[%d] cannot be opened read-write%s\n"),
3941 dev->devnum, from_sfx, to_sfx,
3942 to_sfx == 0 && dev->ckdrdonly && !force
3943 ? ", try `force'" : "");
3944 goto sf_remove_exit;
3945 }
3946 else
3947 add = 1;
3948 }
3949 else
3950 {
3951 /* `from' file opened read-write */
3952 cckd->sfn = to_sfx;
3953 if (cckd_chkdsk (dev, 0) < 0)
3954 {
3955 cckd->sfn = from_sfx;
3956 logmsg (_("HHCCD173E %4.4X file[%d] not merged, "
3957 "file[%d] check failed\n"),
3958 dev->devnum, to_sfx, to_sfx);
3959 goto sf_remove_exit;
3960 }
3961 }
3962
3963 cckd->sfn = to_sfx;
3964
3965 /* Perform backwards merge */
3966 if (merge)
3967 {
3968 cckd_trace (dev, "merging to file[%d]\n", to_sfx);
3969
3970 /* Make the target file the active file */
3971 cckd->sfn = to_sfx;
3972 cckd->cdevhdr[to_sfx].options |= (CCKD_OPENED | CCKD_ORDWR);
3973
3974 /* Loop for each level 1 table entry */
3975 for (i = 0; i < cckd->cdevhdr[from_sfx].numl1tab; i++)
3976 {
3977 l2updated = 0;
3978 /* Continue if from L2 doesn't exist */
3979 if (cckd->l1[from_sfx][i] == 0xffffffff
3980 || (cckd->l1[from_sfx][i] == 0 && cckd->l1[to_sfx][i] == 0))
3981 continue;
3982
3983 trk = i*256;
3984
3985 /* Read `from' l2 table */
3986 if (cckd->l1[from_sfx][i] == 0)
3987 memset (&from_l2, 0, CCKD_L2TAB_SIZE);
3988 else
3989 {
3990 pos = (off_t)cckd->l1[from_sfx][i];
3991 if (cckd_read(dev, from_sfx, pos, &from_l2, CCKD_L2TAB_SIZE) < 0)
3992 goto sf_merge_error;
3993 }
3994
3995 /* Read `to' l2 table */
3996 if (cckd->l1[to_sfx][i] == 0)
3997 memset (&to_l2, 0, CCKD_L2TAB_SIZE);
3998 else if (cckd->l1[to_sfx][i] == 0xffffffff)
3999 memset (&to_l2, 0xff, CCKD_L2TAB_SIZE);
4000 else
4001 {
4002 pos = (off_t)cckd->l1[to_sfx][i];
4003 if (cckd_read(dev, to_sfx, pos, &to_l2, CCKD_L2TAB_SIZE) < 0)
4004 goto sf_merge_error;
4005 }
4006
4007 /* Loop for each level 2 table entry */
4008 for (j = 0; j < 256; j++)
4009 {
4010 trk = i*256 + j;
4011 /* Continue if from L2 entry doesn't exist */
4012 if (from_l2[j].pos == 0xffffffff
4013 || (from_l2[j].pos == 0 && to_l2[j].pos == 0))
4014 continue;
4015
4016 /* Read the `from' track/blkgrp image */
4017 len = (int)from_l2[j].len;
4018 if (len > CKDDASD_NULLTRK_FMTMAX)
4019 {
4020 pos = (off_t)from_l2[j].pos;
4021 if (cckd_read (dev, from_sfx, pos, buf, len) < 0)
4022 goto sf_merge_error;
4023
4024 /* Get space for the `to' track/blkgrp image */
4025 size = len;
4026 if ((pos = cckd_get_space (dev, &size, CCKD_SIZE_EXACT)) < 0)
4027 goto sf_merge_error;
4028
4029 new_l2.pos = (U32)pos;
4030 new_l2.len = (U16)len;
4031 new_l2.size = (U16)size;
4032
4033 /* Write the `to' track/blkgrp image */
4034 if (cckd_write(dev, to_sfx, pos, buf, len) < 0)
4035 goto sf_merge_error;
4036 }
4037 else
4038 {
4039 new_l2.pos = 0;
4040 new_l2.len = new_l2.size = (U16)len;
4041 }
4042
4043 /* Release space occupied by old `to' entry */
4044 cckd_rel_space (dev, (off_t)to_l2[j].pos, (int)to_l2[j].len,
4045 (int)to_l2[j].size);
4046
4047 /* Update `to' l2 table entry */
4048 l2updated = 1;
4049 to_l2[j].pos = new_l2.pos;
4050 to_l2[j].len = new_l2.len;
4051 to_l2[j].size = new_l2.size;
4052 } /* for each level 2 table entry */
4053
4054 /* Update the `to' level 2 table */
4055 if (l2updated)
4056 {
4057 l2updated = 0;
4058 pos = (off_t)cckd->l1[to_sfx][i];
4059 if (memcmp (&to_l2, &empty_l2[fix], CCKD_L2TAB_SIZE) == 0)
4060 {
4061 cckd_rel_space (dev, pos, CCKD_L2TAB_SIZE, CCKD_L2TAB_SIZE);
4062 pos = 0;
4063 }
4064 else
4065 {
4066 size = CCKD_L2TAB_SIZE;
4067 if (pos == 0 || pos == (off_t)0xffffffff)
4068 if ((pos = cckd_get_space (dev, &size, CCKD_L2SPACE)) < 0)
4069 goto sf_merge_error;
4070 if (cckd_write(dev, to_sfx, pos, &to_l2, CCKD_L2TAB_SIZE) < 0)
4071 goto sf_merge_error;
4072 } /* `to' level 2 table not null */
4073
4074 /* Update the level 1 table index */
4075 cckd->l1[to_sfx][i] = (U32)pos;
4076
4077 /* Flush free space */
4078 cckd_flush_space (dev);
4079
4080 } /* Update level 2 table */
4081
4082 } /* For each level 1 table entry */
4083
4084 /* Validate the merge */
4085 cckd_harden (dev);
4086 cckd_chkdsk (dev, 0);
4087 cckd_read_init (dev);
4088
4089 } /* if merge */
4090
4091 /* Remove the old file */
4092 cckd_close (dev, from_sfx);
4093 cckd->l1[from_sfx] = cckd_free (dev, "l1", cckd->l1[from_sfx]);
4094 memset (&cckd->cdevhdr[from_sfx], 0, CCKDDASD_DEVHDR_SIZE);
4095 rc = unlink (cckd_sf_name (dev, from_sfx));
4096
4097 /* Add the file back if necessary */
4098 if (add) rc = cckd_sf_new (dev) ;
4099
4100 logmsg (_("HHCCD181I %4.4X shadow file [%d] successfully %s\n"),
4101 dev->devnum, from_sfx, merge ? "merged" : add ? "re-added" : "removed");
4102
4103 sf_remove_exit:
4104
4105 /* Re-read the l1 to set l2bounds, l2ok */
4106 cckd_read_l1 (dev);
4107
4108 release_lock (&cckd->filelock);
4109
4110 obtain_lock (&cckd->iolock);
4111 cckd_purge_cache (dev); cckd_purge_l2 (dev);
4112 dev->bufcur = dev->cache = -1;
4113 cckd->merging = 0;
4114 if (cckd->iowaiters)
4115 broadcast_condition (&cckd->iocond);
4116 dev->syncio = syncio;
4117 cckd_trace (dev, "merge complete%s\n","");
4118 release_lock (&cckd->iolock);
4119
4120 cckd_sf_stats (dev);
4121 return NULL;
4122
4123 sf_merge_error:
4124
4125 if (trk < 0)
4126 logmsg (_("HHCCD180E %4.4X file[%d] not merged, error during merge\n"),
4127 dev->devnum, from_sfx);
4128 else
4129 logmsg (_("HHCCD180E %4.4X file[%d] not merged, error processing trk %d\n"),
4130 dev->devnum, from_sfx, trk);
4131
4132 if (l2updated && cckd->l1[to_sfx][i] && cckd->l1[to_sfx][i] != 0xffffffff)
4133 {
4134 l2updated = 0;
4135 pos = (off_t)cckd->l1[to_sfx][i];
4136 cckd_write(dev, to_sfx, pos, &to_l2, CCKD_L2TAB_SIZE);
4137 }
4138 cckd_harden(dev);
4139 cckd_chkdsk (dev, 2);
4140 cckd->sfn = from_sfx;
4141 cckd_harden(dev);
4142 cckd_chkdsk (dev, 2);
4143 goto sf_remove_exit;
4144
4145 } /* end function cckd_sf_remove */
4146
4147 /*-------------------------------------------------------------------*/
4148 /* Check and compress a shadow file (sfc) */
4149 /*-------------------------------------------------------------------*/
cckd_sf_comp(void * data)4150 void *cckd_sf_comp (void *data)
4151 {
4152 DEVBLK *dev = data; /* -> DEVBLK */
4153 CCKDDASD_EXT *cckd; /* -> cckd extension */
4154 int syncio; /* Saved syncio bit */
4155 int rc; /* Return code */
4156
4157 if (dev == NULL)
4158 {
4159 int n = 0;
4160 for (dev=sysblk.firstdev; dev; dev=dev->nextdev)
4161 if (dev->cckd_ext)
4162 {
4163 logmsg( _("HHCCD207I Compressing device %d:%4.4X\n"),
4164 SSID_TO_LCSS(dev->ssid), dev->devnum );
4165 cckd_sf_comp (dev);
4166 n++;
4167 }
4168 logmsg( _("HHCCD092I %d devices processed\n"), n );
4169 return NULL;
4170 }
4171
4172 cckd = dev->cckd_ext;
4173 if (!cckd)
4174 {
4175 logmsg (_("HHCCD205W %4.4X device is not a cckd device\n"), dev->devnum);
4176 return NULL;
4177 }
4178
4179 /* Disable synchronous I/O for the device */
4180 syncio = cckd_disable_syncio(dev);
4181
4182 /* schedule updated track entries to be written */
4183 obtain_lock (&cckd->iolock);
4184 if (cckd->merging)
4185 {
4186 dev->syncio = syncio;
4187 release_lock (&cckd->iolock);
4188 logmsg (_("HHCCD206W %4.4X file[%d] compress failed, "
4189 "sf command busy on device\n"),
4190 dev->devnum,cckd->sfn);
4191 return NULL;
4192 }
4193 cckd->merging = 1;
4194 cckd_flush_cache (dev);
4195 while (cckd->wrpending || cckd->ioactive)
4196 {
4197 cckd->iowaiters++;
4198 wait_condition (&cckd->iocond, &cckd->iolock);
4199 cckd->iowaiters--;
4200 cckd_flush_cache (dev);
4201 }
4202 cckd_purge_cache (dev); cckd_purge_l2 (dev);
4203 dev->bufcur = dev->cache = -1;
4204 release_lock (&cckd->iolock);
4205
4206 /* obtain control of the file */
4207 obtain_lock (&cckd->filelock);
4208
4209 /* harden the current file */
4210 cckd_harden (dev);
4211
4212 /* Call the compress function */
4213 rc = cckd_comp (dev);
4214
4215 /* Perform initial read */
4216 rc = cckd_read_init (dev);
4217
4218 release_lock (&cckd->filelock);
4219
4220 obtain_lock (&cckd->iolock);
4221 cckd->merging = 0;
4222 if (cckd->iowaiters)
4223 broadcast_condition (&cckd->iocond);
4224 dev->syncio = syncio;
4225 release_lock (&cckd->iolock);
4226
4227 /* Display the shadow file statistics */
4228 cckd_sf_stats (dev);
4229
4230 return NULL;
4231 } /* end function cckd_sf_comp */
4232
4233 /*-------------------------------------------------------------------*/
4234 /* Check a shadow file (sfk) */
4235 /*-------------------------------------------------------------------*/
cckd_sf_chk(void * data)4236 void *cckd_sf_chk (void *data)
4237 {
4238 DEVBLK *dev = data; /* -> DEVBLK */
4239 CCKDDASD_EXT *cckd; /* -> cckd extension */
4240 int syncio; /* Saved syncio bit */
4241 int rc; /* Return code */
4242 int level = 2; /* Check level */
4243
4244 if (dev == NULL)
4245 {
4246 int n = 0;
4247 level = cckdblk.sflevel;
4248 cckdblk.sflevel = 0;
4249 for (dev=sysblk.firstdev; dev; dev=dev->nextdev)
4250 if ((cckd = dev->cckd_ext))
4251 {
4252 logmsg( _("HHCCD207I Checking device %d:%4.4X level %d\n"),
4253 SSID_TO_LCSS(dev->ssid), dev->devnum, level );
4254 cckd->sflevel = level;
4255 cckd_sf_chk (dev);
4256 n++;
4257 }
4258 logmsg( _("HHCCD092I %d devices processed\n"), n );
4259 return NULL;
4260 }
4261
4262 cckd = dev->cckd_ext;
4263 if (!cckd)
4264 {
4265 logmsg (_("HHCCD205W %4.4X device is not a cckd device\n"), dev->devnum);
4266 return NULL;
4267 }
4268
4269 level = cckd->sflevel;
4270 cckd->sflevel = 0;
4271
4272 /* Disable synchronous I/O for the device */
4273 syncio = cckd_disable_syncio(dev);
4274
4275 /* schedule updated track entries to be written */
4276 obtain_lock (&cckd->iolock);
4277 if (cckd->merging)
4278 {
4279 dev->syncio = syncio;
4280 release_lock (&cckd->iolock);
4281 logmsg (_("HHCCD206W %4.4X file[%d] check failed, "
4282 "sf command busy on device\n"),
4283 dev->devnum,cckd->sfn);
4284 return NULL;
4285 }
4286 cckd->merging = 1;
4287 cckd_flush_cache (dev);
4288 while (cckd->wrpending || cckd->ioactive)
4289 {
4290 cckd->iowaiters++;
4291 wait_condition (&cckd->iocond, &cckd->iolock);
4292 cckd->iowaiters--;
4293 cckd_flush_cache (dev);
4294 }
4295 cckd_purge_cache (dev); cckd_purge_l2 (dev);
4296 dev->bufcur = dev->cache = -1;
4297 release_lock (&cckd->iolock);
4298
4299 /* obtain control of the file */
4300 obtain_lock (&cckd->filelock);
4301
4302 /* harden the current file */
4303 cckd_harden (dev);
4304
4305 /* Call the chkdsk function */
4306 rc = cckd_chkdsk (dev, level);
4307
4308 /* Perform initial read */
4309 rc = cckd_read_init (dev);
4310
4311 release_lock (&cckd->filelock);
4312
4313 obtain_lock (&cckd->iolock);
4314 cckd->merging = 0;
4315 if (cckd->iowaiters)
4316 broadcast_condition (&cckd->iocond);
4317 dev->syncio = syncio;
4318 release_lock (&cckd->iolock);
4319
4320 /* Display the shadow file statistics */
4321 cckd_sf_stats (dev);
4322
4323 return NULL;
4324 } /* end function cckd_sf_chk */
4325
4326 /*-------------------------------------------------------------------*/
4327 /* Display shadow file statistics (sfd) */
4328 /*-------------------------------------------------------------------*/
cckd_sf_stats(void * data)4329 void *cckd_sf_stats (void *data)
4330 {
4331 DEVBLK *dev = data; /* -> DEVBLK */
4332 CCKDDASD_EXT *cckd; /* -> cckd extension */
4333 struct stat st; /* File information */
4334 int i; /* Index */
4335 int rc; /* Return code */
4336 char *ost[] = {" ", "ro", "rd", "rw"};
4337 unsigned long long size=0,free=0; /* Total size, free space */
4338 int freenbr=0; /* Total number free spaces */
4339
4340 if (dev == NULL)
4341 {
4342 int n = 0;
4343 for (dev=sysblk.firstdev; dev; dev=dev->nextdev)
4344 if (dev->cckd_ext)
4345 {
4346 logmsg( _("HHCCD208I Displaying device %d:%4.4X\n"),
4347 SSID_TO_LCSS(dev->ssid), dev->devnum );
4348 cckd_sf_stats (dev);
4349 n++;
4350 }
4351 logmsg( _("HHCCD092I %d devices processed\n"), n );
4352 return NULL;
4353 }
4354
4355 cckd = dev->cckd_ext;
4356 if (!cckd)
4357 {
4358 logmsg (_("HHCCD209W %4.4X device is not a cckd device\n"));
4359 return NULL;
4360 }
4361
4362 // obtain_lock (&cckd->filelock);
4363
4364 /* Calculate totals */
4365 rc = fstat (cckd->fd[0], &st);
4366 for (i = 0; i <= cckd->sfn; i++)
4367 {
4368 if (!i) size = st.st_size;
4369 else size += cckd->cdevhdr[i].size;
4370 free += cckd->cdevhdr[i].free_total;
4371 freenbr += cckd->cdevhdr[i].free_number;
4372 }
4373
4374 /* header */
4375 logmsg (_("HHCCD210I size free nbr st reads writes l2reads hits switches\n"));
4376 if (cckd->readaheads || cckd->misses)
4377 logmsg (_("HHCCD211I readaheads misses\n"));
4378 logmsg (_("HHCCD212I --------------------------------------------------------------------\n"));
4379
4380 /* total statistics */
4381 logmsg (_("HHCCD213I [*] %10" I64_FMT "d %3" I64_FMT "d%% %4d %7d %7d %7d %7d %7d\n"),
4382 size, (free * 100) / size, freenbr,
4383 cckd->totreads, cckd->totwrites, cckd->totl2reads,
4384 cckd->cachehits, cckd->switches);
4385 if (cckd->readaheads || cckd->misses)
4386 logmsg (_("HHCCD214I %7d %7d\n"),
4387 cckd->readaheads, cckd->misses);
4388
4389 /* base file statistics */
4390 logmsg (_("HHCCD215I %s\n"), dev->filename);
4391 logmsg (_("HHCCD216I [0] %10" I64_FMT "d %3" I64_FMT "d%% %4d %s %7d %7d %7d\n"),
4392 (long long)st.st_size,
4393 (long long)((long long)((long long)cckd->cdevhdr[0].free_total * 100) / st.st_size),
4394 cckd->cdevhdr[0].free_number, ost[cckd->open[0]],
4395 cckd->reads[0], cckd->writes[0], cckd->l2reads[0]);
4396
4397 if (dev->dasdsfn != NULL && CCKD_MAX_SF > 0)
4398 logmsg (_("HHCCD217I %s\n"), cckd_sf_name(dev, -1));
4399
4400 /* shadow file statistics */
4401 for (i = 1; i <= cckd->sfn; i++)
4402 {
4403 logmsg (_("HHCCD218I [%d] %10" I64_FMT "d %3" I64_FMT "d%% %4d %s %7d %7d %7d\n"),
4404 i, (long long)cckd->cdevhdr[i].size,
4405 (long long)((long long)((long long)cckd->cdevhdr[i].free_total * 100) / cckd->cdevhdr[i].size),
4406 cckd->cdevhdr[i].free_number, ost[cckd->open[i]],
4407 cckd->reads[i], cckd->writes[i], cckd->l2reads[i]);
4408 }
4409 // release_lock (&cckd->filelock);
4410 return NULL;
4411 } /* end function cckd_sf_stats */
4412
4413 /*-------------------------------------------------------------------*/
4414 /* Disable synchronous I/O for a device */
4415 /*-------------------------------------------------------------------*/
cckd_disable_syncio(DEVBLK * dev)4416 int cckd_disable_syncio(DEVBLK *dev)
4417 {
4418 if (!dev->syncio) return 0;
4419 obtain_lock(&dev->lock);
4420 while (dev->syncio_active)
4421 {
4422 release_lock(&dev->lock);
4423 usleep(500);
4424 obtain_lock(&dev->lock);
4425 }
4426 dev->syncio = 0;
4427 release_lock(&dev->lock);
4428 cckd_trace (dev, "syncio disabled%s\n","");
4429 return 1;
4430 }
4431
4432 /*-------------------------------------------------------------------*/
4433 /* Lock/unlock the device chain */
4434 /*-------------------------------------------------------------------*/
cckd_lock_devchain(int flag)4435 void cckd_lock_devchain(int flag)
4436 {
4437 //struct timespec tm;
4438 //struct timeval now;
4439 //int timeout;
4440
4441 obtain_lock(&cckdblk.devlock);
4442 while ((flag && cckdblk.devusers != 0)
4443 || (!flag && cckdblk.devusers < 0))
4444 {
4445 //gettimeofday(&now,NULL);
4446 //tm.tv_sec = now.tv_sec + 2;
4447 //tm.tv_nsec = now.tv_usec * 1000;
4448 cckdblk.devwaiters++;
4449 wait_condition(&cckdblk.devcond, &cckdblk.devlock);
4450 //timeout = timed_wait_condition(&cckdblk.devcond, &cckdblk.devlock, &tm);
4451 //if (timeout) cckd_print_itrace();
4452 cckdblk.devwaiters--;
4453 }
4454 if (flag) cckdblk.devusers--;
4455 else cckdblk.devusers++;
4456 release_lock(&cckdblk.devlock);
4457 }
cckd_unlock_devchain()4458 void cckd_unlock_devchain()
4459 {
4460 obtain_lock(&cckdblk.devlock);
4461 if (cckdblk.devusers < 0) cckdblk.devusers++;
4462 else cckdblk.devusers--;
4463 if (cckdblk.devusers == 0 && cckdblk.devwaiters)
4464 signal_condition(&cckdblk.devcond);
4465 release_lock(&cckdblk.devlock);
4466 }
4467
4468 /*-------------------------------------------------------------------*/
4469 /* Garbage Collection thread */
4470 /*-------------------------------------------------------------------*/
cckd_gcol()4471 void cckd_gcol()
4472 {
4473 int gcol; /* Identifier */
4474 int rc; /* Return code */
4475 DEVBLK *dev; /* -> device block */
4476 CCKDDASD_EXT *cckd; /* -> cckd extension */
4477 long long size, fsiz; /* File size, free size */
4478 struct timeval tv_now; /* Time-of-day (as timeval) */
4479 time_t tt_now; /* Time-of-day (as time_t) */
4480 struct timespec tm; /* Time-of-day to wait */
4481 int gc; /* Garbage collection state */
4482 int gctab[5]= { /* default gcol parameters */
4483 4096, /* critical 50% - 100% */
4484 2048, /* severe 25% - 50% */
4485 1024, /* moderate 12.5% - 25% */
4486 512, /* light 6.3% - 12.5% */
4487 256}; /* none 0% - 6.3% */
4488 //char *gcstates[] = {"critical","severe","moderate","light","none"};
4489
4490 obtain_lock (&cckdblk.gclock);
4491 gcol = ++cckdblk.gcs;
4492
4493 /* Return without messages if too many already started */
4494 if (gcol > cckdblk.gcmax)
4495 {
4496 --cckdblk.gcs;
4497 release_lock (&cckdblk.gclock);
4498 return;
4499 }
4500
4501 if (!cckdblk.batch)
4502 {
4503 logmsg (_("HHCCD003I Garbage collector thread started: tid="TIDPAT", pid=%d \n"),
4504 thread_id(), getpid());
4505 }
4506
4507 while (gcol <= cckdblk.gcmax)
4508 {
4509 cckd_lock_devchain(0);
4510 /* Perform collection on each device */
4511 for (dev = cckdblk.dev1st; dev; dev = cckd->devnext)
4512 {
4513 cckd = dev->cckd_ext;
4514 obtain_lock (&cckd->iolock);
4515
4516 /* Bypass if merging or stopping */
4517 if (cckd->merging || cckd->stopping)
4518 {
4519 release_lock (&cckd->iolock);
4520 continue;
4521 }
4522
4523 /* Bypass if not opened read-write */
4524 if (cckd->open[cckd->sfn] != CCKD_OPEN_RW)
4525 {
4526 release_lock (&cckd->iolock);
4527 continue;
4528 }
4529
4530 /* Free newbuf if it hasn't been used */
4531 if (!cckd->ioactive && !cckd->bufused && cckd->newbuf)
4532 cckd->newbuf = cckd_free (dev, "newbuf", cckd->newbuf);
4533 cckd->bufused = 0;
4534
4535 /* If OPENED bit not on then flush if updated */
4536 if (!(cckd->cdevhdr[cckd->sfn].options & CCKD_OPENED))
4537 {
4538 if (cckd->updated) cckd_flush_cache (dev);
4539 release_lock (&cckd->iolock);
4540 continue;
4541 }
4542
4543 /* Determine garbage state */
4544 size = (long long)cckd->cdevhdr[cckd->sfn].size;
4545 fsiz = (long long)cckd->cdevhdr[cckd->sfn].free_total;
4546 if (fsiz >= (size = size/2)) gc = 0;
4547 else if (fsiz >= (size = size/2)) gc = 1;
4548 else if (fsiz >= (size = size/2)) gc = 2;
4549 else if (fsiz >= (size = size/2)) gc = 3;
4550 else gc = 4;
4551
4552 /* Adjust the state based on the number of free spaces */
4553 if (cckd->cdevhdr[cckd->sfn].free_number > 800 && gc > 0) gc--;
4554 if (cckd->cdevhdr[cckd->sfn].free_number > 1800 && gc > 0) gc--;
4555 if (cckd->cdevhdr[cckd->sfn].free_number > 3000) gc = 0;
4556
4557 /* Set the size */
4558 if (cckdblk.gcparm > 0) size = gctab[gc] << cckdblk.gcparm;
4559 else if (cckdblk.gcparm < 0) size = gctab[gc] >> abs(cckdblk.gcparm);
4560 else size = gctab[gc];
4561 if (size > cckd->cdevhdr[cckd->sfn].used >> 10)
4562 size = cckd->cdevhdr[cckd->sfn].used >> 10;
4563 if (size < 64) size = 64;
4564
4565 release_lock (&cckd->iolock);
4566
4567 /* Call the garbage collector */
4568 cckd_gc_percolate (dev, (unsigned int)size);
4569
4570 /* Schedule any updated tracks to be written */
4571 obtain_lock (&cckd->iolock);
4572 cckd_flush_cache (dev);
4573 while (cckdblk.fsync && cckd->wrpending)
4574 {
4575 cckd->iowaiters++;
4576 wait_condition (&cckd->iocond, &cckd->iolock);
4577 cckd->iowaiters--;
4578 }
4579 release_lock (&cckd->iolock);
4580
4581 /* Sync the file */
4582 if (cckdblk.fsync && cckd->lastsync + 10 <= tv_now.tv_sec)
4583 {
4584 obtain_lock (&cckd->filelock);
4585 rc = fdatasync (cckd->fd[cckd->sfn]);
4586 cckd->lastsync = tv_now.tv_sec;
4587 release_lock (&cckd->filelock);
4588 }
4589
4590 /* Flush the free space */
4591 if (cckd->cdevhdr[cckd->sfn].free_number)
4592 {
4593 obtain_lock (&cckd->filelock);
4594 cckd_flush_space (dev);
4595 release_lock (&cckd->filelock);
4596 }
4597
4598 } /* for each cckd device */
4599 cckd_unlock_devchain();
4600
4601 /* wait a bit */
4602 gettimeofday (&tv_now, NULL);
4603 tm.tv_sec = tv_now.tv_sec + cckdblk.gcwait;
4604 tm.tv_nsec = tv_now.tv_usec * 1000;
4605 tt_now = tv_now.tv_sec + ((tv_now.tv_usec + 500000)/1000000);
4606 cckd_trace (dev, "gcol wait %d seconds at %s",
4607 cckdblk.gcwait, ctime (&tt_now));
4608 timed_wait_condition (&cckdblk.gccond, &cckdblk.gclock, &tm);
4609 }
4610
4611 if (!cckdblk.batch)
4612 logmsg (_("HHCCD013I Garbage collector thread stopping: tid="TIDPAT", pid=%d\n"),
4613 thread_id(), getpid());
4614
4615 cckdblk.gcs--;
4616 if (!cckdblk.gcs) signal_condition (&cckdblk.termcond);
4617 release_lock (&cckdblk.gclock);
4618 } /* end thread cckd_gcol */
4619
4620 /*-------------------------------------------------------------------*/
4621 /* Garbage Collection -- Percolate algorithm */
4622 /*-------------------------------------------------------------------*/
cckd_gc_percolate(DEVBLK * dev,unsigned int size)4623 int cckd_gc_percolate(DEVBLK *dev, unsigned int size)
4624 {
4625 CCKDDASD_EXT *cckd; /* -> cckd extension */
4626 int rc; /* Return code */
4627 size_t moved = 0; /* Space moved */
4628 int after = 0, a; /* New space after old */
4629 int sfx; /* File index */
4630 int i, j, l; /* Indexes */
4631 int flags; /* Write trkimg flags */
4632 off_t fpos, upos; /* File offsets */
4633 size_t flen, ulen, len; /* Lengths */
4634 int trk; /* Track number */
4635 int l1x,l2x; /* Table Indexes */
4636 CCKD_L2ENT l2; /* Copied level 2 entry */
4637 BYTE buf[256*1024]; /* Buffer */
4638
4639 cckd = dev->cckd_ext;
4640 size = size << 10;
4641
4642 /* Debug */
4643 if (cckdblk.itracen)
4644 {
4645 cckd_trace (dev, "gcperc size %d 1st 0x%x nbr %d largest %u\n",
4646 size, cckd->cdevhdr[cckd->sfn].free,
4647 cckd->cdevhdr[cckd->sfn].free_number,
4648 cckd->cdevhdr[cckd->sfn].free_largest);
4649 fpos = (off_t)cckd->cdevhdr[cckd->sfn].free;
4650 for (i = cckd->free1st; i >= 0; i = cckd->free[i].next)
4651 {
4652 cckd_trace (dev, "gcperc free[%4d]:%8.8x end %8.8x len %10d%cpend %d\n",
4653 i,(int)fpos,(int)(fpos+cckd->free[i].len),(int)cckd->free[i].len,
4654 fpos+(int)cckd->free[i].len == (int)cckd->free[i].pos ?
4655 '*' : ' ',cckd->free[i].pending);
4656 fpos = cckd->free[i].pos;
4657 }
4658 }
4659
4660 if (!cckd->l2ok)
4661 cckd_gc_l2(dev, buf);
4662
4663 /* garbage collection cycle */
4664 while (moved < size && after < 4)
4665 {
4666 obtain_lock (&cckd->filelock);
4667 sfx = cckd->sfn;
4668
4669 /* Exit if no more free space */
4670 if (cckd->cdevhdr[sfx].free_total == 0)
4671 {
4672 release_lock (&cckd->filelock);
4673 return moved;
4674 }
4675
4676 /* Make sure the free space chain is built */
4677 if (!cckd->free) cckd_read_fsp (dev);
4678
4679 /* Find a space to start with */
4680 l = -1;
4681 upos = ulen = flen = 0;
4682 fpos = cckd->cdevhdr[sfx].free;
4683
4684 /* First non-pending free space */
4685 for (i = cckd->free1st; i >= 0; i = cckd->free[i].next)
4686 {
4687 if (!cckd->free[i].pending)
4688 {
4689 flen += cckd->free[i].len;
4690 break;
4691 }
4692 fpos = cckd->free[i].pos;
4693 }
4694
4695 /* Continue to largest if non-zero `after' */
4696 for ( ; i >= 0 && after; i = cckd->free[i].next)
4697 {
4698 l = i;
4699 if (!cckd->free[i].pending) flen += cckd->free[i].len;
4700 if (cckd->free[i].len == cckd->cdevhdr[sfx].free_largest)
4701 break;
4702 fpos = cckd->free[i].pos;
4703 }
4704
4705 /* Skip following free spaces */
4706 for ( ; i >= 0; i = cckd->free[i].next)
4707 {
4708 if (!cckd->free[i].pending) flen += cckd->free[i].len;
4709 if (fpos + cckd->free[i].len != cckd->free[i].pos) break;
4710 fpos = cckd->free[i].pos;
4711 }
4712
4713 /* Space preceding largest if largest is at the end */
4714 if (i < 0 && l >= 0)
4715 {
4716 if (!cckd->free[l].pending) flen -= cckd->free[i].len;
4717 for (i = cckd->free[l].prev; i >= 0; i = cckd->free[i].prev)
4718 {
4719 fpos = cckd->free[i].prev >= 0
4720 ? cckd->free[cckd->free[i].prev].pos
4721 : cckd->cdevhdr[sfx].free;
4722 if (fpos + cckd->free[i].len < cckd->free[i].pos) break;
4723 if (!cckd->free[i].pending) flen -= cckd->free[i].len;
4724 }
4725 }
4726
4727 /* Calculate the offset/length of the used space.
4728 * If only imbedded free space is left, then start
4729 * with the first used space that is not an l2 table.
4730 */
4731 if (i >= 0)
4732 {
4733 upos = fpos + cckd->free[i].len;
4734 ulen = (cckd->free[i].pos ? cckd->free[i].pos : cckd->cdevhdr[sfx].size) - upos;
4735 }
4736 else if (!cckd->cdevhdr[sfx].free_number && cckd->cdevhdr[sfx].free_imbed)
4737 {
4738 upos = (off_t)(CCKD_L1TAB_POS + cckd->cdevhdr[sfx].numl1tab * CCKD_L1ENT_SIZE);
4739 while (1)
4740 {
4741 for (i = 0; i < cckd->cdevhdr[sfx].numl1tab; i++)
4742 if (cckd->l1[sfx][i] == (U32)upos)
4743 break;
4744 if (i >= cckd->cdevhdr[sfx].numl1tab)
4745 break;
4746 upos += CCKD_L2TAB_SIZE;
4747 }
4748 ulen = cckd->cdevhdr[sfx].size - upos;
4749 }
4750
4751 /* Return if no applicable used space */
4752 if (ulen == 0)
4753 {
4754 cckd_trace (dev, "gcperc no applicable space, moved %ld\n",(long)moved);
4755 release_lock (&cckd->filelock);
4756 return moved;
4757 }
4758
4759 /* Reduce ulen size to minimize `after' relocations */
4760 if (ulen > flen + 65536) ulen = flen + 65536;
4761 if (ulen > sizeof(buf)) ulen = sizeof(buf);
4762
4763 cckd_trace (dev, "gcperc selected space 0x%" I64_FMT "x len %ld\n",
4764 (long long)upos, (long)ulen);
4765
4766 if (cckd_read (dev, sfx, upos, buf, ulen) < 0)
4767 goto cckd_gc_perc_error;
4768
4769 /* Process each space in the buffer */
4770 flags = cckd->cdevhdr[sfx].free_number < 100 ? CCKD_SIZE_EXACT : CCKD_SIZE_ANY;
4771 for (i = a = 0; i + CKDDASD_TRKHDR_SIZE <= (int)ulen; i += len)
4772 {
4773 /* Check for level 2 table */
4774 for (j = 0; j < cckd->cdevhdr[sfx].numl1tab; j++)
4775 if (cckd->l1[sfx][j] == (U32)(upos + i)) break;
4776
4777 if (j < cckd->cdevhdr[sfx].numl1tab)
4778 {
4779 /* Moving a level 2 table */
4780 len = CCKD_L2TAB_SIZE;
4781 if (i + len > ulen) break;
4782 cckd_trace (dev, "gcperc move l2tab[%d] at pos 0x%" I64_FMT "x len %ld\n",
4783 j, (unsigned long long)(upos + i), (long)len);
4784
4785 /* Make the level 2 table active */
4786 if (cckd_read_l2 (dev, sfx, j) < 0)
4787 goto cckd_gc_perc_error;
4788
4789 /* Write the level 2 table */
4790 if (cckd_write_l2 (dev) < 0)
4791 goto cckd_gc_perc_error;
4792 }
4793 else
4794 {
4795 /* Moving a track image */
4796 if ((trk = cckd_cchh (dev, buf + i, -1)) < 0)
4797 goto cckd_gc_perc_space_error;
4798
4799 l1x = trk >> 8;
4800 l2x = trk & 0xff;
4801
4802 /* Read the lookup entry for the track */
4803 if (cckd_read_l2ent (dev, &l2, trk) < 0)
4804 goto cckd_gc_perc_error;
4805 if (l2.pos != (U32)(upos + i))
4806 goto cckd_gc_perc_space_error;
4807 len = (int)l2.size;
4808 if (i + l2.len > (int)ulen) break;
4809
4810 cckd_trace (dev, "gcperc move trk %d at pos 0x%" I64_FMT "x len %d\n",
4811 trk, (long long)(upos + i), (int)l2.len);
4812
4813 /* Relocate the track image somewhere else */
4814 if ((rc = cckd_write_trkimg (dev, buf + i, (int)l2.len, trk, flags)) < 0)
4815 goto cckd_gc_perc_error;
4816 a += rc;
4817 }
4818 } /* for each space in the used space */
4819
4820 /* Set `after' to 1 if first time space was relocated after */
4821 after += after ? a : (a > 0);
4822 moved += i;
4823
4824 cckdblk.stats_gcolmoves++;
4825 cckdblk.stats_gcolbytes += i;
4826
4827 release_lock (&cckd->filelock);
4828
4829 } /* while (moved < size) */
4830
4831 cckd_trace (dev, "gcperc moved %ld 1st 0x%x nbr %d\n", (long)moved,
4832 cckd->cdevhdr[cckd->sfn].free,cckd->cdevhdr[cckd->sfn].free_number);
4833 return moved;
4834
4835 cckd_gc_perc_space_error:
4836
4837 logmsg (_("HHCCD190E %4.4X file[%d] offset 0x%" I64_FMT "x unknown space: "
4838 "%2.2x%2.2x%2.2x%2.2x%2.2x\n"),
4839 dev->devnum,cckd->sfn,(long long)(upos + i),
4840 buf[i], buf[i+1],buf[i+2], buf[i+3], buf[i+4]);
4841 cckd->cdevhdr[cckd->sfn].options |= CCKD_SPERRS;
4842 cckd_print_itrace();
4843
4844 cckd_gc_perc_error:
4845
4846 cckd_trace (dev, "gcperc exiting due to error, moved %ld\n", (long)moved);
4847 release_lock (&cckd->filelock);
4848 return moved;
4849
4850 } /* end function cckd_gc_percolate */
4851
4852 /*-------------------------------------------------------------------*/
4853 /* Garbage Collection -- Reposition level 2 tables */
4854 /* */
4855 /* General idea is to relocate all level 2 tables as close to the */
4856 /* beginning of the file as possible. This can help speed up, for */
4857 /* example, chkdsk processing. */
4858 /* */
4859 /* If any level 2 tables reside outside of the bounds (that is, if */
4860 /* any level 2 table could be moved closer to the beginning of the */
4861 /* file) then first we relocate all track images within the bounds. */
4862 /* Note that cckd_get_space will not allocate space within the */
4863 /* the bounds for track images. Next we try to relocate all level 2 */
4864 /* tables outside the bounds. This may take a few iterations for */
4865 /* the freed space within the bounds to become non-pending. */
4866 /* */
4867 /* The bounds can change as level 2 tables are added or removed. */
4868 /* cckd_read_l1 sets the bounds and they are adjusted by */
4869 /* cckd_write_l2. */
4870 /*-------------------------------------------------------------------*/
cckd_gc_l2(DEVBLK * dev,BYTE * buf)4871 int cckd_gc_l2(DEVBLK *dev, BYTE *buf)
4872 {
4873 CCKDDASD_EXT *cckd; /* -> cckd extension */
4874 int sfx; /* Shadow file index */
4875 int i, j; /* Work variables */
4876 int trk; /* Track number */
4877 int len; /* Track length */
4878 off_t pos, fpos; /* File offsets */
4879
4880 cckd = dev->cckd_ext;
4881
4882 obtain_lock (&cckd->filelock);
4883 sfx = cckd->sfn;
4884
4885 if (cckd->l2ok || cckd->cdevhdr[cckd->sfn].free_total == 0)
4886 goto cckd_gc_l2_exit;
4887
4888 /* Find any level 2 table out of bounds */
4889 for (i = 0; i < cckd->cdevhdr[sfx].numl1tab; i++)
4890 if (cckd->l1[sfx][i] != 0 && cckd->l1[sfx][i] != 0xffffffff
4891 && cckd->l2bounds - CCKD_L2TAB_SIZE < (off_t)cckd->l1[sfx][i])
4892 break;
4893
4894 /* Return OK if no l2 tables out of bounds */
4895 if (i >= cckd->cdevhdr[sfx].numl1tab)
4896 goto cckd_gc_l2_exit_ok;
4897
4898 /* Relocate all track images within the bounds */
4899 pos = CCKD_L1TAB_POS + (cckd->cdevhdr[sfx].numl1tab * CCKD_L1ENT_SIZE);
4900 i = cckd->free1st;
4901 fpos = (off_t)cckd->cdevhdr[sfx].free;
4902 while (pos < cckd->l2bounds)
4903 {
4904 if (i >= 0 && pos == fpos)
4905 {
4906 pos += cckd->free[i].len;
4907 fpos = (off_t)cckd->free[i].pos;
4908 i = cckd->free[i].next;
4909 j = 0;
4910 }
4911 else
4912 {
4913 for (j = 0; j < cckd->cdevhdr[sfx].numl1tab; j++)
4914 if (pos == (off_t)cckd->l1[sfx][j])
4915 {
4916 pos += CCKD_L2TAB_SIZE;
4917 break;
4918 }
4919 }
4920 if (j >= cckd->cdevhdr[sfx].numl1tab)
4921 {
4922 /* Found a track to relocate */
4923 if (cckd_read (dev, sfx, pos, buf, CKDDASD_TRKHDR_SIZE) < 0)
4924 goto cckd_gc_l2_exit;
4925 if ((trk = cckd_cchh (dev, buf, -1)) < 0)
4926 goto cckd_gc_l2_exit;
4927 cckd_trace (dev, "gc_l2 relocate trk[%d] offset 0x%x\n", trk, pos);
4928 if ((len = cckd_read_trkimg (dev, buf, trk, NULL)) < 0)
4929 goto cckd_gc_l2_exit;
4930 if (cckd_write_trkimg (dev, buf, len, trk, CCKD_SIZE_EXACT) < 0)
4931 goto cckd_gc_l2_exit;
4932 /* Start over */
4933 pos = CCKD_L1TAB_POS + (cckd->cdevhdr[sfx].numl1tab * CCKD_L1ENT_SIZE);
4934 i = cckd->free1st;
4935 fpos = (off_t)cckd->cdevhdr[sfx].free;
4936 }
4937 }
4938
4939 do {
4940 /* Find a level 2 table to relocate */
4941 i = cckd->free1st;
4942 fpos = (off_t)cckd->cdevhdr[sfx].free;
4943 cckd_trace (dev, "gc_l2 first free[%d] pos 0x%x len %d pending %d\n",
4944 i, (int)fpos, i >= 0 ? (int)cckd->free[i].len : -1,
4945 i >= 0 ? cckd->free[i].pending : -1);
4946 if (i < 0 || fpos >= cckd->l2bounds || cckd->free[i].pending)
4947 goto cckd_gc_l2_exit;
4948
4949 if (cckd->free[i].len < CCKD_L2TAB_SIZE
4950 || (cckd->free[i].len != CCKD_L2TAB_SIZE
4951 && cckd->free[i].len < CCKD_L2TAB_SIZE + CCKD_FREEBLK_SIZE
4952 )
4953 )
4954 {
4955 for (i = 0; i < cckd->cdevhdr[sfx].numl1tab; i++)
4956 if (fpos + cckd->free[i].len == (off_t)cckd->l1[sfx][i])
4957 break;
4958 }
4959 else
4960 {
4961 for (i = 0; i < cckd->cdevhdr[sfx].numl1tab; i++)
4962 if (cckd->l2bounds - CCKD_L2TAB_SIZE < (off_t)cckd->l1[sfx][i]
4963 && cckd->l1[sfx][i] != 0xffffffff)
4964 break;
4965 }
4966
4967 if (i < cckd->cdevhdr[sfx].numl1tab)
4968 {
4969 cckd_trace (dev, "gc_l2 relocate l2[%d] pos 0x%x\n",
4970 i, cckd->l1[sfx][i]);
4971 if (cckd_read_l2 (dev, sfx, i) < 0)
4972 goto cckd_gc_l2_exit;
4973 if (cckd_write_l2 (dev) < 0)
4974 goto cckd_gc_l2_exit;
4975 }
4976 } while (i < cckd->cdevhdr[sfx].numl1tab);
4977
4978 cckd_gc_l2_exit:
4979 release_lock (&cckd->filelock);
4980 return 0;
4981
4982 cckd_gc_l2_exit_ok:
4983 cckd_trace (dev, "gc_l2 ok%s\n", "");
4984 cckd->l2ok = 1;
4985 goto cckd_gc_l2_exit;
4986 }
4987
4988 /*-------------------------------------------------------------------*/
4989 /* Find device by devnum */
4990 /*-------------------------------------------------------------------*/
cckd_find_device_by_devnum(U16 devnum)4991 DEVBLK *cckd_find_device_by_devnum (U16 devnum)
4992 {
4993 DEVBLK *dev;
4994 CCKDDASD_EXT *cckd;
4995
4996 cckd_lock_devchain (0);
4997 for (dev = cckdblk.dev1st; dev; dev = cckd->devnext)
4998 {
4999 if (dev->devnum == devnum) break;
5000 cckd = dev->cckd_ext;
5001 }
5002 cckd_unlock_devchain ();
5003 return dev;
5004 } /* end function cckd_find_device_by_devnum */
5005
5006 /*-------------------------------------------------------------------*/
5007 /* Uncompress a track image */
5008 /*-------------------------------------------------------------------*/
cckd_uncompress(DEVBLK * dev,BYTE * from,int len,int maxlen,int trk)5009 BYTE *cckd_uncompress (DEVBLK *dev, BYTE *from, int len, int maxlen,
5010 int trk)
5011 {
5012 CCKDDASD_EXT *cckd;
5013 BYTE *to = NULL; /* Uncompressed buffer */
5014 int newlen; /* Uncompressed length */
5015 BYTE comp; /* Compression type */
5016 static char *compress[] = {"none", "zlib", "bzip2"};
5017
5018 cckd = dev->cckd_ext;
5019
5020 cckd_trace (dev, "uncompress comp %d len %d maxlen %d trk %d\n",
5021 from[0] & CCKD_COMPRESS_MASK, len, maxlen, trk);
5022
5023 /* Extract compression type */
5024 comp = (from[0] & CCKD_COMPRESS_MASK);
5025
5026 /* Get a buffer to uncompress into */
5027 if (comp != CCKD_COMPRESS_NONE && cckd->newbuf == NULL)
5028 {
5029 cckd->newbuf = cckd_malloc (dev, "newbuf", maxlen);
5030 if (cckd->newbuf == NULL)
5031 return NULL;
5032 }
5033
5034 /* Uncompress the track image */
5035 switch (comp) {
5036
5037 case CCKD_COMPRESS_NONE:
5038 newlen = cckd_trklen (dev, from);
5039 to = from;
5040 break;
5041 case CCKD_COMPRESS_ZLIB:
5042 to = cckd->newbuf;
5043 newlen = cckd_uncompress_zlib (dev, to, from, len, maxlen);
5044 break;
5045 case CCKD_COMPRESS_BZIP2:
5046 to = cckd->newbuf;
5047 newlen = cckd_uncompress_bzip2 (dev, to, from, len, maxlen);
5048 break;
5049 default:
5050 newlen = -1;
5051 break;
5052 }
5053
5054 /* Validate the uncompressed track image */
5055 newlen = cckd_validate (dev, to, trk, newlen);
5056
5057 /* Return if successful */
5058 if (newlen > 0)
5059 {
5060 if (to != from)
5061 {
5062 cckd->newbuf = from;
5063 cckd->bufused = 1;
5064 }
5065 return to;
5066 }
5067
5068 /* Get a buffer now if we haven't gotten one */
5069 if (cckd->newbuf == NULL)
5070 {
5071 cckd->newbuf = cckd_malloc (dev, "newbuf2", maxlen);
5072 if (cckd->newbuf == NULL)
5073 return NULL;
5074 }
5075
5076 /* Try each uncompression routine in turn */
5077
5078 /* uncompressed */
5079 newlen = cckd_trklen (dev, from);
5080 newlen = cckd_validate (dev, from, trk, newlen);
5081 if (newlen > 0)
5082 return from;
5083
5084 /* zlib compression */
5085 to = cckd->newbuf;
5086 newlen = cckd_uncompress_zlib (dev, to, from, len, maxlen);
5087 newlen = cckd_validate (dev, to, trk, newlen);
5088 if (newlen > 0)
5089 {
5090 cckd->newbuf = from;
5091 cckd->bufused = 1;
5092 return to;
5093 }
5094
5095 /* bzip2 compression */
5096 to = cckd->newbuf;
5097 newlen = cckd_uncompress_bzip2 (dev, to, from, len, maxlen);
5098 newlen = cckd_validate (dev, to, trk, newlen);
5099 if (newlen > 0)
5100 {
5101 cckd->newbuf = from;
5102 cckd->bufused = 1;
5103 return to;
5104 }
5105
5106 /* Unable to uncompress */
5107 logmsg (_("HHCCD193E %4.4X file[%d] uncompress error trk %d: %2.2x%2.2x%2.2x%2.2x%2.2x\n"),
5108 dev->devnum, cckd->sfn, trk, from[0], from[1], from[2], from[3], from[4]);
5109 if (comp & ~cckdblk.comps)
5110 logmsg (_("HHCCD194E %4.4X file[%d] %s compression not supported\n"),
5111 dev->devnum, cckd->sfn, compress[comp]);
5112 return NULL;
5113 }
5114
cckd_uncompress_zlib(DEVBLK * dev,BYTE * to,BYTE * from,int len,int maxlen)5115 int cckd_uncompress_zlib (DEVBLK *dev, BYTE *to, BYTE *from, int len, int maxlen)
5116 {
5117 #if defined(HAVE_LIBZ)
5118 unsigned long newlen;
5119 int rc;
5120
5121 UNREFERENCED(dev);
5122 memcpy (to, from, CKDDASD_TRKHDR_SIZE);
5123 newlen = maxlen - CKDDASD_TRKHDR_SIZE;
5124 rc = uncompress(&to[CKDDASD_TRKHDR_SIZE], &newlen,
5125 &from[CKDDASD_TRKHDR_SIZE], len - CKDDASD_TRKHDR_SIZE);
5126 if (rc == Z_OK)
5127 {
5128 newlen += CKDDASD_TRKHDR_SIZE;
5129 to[0] = 0;
5130 }
5131 else
5132 newlen = -1;
5133
5134 cckd_trace (dev, "uncompress zlib newlen %d rc %d\n",(int)newlen,rc);
5135
5136 return (int)newlen;
5137 #else
5138 UNREFERENCED(dev);
5139 UNREFERENCED(to);
5140 UNREFERENCED(from);
5141 UNREFERENCED(len);
5142 UNREFERENCED(maxlen);
5143 return -1;
5144 #endif
5145 }
cckd_uncompress_bzip2(DEVBLK * dev,BYTE * to,BYTE * from,int len,int maxlen)5146 int cckd_uncompress_bzip2 (DEVBLK *dev, BYTE *to, BYTE *from, int len, int maxlen)
5147 {
5148 #if defined(CCKD_BZIP2)
5149 unsigned int newlen;
5150 int rc;
5151
5152 UNREFERENCED(dev);
5153 memcpy (to, from, CKDDASD_TRKHDR_SIZE);
5154 newlen = maxlen - CKDDASD_TRKHDR_SIZE;
5155 rc = BZ2_bzBuffToBuffDecompress (
5156 (void *)&to[CKDDASD_TRKHDR_SIZE], &newlen,
5157 (void *)&from[CKDDASD_TRKHDR_SIZE], len - CKDDASD_TRKHDR_SIZE,
5158 0, 0);
5159 if (rc == BZ_OK)
5160 {
5161 newlen += CKDDASD_TRKHDR_SIZE;
5162 to[0] = 0;
5163 }
5164 else
5165 newlen = -1;
5166
5167 cckd_trace (dev, "uncompress bz2 newlen %d rc %d\n",newlen,rc);
5168
5169 return (int)newlen;
5170 #else
5171 UNREFERENCED(dev);
5172 UNREFERENCED(to);
5173 UNREFERENCED(from);
5174 UNREFERENCED(len);
5175 UNREFERENCED(maxlen);
5176 return -1;
5177 #endif
5178 }
5179
5180 /*-------------------------------------------------------------------*/
5181 /* Compress a track image */
5182 /*-------------------------------------------------------------------*/
cckd_compress(DEVBLK * dev,BYTE ** to,BYTE * from,int len,int comp,int parm)5183 int cckd_compress (DEVBLK *dev, BYTE **to, BYTE *from, int len,
5184 int comp, int parm)
5185 {
5186 int newlen;
5187
5188 switch (comp) {
5189 case CCKD_COMPRESS_NONE:
5190 newlen = cckd_compress_none (dev, to, from, len, parm);
5191 break;
5192 case CCKD_COMPRESS_ZLIB:
5193 newlen = cckd_compress_zlib (dev, to, from, len, parm);
5194 break;
5195 case CCKD_COMPRESS_BZIP2:
5196 newlen = cckd_compress_bzip2 (dev, to, from, len, parm);
5197 break;
5198 default:
5199 newlen = cckd_compress_bzip2 (dev, to, from, len, parm);
5200 break;
5201 }
5202 return newlen;
5203 }
cckd_compress_none(DEVBLK * dev,BYTE ** to,BYTE * from,int len,int parm)5204 int cckd_compress_none (DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm)
5205 {
5206 UNREFERENCED(dev);
5207 UNREFERENCED(parm);
5208 *to = from;
5209 from[0] = CCKD_COMPRESS_NONE;
5210 return len;
5211 }
cckd_compress_zlib(DEVBLK * dev,BYTE ** to,BYTE * from,int len,int parm)5212 int cckd_compress_zlib (DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm)
5213 {
5214 #if defined(HAVE_LIBZ)
5215 unsigned long newlen;
5216 int rc;
5217 BYTE *buf;
5218
5219 UNREFERENCED(dev);
5220 buf = *to;
5221 from[0] = CCKD_COMPRESS_NONE;
5222 memcpy (buf, from, CKDDASD_TRKHDR_SIZE);
5223 buf[0] = CCKD_COMPRESS_ZLIB;
5224 newlen = 65535 - CKDDASD_TRKHDR_SIZE;
5225 rc = compress2 (&buf[CKDDASD_TRKHDR_SIZE], &newlen,
5226 &from[CKDDASD_TRKHDR_SIZE], len - CKDDASD_TRKHDR_SIZE,
5227 parm);
5228 newlen += CKDDASD_TRKHDR_SIZE;
5229 if (rc != Z_OK || (int)newlen >= len)
5230 {
5231 *to = from;
5232 newlen = len;
5233 }
5234 return (int)newlen;
5235 #else
5236
5237 #if defined(CCKD_BZIP2)
5238 return cckd_compress_bzip2 (dev, to, from, len, parm);
5239 #else
5240 return cckd_compress_none (dev, to, from, len, parm);
5241 #endif
5242
5243 #endif
5244 }
cckd_compress_bzip2(DEVBLK * dev,BYTE ** to,BYTE * from,int len,int parm)5245 int cckd_compress_bzip2 (DEVBLK *dev, BYTE **to, BYTE *from, int len, int parm)
5246 {
5247 #if defined(CCKD_BZIP2)
5248 unsigned int newlen;
5249 int rc;
5250 BYTE *buf;
5251
5252 UNREFERENCED(dev);
5253 buf = *to;
5254 from[0] = CCKD_COMPRESS_NONE;
5255 memcpy (buf, from, CKDDASD_TRKHDR_SIZE);
5256 buf[0] = CCKD_COMPRESS_BZIP2;
5257 newlen = 65535 - CKDDASD_TRKHDR_SIZE;
5258 rc = BZ2_bzBuffToBuffCompress (
5259 (void *)&buf[CKDDASD_TRKHDR_SIZE], &newlen,
5260 (void *)&from[CKDDASD_TRKHDR_SIZE], len - CKDDASD_TRKHDR_SIZE,
5261 parm >= 1 && parm <= 9 ? parm : 5, 0, 0);
5262 newlen += CKDDASD_TRKHDR_SIZE;
5263 if (rc != BZ_OK || newlen >= (unsigned int)len)
5264 {
5265 *to = from;
5266 newlen = len;
5267 }
5268 return newlen;
5269 #else
5270 return cckd_compress_zlib (dev, to, from, len, parm);
5271 #endif
5272 }
5273
5274 /*-------------------------------------------------------------------*/
5275 /* cckd command help */
5276 /*-------------------------------------------------------------------*/
cckd_command_help()5277 void cckd_command_help()
5278 {
5279 logmsg ("cckd command parameters:\n"
5280 "help\t\tDisplay help message\n"
5281 "stats\t\tDisplay cckd statistics\n"
5282 "opts\t\tDisplay cckd options\n"
5283 "comp=<n>\t\tOverride compression\t\t(-1 .. 2)\n"
5284 "compparm=<n>\tOverride compression parm\t\t(-1 .. 9)\n"
5285 "ra=<n>\t\tSet number readahead threads\t\t(1 .. 9)\n"
5286 "raq=<n>\t\tSet readahead queue size\t\t(0 .. 16)\n"
5287 "rat=<n>\t\tSet number tracks to read ahead\t\t(0 .. 16)\n"
5288 "wr=<n>\t\tSet number writer threads\t\t(1 .. 9)\n"
5289 "gcint=<n>\tSet garbage collector interval (sec)\t(1 .. 60)\n"
5290 "gcparm=<n>\tSet garbage collector parameter\t\t(-8 .. 8)\n"
5291 "\t\t (least agressive ... most aggressive)\n"
5292 "nostress=<n>\t1=Disable stress writes\n"
5293 "freepend=<n>\tSet free pending cycles\t\t\t(-1 .. 4)\n"
5294 "fsync=<n>\t1=Enable fsync()\n"
5295 "trace=<n>\tSet trace table size\t\t\t(0 .. 200000)\n"
5296 );
5297 } /* end function cckd_command_help */
5298
5299 /*-------------------------------------------------------------------*/
5300 /* cckd command stats */
5301 /*-------------------------------------------------------------------*/
cckd_command_opts()5302 void cckd_command_opts()
5303 {
5304 logmsg ("comp=%d,compparm=%d,ra=%d,raq=%d,rat=%d,"
5305 "wr=%d,gcint=%d,gcparm=%d,nostress=%d,\n"
5306 "\tfreepend=%d,fsync=%d,trace=%d,linuxnull=%d\n",
5307 cckdblk.comp == 0xff ? -1 : cckdblk.comp,
5308 cckdblk.compparm, cckdblk.ramax,
5309 cckdblk.ranbr, cckdblk.readaheads,
5310 cckdblk.wrmax, cckdblk.gcwait,
5311 cckdblk.gcparm, cckdblk.nostress, cckdblk.freepend,
5312 cckdblk.fsync, cckdblk.itracen, cckdblk.linuxnull);
5313 } /* end function cckd_command_opts */
5314
5315 /*-------------------------------------------------------------------*/
5316 /* cckd command stats */
5317 /*-------------------------------------------------------------------*/
cckd_command_stats()5318 void cckd_command_stats()
5319 {
5320 logmsg("reads....%10" I64_FMT "d Kbytes...%10" I64_FMT "d writes...%10" I64_FMT "d Kbytes...%10" I64_FMT "d\n"
5321 "readaheads%9" I64_FMT "d misses...%10" I64_FMT "d syncios..%10" I64_FMT "d misses...%10" I64_FMT "d\n"
5322 "switches.%10" I64_FMT "d l2 reads.%10" I64_FMT "d stress writes...%10" I64_FMT "d\n"
5323 "cachehits%10" I64_FMT "d misses...%10" I64_FMT "d l2 hits..%10" I64_FMT "d misses...%10" I64_FMT "d\n"
5324 "waits i/o......%10" I64_FMT "d cache....%10" I64_FMT "d\n"
5325 "garbage collector moves....%10" I64_FMT "d Kbytes...%10" I64_FMT "d\n",
5326 cckdblk.stats_reads, cckdblk.stats_readbytes >> 10,
5327 cckdblk.stats_writes, cckdblk.stats_writebytes >> 10,
5328 cckdblk.stats_readaheads, cckdblk.stats_readaheadmisses,
5329 cckdblk.stats_syncios, cckdblk.stats_synciomisses,
5330 cckdblk.stats_switches, cckdblk.stats_l2reads,
5331 cckdblk.stats_stresswrites,
5332 cckdblk.stats_cachehits, cckdblk.stats_cachemisses,
5333 cckdblk.stats_l2cachehits, cckdblk.stats_l2cachemisses,
5334 cckdblk.stats_iowaits, cckdblk.stats_cachewaits,
5335 cckdblk.stats_gcolmoves, cckdblk.stats_gcolbytes >> 10);
5336 } /* end function cckd_command_stats */
5337
5338 /*-------------------------------------------------------------------*/
5339 /* cckd command debug */
5340 /*-------------------------------------------------------------------*/
cckd_command_debug()5341 void cckd_command_debug()
5342 {
5343 }
5344
5345 /*-------------------------------------------------------------------*/
5346 /* cckd command processor */
5347 /*-------------------------------------------------------------------*/
cckd_command(char * op,int cmd)5348 DLL_EXPORT int cckd_command(char *op, int cmd)
5349 {
5350 char *kw, *p, c = '\0', buf[256];
5351 int val, opts = 0;
5352
5353 /* Display help for null operand */
5354 if (op == NULL)
5355 {
5356 if (memcmp (&cckdblk.id, "CCKDBLK ", sizeof(cckdblk.id)) == 0 && cmd)
5357 cckd_command_help();
5358 return 0;
5359 }
5360
5361 strcpy(buf, op);
5362 op = buf;
5363
5364 /* Initialize the global cckd block if necessary */
5365 if (memcmp (&cckdblk.id, "CCKDBLK ", sizeof(cckdblk.id)))
5366 cckddasd_init (0, NULL);
5367
5368 while (op)
5369 {
5370 /* Operands are delimited by commas */
5371 kw = op;
5372 op = strchr (op, ',');
5373 if (op) *op++ = '\0';
5374
5375 /* Check for keyword = value */
5376 if ((p = strchr (kw, '=')))
5377 {
5378 *p++ = '\0';
5379 sscanf (p, "%d%c", &val, &c);
5380 }
5381 else val = -77;
5382
5383 /* Parse the keyword */
5384 if (strcasecmp (kw, "help") == 0)
5385 {
5386 if (!cmd) return 0;
5387 cckd_command_help();
5388 }
5389 else if (strcasecmp (kw, "stats") == 0)
5390 {
5391 if (!cmd) return 0;
5392 cckd_command_stats ();
5393 }
5394 else if (strcasecmp (kw, "opts") == 0)
5395 {
5396 if (!cmd) return 0;
5397 cckd_command_opts();
5398 }
5399 else if (strcasecmp (kw, "debug") == 0)
5400 {
5401 if (!cmd) return 0;
5402 cckd_command_debug();
5403 }
5404 else if (strcasecmp (kw, "comp") == 0)
5405 {
5406 if (val < -1 || (val & ~cckdblk.comps) || c != '\0')
5407 {
5408 logmsg ("Invalid value for comp=\n");
5409 return -1;
5410 }
5411 else
5412 {
5413 cckdblk.comp = val < 0 ? 0xff : val;
5414 opts = 1;
5415 }
5416 }
5417 else if (strcasecmp (kw, "compparm") == 0)
5418 {
5419 if (val < -1 || val > 9 || c != '\0')
5420 {
5421 logmsg ("Invalid value for compparm=\n");
5422 return -1;
5423 }
5424 else
5425 {
5426 cckdblk.compparm = val;
5427 opts = 1;
5428 }
5429 }
5430 else if (strcasecmp (kw, "ra") == 0)
5431 {
5432 if (val < CCKD_MIN_RA || val > CCKD_MAX_RA || c != '\0')
5433 {
5434 logmsg ("Invalid value for ra=\n");
5435 return -1;
5436 }
5437 else
5438 {
5439 cckdblk.ramax = val;
5440 opts = 1;
5441 }
5442 }
5443 else if (strcasecmp (kw, "raq") == 0)
5444 {
5445 if (val < 0 || val > CCKD_MAX_RA_SIZE || c != '\0')
5446 {
5447 logmsg ("Invalid value for raq=\n");
5448 return -1;
5449 }
5450 else
5451 {
5452 cckdblk.ranbr = val;
5453 opts = 1;
5454 }
5455 }
5456 else if (strcasecmp (kw, "rat") == 0)
5457 {
5458 if (val < 0 || val > CCKD_MAX_RA_SIZE || c != '\0')
5459 {
5460 logmsg ("Invalid value for rat=\n");
5461 return -1;
5462 }
5463 else
5464 {
5465 cckdblk.readaheads = val;
5466 opts = 1;
5467 }
5468 }
5469 else if (strcasecmp (kw, "wr") == 0)
5470 {
5471 if (val < CCKD_MIN_WRITER || val > CCKD_MAX_WRITER || c != '\0')
5472 {
5473 logmsg ("Invalid value for wr=\n");
5474 return -1;
5475 }
5476 else
5477 {
5478 cckdblk.wrmax = val;
5479 opts = 1;
5480 }
5481 }
5482 else if (strcasecmp (kw, "gcint") == 0)
5483 {
5484 if (val < 1 || val > 60 || c != '\0')
5485 {
5486 logmsg ("Invalid value for gcint=\n");
5487 return -1;
5488 }
5489 else
5490 {
5491 cckdblk.gcwait = val;
5492 opts = 1;
5493 }
5494 }
5495 else if (strcasecmp (kw, "gcparm") == 0)
5496 {
5497 if (val < -8 || val > 8 || c != '\0')
5498 {
5499 logmsg ("Invalid value for gcparm=\n");
5500 return -1;
5501 }
5502 else
5503 {
5504 cckdblk.gcparm = val;
5505 opts = 1;
5506 }
5507 }
5508 else if (strcasecmp (kw, "nostress") == 0)
5509 {
5510 if (val < 0 || val > 1 || c != '\0')
5511 {
5512 logmsg ("Invalid value for nostress=\n");
5513 return -1;
5514 }
5515 else
5516 {
5517 cckdblk.nostress = val;
5518 opts = 1;
5519 }
5520 }
5521 else if (strcasecmp (kw, "freepend") == 0)
5522 {
5523 if (val < -1 || val > CCKD_MAX_FREEPEND || c != '\0')
5524 {
5525 logmsg ("Invalid value for freepend=\n");
5526 return -1;
5527 }
5528 else
5529 {
5530 cckdblk.freepend = val;
5531 opts = 1;
5532 }
5533 }
5534 else if (strcasecmp (kw, "fsync") == 0)
5535 {
5536 if (val < 0 || val > 1 || c != '\0')
5537 {
5538 logmsg ("Invalid value for fsync=\n");
5539 return -1;
5540 }
5541 else
5542 {
5543 cckdblk.fsync = val;
5544 opts = 1;
5545 }
5546 }
5547 else if (strcasecmp (kw, "trace") == 0)
5548 {
5549 if (val < 0 || val > CCKD_MAX_TRACE || c != '\0')
5550 {
5551 logmsg ("Invalid value for trace=\n");
5552 return -1;
5553 }
5554 else
5555 {
5556 /* Disable tracing in case it's already active */
5557 CCKD_TRACE *p = cckdblk.itrace;
5558 cckdblk.itrace = NULL;
5559 if (p)
5560 {
5561 SLEEP (1);
5562 cckdblk.itrace = cckdblk.itracep = cckdblk.itracex = NULL;
5563 cckdblk.itracen = 0;
5564 cckd_free (NULL, "trace", p);
5565 }
5566
5567 /* Get a new trace table */
5568 if (val > 0)
5569 {
5570 p = cckd_calloc (NULL, "trace", val, sizeof(CCKD_TRACE));
5571 if (p)
5572 {
5573 cckdblk.itracen = val;
5574 cckdblk.itracex = p + val;
5575 cckdblk.itracep = p;
5576 cckdblk.itrace = p;
5577 }
5578 }
5579 opts = 1;
5580 }
5581 }
5582 else if (strcasecmp (kw, "linuxnull") == 0)
5583 {
5584 if (val < 0 || val > 1 || c != '\0')
5585 {
5586 logmsg ("Invalid value for linuxnull=\n");
5587 return -1;
5588 }
5589 else
5590 {
5591 cckdblk.linuxnull = val;
5592 opts = 1;
5593 }
5594 }
5595 else if (strcasecmp (kw, "gcstart") == 0)
5596 {
5597 DEVBLK *dev;
5598 CCKDDASD_EXT *cckd;
5599 TID tid;
5600 int flag = 0;
5601
5602 cckd_lock_devchain(0);
5603 for (dev = cckdblk.dev1st; dev; dev = cckd->devnext)
5604 {
5605 cckd = dev->cckd_ext;
5606 obtain_lock (&cckd->filelock);
5607 if (cckd->cdevhdr[cckd->sfn].free_total)
5608 {
5609 cckd->cdevhdr[cckd->sfn].options |= (CCKD_OPENED | CCKD_ORDWR);
5610 cckd_write_chdr (dev);
5611 flag = 1;
5612 }
5613 release_lock (&cckd->filelock);
5614 }
5615 cckd_unlock_devchain();
5616 if (flag && cckdblk.gcs < cckdblk.gcmax)
5617 create_thread (&tid, JOINABLE, cckd_gcol, NULL, "cckd_gcol");
5618 }
5619 else
5620 {
5621 logmsg ("cckd invalid keyword: %s\n",kw);
5622 if (!cmd) return -1;
5623 cckd_command_help ();
5624 op = NULL;
5625 }
5626 }
5627
5628 if (cmd && opts) cckd_command_opts();
5629 return 0;
5630 } /* end function cckd_command */
5631
5632 /*-------------------------------------------------------------------*/
5633 /* Print internal trace */
5634 /*-------------------------------------------------------------------*/
cckd_print_itrace()5635 DLL_EXPORT void cckd_print_itrace()
5636 {
5637 CCKD_TRACE *i, *p; /* Trace table pointers */
5638
5639 if (!cckdblk.itrace) return;
5640 logmsg (_("HHCCD900I print_itrace\n"));
5641 i = cckdblk.itrace;
5642 cckdblk.itrace = NULL;
5643 SLEEP (1);
5644 p = cckdblk.itracep;
5645 if (p >= cckdblk.itracex) p = i;
5646 do
5647 {
5648 if (p[0] != '\0')
5649 logmsg ("%s", (char *)p);
5650 if (++p >= cckdblk.itracex) p = i;
5651 } while (p != cckdblk.itracep);
5652 memset (i, 0, cckdblk.itracen * sizeof(CCKD_TRACE));
5653 cckdblk.itracep = i;
5654 cckdblk.itrace = i;
5655 } /* end function cckd_print_itrace */
5656
5657 /*-------------------------------------------------------------------*/
5658 /* Write internal trace entry */
5659 /*-------------------------------------------------------------------*/
cckd_trace(DEVBLK * dev,char * msg,...)5660 void cckd_trace(DEVBLK *dev, char *msg, ...)
5661 {
5662 va_list vl;
5663 struct timeval tv;
5664 time_t t;
5665 char tbuf[64];
5666 CCKD_TRACE *p;
5667 int l;
5668
5669 if (dev && (dev->ccwtrace||dev->ccwstep))
5670 {
5671 char *bfr;
5672 int sz=1024,rc;
5673 bfr=malloc(1024);
5674 va_start(vl,msg);
5675 while(1)
5676 {
5677 rc=vsnprintf(bfr,sz,msg,vl);
5678 if(rc<0)
5679 {
5680 free(bfr);
5681 bfr=NULL;
5682 break;
5683 }
5684 if(rc<sz)
5685 {
5686 break;
5687 }
5688 sz+=256;
5689 bfr=realloc(bfr,sz);
5690 }
5691 if(bfr)
5692 {
5693 logmsg("%4.4X:%s",dev->devnum,bfr);
5694 }
5695 va_end(vl);
5696 }
5697 /* ISW FIXME : The following code has a potential */
5698 /* for heap overrun (vsprintf) */
5699 if (cckdblk.itrace)
5700 {
5701 gettimeofday(&tv, NULL);
5702 t = tv.tv_sec;
5703 strcpy(tbuf, ctime(&t));
5704 tbuf[19] = '\0';
5705
5706 va_start(vl,msg);
5707
5708 p = cckdblk.itracep++;
5709 if (p >= cckdblk.itracex)
5710 {
5711 p = cckdblk.itrace;
5712 cckdblk.itracep = p + 1;
5713 }
5714
5715 if (p)
5716 {
5717 l = sprintf ((char *)p, "%s" "." "%6.6ld %4.4X:",
5718 tbuf+11, (long)(tv.tv_usec), dev ? dev->devnum : 0);
5719 vsprintf ((char *)p + l, msg, vl);
5720 }
5721 }
5722 } /* end function cckd_trace */
5723
5724 DEVHND cckddasd_device_hndinfo = {
5725 &ckddasd_init_handler, /* Device Initialisation */
5726 &ckddasd_execute_ccw, /* Device CCW execute */
5727 &cckddasd_close_device, /* Device Close */
5728 &ckddasd_query_device, /* Device Query */
5729 &cckddasd_start, /* Device Start channel pgm */
5730 &cckddasd_end, /* Device End channel pgm */
5731 &cckddasd_start, /* Device Resume channel pgm */
5732 &cckddasd_end, /* Device Suspend channel pgm */
5733 &cckd_read_track, /* Device Read */
5734 &cckd_update_track, /* Device Write */
5735 &cckd_used, /* Device Query used */
5736 NULL, /* Device Reserve */
5737 NULL, /* Device Release */
5738 NULL, /* Device Attention */
5739 NULL, /* Immediate CCW Codes */
5740 NULL, /* Signal Adapter Input */
5741 NULL, /* Signal Adapter Ouput */
5742 &ckddasd_hsuspend, /* Hercules suspend */
5743 &ckddasd_hresume /* Hercules resume */
5744 };
5745
5746 DEVHND cfbadasd_device_hndinfo = {
5747 &fbadasd_init_handler, /* Device Initialisation */
5748 &fbadasd_execute_ccw, /* Device CCW execute */
5749 &cckddasd_close_device, /* Device Close */
5750 &fbadasd_query_device, /* Device Query */
5751 &cckddasd_start, /* Device Start channel pgm */
5752 &cckddasd_end, /* Device End channel pgm */
5753 &cckddasd_start, /* Device Resume channel pgm */
5754 &cckddasd_end, /* Device Suspend channel pgm */
5755 &cfba_read_block, /* Device Read */
5756 &cfba_write_block, /* Device Write */
5757 &cfba_used, /* Device Query used */
5758 NULL, /* Device Reserve */
5759 NULL, /* Device Release */
5760 NULL, /* Device Attention */
5761 NULL, /* Immediate CCW Codes */
5762 NULL, /* Signal Adapter Input */
5763 NULL, /* Signal Adapter Ouput */
5764 &fbadasd_hsuspend, /* Hercules suspend */
5765 &fbadasd_hresume /* Hercules resume */
5766 };
5767