1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 1994-2000 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/param.h>
31*0Sstevel@tonic-gate #include <sys/systm.h>		/* for bzero */
32*0Sstevel@tonic-gate #include <sys/machlock.h>
33*0Sstevel@tonic-gate #include <sys/spl.h>
34*0Sstevel@tonic-gate #include <sys/promif.h>
35*0Sstevel@tonic-gate #include <sys/debug.h>
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #include "tnf_buf.h"
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate /*
40*0Sstevel@tonic-gate  * Defines
41*0Sstevel@tonic-gate  */
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #define	TNFW_B_ALLOC_LO		0x1
44*0Sstevel@tonic-gate #define	TNFW_B_MAXALLOCTRY 	32
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate #define	TNF_MAXALLOC		(TNF_BLOCK_SIZE - sizeof (tnf_block_header_t))
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate /*
49*0Sstevel@tonic-gate  * Globals
50*0Sstevel@tonic-gate  */
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate TNFW_B_STATE tnfw_b_state = TNFW_B_NOBUFFER | TNFW_B_STOPPED;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate /*
55*0Sstevel@tonic-gate  * Locals
56*0Sstevel@tonic-gate  */
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate static int	spinlock_spl;
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /*
61*0Sstevel@tonic-gate  * Declarations
62*0Sstevel@tonic-gate  */
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate static tnf_block_header_t *tnfw_b_alloc_block(tnf_buf_file_header_t *,
65*0Sstevel@tonic-gate     enum tnf_alloc_mode);
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate /*
68*0Sstevel@tonic-gate  * (Private) Allocate a new block.  Return NULL on failure and mark
69*0Sstevel@tonic-gate  * tracing as broken.  'istag' is non-zero if the block is to be
70*0Sstevel@tonic-gate  * non-reclaimable.  All blocks are returned A-locked.
71*0Sstevel@tonic-gate  */
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate static tnf_block_header_t *
74*0Sstevel@tonic-gate tnfw_b_alloc_block(tnf_buf_file_header_t *fh, enum tnf_alloc_mode istag)
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate 	tnf_block_header_t 	*block;
77*0Sstevel@tonic-gate 	ulong_t			bcount;
78*0Sstevel@tonic-gate 	ulong_t			tmp_bn, bn, new_bn;
79*0Sstevel@tonic-gate 	ulong_t			tmp_gen, gen, new_gen;
80*0Sstevel@tonic-gate 	ulong_t			next;
81*0Sstevel@tonic-gate 	int			i;
82*0Sstevel@tonic-gate 	lock_t			*lp;
83*0Sstevel@tonic-gate 	ushort_t		spl;
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	if (tnfw_b_state != TNFW_B_RUNNING)
86*0Sstevel@tonic-gate 		return (NULL);
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 	lp = &fh->lock;
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 	/*
91*0Sstevel@tonic-gate 	 * Check reserved area first for tag block allocations
92*0Sstevel@tonic-gate 	 * Tag allocations are rare, so we move the code out of line
93*0Sstevel@tonic-gate 	 */
94*0Sstevel@tonic-gate 	if (istag)
95*0Sstevel@tonic-gate 		goto try_reserved;
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate try_loop:
98*0Sstevel@tonic-gate 	/*
99*0Sstevel@tonic-gate 	 * Search for a block, using hint as starting point.
100*0Sstevel@tonic-gate 	 */
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 	bcount = fh->com.block_count;	/* total block count */
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	gen = fh->next_alloc.gen;
105*0Sstevel@tonic-gate 	bn = fh->next_alloc.block[gen & TNFW_B_ALLOC_LO];
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	for (i = 0; i < TNFW_B_MAXALLOCTRY; i++) {
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 		/*
110*0Sstevel@tonic-gate 		 * Calculate next (not this) block to look for.
111*0Sstevel@tonic-gate 		 * Needed for updating the hint.
112*0Sstevel@tonic-gate 		 */
113*0Sstevel@tonic-gate 		if ((new_bn = bn + 1) >= bcount) {
114*0Sstevel@tonic-gate 			new_bn = TNFW_B_DATA_BLOCK_BEGIN >> TNF_BLOCK_SHIFT;
115*0Sstevel@tonic-gate 			new_gen = gen + 1;
116*0Sstevel@tonic-gate 		} else
117*0Sstevel@tonic-gate 			new_gen = gen;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 		/*
120*0Sstevel@tonic-gate 		 * Try to reserve candidate block
121*0Sstevel@tonic-gate 		 */
122*0Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
123*0Sstevel@tonic-gate 		block = (tnf_block_header_t *)
124*0Sstevel@tonic-gate 			((char *)fh + (bn << TNF_BLOCK_SHIFT));
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 		if (lock_try(&block->A_lock))
127*0Sstevel@tonic-gate 			if (block->generation < gen &&
128*0Sstevel@tonic-gate 			    lock_try(&block->B_lock))
129*0Sstevel@tonic-gate 				goto update_hint;
130*0Sstevel@tonic-gate 			else
131*0Sstevel@tonic-gate 				lock_clear(&block->A_lock);
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate 		/* Reload hint values */
134*0Sstevel@tonic-gate 		gen = fh->next_alloc.gen;
135*0Sstevel@tonic-gate 		bn = fh->next_alloc.block[gen & TNFW_B_ALLOC_LO];
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 		/* adjust if we know a little better than the hint */
138*0Sstevel@tonic-gate 		if ((new_bn > bn && new_gen == gen) || new_gen > gen) {
139*0Sstevel@tonic-gate 			gen = new_gen;
140*0Sstevel@tonic-gate 			bn = new_bn;
141*0Sstevel@tonic-gate 		}
142*0Sstevel@tonic-gate 	}
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	goto loop_fail;
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate update_hint:
147*0Sstevel@tonic-gate 	/*
148*0Sstevel@tonic-gate 	 * Re-read the hint and update it only if we'll be increasing it.
149*0Sstevel@tonic-gate 	 */
150*0Sstevel@tonic-gate 	lock_set_spl(lp, spinlock_spl, &spl);
151*0Sstevel@tonic-gate 	tmp_gen = fh->next_alloc.gen;
152*0Sstevel@tonic-gate 	tmp_bn = fh->next_alloc.block[tmp_gen & TNFW_B_ALLOC_LO];
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	if ((new_gen == tmp_gen && new_bn > tmp_bn) || new_gen > tmp_gen) {
155*0Sstevel@tonic-gate 		/*
156*0Sstevel@tonic-gate 		 * Order is important here!  It is the write to
157*0Sstevel@tonic-gate 		 * next_alloc.gen that atomically records the new
158*0Sstevel@tonic-gate 		 * value.
159*0Sstevel@tonic-gate 		 */
160*0Sstevel@tonic-gate 		fh->next_alloc.block[new_gen & TNFW_B_ALLOC_LO] = new_bn;
161*0Sstevel@tonic-gate 		fh->next_alloc.gen = new_gen;
162*0Sstevel@tonic-gate 	}
163*0Sstevel@tonic-gate 	lock_clear_splx(lp, spl);
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate got_block:
166*0Sstevel@tonic-gate 	/*
167*0Sstevel@tonic-gate 	 * Initialize and return the block
168*0Sstevel@tonic-gate 	 */
169*0Sstevel@tonic-gate 	/* ASSERT(block->tag == TNF_BLOCK_HEADER_TAG); */
170*0Sstevel@tonic-gate 	block->bytes_valid = sizeof (tnf_block_header_t);
171*0Sstevel@tonic-gate 	block->next_block = NULL;
172*0Sstevel@tonic-gate 	/* LINTED assignment of 64-bit integer to 32-bit integer */
173*0Sstevel@tonic-gate 	block->generation = istag ? TNF_TAG_GENERATION_NUM : gen;
174*0Sstevel@tonic-gate 	/* ASSERT(LOCK_HELD(&block->A_lock); */
175*0Sstevel@tonic-gate 	lock_clear(&block->B_lock);
176*0Sstevel@tonic-gate 	return (block);
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate try_reserved:
179*0Sstevel@tonic-gate 	/*
180*0Sstevel@tonic-gate 	 * Look for a free tag block in reserved area
181*0Sstevel@tonic-gate 	 */
182*0Sstevel@tonic-gate 	next = fh->next_tag_alloc;
183*0Sstevel@tonic-gate 	while (next < (TNFW_B_DATA_BLOCK_BEGIN >> TNF_BLOCK_SHIFT)) {
184*0Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
185*0Sstevel@tonic-gate 		block = (tnf_block_header_t *)
186*0Sstevel@tonic-gate 			((char *)fh + (next << TNF_BLOCK_SHIFT));
187*0Sstevel@tonic-gate 		next++;
188*0Sstevel@tonic-gate 		/*
189*0Sstevel@tonic-gate 		 * See if block is unclaimed.
190*0Sstevel@tonic-gate 		 * Don't bother clearing the A-lock if the
191*0Sstevel@tonic-gate 		 * block was claimed and released, since it
192*0Sstevel@tonic-gate 		 * will never be reallocated anyway.
193*0Sstevel@tonic-gate 		 */
194*0Sstevel@tonic-gate 		if (lock_try(&block->A_lock) &&
195*0Sstevel@tonic-gate 		    block->generation == 0) {
196*0Sstevel@tonic-gate 			lock_set_spl(lp, spinlock_spl, &spl);
197*0Sstevel@tonic-gate 			if (next > fh->next_tag_alloc)
198*0Sstevel@tonic-gate 				fh->next_tag_alloc = next;
199*0Sstevel@tonic-gate 			lock_clear_splx(lp, spl);
200*0Sstevel@tonic-gate 			goto got_block;
201*0Sstevel@tonic-gate 		}
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 	goto try_loop;
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate loop_fail:
206*0Sstevel@tonic-gate 	/*
207*0Sstevel@tonic-gate 	 * Only get here if we failed the for loop
208*0Sstevel@tonic-gate 	 */
209*0Sstevel@tonic-gate 	ASSERT(i == TNFW_B_MAXALLOCTRY);
210*0Sstevel@tonic-gate 	tnfw_b_state = TNFW_B_BROKEN;
211*0Sstevel@tonic-gate #ifdef DEBUG
212*0Sstevel@tonic-gate 	prom_printf("kernel probes: alloc_block failed\n");
213*0Sstevel@tonic-gate #endif
214*0Sstevel@tonic-gate 	return (NULL);
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate /*
219*0Sstevel@tonic-gate  * Allocate size bytes from the trace buffer.  Return NULL on failure,
220*0Sstevel@tonic-gate  * and mark tracing as broken.  We're guaranteed that the buffer will
221*0Sstevel@tonic-gate  * not be deallocated while we're in this routine.
222*0Sstevel@tonic-gate  * Allocation requests must be word-sized and are word-aligned.
223*0Sstevel@tonic-gate  */
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate void *
226*0Sstevel@tonic-gate tnfw_b_alloc(TNFW_B_WCB *wcb, size_t size, enum tnf_alloc_mode istag)
227*0Sstevel@tonic-gate {
228*0Sstevel@tonic-gate 	TNFW_B_POS 		*pos;
229*0Sstevel@tonic-gate 	ushort_t		offset;
230*0Sstevel@tonic-gate 	void 			*destp;
231*0Sstevel@tonic-gate 	tnf_block_header_t	*block, *new_block;
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	pos = &wcb->tnfw_w_pos;	/* common case */
234*0Sstevel@tonic-gate 	if (istag)
235*0Sstevel@tonic-gate 		pos = &wcb->tnfw_w_tag_pos;
236*0Sstevel@tonic-gate 	block = pos->tnfw_w_block;
237*0Sstevel@tonic-gate 	offset = pos->tnfw_w_write_off;
238*0Sstevel@tonic-gate 	/* Round size up to a multiple of 8. */
239*0Sstevel@tonic-gate 	size = (size + 7) & ~7;
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	if (block == NULL || offset + size > TNF_BLOCK_SIZE) {
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 		/* Get a new block */
244*0Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
245*0Sstevel@tonic-gate 		new_block = tnfw_b_alloc_block(TNF_FILE_HEADER(), istag);
246*0Sstevel@tonic-gate 		if (new_block == NULL)
247*0Sstevel@tonic-gate 			/* tracing has been marked as broken at this point */
248*0Sstevel@tonic-gate 			return (NULL);
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 		/* ASSERT(size <= TNF_MAXALLOC); */
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 		/*
253*0Sstevel@tonic-gate 		 * If the old block is clean (i.e., we're in a new
254*0Sstevel@tonic-gate 		 * transaction), just release it.  Else, pad it out
255*0Sstevel@tonic-gate 		 * and attach it to the list of uncommitted blocks.
256*0Sstevel@tonic-gate 		 */
257*0Sstevel@tonic-gate 		if (block != NULL) {
258*0Sstevel@tonic-gate 			if (block->bytes_valid == offset &&
259*0Sstevel@tonic-gate 			    !pos->tnfw_w_dirty) {
260*0Sstevel@tonic-gate 				/* block is clean: release it */
261*0Sstevel@tonic-gate 				lock_clear(&block->A_lock);
262*0Sstevel@tonic-gate 			} else {
263*0Sstevel@tonic-gate 				/* block is dirty */
264*0Sstevel@tonic-gate 				ulong_t *p, *q;
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 				/* LINTED pointer cast */
267*0Sstevel@tonic-gate 				p = (ulong_t *)((char *)block + offset);
268*0Sstevel@tonic-gate 				/* LINTED pointer cast */
269*0Sstevel@tonic-gate 				q = (ulong_t *)((char *)block + TNF_BLOCK_SIZE);
270*0Sstevel@tonic-gate 				while (p < q)
271*0Sstevel@tonic-gate 					*p++ = TNF_NULL;
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 				/* append block to release list */
274*0Sstevel@tonic-gate 				new_block->next_block = block;
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 				/* we have at least one dirty block */
277*0Sstevel@tonic-gate 				pos->tnfw_w_dirty = 1;
278*0Sstevel@tonic-gate 			}
279*0Sstevel@tonic-gate 		}
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 		/* make new_block the current block */
282*0Sstevel@tonic-gate 		pos->tnfw_w_block = block = new_block;
283*0Sstevel@tonic-gate 		/* write_off is updated below */
284*0Sstevel@tonic-gate 		offset = sizeof (tnf_block_header_t);
285*0Sstevel@tonic-gate 		/* ASSERT(new_block->bytes_valid == offset); */
286*0Sstevel@tonic-gate 	}
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	destp = (char *)block + offset;
289*0Sstevel@tonic-gate 	/* update write_off */
290*0Sstevel@tonic-gate 	pos->tnfw_w_write_off = offset + size;
291*0Sstevel@tonic-gate 	/*
292*0Sstevel@tonic-gate 	 * Unconditionally write a 0 into the last word allocated,
293*0Sstevel@tonic-gate 	 * in case we left an alignment gap.  (Assume that doing an
294*0Sstevel@tonic-gate 	 * unconditional write is cheaper than testing and branching
295*0Sstevel@tonic-gate 	 * around the write half the time.)
296*0Sstevel@tonic-gate 	 */
297*0Sstevel@tonic-gate 	/* LINTED pointer cast may result in improper alignment */
298*0Sstevel@tonic-gate 	*((int *)((char *)destp + size - sizeof (int))) = 0;
299*0Sstevel@tonic-gate 	return (destp);
300*0Sstevel@tonic-gate }
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate /*
303*0Sstevel@tonic-gate  * Allocate a directory entry.
304*0Sstevel@tonic-gate  */
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate /*ARGSUSED0*/
307*0Sstevel@tonic-gate void *
308*0Sstevel@tonic-gate tnfw_b_fw_alloc(TNFW_B_WCB *wcb)
309*0Sstevel@tonic-gate {
310*0Sstevel@tonic-gate 	tnf_buf_file_header_t	*fh;
311*0Sstevel@tonic-gate 	lock_t			*lp;
312*0Sstevel@tonic-gate 	ushort_t		spl;
313*0Sstevel@tonic-gate 	caddr_t			cell;
314*0Sstevel@tonic-gate 	ulong_t			next;
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	/* LINTED pointer cast may result in improper alignment */
317*0Sstevel@tonic-gate 	fh = TNF_FILE_HEADER();
318*0Sstevel@tonic-gate 	lp = &fh->lock;
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	lock_set_spl(lp, spinlock_spl, &spl);
321*0Sstevel@tonic-gate 	next = fh->next_fw_alloc;
322*0Sstevel@tonic-gate 	if (next < TNFW_B_FW_ZONE) {
323*0Sstevel@tonic-gate 		cell = (caddr_t)fh + next;
324*0Sstevel@tonic-gate 		fh->next_fw_alloc = next + sizeof (tnf_ref32_t);
325*0Sstevel@tonic-gate 	} else
326*0Sstevel@tonic-gate 		cell = NULL;
327*0Sstevel@tonic-gate 	lock_clear_splx(lp, spl);
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	return (cell);
330*0Sstevel@tonic-gate }
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate /*
333*0Sstevel@tonic-gate  * Initialize a buffer.
334*0Sstevel@tonic-gate  */
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate void
337*0Sstevel@tonic-gate tnfw_b_init_buffer(caddr_t buf, size_t size)
338*0Sstevel@tonic-gate {
339*0Sstevel@tonic-gate 	int 	gen_shift;
340*0Sstevel@tonic-gate 	int 	i;
341*0Sstevel@tonic-gate 	ulong_t	b;
342*0Sstevel@tonic-gate 	ulong_t	blocks;
343*0Sstevel@tonic-gate 	tnf_block_header_t *block;
344*0Sstevel@tonic-gate 	tnf_buf_file_header_t *fh;
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	/* Compute platform-specific spinlock_spl */
347*0Sstevel@tonic-gate 	spinlock_spl = __ipltospl(LOCK_LEVEL + 1);
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	/* LINTED pointer cast may result in improper alignment */
350*0Sstevel@tonic-gate 	fh = (tnf_buf_file_header_t *)buf;
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	/* LINTED logical expression always true: op "||" */
353*0Sstevel@tonic-gate 	ASSERT(TNF_DIRECTORY_SIZE > TNF_BLOCK_SIZE);
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	/*
356*0Sstevel@tonic-gate 	 * This assertion is needed because we cannot change
357*0Sstevel@tonic-gate 	 * sys/tnf_com.h this late in the release cycle, but we need the
358*0Sstevel@tonic-gate 	 * interface in sys/machlock.h for locking operations.
359*0Sstevel@tonic-gate 	 */
360*0Sstevel@tonic-gate 	/* LINTED logical expression always true: op "||" */
361*0Sstevel@tonic-gate 	ASSERT(sizeof (tnf_byte_lock_t) == sizeof (lock_t));
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	/* Calculate number of blocks */
364*0Sstevel@tonic-gate 	blocks = size >> TNF_BLOCK_SHIFT;
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	/* Calculate generation shift */
367*0Sstevel@tonic-gate 	gen_shift = 0;
368*0Sstevel@tonic-gate 	b = 1;
369*0Sstevel@tonic-gate 	while (b < blocks) {
370*0Sstevel@tonic-gate 		b <<= 1;
371*0Sstevel@tonic-gate 		++gen_shift;
372*0Sstevel@tonic-gate 	}
373*0Sstevel@tonic-gate 	ASSERT(gen_shift < 32);
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	/* fill in file header */
376*0Sstevel@tonic-gate 	/* magic number comes last */
377*0Sstevel@tonic-gate 	/* LINTED constant truncated by assignment */
378*0Sstevel@tonic-gate 	fh->com.tag = TNF_FILE_HEADER_TAG;
379*0Sstevel@tonic-gate 	fh->com.file_version = TNF_FILE_VERSION;
380*0Sstevel@tonic-gate 	fh->com.file_header_size = sizeof (tnf_file_header_t);
381*0Sstevel@tonic-gate 	fh->com.file_log_size = gen_shift + TNF_BLOCK_SHIFT;
382*0Sstevel@tonic-gate 	fh->com.block_header_size = sizeof (tnf_block_header_t);
383*0Sstevel@tonic-gate 	fh->com.block_size = TNF_BLOCK_SIZE;
384*0Sstevel@tonic-gate 	fh->com.directory_size = TNF_DIRECTORY_SIZE;
385*0Sstevel@tonic-gate 	/* LINTED assignment of 64-bit integer to 32-bit integer */
386*0Sstevel@tonic-gate 	fh->com.block_count = blocks;
387*0Sstevel@tonic-gate 	/* com.blocks_valid is unused */
388*0Sstevel@tonic-gate 	fh->next_alloc.gen = 1;
389*0Sstevel@tonic-gate 	fh->next_alloc.block[0] = 0;
390*0Sstevel@tonic-gate 	fh->next_alloc.block[1] = TNFW_B_DATA_BLOCK_BEGIN >> TNF_BLOCK_SHIFT;
391*0Sstevel@tonic-gate 	fh->next_tag_alloc = TNF_DIRECTORY_SIZE >> TNF_BLOCK_SHIFT;
392*0Sstevel@tonic-gate 	fh->next_fw_alloc = TNF_DIRENT_LAST + 4;
393*0Sstevel@tonic-gate 	LOCK_INIT_CLEAR(&fh->lock);
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	(void) bzero(buf + sizeof (*fh), TNF_DIRECTORY_SIZE - sizeof (*fh));
396*0Sstevel@tonic-gate 	i = TNF_DIRECTORY_SIZE >> TNF_BLOCK_SHIFT;
397*0Sstevel@tonic-gate 	for (; i < blocks; ++i) {
398*0Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
399*0Sstevel@tonic-gate 		block =	(tnf_block_header_t *)(buf + (i << TNF_BLOCK_SHIFT));
400*0Sstevel@tonic-gate 		block->tag = (tnf_ref32_t)TNF_BLOCK_HEADER_TAG;
401*0Sstevel@tonic-gate 		block->generation = 0;
402*0Sstevel@tonic-gate 		block->bytes_valid = sizeof (tnf_block_header_t);
403*0Sstevel@tonic-gate 		LOCK_INIT_CLEAR(&block->A_lock);
404*0Sstevel@tonic-gate 		LOCK_INIT_CLEAR(&block->B_lock);
405*0Sstevel@tonic-gate 	}
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 	/* snap in magic number */
408*0Sstevel@tonic-gate 	fh->magic = TNF_MAGIC;
409*0Sstevel@tonic-gate }
410