xref: /onnv-gate/usr/src/uts/common/avs/ns/sdbc/sd_pcu.c (revision 7836:4e95154b5b7a)
1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM  * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM  *
4*7836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM  *
8*7836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM  * and limitations under the License.
12*7836SJohn.Forte@Sun.COM  *
13*7836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM  *
19*7836SJohn.Forte@Sun.COM  * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM  */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7836SJohn.Forte@Sun.COM  * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM  */
25*7836SJohn.Forte@Sun.COM 
26*7836SJohn.Forte@Sun.COM #include <sys/types.h>
27*7836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
28*7836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
29*7836SJohn.Forte@Sun.COM #include <sys/errno.h>
30*7836SJohn.Forte@Sun.COM #include <sys/kmem.h>
31*7836SJohn.Forte@Sun.COM #include <sys/cred.h>
32*7836SJohn.Forte@Sun.COM #include <sys/buf.h>
33*7836SJohn.Forte@Sun.COM #include <sys/ddi.h>
34*7836SJohn.Forte@Sun.COM #include <sys/nsc_thread.h>
35*7836SJohn.Forte@Sun.COM 
36*7836SJohn.Forte@Sun.COM 
37*7836SJohn.Forte@Sun.COM #include "sd_bcache.h"
38*7836SJohn.Forte@Sun.COM #include "sd_trace.h"
39*7836SJohn.Forte@Sun.COM #include "sd_io.h"
40*7836SJohn.Forte@Sun.COM #include "sd_bio.h"
41*7836SJohn.Forte@Sun.COM #include "sd_ft.h"
42*7836SJohn.Forte@Sun.COM #include "sd_misc.h"
43*7836SJohn.Forte@Sun.COM #include "sd_pcu.h"
44*7836SJohn.Forte@Sun.COM 
45*7836SJohn.Forte@Sun.COM /*
46*7836SJohn.Forte@Sun.COM  * PCU (aka UPS) handling -
47*7836SJohn.Forte@Sun.COM  */
48*7836SJohn.Forte@Sun.COM #define	bitmap_next cc_dirty_link
49*7836SJohn.Forte@Sun.COM #define	bitmap_tail cc_dirty_next
50*7836SJohn.Forte@Sun.COM 
51*7836SJohn.Forte@Sun.COM #define	anon_next cc_dirty_link
52*7836SJohn.Forte@Sun.COM #define	anon_tail cc_dirty_next
53*7836SJohn.Forte@Sun.COM #define	anon_data cc_data
54*7836SJohn.Forte@Sun.COM 
55*7836SJohn.Forte@Sun.COM struct bitmap {
56*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *bmps;
57*7836SJohn.Forte@Sun.COM 	int bmaps_per_block;
58*7836SJohn.Forte@Sun.COM 	int inuse;			/* In use in the _last_ block */
59*7836SJohn.Forte@Sun.COM };
60*7836SJohn.Forte@Sun.COM 
61*7836SJohn.Forte@Sun.COM #define	SDBC_PCU_MAXSWAPIL  3		/* Watch for 5 fields in ioctl arg. */
62*7836SJohn.Forte@Sun.COM 
63*7836SJohn.Forte@Sun.COM struct swapfiles {
64*7836SJohn.Forte@Sun.COM 	int nswpf;			/* Number of filenames */
65*7836SJohn.Forte@Sun.COM 	int colsize;			/* In cache blocks */
66*7836SJohn.Forte@Sun.COM 	char *names[SDBC_PCU_MAXSWAPIL];
67*7836SJohn.Forte@Sun.COM };
68*7836SJohn.Forte@Sun.COM 
69*7836SJohn.Forte@Sun.COM static void _sdbc_pcu_cleanup(struct swapfiles *);
70*7836SJohn.Forte@Sun.COM 
71*7836SJohn.Forte@Sun.COM /*
72*7836SJohn.Forte@Sun.COM  * Forward declare functions containing 64-bit argument types to enforce
73*7836SJohn.Forte@Sun.COM  * type-checking.
74*7836SJohn.Forte@Sun.COM  */
75*7836SJohn.Forte@Sun.COM static int add_bitmap_entry(struct bitmap *bmp, _sd_bitmap_t bits, int any_fail,
76*7836SJohn.Forte@Sun.COM     nsc_off_t fba_num);
77*7836SJohn.Forte@Sun.COM static int flush_bitmap_list(struct bitmap *bmp, dev_t dev, nsc_off_t *blkno);
78*7836SJohn.Forte@Sun.COM static int flush_centry_list(_sd_cd_info_t *cdi, _sd_cctl_t *dirty, dev_t dev,
79*7836SJohn.Forte@Sun.COM     nsc_off_t *blkno, int failed, struct bitmap *bmaps);
80*7836SJohn.Forte@Sun.COM static int flush_hdr(_sd_cctl_t *hdr, dev_t dev, nsc_off_t blkno);
81*7836SJohn.Forte@Sun.COM static int flush_anon_list(_sd_cctl_t *anon_list, dev_t dev, nsc_off_t *blkno);
82*7836SJohn.Forte@Sun.COM static void sdbc_anon_copy(caddr_t src, nsc_size_t len, _sd_cctl_t *dest,
83*7836SJohn.Forte@Sun.COM     nsc_off_t dest_off);
84*7836SJohn.Forte@Sun.COM static void sdbc_anon_get(_sd_cctl_t *src, nsc_off_t src_off, caddr_t dest,
85*7836SJohn.Forte@Sun.COM     nsc_size_t len);
86*7836SJohn.Forte@Sun.COM static _sd_cctl_t *sdbc_get_anon_list(nsc_size_t bytes);
87*7836SJohn.Forte@Sun.COM 
88*7836SJohn.Forte@Sun.COM static int got_hint;			/* did we capture hint at power_lost */
89*7836SJohn.Forte@Sun.COM static unsigned int wrthru_hint;	/* saved hint at power_lost */
90*7836SJohn.Forte@Sun.COM static int saw_power_lost;
91*7836SJohn.Forte@Sun.COM 
92*7836SJohn.Forte@Sun.COM char _sdbc_shutdown_in_progress;
93*7836SJohn.Forte@Sun.COM static struct swapfiles swfs;
94*7836SJohn.Forte@Sun.COM 
95*7836SJohn.Forte@Sun.COM /*
96*7836SJohn.Forte@Sun.COM  * sdbc_get_anon_list - allocate a set of anonymous cache block
97*7836SJohn.Forte@Sun.COM  * entries that can pretend to be a single blocks of data holding
98*7836SJohn.Forte@Sun.COM  * a virtual character array holding "bytes" entries.
99*7836SJohn.Forte@Sun.COM  *
100*7836SJohn.Forte@Sun.COM  * returns - the cache block heading the chain.
101*7836SJohn.Forte@Sun.COM  */
102*7836SJohn.Forte@Sun.COM static _sd_cctl_t *
sdbc_get_anon_list(nsc_size_t bytes)103*7836SJohn.Forte@Sun.COM sdbc_get_anon_list(nsc_size_t bytes)
104*7836SJohn.Forte@Sun.COM {
105*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *list, *prev;
106*7836SJohn.Forte@Sun.COM 	nsc_size_t i, blks;
107*7836SJohn.Forte@Sun.COM 
108*7836SJohn.Forte@Sun.COM 	prev = NULL;
109*7836SJohn.Forte@Sun.COM 	blks = (bytes + CACHE_BLOCK_SIZE - 1) / CACHE_BLOCK_SIZE;
110*7836SJohn.Forte@Sun.COM 	for (i = 0; i < blks; i++) {
111*7836SJohn.Forte@Sun.COM 
112*7836SJohn.Forte@Sun.COM 		list = sdbc_centry_alloc_blks(_CD_NOHASH, 0, 1, 0);
113*7836SJohn.Forte@Sun.COM 		bzero(list->cc_data, CACHE_BLOCK_SIZE);
114*7836SJohn.Forte@Sun.COM 		list->anon_next = prev;
115*7836SJohn.Forte@Sun.COM 		prev = list;
116*7836SJohn.Forte@Sun.COM 	};
117*7836SJohn.Forte@Sun.COM 
118*7836SJohn.Forte@Sun.COM 	return (list);
119*7836SJohn.Forte@Sun.COM }
120*7836SJohn.Forte@Sun.COM 
121*7836SJohn.Forte@Sun.COM /*
122*7836SJohn.Forte@Sun.COM  * sdbc_anon_get - gets "len" bytes of data virtual character array represented
123*7836SJohn.Forte@Sun.COM  * by "src" begining at index "dest_off" and copy to buffer "dest".
124*7836SJohn.Forte@Sun.COM  *
125*7836SJohn.Forte@Sun.COM  * dest - pointer to our virtual array (chain of cache blocks).
126*7836SJohn.Forte@Sun.COM  * dest_off - first location to copy data to.
127*7836SJohn.Forte@Sun.COM  * src - pointer to data to copy
128*7836SJohn.Forte@Sun.COM  * len - the number of bytes of data to copy
129*7836SJohn.Forte@Sun.COM  *
130*7836SJohn.Forte@Sun.COM  */
131*7836SJohn.Forte@Sun.COM static void
sdbc_anon_get(_sd_cctl_t * src,nsc_off_t src_off,caddr_t dest,nsc_size_t len)132*7836SJohn.Forte@Sun.COM sdbc_anon_get(_sd_cctl_t *src, nsc_off_t src_off, caddr_t dest, nsc_size_t len)
133*7836SJohn.Forte@Sun.COM {
134*7836SJohn.Forte@Sun.COM 	nsc_size_t i;
135*7836SJohn.Forte@Sun.COM 	nsc_size_t nlen;
136*7836SJohn.Forte@Sun.COM 	nsc_off_t blk_start, blk_end;
137*7836SJohn.Forte@Sun.COM 
138*7836SJohn.Forte@Sun.COM 	if (len == 0)
139*7836SJohn.Forte@Sun.COM 		return;
140*7836SJohn.Forte@Sun.COM 
141*7836SJohn.Forte@Sun.COM 	blk_start = src_off / CACHE_BLOCK_SIZE;
142*7836SJohn.Forte@Sun.COM 	blk_end = (src_off + len) / CACHE_BLOCK_SIZE;
143*7836SJohn.Forte@Sun.COM 
144*7836SJohn.Forte@Sun.COM 	for (i = 0; i < blk_start; i++) {
145*7836SJohn.Forte@Sun.COM 		src = src->anon_next;
146*7836SJohn.Forte@Sun.COM 		src_off -= CACHE_BLOCK_SIZE;
147*7836SJohn.Forte@Sun.COM 	}
148*7836SJohn.Forte@Sun.COM 
149*7836SJohn.Forte@Sun.COM 	nlen = min(len, CACHE_BLOCK_SIZE - src_off);
150*7836SJohn.Forte@Sun.COM 	bcopy(&src->anon_data[src_off], dest, (size_t)nlen);
151*7836SJohn.Forte@Sun.COM 
152*7836SJohn.Forte@Sun.COM 	for (i = 1; i < blk_end - blk_start; i++) {
153*7836SJohn.Forte@Sun.COM 		bcopy(src->anon_data, &dest[nlen], (size_t)CACHE_BLOCK_SIZE);
154*7836SJohn.Forte@Sun.COM 		nlen += CACHE_BLOCK_SIZE;
155*7836SJohn.Forte@Sun.COM 		src = src->anon_next;
156*7836SJohn.Forte@Sun.COM 	}
157*7836SJohn.Forte@Sun.COM 	if (nlen != len) {
158*7836SJohn.Forte@Sun.COM 		bcopy(src->anon_data, &dest[nlen], (size_t)(len - nlen));
159*7836SJohn.Forte@Sun.COM 	}
160*7836SJohn.Forte@Sun.COM }
161*7836SJohn.Forte@Sun.COM 
162*7836SJohn.Forte@Sun.COM /*
163*7836SJohn.Forte@Sun.COM  * sdbc_anon_copy - copies "len" bytes of data from "src" to the
164*7836SJohn.Forte@Sun.COM  * virtual character array represented by "dest" begining at index
165*7836SJohn.Forte@Sun.COM  * "dest_off".
166*7836SJohn.Forte@Sun.COM  *
167*7836SJohn.Forte@Sun.COM  * src - pointer to data to copy
168*7836SJohn.Forte@Sun.COM  * len - the number of bytes of data to copy
169*7836SJohn.Forte@Sun.COM  * dest - pointer to our virtual array (chain of cache blocks).
170*7836SJohn.Forte@Sun.COM  * dest_off - first location to copy data to.
171*7836SJohn.Forte@Sun.COM  *
172*7836SJohn.Forte@Sun.COM  */
173*7836SJohn.Forte@Sun.COM static void
sdbc_anon_copy(caddr_t src,nsc_size_t len,_sd_cctl_t * dest,nsc_off_t dest_off)174*7836SJohn.Forte@Sun.COM sdbc_anon_copy(caddr_t src, nsc_size_t len, _sd_cctl_t *dest,
175*7836SJohn.Forte@Sun.COM     nsc_off_t dest_off)
176*7836SJohn.Forte@Sun.COM {
177*7836SJohn.Forte@Sun.COM 	nsc_size_t i;
178*7836SJohn.Forte@Sun.COM 	nsc_size_t nlen;
179*7836SJohn.Forte@Sun.COM 	nsc_off_t blk_start, blk_end;
180*7836SJohn.Forte@Sun.COM 
181*7836SJohn.Forte@Sun.COM 	if (len == 0)
182*7836SJohn.Forte@Sun.COM 		return;
183*7836SJohn.Forte@Sun.COM 
184*7836SJohn.Forte@Sun.COM 	blk_start = dest_off / CACHE_BLOCK_SIZE;
185*7836SJohn.Forte@Sun.COM 	blk_end = (dest_off + len) / CACHE_BLOCK_SIZE;
186*7836SJohn.Forte@Sun.COM 
187*7836SJohn.Forte@Sun.COM 	for (i = 0; i < blk_start; i++) {
188*7836SJohn.Forte@Sun.COM 		dest = dest->anon_next;
189*7836SJohn.Forte@Sun.COM 		dest_off -= CACHE_BLOCK_SIZE;
190*7836SJohn.Forte@Sun.COM 	}
191*7836SJohn.Forte@Sun.COM 
192*7836SJohn.Forte@Sun.COM 	nlen = min(len, CACHE_BLOCK_SIZE - dest_off);
193*7836SJohn.Forte@Sun.COM 	bcopy(src, &dest->anon_data[dest_off], (size_t)nlen);
194*7836SJohn.Forte@Sun.COM 
195*7836SJohn.Forte@Sun.COM 	for (i = 1; i < blk_end - blk_start; i++) {
196*7836SJohn.Forte@Sun.COM 		bcopy(&src[nlen], dest->anon_data, (size_t)CACHE_BLOCK_SIZE);
197*7836SJohn.Forte@Sun.COM 		nlen += CACHE_BLOCK_SIZE;
198*7836SJohn.Forte@Sun.COM 		dest = dest->anon_next;
199*7836SJohn.Forte@Sun.COM 	}
200*7836SJohn.Forte@Sun.COM 	if (nlen != len) {
201*7836SJohn.Forte@Sun.COM 		bcopy(&src[nlen], dest->anon_data, (size_t)(len - nlen));
202*7836SJohn.Forte@Sun.COM 	}
203*7836SJohn.Forte@Sun.COM }
204*7836SJohn.Forte@Sun.COM 
205*7836SJohn.Forte@Sun.COM /*
206*7836SJohn.Forte@Sun.COM  * flush_anon_list - flush a chain of anonymous cache blocks
207*7836SJohn.Forte@Sun.COM  * to the state file. Anonymous chains of cache blocks represent
208*7836SJohn.Forte@Sun.COM  * virtual arrays for the state flushing code and can contain
209*7836SJohn.Forte@Sun.COM  * various types of data.
210*7836SJohn.Forte@Sun.COM  *
211*7836SJohn.Forte@Sun.COM  * anon_list - chain of cache blocks to flush.
212*7836SJohn.Forte@Sun.COM  *
213*7836SJohn.Forte@Sun.COM  * dev - the state file device
214*7836SJohn.Forte@Sun.COM  *
215*7836SJohn.Forte@Sun.COM  * blkno - on input the cache block number to begin writing at.
216*7836SJohn.Forte@Sun.COM  * On exit the next cache block number following the data
217*7836SJohn.Forte@Sun.COM  * just written.
218*7836SJohn.Forte@Sun.COM  *
219*7836SJohn.Forte@Sun.COM  * returns - 0 on success, error number on failure.
220*7836SJohn.Forte@Sun.COM  */
221*7836SJohn.Forte@Sun.COM static int
flush_anon_list(_sd_cctl_t * anon_list,dev_t dev,nsc_off_t * blkno)222*7836SJohn.Forte@Sun.COM flush_anon_list(_sd_cctl_t *anon_list,
223*7836SJohn.Forte@Sun.COM 		dev_t dev,
224*7836SJohn.Forte@Sun.COM 		nsc_off_t *blkno)
225*7836SJohn.Forte@Sun.COM {
226*7836SJohn.Forte@Sun.COM 	struct buf *bp;
227*7836SJohn.Forte@Sun.COM 	int rc;
228*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *prev;
229*7836SJohn.Forte@Sun.COM 	nsc_size_t bcnt;
230*7836SJohn.Forte@Sun.COM 
231*7836SJohn.Forte@Sun.COM 	if (anon_list == NULL)
232*7836SJohn.Forte@Sun.COM 		return (0);
233*7836SJohn.Forte@Sun.COM 
234*7836SJohn.Forte@Sun.COM 	bcnt = 0;
235*7836SJohn.Forte@Sun.COM 	do {
236*7836SJohn.Forte@Sun.COM 		bp = sd_alloc_iob(dev, BLK_TO_FBA_NUM(*blkno),
237*7836SJohn.Forte@Sun.COM 		    BLK_TO_FBA_NUM(1), 0);
238*7836SJohn.Forte@Sun.COM 		sd_add_fba(bp, &anon_list->cc_addr, 0, BLK_FBAS);
239*7836SJohn.Forte@Sun.COM 		rc = sd_start_io(bp, NULL, NULL, 0);
240*7836SJohn.Forte@Sun.COM 		(*blkno)++;
241*7836SJohn.Forte@Sun.COM 
242*7836SJohn.Forte@Sun.COM 		/*
243*7836SJohn.Forte@Sun.COM 		 * A failure here is death. This is harsh but not sure
244*7836SJohn.Forte@Sun.COM 		 * what else to do
245*7836SJohn.Forte@Sun.COM 		 */
246*7836SJohn.Forte@Sun.COM 
247*7836SJohn.Forte@Sun.COM 		if (rc != NSC_DONE)
248*7836SJohn.Forte@Sun.COM 			return (rc);
249*7836SJohn.Forte@Sun.COM 		bcnt++;
250*7836SJohn.Forte@Sun.COM 
251*7836SJohn.Forte@Sun.COM 		prev = anon_list;
252*7836SJohn.Forte@Sun.COM 		anon_list = anon_list->anon_next;
253*7836SJohn.Forte@Sun.COM 		_sd_centry_release(prev);
254*7836SJohn.Forte@Sun.COM 
255*7836SJohn.Forte@Sun.COM 	} while (anon_list);
256*7836SJohn.Forte@Sun.COM 
257*7836SJohn.Forte@Sun.COM 	cmn_err(CE_CONT, "sdbc(flush_anon_list) %" NSC_SZFMT "\n", bcnt);
258*7836SJohn.Forte@Sun.COM 	return (0);
259*7836SJohn.Forte@Sun.COM 
260*7836SJohn.Forte@Sun.COM }
261*7836SJohn.Forte@Sun.COM 
262*7836SJohn.Forte@Sun.COM /*
263*7836SJohn.Forte@Sun.COM  * start_bitmap_list - allocate an anonymous cache block entry
264*7836SJohn.Forte@Sun.COM  * to anchor a chain of cache blocks representing a virtual
265*7836SJohn.Forte@Sun.COM  * array of bitmap entries.
266*7836SJohn.Forte@Sun.COM  *
267*7836SJohn.Forte@Sun.COM  * returns - the cache block heading the chain.
268*7836SJohn.Forte@Sun.COM  */
269*7836SJohn.Forte@Sun.COM static void
start_bitmap_list(struct bitmap * bmp,int bpb)270*7836SJohn.Forte@Sun.COM start_bitmap_list(struct bitmap *bmp, int bpb)
271*7836SJohn.Forte@Sun.COM {
272*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *list;
273*7836SJohn.Forte@Sun.COM 
274*7836SJohn.Forte@Sun.COM 	list = sdbc_centry_alloc_blks(_CD_NOHASH, 0, 1, 0);
275*7836SJohn.Forte@Sun.COM 	bzero(list->cc_data, CACHE_BLOCK_SIZE);
276*7836SJohn.Forte@Sun.COM 	list->bitmap_next = NULL;
277*7836SJohn.Forte@Sun.COM 	list->bitmap_tail = list;
278*7836SJohn.Forte@Sun.COM 
279*7836SJohn.Forte@Sun.COM 	bmp->bmps = list;
280*7836SJohn.Forte@Sun.COM 	bmp->inuse = 0;
281*7836SJohn.Forte@Sun.COM 	bmp->bmaps_per_block = bpb;
282*7836SJohn.Forte@Sun.COM }
283*7836SJohn.Forte@Sun.COM 
284*7836SJohn.Forte@Sun.COM /*
285*7836SJohn.Forte@Sun.COM  * add_bitmap_entry - Add a bitmap entry to the chain of bitmap
286*7836SJohn.Forte@Sun.COM  * entries we are creating for cd's entry in the state file.
287*7836SJohn.Forte@Sun.COM  *
288*7836SJohn.Forte@Sun.COM  * Bitmaps are stored in a chain of anonymous cache blocks. Each
289*7836SJohn.Forte@Sun.COM  * cache block can hold bmaps_per_block in it. As each block is
290*7836SJohn.Forte@Sun.COM  * filled a new block is added to the tail of the chain.
291*7836SJohn.Forte@Sun.COM  *
292*7836SJohn.Forte@Sun.COM  * list - the chain of cache blocks containing the bitmaps.
293*7836SJohn.Forte@Sun.COM  * bits - the bitmap entry to add.
294*7836SJohn.Forte@Sun.COM  * any_fail - flag saying whether the data corresponding to this
295*7836SJohn.Forte@Sun.COM  * bitmap entry had previously failed going to disk.
296*7836SJohn.Forte@Sun.COM  * fba_num - FBA number corresponding to the entry.
297*7836SJohn.Forte@Sun.COM  *
298*7836SJohn.Forte@Sun.COM  * returns - 0 on success, error number on failure.
299*7836SJohn.Forte@Sun.COM  */
300*7836SJohn.Forte@Sun.COM static int
add_bitmap_entry(struct bitmap * bmp,_sd_bitmap_t bits,int any_fail,nsc_off_t fba_num)301*7836SJohn.Forte@Sun.COM add_bitmap_entry(struct bitmap *bmp,
302*7836SJohn.Forte@Sun.COM     _sd_bitmap_t bits, int any_fail, nsc_off_t fba_num)
303*7836SJohn.Forte@Sun.COM {
304*7836SJohn.Forte@Sun.COM 	sdbc_pwf_bitmap_t *bmap;
305*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *list = bmp->bmps;
306*7836SJohn.Forte@Sun.COM 	int i;
307*7836SJohn.Forte@Sun.COM 
308*7836SJohn.Forte@Sun.COM 	bmap = (sdbc_pwf_bitmap_t *)list->bitmap_tail->cc_data;
309*7836SJohn.Forte@Sun.COM 	if (bmp->inuse == bmp->bmaps_per_block) {
310*7836SJohn.Forte@Sun.COM 		_sd_cctl_t *nlist;
311*7836SJohn.Forte@Sun.COM 
312*7836SJohn.Forte@Sun.COM 		nlist = sdbc_centry_alloc_blks(_CD_NOHASH, 0, 1, 0);
313*7836SJohn.Forte@Sun.COM 		bzero(nlist->cc_data, CACHE_BLOCK_SIZE);
314*7836SJohn.Forte@Sun.COM 		nlist->bitmap_next = NULL;
315*7836SJohn.Forte@Sun.COM 		nlist->bitmap_tail = NULL;
316*7836SJohn.Forte@Sun.COM 		list->bitmap_tail->bitmap_next = nlist;
317*7836SJohn.Forte@Sun.COM 		list->bitmap_tail = nlist;
318*7836SJohn.Forte@Sun.COM 		bmp->inuse = 0;
319*7836SJohn.Forte@Sun.COM 	}
320*7836SJohn.Forte@Sun.COM 	i = bmp->inuse++;
321*7836SJohn.Forte@Sun.COM 	bmap->bitmaps[i].fba_num = fba_num;
322*7836SJohn.Forte@Sun.COM 	bmap->bitmaps[i].dirty = bits;
323*7836SJohn.Forte@Sun.COM 	bmap->bitmaps[i].errs = (char)any_fail;
324*7836SJohn.Forte@Sun.COM 
325*7836SJohn.Forte@Sun.COM 	return (0);
326*7836SJohn.Forte@Sun.COM }
327*7836SJohn.Forte@Sun.COM 
328*7836SJohn.Forte@Sun.COM /*
329*7836SJohn.Forte@Sun.COM  * flush_bitmap_list - flush a chain of anonymous cache blocks
330*7836SJohn.Forte@Sun.COM  * containing the dirty/valid bitmaps for a set of cache blocks.
331*7836SJohn.Forte@Sun.COM  *
332*7836SJohn.Forte@Sun.COM  * b_list - the chain of bitmap data.
333*7836SJohn.Forte@Sun.COM  * dev - the state file device.
334*7836SJohn.Forte@Sun.COM  * blkno - on input the cache block number to begin writing at.
335*7836SJohn.Forte@Sun.COM  * On exit the next cache block number following the data
336*7836SJohn.Forte@Sun.COM  * just written.
337*7836SJohn.Forte@Sun.COM  *
338*7836SJohn.Forte@Sun.COM  * returns - 0 on success, error number on failure.
339*7836SJohn.Forte@Sun.COM  */
340*7836SJohn.Forte@Sun.COM static int
flush_bitmap_list(struct bitmap * bmp,dev_t dev,nsc_off_t * blkno)341*7836SJohn.Forte@Sun.COM flush_bitmap_list(struct bitmap *bmp, dev_t dev, nsc_off_t *blkno)
342*7836SJohn.Forte@Sun.COM {
343*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *b_list;
344*7836SJohn.Forte@Sun.COM 	struct buf *bp;
345*7836SJohn.Forte@Sun.COM 	int rc;
346*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *prev;
347*7836SJohn.Forte@Sun.COM 	int bcnt = 0;	/* P3 temp */
348*7836SJohn.Forte@Sun.COM 
349*7836SJohn.Forte@Sun.COM 	if ((b_list = bmp->bmps) == NULL)
350*7836SJohn.Forte@Sun.COM 		return (0);
351*7836SJohn.Forte@Sun.COM 
352*7836SJohn.Forte@Sun.COM 	do {
353*7836SJohn.Forte@Sun.COM 		bp = sd_alloc_iob(dev, BLK_TO_FBA_NUM(*blkno),
354*7836SJohn.Forte@Sun.COM 		    BLK_TO_FBA_NUM(1), 0);
355*7836SJohn.Forte@Sun.COM 		sd_add_fba(bp, &b_list->cc_addr, 0, BLK_FBAS);
356*7836SJohn.Forte@Sun.COM 		rc = sd_start_io(bp, NULL, NULL, 0);
357*7836SJohn.Forte@Sun.COM 		(*blkno)++;
358*7836SJohn.Forte@Sun.COM 
359*7836SJohn.Forte@Sun.COM 		/*
360*7836SJohn.Forte@Sun.COM 		 * A failure here is death. This is harsh but not sure
361*7836SJohn.Forte@Sun.COM 		 * what else to do
362*7836SJohn.Forte@Sun.COM 		 */
363*7836SJohn.Forte@Sun.COM 
364*7836SJohn.Forte@Sun.COM 		if (rc != NSC_DONE)
365*7836SJohn.Forte@Sun.COM 			return (rc);
366*7836SJohn.Forte@Sun.COM 		bcnt++;
367*7836SJohn.Forte@Sun.COM 
368*7836SJohn.Forte@Sun.COM 		prev = b_list;
369*7836SJohn.Forte@Sun.COM 		b_list = b_list->bitmap_next;
370*7836SJohn.Forte@Sun.COM 		_sd_centry_release(prev);
371*7836SJohn.Forte@Sun.COM 
372*7836SJohn.Forte@Sun.COM 	} while (b_list);
373*7836SJohn.Forte@Sun.COM 	cmn_err(CE_CONT, "sdbc(flush_bitmap_list) %d\n", bcnt);  /* P3 */
374*7836SJohn.Forte@Sun.COM 
375*7836SJohn.Forte@Sun.COM 	return (0);
376*7836SJohn.Forte@Sun.COM 
377*7836SJohn.Forte@Sun.COM }
378*7836SJohn.Forte@Sun.COM 
379*7836SJohn.Forte@Sun.COM /*
380*7836SJohn.Forte@Sun.COM  * flush_centry_list - flush a chain of cache blocks for the
381*7836SJohn.Forte@Sun.COM  * cache descriptor described by "cdi" to the state file.
382*7836SJohn.Forte@Sun.COM  * In addition the bitmaps describing the validity and dirty
383*7836SJohn.Forte@Sun.COM  * state of each entry are captured to the bitmap chain.
384*7836SJohn.Forte@Sun.COM  *
385*7836SJohn.Forte@Sun.COM  * cdi - pointer to description of the cd we are writing.
386*7836SJohn.Forte@Sun.COM  * dirty - chain of dirty cache blocks to flush (linked
387*7836SJohn.Forte@Sun.COM  * by dirty_next (sequential) and dirty_link (disjoint).
388*7836SJohn.Forte@Sun.COM  *
389*7836SJohn.Forte@Sun.COM  * dev - the state file device.
390*7836SJohn.Forte@Sun.COM  *
391*7836SJohn.Forte@Sun.COM  * blkno - on input the cache block number to begin writing at.
392*7836SJohn.Forte@Sun.COM  * On exit the next cache block number following the data
393*7836SJohn.Forte@Sun.COM  * just written.
394*7836SJohn.Forte@Sun.COM  *
395*7836SJohn.Forte@Sun.COM  * failed - a flag noting whether these blocks had already
396*7836SJohn.Forte@Sun.COM  * been attempted to write to their true destination and
397*7836SJohn.Forte@Sun.COM  * failed. (i.e. is the chain from fail_head).
398*7836SJohn.Forte@Sun.COM  *
399*7836SJohn.Forte@Sun.COM  * bmaps - a chain of anonymous cache blocks containing all
400*7836SJohn.Forte@Sun.COM  * the dirty/valid bitmaps for the cache blocks we write.
401*7836SJohn.Forte@Sun.COM  *
402*7836SJohn.Forte@Sun.COM  * returns - 0 on success, error number on failure.
403*7836SJohn.Forte@Sun.COM  */
404*7836SJohn.Forte@Sun.COM static int
flush_centry_list(_sd_cd_info_t * cdi,_sd_cctl_t * dirty,dev_t dev,nsc_off_t * blkno,int failed,struct bitmap * bmaps)405*7836SJohn.Forte@Sun.COM flush_centry_list(_sd_cd_info_t *cdi,
406*7836SJohn.Forte@Sun.COM 		_sd_cctl_t *dirty,
407*7836SJohn.Forte@Sun.COM 		dev_t dev,
408*7836SJohn.Forte@Sun.COM 		nsc_off_t *blkno,
409*7836SJohn.Forte@Sun.COM 		int failed,
410*7836SJohn.Forte@Sun.COM 		struct bitmap *bmaps)
411*7836SJohn.Forte@Sun.COM {
412*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *cc_ent;
413*7836SJohn.Forte@Sun.COM 	nsc_size_t count; /* count of cache blocks in a sequential chain */
414*7836SJohn.Forte@Sun.COM 	struct buf *bp;
415*7836SJohn.Forte@Sun.COM 	int rc;
416*7836SJohn.Forte@Sun.COM 	int bcnt = 0;
417*7836SJohn.Forte@Sun.COM 
418*7836SJohn.Forte@Sun.COM 	if (dirty == NULL)
419*7836SJohn.Forte@Sun.COM 		return (0);
420*7836SJohn.Forte@Sun.COM 
421*7836SJohn.Forte@Sun.COM 	mutex_enter(&cdi->cd_lock);
422*7836SJohn.Forte@Sun.COM 
423*7836SJohn.Forte@Sun.COM 	do {
424*7836SJohn.Forte@Sun.COM 		/*
425*7836SJohn.Forte@Sun.COM 		 * each cache block is written to the disk regardless of its
426*7836SJohn.Forte@Sun.COM 		 * valid/dirty masks.
427*7836SJohn.Forte@Sun.COM 		 */
428*7836SJohn.Forte@Sun.COM 		count = 0;
429*7836SJohn.Forte@Sun.COM 		cc_ent = dirty;
430*7836SJohn.Forte@Sun.COM 		do {
431*7836SJohn.Forte@Sun.COM 			count++;
432*7836SJohn.Forte@Sun.COM 			cc_ent = cc_ent->cc_dirty_next;
433*7836SJohn.Forte@Sun.COM 		} while (cc_ent);
434*7836SJohn.Forte@Sun.COM 
435*7836SJohn.Forte@Sun.COM 		bp = sd_alloc_iob(dev, BLK_TO_FBA_NUM(*blkno),
436*7836SJohn.Forte@Sun.COM 		    BLK_TO_FBA_NUM(count), 0);
437*7836SJohn.Forte@Sun.COM 
438*7836SJohn.Forte@Sun.COM 		cc_ent = dirty;
439*7836SJohn.Forte@Sun.COM 		do {
440*7836SJohn.Forte@Sun.COM 			sd_add_fba(bp, &cc_ent->cc_addr, 0, BLK_FBAS);
441*7836SJohn.Forte@Sun.COM 			rc = add_bitmap_entry(bmaps,
442*7836SJohn.Forte@Sun.COM 			    cc_ent->cc_dirty | cc_ent->cc_toflush, failed,
443*7836SJohn.Forte@Sun.COM 			    BLK_TO_FBA_NUM(CENTRY_BLK(cc_ent)));
444*7836SJohn.Forte@Sun.COM 			if (rc)
445*7836SJohn.Forte@Sun.COM 				return (rc);
446*7836SJohn.Forte@Sun.COM 			cc_ent = cc_ent->cc_dirty_next;
447*7836SJohn.Forte@Sun.COM 		} while (cc_ent);
448*7836SJohn.Forte@Sun.COM 
449*7836SJohn.Forte@Sun.COM 		*blkno += count;
450*7836SJohn.Forte@Sun.COM 		rc = sd_start_io(bp, NULL, NULL, 0);
451*7836SJohn.Forte@Sun.COM 
452*7836SJohn.Forte@Sun.COM 		/*
453*7836SJohn.Forte@Sun.COM 		 * A failure here is death. This is harsh but not sure
454*7836SJohn.Forte@Sun.COM 		 * what else to do
455*7836SJohn.Forte@Sun.COM 		 */
456*7836SJohn.Forte@Sun.COM 
457*7836SJohn.Forte@Sun.COM 		if (rc != NSC_DONE)
458*7836SJohn.Forte@Sun.COM 			return (rc);
459*7836SJohn.Forte@Sun.COM 		bcnt += count;
460*7836SJohn.Forte@Sun.COM 
461*7836SJohn.Forte@Sun.COM 		dirty = dirty->cc_dirty_link;
462*7836SJohn.Forte@Sun.COM 	} while (dirty);
463*7836SJohn.Forte@Sun.COM 	cmn_err(CE_CONT, "sdbc(flush_centry_list) %d\n", bcnt);  /* P3 */
464*7836SJohn.Forte@Sun.COM 
465*7836SJohn.Forte@Sun.COM 	mutex_exit(&cdi->cd_lock);
466*7836SJohn.Forte@Sun.COM 	return (0);
467*7836SJohn.Forte@Sun.COM }
468*7836SJohn.Forte@Sun.COM 
469*7836SJohn.Forte@Sun.COM /*
470*7836SJohn.Forte@Sun.COM  * flush_hdr - Flush the state file header to the disk partition
471*7836SJohn.Forte@Sun.COM  * "dev" at FBA "blkno". Return the result of the i/o operation.
472*7836SJohn.Forte@Sun.COM  * hdr - a cache block containing the header.
473*7836SJohn.Forte@Sun.COM  * dev - the state file device.
474*7836SJohn.Forte@Sun.COM  * blkno -  cache block position to write the header.
475*7836SJohn.Forte@Sun.COM  *
476*7836SJohn.Forte@Sun.COM  * returns - 0 on success, error number on failure.
477*7836SJohn.Forte@Sun.COM  */
478*7836SJohn.Forte@Sun.COM static int
flush_hdr(_sd_cctl_t * hdr,dev_t dev,nsc_off_t blkno)479*7836SJohn.Forte@Sun.COM flush_hdr(_sd_cctl_t *hdr, dev_t dev, nsc_off_t blkno)
480*7836SJohn.Forte@Sun.COM {
481*7836SJohn.Forte@Sun.COM 	struct buf *bp;
482*7836SJohn.Forte@Sun.COM 	int rc;
483*7836SJohn.Forte@Sun.COM 
484*7836SJohn.Forte@Sun.COM 	bp = sd_alloc_iob(dev, BLK_TO_FBA_NUM(blkno), BLK_TO_FBA_NUM(1), 0);
485*7836SJohn.Forte@Sun.COM 	sd_add_fba(bp, &hdr->cc_addr, 0, BLK_FBAS);
486*7836SJohn.Forte@Sun.COM 	rc = sd_start_io(bp, NULL, NULL, 0);
487*7836SJohn.Forte@Sun.COM 	_sd_centry_release(hdr);
488*7836SJohn.Forte@Sun.COM 	return (rc);
489*7836SJohn.Forte@Sun.COM 
490*7836SJohn.Forte@Sun.COM }
491*7836SJohn.Forte@Sun.COM 
492*7836SJohn.Forte@Sun.COM /*
493*7836SJohn.Forte@Sun.COM  * _sdbc_power_flush - flushd the state of sdbc to the state "file"
494*7836SJohn.Forte@Sun.COM  * on the system disk. All dirty blocks (in progress, unscheduled,
495*7836SJohn.Forte@Sun.COM  * failed) are written along with the bitmap for each block. The
496*7836SJohn.Forte@Sun.COM  * data is written using normal sdbc i/o via anonymous cache blocks.
497*7836SJohn.Forte@Sun.COM  * This is done to simplify the job here (and to limit memory
498*7836SJohn.Forte@Sun.COM  * requests) at the expense of making the recovery programs more
499*7836SJohn.Forte@Sun.COM  * complex. Since recovery is done at user level this seems to be
500*7836SJohn.Forte@Sun.COM  * a good trade off.
501*7836SJohn.Forte@Sun.COM  *
502*7836SJohn.Forte@Sun.COM  * Returns: 0 on success, error number on failure.
503*7836SJohn.Forte@Sun.COM  */
504*7836SJohn.Forte@Sun.COM static int
_sdbc_power_flush(void)505*7836SJohn.Forte@Sun.COM _sdbc_power_flush(void)
506*7836SJohn.Forte@Sun.COM {
507*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *name_pool;
508*7836SJohn.Forte@Sun.COM 	int string_size;
509*7836SJohn.Forte@Sun.COM 
510*7836SJohn.Forte@Sun.COM 	sdbc_pwf_hdr_t *hdr;
511*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *hdrblk;
512*7836SJohn.Forte@Sun.COM 
513*7836SJohn.Forte@Sun.COM 	struct bitmap bmap;
514*7836SJohn.Forte@Sun.COM 
515*7836SJohn.Forte@Sun.COM 	_sd_cd_info_t *cdi;
516*7836SJohn.Forte@Sun.COM 	int open_files;
517*7836SJohn.Forte@Sun.COM 	_sd_cctl_t *file_pool;
518*7836SJohn.Forte@Sun.COM 	sdbc_pwf_desc_t current;
519*7836SJohn.Forte@Sun.COM 
520*7836SJohn.Forte@Sun.COM 	nsc_fd_t *state_fd;
521*7836SJohn.Forte@Sun.COM 	dev_t state_rdev;
522*7836SJohn.Forte@Sun.COM 	int devmaj, devmin;
523*7836SJohn.Forte@Sun.COM 	nsc_off_t blkno;
524*7836SJohn.Forte@Sun.COM 	long len;
525*7836SJohn.Forte@Sun.COM 	long total_len;
526*7836SJohn.Forte@Sun.COM 	int pending;
527*7836SJohn.Forte@Sun.COM 	int rc = 0;
528*7836SJohn.Forte@Sun.COM 
529*7836SJohn.Forte@Sun.COM 	/*
530*7836SJohn.Forte@Sun.COM 	 * Force wrthru just in case SLM software didn't really send us a
531*7836SJohn.Forte@Sun.COM 	 * warning. (Also makes for easier testing)
532*7836SJohn.Forte@Sun.COM 	 */
533*7836SJohn.Forte@Sun.COM 	(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
534*7836SJohn.Forte@Sun.COM 	/* disable all (dangerous) cache entry points */
535*7836SJohn.Forte@Sun.COM 
536*7836SJohn.Forte@Sun.COM 	cmn_err(CE_CONT, "sdbc(sdbc_power_flush) hint set..\n"); /* P3 */
537*7836SJohn.Forte@Sun.COM 
538*7836SJohn.Forte@Sun.COM 	_sdbc_shutdown_in_progress = 1;
539*7836SJohn.Forte@Sun.COM 
540*7836SJohn.Forte@Sun.COM #if 0
541*7836SJohn.Forte@Sun.COM 	if (sdbc_io && (rc = nsc_unregister_io(sdbc_io, NSC_PCATCH)) != 0) {
542*7836SJohn.Forte@Sun.COM 		/*
543*7836SJohn.Forte@Sun.COM 		 * this is bad, in theory we could just busy-out all our
544*7836SJohn.Forte@Sun.COM 		 * interfaces and continue.
545*7836SJohn.Forte@Sun.COM 		 */
546*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN,
547*7836SJohn.Forte@Sun.COM 		    "sdbc(_sdbc_power_flush) couldn't unregister i/o %d", rc);
548*7836SJohn.Forte@Sun.COM 		return (rc);
549*7836SJohn.Forte@Sun.COM 	}
550*7836SJohn.Forte@Sun.COM 
551*7836SJohn.Forte@Sun.COM 	sdbc_io = NULL;
552*7836SJohn.Forte@Sun.COM #endif
553*7836SJohn.Forte@Sun.COM 
554*7836SJohn.Forte@Sun.COM 	/* wait for all i/o to finish/timeout ? */
555*7836SJohn.Forte@Sun.COM 
556*7836SJohn.Forte@Sun.COM 	if ((pending = _sdbc_wait_pending()) != 0)
557*7836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "sdbc(_sdbc_power_flush) %d I/Os were"
558*7836SJohn.Forte@Sun.COM 		    " pending at power shutdown", pending);
559*7836SJohn.Forte@Sun.COM 
560*7836SJohn.Forte@Sun.COM 	cmn_err(CE_CONT, "sdbc(sdbc_power_flush) over pending\n"); /* P3 */
561*7836SJohn.Forte@Sun.COM 
562*7836SJohn.Forte@Sun.COM 	/* prevent any further async flushing */
563*7836SJohn.Forte@Sun.COM 
564*7836SJohn.Forte@Sun.COM 	_sdbc_flush_deconfigure();
565*7836SJohn.Forte@Sun.COM 
566*7836SJohn.Forte@Sun.COM 	/*
567*7836SJohn.Forte@Sun.COM 	 * At this point no higher level clients should be able to get thru.
568*7836SJohn.Forte@Sun.COM 	 * Failover i/o from the other node is our only other concern as
569*7836SJohn.Forte@Sun.COM 	 * far as disturbing the state of sdbc.
570*7836SJohn.Forte@Sun.COM 	 */
571*7836SJohn.Forte@Sun.COM 
572*7836SJohn.Forte@Sun.COM 	/* figure out the names for the string pool */
573*7836SJohn.Forte@Sun.COM 
574*7836SJohn.Forte@Sun.COM 	string_size = 0;
575*7836SJohn.Forte@Sun.COM 	open_files = 0;
576*7836SJohn.Forte@Sun.COM 	cdi = _sd_cache_files;
577*7836SJohn.Forte@Sun.COM 	do {
578*7836SJohn.Forte@Sun.COM 
579*7836SJohn.Forte@Sun.COM 		if (cdi->cd_info == NULL)
580*7836SJohn.Forte@Sun.COM 			continue;
581*7836SJohn.Forte@Sun.COM 		if (cdi->cd_info->sh_alloc == 0)
582*7836SJohn.Forte@Sun.COM 			continue;
583*7836SJohn.Forte@Sun.COM 		open_files++;
584*7836SJohn.Forte@Sun.COM 		string_size += strlen(cdi->cd_info->sh_filename) + 1;
585*7836SJohn.Forte@Sun.COM 	} while (++cdi != &_sd_cache_files[sdbc_max_devs]);
586*7836SJohn.Forte@Sun.COM 
587*7836SJohn.Forte@Sun.COM 	if (open_files == 0) {
588*7836SJohn.Forte@Sun.COM 		return (0);
589*7836SJohn.Forte@Sun.COM 	}
590*7836SJohn.Forte@Sun.COM 
591*7836SJohn.Forte@Sun.COM 	hdrblk = sdbc_centry_alloc_blks(_CD_NOHASH, 0, 1, 0);
592*7836SJohn.Forte@Sun.COM 	bzero(hdrblk->cc_data, CACHE_BLOCK_SIZE);
593*7836SJohn.Forte@Sun.COM 	hdr = (sdbc_pwf_hdr_t *)hdrblk->cc_data;
594*7836SJohn.Forte@Sun.COM 	hdr->magic = SDBC_PWF_MAGIC;
595*7836SJohn.Forte@Sun.COM 	hdr->alignment = CACHE_BLOCK_SIZE;
596*7836SJohn.Forte@Sun.COM 	hdr->cd_count = open_files;
597*7836SJohn.Forte@Sun.COM 	/* XXX bmap_size is redundant */
598*7836SJohn.Forte@Sun.COM 	hdr->bmap_size = CACHE_BLOCK_SIZE / sizeof (sdbc_pwf_bitmap_t);
599*7836SJohn.Forte@Sun.COM 
600*7836SJohn.Forte@Sun.COM 	name_pool = sdbc_get_anon_list(string_size);
601*7836SJohn.Forte@Sun.COM 	file_pool = sdbc_get_anon_list(sizeof (sdbc_pwf_desc_t) * open_files);
602*7836SJohn.Forte@Sun.COM 
603*7836SJohn.Forte@Sun.COM 	open_files = 0;
604*7836SJohn.Forte@Sun.COM 	cdi = _sd_cache_files;
605*7836SJohn.Forte@Sun.COM 	total_len = 0;
606*7836SJohn.Forte@Sun.COM 	do {
607*7836SJohn.Forte@Sun.COM 
608*7836SJohn.Forte@Sun.COM 		if (cdi->cd_info == NULL)
609*7836SJohn.Forte@Sun.COM 			continue;
610*7836SJohn.Forte@Sun.COM 		if (cdi->cd_info->sh_alloc == 0)
611*7836SJohn.Forte@Sun.COM 			continue;
612*7836SJohn.Forte@Sun.COM 
613*7836SJohn.Forte@Sun.COM 		len = strlen(cdi->cd_info->sh_filename) + 1;
614*7836SJohn.Forte@Sun.COM 
615*7836SJohn.Forte@Sun.COM 		/* copy the name to string pool */
616*7836SJohn.Forte@Sun.COM 		sdbc_anon_copy(cdi->cd_info->sh_filename,
617*7836SJohn.Forte@Sun.COM 		    len, name_pool, total_len);
618*7836SJohn.Forte@Sun.COM 
619*7836SJohn.Forte@Sun.COM 		bzero(&current, sizeof (current));
620*7836SJohn.Forte@Sun.COM 		current.name = total_len;
621*7836SJohn.Forte@Sun.COM 		sdbc_anon_copy((caddr_t)&current, sizeof (current), file_pool,
622*7836SJohn.Forte@Sun.COM 		    open_files * sizeof (sdbc_pwf_desc_t));
623*7836SJohn.Forte@Sun.COM 
624*7836SJohn.Forte@Sun.COM 		open_files++;
625*7836SJohn.Forte@Sun.COM 		total_len += len;
626*7836SJohn.Forte@Sun.COM 
627*7836SJohn.Forte@Sun.COM 	} while (++cdi != &_sd_cache_files[sdbc_max_devs]);
628*7836SJohn.Forte@Sun.COM 
629*7836SJohn.Forte@Sun.COM 	/* flush dirty data */
630*7836SJohn.Forte@Sun.COM 
631*7836SJohn.Forte@Sun.COM 	if (swfs.nswpf == 0 || swfs.names[0] == NULL) {
632*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "sdbc(_sdbc_power_flush): State file"
633*7836SJohn.Forte@Sun.COM 		    " is not configured");
634*7836SJohn.Forte@Sun.COM 		rc = ENODEV;
635*7836SJohn.Forte@Sun.COM 		goto cleanup;
636*7836SJohn.Forte@Sun.COM 	}
637*7836SJohn.Forte@Sun.COM 
638*7836SJohn.Forte@Sun.COM 	if (!(state_fd =
639*7836SJohn.Forte@Sun.COM 	    nsc_open(swfs.names[0], NSC_DEVICE, NULL, NULL, &rc)) ||
640*7836SJohn.Forte@Sun.COM 	    !nsc_getval(state_fd, "DevMaj", (int *)&devmaj) ||
641*7836SJohn.Forte@Sun.COM 	    !nsc_getval(state_fd, "DevMin", (int *)&devmin)) {
642*7836SJohn.Forte@Sun.COM 		if (state_fd) {
643*7836SJohn.Forte@Sun.COM 			(void) nsc_close(state_fd);
644*7836SJohn.Forte@Sun.COM 		}
645*7836SJohn.Forte@Sun.COM 		/*
646*7836SJohn.Forte@Sun.COM 		 * We are hosed big time. We can't get device to write the
647*7836SJohn.Forte@Sun.COM 		 * state file opened.
648*7836SJohn.Forte@Sun.COM 		 */
649*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "sdbc(_sdbc_power_flush): Couldn't "
650*7836SJohn.Forte@Sun.COM 		    "open %s for saved state file", swfs.names[0]);
651*7836SJohn.Forte@Sun.COM 		rc = EIO;
652*7836SJohn.Forte@Sun.COM 		goto cleanup;
653*7836SJohn.Forte@Sun.COM 	}
654*7836SJohn.Forte@Sun.COM 
655*7836SJohn.Forte@Sun.COM 	state_rdev = makedevice(devmaj, devmin);
656*7836SJohn.Forte@Sun.COM 
657*7836SJohn.Forte@Sun.COM 	blkno = 1;
658*7836SJohn.Forte@Sun.COM 
659*7836SJohn.Forte@Sun.COM 	hdr->string_pool = blkno;
660*7836SJohn.Forte@Sun.COM 	rc = flush_anon_list(name_pool, state_rdev, &blkno);
661*7836SJohn.Forte@Sun.COM 
662*7836SJohn.Forte@Sun.COM 	hdr->descriptor_pool = blkno;
663*7836SJohn.Forte@Sun.COM 	rc = flush_anon_list(file_pool, state_rdev, &blkno);
664*7836SJohn.Forte@Sun.COM 
665*7836SJohn.Forte@Sun.COM 	/*
666*7836SJohn.Forte@Sun.COM 	 * iterate across all devices, flushing the data and collecting bitmaps
667*7836SJohn.Forte@Sun.COM 	 */
668*7836SJohn.Forte@Sun.COM 
669*7836SJohn.Forte@Sun.COM 	open_files = 0;
670*7836SJohn.Forte@Sun.COM 	for (cdi = _sd_cache_files;
671*7836SJohn.Forte@Sun.COM 	    cdi != &_sd_cache_files[sdbc_max_devs]; cdi++) {
672*7836SJohn.Forte@Sun.COM 		nsc_off_t blk2;
673*7836SJohn.Forte@Sun.COM 		nsc_off_t fp_off;
674*7836SJohn.Forte@Sun.COM 
675*7836SJohn.Forte@Sun.COM 		if (cdi->cd_info == NULL)
676*7836SJohn.Forte@Sun.COM 			continue;
677*7836SJohn.Forte@Sun.COM 		if (cdi->cd_info->sh_alloc == 0)
678*7836SJohn.Forte@Sun.COM 			continue;
679*7836SJohn.Forte@Sun.COM 
680*7836SJohn.Forte@Sun.COM 		/* retrieve the file description so we can update it */
681*7836SJohn.Forte@Sun.COM 		fp_off = (open_files++) * sizeof (sdbc_pwf_desc_t);
682*7836SJohn.Forte@Sun.COM 		sdbc_anon_get(file_pool, fp_off,
683*7836SJohn.Forte@Sun.COM 		    (caddr_t)&current, sizeof (current));
684*7836SJohn.Forte@Sun.COM 
685*7836SJohn.Forte@Sun.COM 		current.blocks = blkno;
686*7836SJohn.Forte@Sun.COM 
687*7836SJohn.Forte@Sun.COM 		if (cdi->cd_io_head) {
688*7836SJohn.Forte@Sun.COM 			/*
689*7836SJohn.Forte@Sun.COM 			 * Need to wait for this to timeout?
690*7836SJohn.Forte@Sun.COM 			 * Seems like worst case we just write the data twice
691*7836SJohn.Forte@Sun.COM 			 * so we should be ok.
692*7836SJohn.Forte@Sun.COM 			 */
693*7836SJohn.Forte@Sun.COM 			/*EMPTY*/
694*7836SJohn.Forte@Sun.COM 			;
695*7836SJohn.Forte@Sun.COM 		}
696*7836SJohn.Forte@Sun.COM 
697*7836SJohn.Forte@Sun.COM 		start_bitmap_list(&bmap, hdr->bmap_size);
698*7836SJohn.Forte@Sun.COM 
699*7836SJohn.Forte@Sun.COM 		/* Flush the enqueued dirty data blocks */
700*7836SJohn.Forte@Sun.COM 
701*7836SJohn.Forte@Sun.COM 		(void) flush_centry_list(cdi, cdi->cd_dirty_head, state_rdev,
702*7836SJohn.Forte@Sun.COM 		    &blkno, 0, &bmap);
703*7836SJohn.Forte@Sun.COM 		cdi->cd_dirty_head = NULL;
704*7836SJohn.Forte@Sun.COM 		cdi->cd_dirty_tail = NULL;
705*7836SJohn.Forte@Sun.COM 
706*7836SJohn.Forte@Sun.COM 		/* Flush the failed dirty data blocks */
707*7836SJohn.Forte@Sun.COM 
708*7836SJohn.Forte@Sun.COM 		(void) flush_centry_list(cdi, cdi->cd_fail_head, state_rdev,
709*7836SJohn.Forte@Sun.COM 		    &blkno, 1, &bmap);
710*7836SJohn.Forte@Sun.COM 		cdi->cd_fail_head = NULL;
711*7836SJohn.Forte@Sun.COM 
712*7836SJohn.Forte@Sun.COM 		/*
713*7836SJohn.Forte@Sun.COM 		 * Flush the in progress dirty data blocks. These really should
714*7836SJohn.Forte@Sun.COM 		 * really be null by now. Worst case we write the data again
715*7836SJohn.Forte@Sun.COM 		 * on recovery as we know the dirty masks won't change since
716*7836SJohn.Forte@Sun.COM 		 * flusher is stopped.
717*7836SJohn.Forte@Sun.COM 		 */
718*7836SJohn.Forte@Sun.COM 
719*7836SJohn.Forte@Sun.COM 		(void) flush_centry_list(cdi, cdi->cd_io_head, state_rdev,
720*7836SJohn.Forte@Sun.COM 		    &blkno, 0, &bmap);
721*7836SJohn.Forte@Sun.COM 		cdi->cd_io_head = NULL;
722*7836SJohn.Forte@Sun.COM 		cdi->cd_io_tail = NULL;
723*7836SJohn.Forte@Sun.COM 
724*7836SJohn.Forte@Sun.COM 		current.bitmaps = blkno;
725*7836SJohn.Forte@Sun.COM 		current.nblocks = blkno - current.blocks;
726*7836SJohn.Forte@Sun.COM 
727*7836SJohn.Forte@Sun.COM 		(void) flush_bitmap_list(&bmap, state_rdev, &blkno);
728*7836SJohn.Forte@Sun.COM 
729*7836SJohn.Forte@Sun.COM 		/* update the current cd's file description */
730*7836SJohn.Forte@Sun.COM 		sdbc_anon_copy((caddr_t)&current, sizeof (current), file_pool,
731*7836SJohn.Forte@Sun.COM 		    fp_off);
732*7836SJohn.Forte@Sun.COM 
733*7836SJohn.Forte@Sun.COM 		blk2 = hdr->descriptor_pool;
734*7836SJohn.Forte@Sun.COM 		rc = flush_anon_list(file_pool, state_rdev, &blk2);
735*7836SJohn.Forte@Sun.COM 	}
736*7836SJohn.Forte@Sun.COM 
737*7836SJohn.Forte@Sun.COM #if !defined(_SunOS_5_6)
738*7836SJohn.Forte@Sun.COM 	hdr->dump_time = ddi_get_time();
739*7836SJohn.Forte@Sun.COM #else
740*7836SJohn.Forte@Sun.COM 	hdr->dump_time = hrestime.tv_sec;
741*7836SJohn.Forte@Sun.COM #endif
742*7836SJohn.Forte@Sun.COM 	/* write the header at front and back */
743*7836SJohn.Forte@Sun.COM 	(void) flush_hdr(hdrblk, state_rdev, blkno);
744*7836SJohn.Forte@Sun.COM 	(void) flush_hdr(hdrblk, state_rdev, 0L);
745*7836SJohn.Forte@Sun.COM 
746*7836SJohn.Forte@Sun.COM 	/* P3 */
747*7836SJohn.Forte@Sun.COM 	cmn_err(CE_CONT, "sdbc(sdbc_power_flush) %" NSC_SZFMT " total\n",
748*7836SJohn.Forte@Sun.COM 	    blkno);
749*7836SJohn.Forte@Sun.COM 
750*7836SJohn.Forte@Sun.COM cleanup:
751*7836SJohn.Forte@Sun.COM 	;
752*7836SJohn.Forte@Sun.COM 	return (rc);
753*7836SJohn.Forte@Sun.COM 
754*7836SJohn.Forte@Sun.COM }
755*7836SJohn.Forte@Sun.COM 
756*7836SJohn.Forte@Sun.COM /*
757*7836SJohn.Forte@Sun.COM  * _sdbc_power_lost - System is running on UPS power we have "rideout"
758*7836SJohn.Forte@Sun.COM  * minutes of power left prior to shutdown. Get into a state where we
759*7836SJohn.Forte@Sun.COM  * will be ready should we need to shutdown.
760*7836SJohn.Forte@Sun.COM  *
761*7836SJohn.Forte@Sun.COM  * ARGUMENTS:
762*7836SJohn.Forte@Sun.COM  *	rideout - minutes of power left prior to shutdown.
763*7836SJohn.Forte@Sun.COM  */
764*7836SJohn.Forte@Sun.COM void
_sdbc_power_lost(int rideout)765*7836SJohn.Forte@Sun.COM _sdbc_power_lost(int rideout)
766*7836SJohn.Forte@Sun.COM {
767*7836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "sdbc(_sdbc_power_lost) battery time "
768*7836SJohn.Forte@Sun.COM 	    "remaining %d minute(s)", rideout);
769*7836SJohn.Forte@Sun.COM 
770*7836SJohn.Forte@Sun.COM 	got_hint = 1;
771*7836SJohn.Forte@Sun.COM 	if (_sd_get_node_hint(&wrthru_hint))
772*7836SJohn.Forte@Sun.COM 		got_hint = 0;
773*7836SJohn.Forte@Sun.COM 
774*7836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "sdbc(_sdbc_power_lost) got hint %d "
775*7836SJohn.Forte@Sun.COM 		"hint 0x%x", got_hint, wrthru_hint);
776*7836SJohn.Forte@Sun.COM 
777*7836SJohn.Forte@Sun.COM 	(void) _sd_set_node_hint(NSC_FORCED_WRTHRU);
778*7836SJohn.Forte@Sun.COM 	saw_power_lost = 1;
779*7836SJohn.Forte@Sun.COM }
780*7836SJohn.Forte@Sun.COM 
781*7836SJohn.Forte@Sun.COM /*
782*7836SJohn.Forte@Sun.COM  * _sdbc_power_ok - System is back running on mains power after
783*7836SJohn.Forte@Sun.COM  * seeing a power fail. Return to normal power up operation.
784*7836SJohn.Forte@Sun.COM  *
785*7836SJohn.Forte@Sun.COM  */
786*7836SJohn.Forte@Sun.COM void
_sdbc_power_ok(void)787*7836SJohn.Forte@Sun.COM _sdbc_power_ok(void)
788*7836SJohn.Forte@Sun.COM {
789*7836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "sdbc(_sdbc_power_ok) power ok");
790*7836SJohn.Forte@Sun.COM 	if (saw_power_lost && got_hint) {
791*7836SJohn.Forte@Sun.COM 		/*
792*7836SJohn.Forte@Sun.COM 		 * In theory we have a race here between _sdbc_power_lost
793*7836SJohn.Forte@Sun.COM 		 * and here. However it is expected that power ioctls that
794*7836SJohn.Forte@Sun.COM 		 * cause these to be generated are sequential in nature
795*7836SJohn.Forte@Sun.COM 		 * so there is no race.
796*7836SJohn.Forte@Sun.COM 		 */
797*7836SJohn.Forte@Sun.COM 		saw_power_lost = 0;
798*7836SJohn.Forte@Sun.COM 		if (wrthru_hint & _SD_WRTHRU_MASK)
799*7836SJohn.Forte@Sun.COM 			(void) _sd_set_node_hint(wrthru_hint & _SD_WRTHRU_MASK);
800*7836SJohn.Forte@Sun.COM 		else
801*7836SJohn.Forte@Sun.COM 			(void) _sd_clear_node_hint(_SD_WRTHRU_MASK);
802*7836SJohn.Forte@Sun.COM 	}
803*7836SJohn.Forte@Sun.COM }
804*7836SJohn.Forte@Sun.COM 
805*7836SJohn.Forte@Sun.COM /*
806*7836SJohn.Forte@Sun.COM  * _sdbc_power_down - System is running on UPS power and we must stop
807*7836SJohn.Forte@Sun.COM  * operation as the machine is now going down. Schedule a shutdown
808*7836SJohn.Forte@Sun.COM  * thread.
809*7836SJohn.Forte@Sun.COM  *
810*7836SJohn.Forte@Sun.COM  * When we return all cache activity will be blocked.
811*7836SJohn.Forte@Sun.COM  */
812*7836SJohn.Forte@Sun.COM void
_sdbc_power_down(void)813*7836SJohn.Forte@Sun.COM _sdbc_power_down(void)
814*7836SJohn.Forte@Sun.COM {
815*7836SJohn.Forte@Sun.COM 	cmn_err(CE_WARN, "sdbc(_sdbc_power_down) powering down...");
816*7836SJohn.Forte@Sun.COM 	(void) _sdbc_power_flush();
817*7836SJohn.Forte@Sun.COM }
818*7836SJohn.Forte@Sun.COM 
819*7836SJohn.Forte@Sun.COM /*
820*7836SJohn.Forte@Sun.COM  * Configure safe store from the general cache configuration ioctl.
821*7836SJohn.Forte@Sun.COM  */
822*7836SJohn.Forte@Sun.COM int
_sdbc_pcu_config(int namec,char ** namev)823*7836SJohn.Forte@Sun.COM _sdbc_pcu_config(int namec, char **namev)
824*7836SJohn.Forte@Sun.COM {
825*7836SJohn.Forte@Sun.COM 	int i;
826*7836SJohn.Forte@Sun.COM 
827*7836SJohn.Forte@Sun.COM 	if (swfs.nswpf != 0) {
828*7836SJohn.Forte@Sun.COM 		/*
829*7836SJohn.Forte@Sun.COM 		 * This should not happen because cache protects itself
830*7836SJohn.Forte@Sun.COM 		 * from double configuration in sd_conf.c.
831*7836SJohn.Forte@Sun.COM 		 */
832*7836SJohn.Forte@Sun.COM 		cmn_err(CE_CONT, "sdbc(_sdbc_pcu_config) double "
833*7836SJohn.Forte@Sun.COM 		    "configuration of Safe Store\n");
834*7836SJohn.Forte@Sun.COM 		return (EINVAL);
835*7836SJohn.Forte@Sun.COM 	}
836*7836SJohn.Forte@Sun.COM 	swfs.colsize = 32;	/* No way to configure in the general ioctl */
837*7836SJohn.Forte@Sun.COM 
838*7836SJohn.Forte@Sun.COM 	for (i = 0; i < namec; i++) {
839*7836SJohn.Forte@Sun.COM 		if ((swfs.names[i] = kmem_alloc(strlen(namev[i])+1,
840*7836SJohn.Forte@Sun.COM 		    KM_NOSLEEP)) == NULL) {
841*7836SJohn.Forte@Sun.COM 			_sdbc_pcu_cleanup(&swfs);
842*7836SJohn.Forte@Sun.COM 			return (ENOMEM);
843*7836SJohn.Forte@Sun.COM 		}
844*7836SJohn.Forte@Sun.COM 		swfs.nswpf++;
845*7836SJohn.Forte@Sun.COM 		(void) strcpy(swfs.names[i], namev[i]);
846*7836SJohn.Forte@Sun.COM 	}
847*7836SJohn.Forte@Sun.COM 
848*7836SJohn.Forte@Sun.COM 	return (0);
849*7836SJohn.Forte@Sun.COM }
850*7836SJohn.Forte@Sun.COM 
851*7836SJohn.Forte@Sun.COM /*
852*7836SJohn.Forte@Sun.COM  */
853*7836SJohn.Forte@Sun.COM void
_sdbc_pcu_unload()854*7836SJohn.Forte@Sun.COM _sdbc_pcu_unload()
855*7836SJohn.Forte@Sun.COM {
856*7836SJohn.Forte@Sun.COM 	_sdbc_pcu_cleanup(&swfs);
857*7836SJohn.Forte@Sun.COM }
858*7836SJohn.Forte@Sun.COM 
859*7836SJohn.Forte@Sun.COM /*
860*7836SJohn.Forte@Sun.COM  * Destructor for struct swapfiles.
861*7836SJohn.Forte@Sun.COM  */
862*7836SJohn.Forte@Sun.COM static void
_sdbc_pcu_cleanup(struct swapfiles * swp)863*7836SJohn.Forte@Sun.COM _sdbc_pcu_cleanup(struct swapfiles *swp)
864*7836SJohn.Forte@Sun.COM {
865*7836SJohn.Forte@Sun.COM 	int i;
866*7836SJohn.Forte@Sun.COM 	char *s;
867*7836SJohn.Forte@Sun.COM 
868*7836SJohn.Forte@Sun.COM 	for (i = 0; i < swp->nswpf; i++) {
869*7836SJohn.Forte@Sun.COM 		if ((s = swp->names[i]) != NULL)
870*7836SJohn.Forte@Sun.COM 			kmem_free(s, strlen(s)+1);
871*7836SJohn.Forte@Sun.COM 		swp->names[i] = NULL;
872*7836SJohn.Forte@Sun.COM 	}
873*7836SJohn.Forte@Sun.COM 	swp->nswpf = 0;
874*7836SJohn.Forte@Sun.COM }
875