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