File: calc-format.c

package info (click to toggle)
fdutils 5.3-3
  • links: PTS
  • area: main
  • in suites: potato
  • size: 1,004 kB
  • ctags: 621
  • sloc: ansic: 6,098; sh: 2,236; makefile: 279; sed: 4
file content (515 lines) | stat: -rw-r--r-- 11,774 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
#include <sys/types.h>
#include <stdio.h>
#include "superformat.h"
#include "fdutils.h"

#define GAP_DIVISOR (128*128)

#define GAPSIZE(j) (( (128<<j) * gap + GAP_DIVISOR/2 ) / GAP_DIVISOR)
#define SSIZE(j)   ( (128<<j) + GAPSIZE(j) + header_size)


static inline int chunks_in_sect(struct params *fd, int i, 
				 int gap, int chunksize)
{
	return (SSIZE(i)-1) / chunksize + 1;
}

static inline int sizeOfSector(struct params *fd, int i)
{
	int j;

	if(i < 0)
		return -1; /* reserved value, meaning no multisize */

	for(j = MAX_SIZECODE-1; j >= 0 && fd->last_sect[j] <= i; j--);
	return j;
}


static inline int firstSector(struct params *fd, int i)
{
	if(i>=MAX_SIZECODE-1)
		return 1;
	else
		return fd->last_sect[i+1];
}

static inline int lastSector(struct params *fd, int i)
{
	return fd->last_sect[i];
}

static inline int nrSectorsForSize(struct params *fd, int i)
{
	return  lastSector(fd, i) - firstSector(fd, i);
}


static inline int isMultisize(struct params *fd)
{
	int i, n;

	n = 0;
	for(i = 1; i < MAX_SIZECODE; i++) {
		if(nrSectorsForSize(fd, i))
			n++;
	}
	return n > 1;
}

static int compute_tot_size(struct params *fd,
			    int chunksize,
			    int gap,
			    int tailsize)
{
	int i, nr;

	fd->nssect = 0;
	fd->actual_interleave = 1;
	for(i= 0; i < MAX_SIZECODE; i++){
		nr = nrSectorsForSize(fd, i);
		fd->nssect += chunks_in_sect(fd, i, gap, chunksize) * nr;
		if(nr && GAPSIZE(i) < 34)
			fd->actual_interleave = 2;
	}

	if (tailsize >= 0)
		return (fd->nssect - 
			chunks_in_sect(fd, tailsize, gap, chunksize)) *
			chunksize + SSIZE(tailsize);
	else
		return fd->nssect * chunksize;
}

/* find out how many sectors of each size there are */
static void compute_sizes(struct params *fd, 
			  int remaining, /* bytes per track */
			  int max_sizecode) /* size of biggest sector used */
{
	int cur_sector;
	int sizes; /* number of different sizes found along the track */
	int i;
	int nr_sectors;

	cur_sector = 1;
	sizes=0;
	for (i=MAX_SIZECODE-1; i>=0; --i) {
		if(i > max_sizecode)
			nr_sectors = 0;
		else {			
			nr_sectors = remaining >> (i+7);
			remaining -= nr_sectors << (i+7);
		}
		cur_sector += nr_sectors;
		fd->last_sect[i] = cur_sector;
		if(nr_sectors)
			sizes++;
	}
	fd->dsect = cur_sector-1; /* number of data sectors */
	if(sizes > 1)
		fd->need_init = 1;

	if (remaining) {
		fprintf(stderr,"Internal error: remaining not 0\n");
		abort();
	}
}

static int compute_gap(struct params *fd, int track_size)
{
	int gap;

	gap = (fd->raw_capacity-track_size)*track_size/GAP_DIVISOR-header_size;
	if (gap > 0x6c * 32)
		/* kludge to allow to format at least the usual
		 * formats on out of tolerance drives */
		gap = 0x6c * 32;		
	if (gap < 0)
		gap = 0;
	return gap;
}

/*
 * Determine the chunk size for disks which have same sized sectors.
 * We do this by dividing the sector size through ever increasing
 * divisors.  t_chunksize = ceil( sector_size / divisor )
 * We skip divisors yielding unreachable chunk sizes.
 */

static int compute_chunk_size_for_monosize(struct params *fd,
					   int gap,
					   int tailsize)
{
	int min_chunksize; /* minimal chunk size reached so far */
	int t_chunksize; /* tentative chunk size */
	int ceiling; /* maximal divisor */
	int t_sect_size; /* tentative sector size */
	int min_sect_size=0; /* actual sector size */
	int sector_size;
	int chunks_per_sect;
	int i;

	sector_size = SSIZE(sizeOfSector(fd,1));
	min_chunksize = 0;
	ceiling = sector_size /( 129 + header_size);
	for(i= 1; i <= ceiling; i++ ){
		t_chunksize = (sector_size - 1)/i + 1;
		
		/* unreachable chunk sizes */
		if (((t_chunksize-header_size-1) & 511) > 255 &&
		    t_chunksize > 768 + header_size)
			continue;
		
		chunks_per_sect = (sector_size - 1)/t_chunksize + 1;
		t_sect_size = chunks_per_sect * t_chunksize;

		/* find the smallest sector size */
		if (!min_chunksize || t_sect_size < min_sect_size ){
			min_sect_size = t_sect_size;
			min_chunksize = t_chunksize;
		}
		if (t_sect_size == sector_size)
			break;
	}
	if(min_chunksize != sector_size)
		fd->need_init = 1;
	return  min_chunksize;
}


static int compute_chunk_size_for_multisize(struct params *fd,
					    int gap,
					    int tailsize)
{
	int t_chunksize;
	int tot_size;
	int min_chunksize;
	int i;
	int min_tot_size = 0;

	min_chunksize = 0;
	fd->need_init = 1;
	for(t_chunksize = fd->max_chunksize; 
	    t_chunksize > 128+header_size; 
	    t_chunksize--){
		for(i=0; i < MAX_SIZECODE; i++ ){
			if(t_chunksize<(128<<i)+header_size+1){
				t_chunksize=(128<<(i-1)) +
					256 + header_size;
				break;
			}
			if (t_chunksize <= (128 << i) + 256 + header_size)
				break;
		}
		tot_size = compute_tot_size(fd, t_chunksize, gap, tailsize);
		if ( !min_chunksize || tot_size <= min_tot_size ){
#if 0
			if (verbosity >= 6)
				printf("%d chasing %d\n",
				       t_chunksize, min_chunksize);
#endif
			min_tot_size = tot_size;
			min_chunksize = t_chunksize;
		}
	}
	return min_chunksize;
}



static void compute_chunk_size(struct params *fd,
			      int gap,
			      int tailsize)

{
	if (isMultisize(fd))
		fd->chunksize = compute_chunk_size_for_multisize(fd, gap, 
								 tailsize);
	else
		fd->chunksize = compute_chunk_size_for_monosize(fd, gap, 
								tailsize);
}


/* convert chunksize to sizecode/fmt_gap pair */
static void convert_chunksize(struct params *fd)
{
	int i;


	for (i=0; i < MAX_SIZECODE; ++i) {
		if (fd->chunksize < (128 << i) + header_size + 1) {
			fprintf(stderr,"Bad chunksize %d\n", fd->chunksize);
			exit(1);
		}
		if (fd->chunksize <= (128 << i) + 256 + header_size) {
			fd->sizecode = i;
			fd->fmt_gap = fd->chunksize - (128 << i) - header_size;
			break;
		}
	}
	if (i == MAX_SIZECODE){
		fprintf(stderr,"Chunksize %d too big\n", fd->chunksize );
		exit(1);
	}
}



/*
 * calculate the ordering of the sectors along the track in such
 * a way that the last one is sector number <tailsect>
 */
static void calc_sequence(struct params *fd, int tailsect)
{
	int sec_id, cur_sector, i;

	fd->sequence = SafeNewArray(fd->dsect,struct fparm2);
	cur_sector = fd->dsect-1;

	/* construct the sequence while working backwards.  cur_sector
	 * points to the place where the next sector will be placed.
	 * We place it, then move circularily backwards placing more
	 * and more sectors */
	sec_id = tailsect;
	fd->rotations = 0;
	for(i=0; i < fd->dsect; 
	    i++, cur_sector -= fd->actual_interleave, sec_id--) {
		if (sec_id == 0)
			sec_id = fd->dsect;

		if ( cur_sector < 0) {
			cur_sector += fd->dsect;
			if(sec_id != fd->dsect)
				fd->rotations++;
		}
			
		/* slot occupied, look elsewhere */
		while(fd->sequence[cur_sector].sect ){
			cur_sector--;
			if ( cur_sector < 0 ) {
				cur_sector += fd->dsect;
				if(sec_id != fd->dsect)
					fd->rotations++;
			}
		}

		/* place the sector */
		fd->sequence[cur_sector].sect = sec_id;
		fd->sequence[cur_sector].size = sizeOfSector(fd, sec_id);
	}

	/* handle wrap-around between tailsect and tailsect+1 */
	if(tailsect != fd->dsect) {
		/* always add one rotation, because tailsect+1 cannot be
		 * at the last position, thus is necessarily earlyer */
		fd->rotations++;
		
		if(fd->actual_interleave == 2 && 
		   cur_sector + fd->actual_interleave == 1)
			/* if we use interleave, and the last sector was
			 * placed at the first last position, add one
			 * extra rotation for tailsect+1 following tailsect
			 * too closely */
			fd->rotations++;
	}
}


/* given the sequence, calculate the exact placement of the sectors */
static void calc_placement(struct params *fd, int gap)
{
	int cur_sector, i, max_offset;
	int track_end=0;
	int final_slack; /* slack space extending from data start of last
			  * sector on the track to fd->raw_capacity mark */

	/* now compute the placement in terms of small sectors */
	cur_sector = 0;
	for(i=0; i< fd->dsect; i++){
		fd->sequence[i].offset = cur_sector;
		max_offset = cur_sector;

		/* offset of the starting sector */
		if ( fd->sequence[i].sect == 1 )
			fd->min = cur_sector * fd->chunksize;

		/* offset of the end of the of the highest sector */
		if (fd->sequence[i].sect == fd->dsect)
			track_end = cur_sector * fd->chunksize + 
				header_size + index_size +
				SSIZE(fd->sequence[i].size);

		if(i == fd->dsect - 1)
			break;

		cur_sector += chunks_in_sect(fd, 
					     fd->sequence[i].size, 
					     gap, fd->chunksize);
	}
	final_slack = fd->raw_capacity - cur_sector * fd->chunksize -
		header_size - index_size - 1;
	if(final_slack < 0) {
		fprintf(stderr,
			"Internal error, negative final slack %d\n",
			final_slack);
		abort();
	}
	fd->max = fd->min + final_slack;

	fd->length = fd->rotations * fd->raw_capacity + track_end - fd->min;
	if(fd->length < 0) {
		fprintf(stderr,
			"Internal error, negative track length %d %d %d\n",
			fd->length, track_end, fd->min);
		abort();
		exit(1);
	}


	/* this format accepts any offsets ranging from fd->min to fd->max.
	 * After this track, the current offset will be:
	 *  fd->track_end + initial_offset - fd->min
	 */
}


static int compute_chunks_per_sect(struct params *fd,
				    int tracksize,
				    int sizecode,
				    int *gap,
				    int mask,
				    int tailsize)
{
	int tot_size;

	if (! (mask & SET_FMTGAP))
		*gap = compute_gap(fd, tracksize);	
	while(1) {
		compute_chunk_size(fd, *gap, tailsize);
		tot_size=compute_tot_size(fd, fd->chunksize, *gap, tailsize);
		if(fd->raw_capacity >= tot_size)
			/* enough space available, ok */
			break;
		if ((mask & SET_FMTGAP) || *gap <= 0)
			/* does not fit on disk */
			return -1;

		*gap -= (tot_size-fd->raw_capacity) * GAP_DIVISOR / tracksize;
		if (*gap < 0)
			*gap = 0;
	}

	convert_chunksize(fd);
	
	if (mask & SET_INTERLEAVE)
		fd->actual_interleave = fd->preset_interleave;

	if(verbosity >= 9) {
		printf("%d raw bytes per cylinder\n", tot_size );
		printf("%d final gap\n",
			fd->raw_capacity - tot_size );
	}
	return 0;
}

static void compute_sector_sequence(struct params *fd, int tailsect, int gap)
{
	calc_sequence(fd, tailsect);
	calc_placement(fd, gap);

	if (verbosity >= 9)
		printf("chunksize=%d\n", fd->chunksize);
}


static void compute_all_sequences_for_size(struct params *fd,
					   int *offset,
					   int tracksize,
					   int sizecode,
					   int gap,
					   int mask,
					   int tailsize)
{
	int base = *offset;
	int i;

	/* no sectors of this size */
	if(!nrSectorsForSize(fd, tailsize))
		return;

	fd[*offset] = fd[0];
	if(compute_chunks_per_sect(fd + *offset, tracksize, sizecode,
				   &gap, /* gap. expressed in 1/256 bytes */
				   mask, tailsize) < 0) {
		/* not enough raw space for this arrangement */
		return;
	}

	for(i = firstSector(fd, tailsize);
	    i < lastSector(fd, tailsize);
	    i++) {
		fd[*offset] = fd[base];
		compute_sector_sequence(fd+*offset, i, gap);
		(*offset)++;
	}
}



int compute_all_sequences(struct params *fd, 
			  int tracksize,
			  int sizecode,
			  int gap,
			  int mask, 
			  int biggest_last)
{	
	int offset, i;
	
	compute_sizes(fd, sectors*512,sizecode);

	offset = 0;
	for(i=MAX_SIZECODE - 1 ; i >= 0; i--) {
		compute_all_sequences_for_size(fd, &offset, tracksize, 
					       sizecode, gap, mask, i);
		if(biggest_last && offset)
			break;
	}
	
	if(! offset){
		fprintf(stderr,
			"Not enough raw space on this disk for this format\n");
		exit(1);
	}
	return offset;
}



void compute_track0_sequence(struct params *fd)
{
	int i;
	int sectors;

	sectors= fd->nssect = fd->dsect;

	fd->length = fd->raw_capacity;
	fd->chunksize = 0x6c + 574;

	fd->need_init = 0;
	fd->sequence = SafeNewArray(fd->dsect,struct fparm2);

	fd->sizecode = 2;
	if ( fd->rate & 0x40 )
		fd->fmt_gap = 0x54;
	else
		fd->fmt_gap = 0x6c;
	fd->min = 0;

	for(i=0; i<sectors; i++){
		fd->sequence[i].sect = i+1;
		fd->sequence[i].size = 2;
		fd->sequence[i].offset = i;
	}
}