1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #ifndef _RDC_DISKQ_H
27 #define _RDC_DISKQ_H
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33 #ifdef _KERNEL
34
35 #define RDC_DISKQ_HEADER_OFF 0 /* beginning of disk */
36 #define RDC_DISKQ_DATA_OFF FBA_LEN(1024) /* beginning of queue */
37
38 typedef struct qentry {
39 int magic;
40 int type; /* special data ? io? bitmap? */
41 nsc_off_t pos; /* position it will be in the rdc_aio_t */
42 nsc_off_t hpos; /* starting pos of orig nsc_buf_t */
43 nsc_off_t qpos; /* where this info is in the queue */
44 nsc_size_t len; /* len */
45 int flag;
46 int iostatus;
47 uint32_t setid; /* krdc */
48 time_t time;
49 void *next;
50 } q_data;
51
52 typedef union io_dat {
53 q_data dat;
54 char dummy[512];
55 } io_hdr;
56
57 #define RDC_IOHDR_MAGIC 0x494F4844 /* IOHD */
58 #define RDC_IOHDR_DONE 0xDEADCAFE /* this q entry has been flushed */
59 #define RDC_IOHDR_WAITING 0xBEEFCAFE /* this q entry is waiting for ack */
60
61 /* type */
62 #define RDC_QUEUEIO 0x02
63
64 #define RDC_DISKQ_MAGIC 0x44534B51
65 #define RDC_DISKQ_VER_ORIG 0x01
66 #define RDC_DISKQ_VER_64BIT 0x02
67
68 #ifdef NSC_MULTI_TERABYTE
69 #define RDC_DISKQ_VERS RDC_DISKQ_VER_64BIT
70 #else
71 #define RDC_DISKQ_VERS RDC_DISKQ_VER_ORIG
72 #endif
73
74 typedef struct diskqheader1 {
75 int magic;
76 int vers;
77 int state;
78 int head_offset; /* offset of meta-info of head (fbas) */
79 int tail_offset; /* addr of next write (fbas) */
80 int disk_size; /* allow growing ? (fbas) */
81 long nitems; /* items */
82 long blocks; /* fbas */
83 int qwrap; /* where the tail wrapped */
84 int auxqwrap; /* if the tail wraps again, before head wraps once */
85 uint_t seq_last; /* last sequence before suspend */
86 uint_t ack_last; /* last ack before suspend */
87 } diskq_header1;
88
89 typedef struct diskqheader2 {
90 int magic;
91 int vers;
92 int state;
93 uint64_t head_offset; /* offset of meta-info of head (fbas) */
94 uint64_t tail_offset; /* addr of next write (fbas) */
95 uint64_t disk_size; /* allow growing ? (fbas) */
96 uint64_t nitems; /* items */
97 uint64_t blocks; /* fbas */
98 uint64_t qwrap; /* where the tail wrapped */
99 uint64_t auxqwrap; /* if the tail wraps again, before head wraps once */
100 uint_t seq_last; /* last sequence before suspend */
101 uint_t ack_last; /* last ack before suspend */
102 } diskq_header2;
103
104 #ifdef NSC_MULTI_TERABYTE
105 typedef diskq_header2 diskq_header;
106 #ifdef _LP64
107 #define RDC_DQFMT "lu"
108 #else
109 #define RDC_DQFMT "llu"
110 #endif
111 #else
112 typedef diskq_header1 diskq_header;
113 #define RDC_DQFMT "ld"
114 #endif
115 typedef union headr {
116 diskq_header h;
117 char dummy[512];
118 } dqheader;
119
120 /* flags for the state field in the header */
121
122 #define RDC_SHUTDOWN_OK 0x01
123 #define RDC_SHUTDOWN_BAD 0x02
124 #define QNXTIOWRAPD 0x04
125 #define QHEADWRAPD 0x08
126 #define QTAILBUSY 0x10 /* tell flusher not to grab, incomplete */
127 #define RDC_QNOBLOCK 0x10000 /* can also be passed out by status */
128 #define RDC_QBADRESUME 0x20 /* don't resume bit ref */
129 #define RDC_QFULL 0x40 /* the queue is in a full delay loop */
130 #define RDC_STOPPINGFLUSH 0x80
131
132 #define RDC_QFILLSTOP 0x01 /* diskq->memq flusher kill switch */
133 #define RDC_QFILLSLEEP 0x02 /* explicit diskq->memq flusher sleep */
134
135 #define RDC_MAX_DISKQREAD 0x1000 /* max 2 mb q read */
136
137 typedef struct diskqueue { /* the incore info about the diskq */
138 dqheader disk_hdr; /* info about the queue */
139 long nitems_hwm;
140 long blocks_hwm;
141 long throttle_delay;
142 nsc_off_t last_tail; /* pos of the last tail write */
143 volatile int inflbls; /* number of inflight blocks */
144 volatile int inflitems; /* number of inflight blocks */
145
146 kmutex_t disk_qlock; /* protects all things in diskq */
147 /* and all things in dqheader */
148
149 kmutex_t head_lock;
150 kcondvar_t busycv;
151 int busycnt;
152 nsc_off_t nxt_io; /* flushers head pointer */
153 int hdrcnt; /* number of io_hdrs on list */
154 nsc_off_t coalesc_bounds; /* don't coalesce below this offset */
155 rdc_aio_t *lastio; /* cached copy of the last write on q */
156 io_hdr *iohdrs; /* flushed, not ack'd on queue */
157 io_hdr *hdr_last; /* tail of iohdr list */
158 kcondvar_t qfullcv; /* block, queue is full */
159 } disk_queue;
160
161 /* diskq macros (gets) */
162
163 #define QHEAD(q) q->disk_hdr.h.head_offset
164 #define QNXTIO(q) q->nxt_io
165 #define QTAIL(q) q->disk_hdr.h.tail_offset
166 #define QNITEMS(q) q->disk_hdr.h.nitems
167 #define QBLOCKS(q) q->disk_hdr.h.blocks
168 #define QSTATE(q) q->disk_hdr.h.state
169 #define IS_QSTATE(q, s) (q->disk_hdr.h.state & s)
170 #define QSIZE(q) q->disk_hdr.h.disk_size
171 #define QMAGIC(q) q->disk_hdr.h.magic
172 #define QVERS(q) q->disk_hdr.h.vers
173 #define QSEQ(q) q->disk_hdr.h.seq_last
174 #define QACK(q) q->disk_hdr.h.ack_last
175 #define QEMPTY(q) ((QTAIL(q) == QHEAD(q))&&(!(QNITEMS(q))))
176 #define QWRAP(q) q->disk_hdr.h.qwrap
177 #define AUXQWRAP(q) q->disk_hdr.h.auxqwrap
178 #define LASTQTAIL(q) q->last_tail
179 #define QCOALBOUNDS(q) q->coalesc_bounds
180
181 /* diskq macros (sets) */
182
183 #define INC_QHEAD(q, n) q->disk_hdr.h.head_offset += n
184 #define INC_QNXTIO(q, n) q->nxt_io += n
185 #define DEC_QNXTIO(q, n) q->nxt_io -= n
186 #define DEC_QHEAD(q, n) q->disk_hdr.h.head_offset -= n
187 #define INC_QTAIL(q, n) q->disk_hdr.h.tail_offset += n
188 #define DEC_QTAIL(q, n) q->disk_hdr.h.tail_offset -= n
189 #define INC_QNITEMS(q, n) q->disk_hdr.h.nitems += n
190 #define DEC_QNITEMS(q, n) q->disk_hdr.h.nitems -= n
191 #define INC_QBLOCKS(q, n) q->disk_hdr.h.blocks += n
192 #define DEC_QBLOCKS(q, n) q->disk_hdr.h.blocks -= n
193
194 #define SET_QMAGIC(q, n) q->disk_hdr.h.magic = n
195 #define SET_QSTATE(q, n) q->disk_hdr.h.state |= n
196 #define CLR_QSTATE(q, n) q->disk_hdr.h.state &= ~n
197 #define SET_QHEAD(q, n) q->disk_hdr.h.head_offset = n
198 #define SET_QNXTIO(q, n) q->nxt_io = n
199 #define SET_QHDRCNT(q, n) q->hdrcnt = n
200 #define SET_QTAIL(q, n) q->disk_hdr.h.tail_offset = n
201 #define SET_LASTQTAIL(q, n) q->last_tail = n
202 #define SET_LASTQWRITE(q, w) q->last_qwrite = w
203 #define SET_QSIZE(q, n) q->disk_hdr.h.disk_size = n
204 #define SET_QNITEMS(q, n) q->disk_hdr.h.nitems = n
205 #define SET_QBLOCKS(q, n) q->disk_hdr.h.blocks = n
206
207 #define SET_QWRAP(q, n) q->disk_hdr.h.qwrap = n
208 #define CLR_QWRAP(q) q->disk_hdr.h.qwrap = 0
209 #define SET_AUXQWRAP(q, n) q->disk_hdr.h.auxqwrap = n
210 #define CLR_AUXQWRAP(q) q->disk_hdr.h.auxqwrap = 0
211 #define SET_QCOALBOUNDS(q, n) q->coalesc_bounds = n
212
213 #define WRAPQTAIL(q) \
214 do { \
215 if (QWRAP(q)) { \
216 SET_AUXQWRAP(q, QTAIL(q)); \
217 } else { \
218 SET_QWRAP(q, QTAIL(q)); \
219 } \
220 SET_QTAIL(q, RDC_DISKQ_DATA_OFF); \
221 } while (0)
222
223 #define DO_AUXQWRAP(q) \
224 do { \
225 SET_QWRAP(q, AUXQWRAP(q)); \
226 SET_AUXQWRAP(q, 0); \
227 } while (0)
228
229 /* these can be wrapped by different threads, avoid the race */
230 #define WRAPQHEAD(q) \
231 do { \
232 if (IS_QSTATE(q, QNXTIOWRAPD)) { \
233 if (AUXQWRAP(q)) { \
234 DO_AUXQWRAP(q); \
235 } else { \
236 SET_QWRAP(q, 0); \
237 } \
238 CLR_QSTATE(q, QNXTIOWRAPD); \
239 } else { \
240 SET_QSTATE(q, QHEADWRAPD); \
241 } \
242 SET_QHEAD(q, RDC_DISKQ_DATA_OFF); \
243 } while (0)
244
245 #define WRAPQNXTIO(q) \
246 do { \
247 if (IS_QSTATE(q, QHEADWRAPD)) { \
248 if (AUXQWRAP(q)) { \
249 DO_AUXQWRAP(q); \
250 } else { \
251 SET_QWRAP(q, 0); \
252 } \
253 CLR_QSTATE(q, QHEADWRAPD); \
254 } else { \
255 SET_QSTATE(q, QNXTIOWRAPD); \
256 } \
257 SET_QNXTIO(q, RDC_DISKQ_DATA_OFF); \
258 } while (0)
259
260 #define DQEND(q) (QWRAP(q)?QWRAP(q):QSIZE(q))
261
262 #define FITSONQ(q, n) \
263 (((QBLOCKS(q)+QNITEMS(q)+RDC_DISKQ_DATA_OFF+n) >= \
264 (uint64_t)DQEND(q))?0:1)
265
266 /* diskq defines/macros (non-specific) */
267
268 #define RDC_NOLOG 0x00
269 #define RDC_WAIT 0x01
270 #define RDC_NOWAIT 0x02
271 #define RDC_DOLOG 0x04 /* put the group into logging */
272 #define RDC_NOFAIL 0x08 /* don't fail the queue, just init */
273 #define RDC_GROUP_LOCKED 0x10 /* trust me, I have the group lock */
274
275 #define RDC_WRITTEN 0x10 /* data has been commited to queue */
276 #define RDC_LAST 0x20 /* end of dequeued buffer, discard */
277
278 /* CSTYLED */
279 #define RDC_BETWEEN(a,b,c) (a<b?((c>=a)&&(c<=b)):((a!=b)&&((c<b)||(c>=a))))
280 /* CSTYLED */
281
282 #define QHEADSHLDWRAP(q) (QWRAP(q) && (QHEAD(q) >= QWRAP(q)))
283 #define QNXTIOSHLDWRAP(q) (QWRAP(q) && (QNXTIO(q) >= QWRAP(q)))
284 #define QTAILSHLDWRAP(q, size) (QTAIL(q) + size > QSIZE(q))
285 #define QCOALESCEOK(q, dec) ((q->lastio->iostatus & RDC_WRITTEN) && \
286 ((QTAIL(q) > QNXTIO(q)) ? \
287 (((QTAIL(q) - dec) > QNXTIO(q)) && ((QTAIL(q) - dec) > \
288 QCOALBOUNDS(q))):\
289 (QNXTIOSHLDWRAP(q) && QTAIL(q) > RDC_DISKQ_DATA_OFF)))
290
291 #define QLOCK(q) &q->disk_qlock
292 #define QTAILLOCK(q) &q->tail_lock
293 #define QHEADLOCK(q) &q->head_lock
294
295 #define QDISPLAY(q) "qmagic: %x qvers: %d qstate: %x qhead: %" \
296 NSC_SZFMT " qnxtio: %" NSC_SZFMT " qtail: %" NSC_SZFMT " qtaillast: %" \
297 NSC_SZFMT " qsize: %" NSC_SZFMT " qnitems: %" RDC_DQFMT \
298 " qblocks: %" RDC_DQFMT " coalbounds %" NSC_SZFMT, QMAGIC(q), \
299 QVERS(q), QSTATE(q), QHEAD(q), QNXTIO(q), QTAIL(q), LASTQTAIL(q), \
300 QSIZE(q), QNITEMS(q), QBLOCKS(q), QCOALBOUNDS(q)
301
302 #define QDISPLAYND(q) "m: %x v: %d s: %d h: %" NSC_SZFMT " n: %" \
303 NSC_SZFMT " t: %" NSC_SZFMT " l: %" NSC_SZFMT " z: %" NSC_SZFMT \
304 " i: %" RDC_DQFMT " b: %" RDC_DQFMT " w: %" NSC_SZFMT \
305 " a: %" NSC_SZFMT, \
306 QMAGIC(q), QVERS(q), QSTATE(q), QHEAD(q), \
307 QNXTIO(q), QTAIL(q), LASTQTAIL(q), QSIZE(q), QNITEMS(q), \
308 QBLOCKS(q), QWRAP(q), AUXQWRAP(q)
309
310 /* Disk queue flusher state */
311 #define RDC_QFILL_AWAKE (0)
312 #define RDC_QFILL_ASLEEP (1)
313 #define RDC_QFILL_DEAD (-1)
314
315 /* functions */
316
317 int rdc_add_diskq(rdc_config_t *uparms, spcs_s_info_t kstatus);
318 int rdc_rem_diskq(rdc_config_t *uparms, spcs_s_info_t kstatus);
319 int rdc_kill_diskq(rdc_config_t *uparms, spcs_s_info_t kstatus);
320 int rdc_init_diskq(rdc_config_t *uparms, spcs_s_info_t kstatus);
321 int rdc_lookup_diskq(char *path);
322 int rdc_diskq_inuse(rdc_set_t *set, char *diskq);
323 void rdc_dump_iohdrs(disk_queue *q);
324 extern void rdc_fixlen(rdc_aio_t *aio);
325
326 #endif /* _KERNEL */
327
328 #ifdef __cplusplus
329 }
330 #endif
331
332 #endif /* _RDC_DISKQ_H */