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 */