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 30extern "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 38typedef 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 52typedef 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 74typedef 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 89typedef 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 105typedef diskq_header2 diskq_header; 106#ifdef _LP64 107#define RDC_DQFMT "lu" 108#else 109#define RDC_DQFMT "llu" 110#endif 111#else 112typedef diskq_header1 diskq_header; 113#define RDC_DQFMT "ld" 114#endif 115typedef 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 137typedef 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 317int rdc_add_diskq(rdc_config_t *uparms, spcs_s_info_t kstatus); 318int rdc_rem_diskq(rdc_config_t *uparms, spcs_s_info_t kstatus); 319int rdc_kill_diskq(rdc_config_t *uparms, spcs_s_info_t kstatus); 320int rdc_init_diskq(rdc_config_t *uparms, spcs_s_info_t kstatus); 321int rdc_lookup_diskq(char *path); 322int rdc_diskq_inuse(rdc_set_t *set, char *diskq); 323void rdc_dump_iohdrs(disk_queue *q); 324extern void rdc_fixlen(rdc_aio_t *aio); 325 326#endif /* _KERNEL */ 327 328#ifdef __cplusplus 329} 330#endif 331 332#endif /* _RDC_DISKQ_H */ 333