root/sys/dev/raid/vinum/request.h
/*-
 * Copyright (c) 1997, 1998
 *      Nan Yang Computer Services Limited.  All rights reserved.
 *
 *  This software is distributed under the so-called ``Berkeley
 *  License'':
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Nan Yang Computer
 *      Services Limited.
 * 4. Neither the name of the Company nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * This software is provided ``as is'', and any express or implied
 * warranties, including, but not limited to, the implied warranties of
 * merchantability and fitness for a particular purpose are disclaimed.
 * In no event shall the company or contributors be liable for any
 * direct, indirect, incidental, special, exemplary, or consequential
 * damages (including, but not limited to, procurement of substitute
 * goods or services; loss of use, data, or profits; or business
 * interruption) however caused and on any theory of liability, whether
 * in contract, strict liability, or tort (including negligence or
 * otherwise) arising in any way out of the use of this software, even if
 * advised of the possibility of such damage.
 */

/* Information needed to set up a transfer */

enum xferinfo {
        XFR_NORMAL_READ = 1,
        XFR_NORMAL_WRITE = 2,           /* write request in normal mode */
        XFR_RECOVERY_READ = 4,
        XFR_DEGRADED_WRITE = 8,
        XFR_PARITYLESS_WRITE = 0x10,
        XFR_NO_PARITY_STRIPE = 0x20,    /* parity stripe is not available */
        XFR_DATA_BLOCK = 0x40,          /* data block in request */
        XFR_PARITY_BLOCK = 0x80,        /* parity block in request */
        XFR_BAD_SUBDISK = 0x100,        /* this subdisk is dead */
        XFR_MALLOCED = 0x200,           /* this buffer is malloced */
#ifdef VINUMDEBUG
        XFR_PHASE2 = 0x800,             /* debug only: 2nd phase write */
#endif
        XFR_REVIVECONFLICT = 0x1000,    /* possible conflict with a revive */
        XFR_BUFLOCKED = 0x2000,         /* BUF_LOCK performed on this buffer */

        /*
         * operations that need a parity block
         */
        XFR_PARITYOP = (XFR_NORMAL_WRITE | XFR_RECOVERY_READ |
                        XFR_DEGRADED_WRITE),

        /*
         * operations that use the group parameters
         */
        XFR_GROUPOP = (XFR_DEGRADED_WRITE | XFR_RECOVERY_READ),

        /*
         * operations that that use the data parameters
         */
        XFR_DATAOP = (XFR_NORMAL_READ | XFR_NORMAL_WRITE |
                      XFR_PARITYLESS_WRITE),

        /*
         * operations requiring read before write
         */
        XFR_RBW = (XFR_NORMAL_WRITE | XFR_DEGRADED_WRITE),

        /*
         * operations that need a malloced buffer
         */
        XFR_NEEDS_MALLOC = (XFR_NORMAL_WRITE | XFR_RECOVERY_READ |
                            XFR_DEGRADED_WRITE)
};

/*
 * Describe one low-level request, part of a
 * high-level request.  This is an extended
 * struct buf buffer, and the first element
 * *must* be a struct buf.  We pass this
 * structure to the I/O routines instead of a
 * struct buf in order to be able to locate the
 * high-level request when it completes.
 *
 * All offsets and lengths are in sectors.
 */
struct rqelement {
        struct buf b;                   /* buf structure */
        struct rqgroup *rqg;            /* pointer to our group */

        vinum_off_t sdoffset;           /* offset in subdisk */
        int useroffset;                 /* offset of data in user buffer */

        /*
         * dataoffset and datalen refer to "individual" data
         * transfers which involve only this drive (normal read,
         * parityless write) and also degraded write.
         *
         * groupoffset and grouplen refer to the other "group"
         * operations (normal write, recovery read) which involve
         * more than one drive.  Both the offsets are relative to
         * the start of the local buffer.
         */
        int dataoffset;                 /* offset of the normal data */
        int groupoffset;                /* offset of group data */
        short datalen;                  /* length of normal data (sectors) */
        short grouplen;                 /* length of group data (sectors) */
        short buflen;                   /* total buffer length to allocate */
        short flags;                    /* really enum xferinfo (see above) */

        /*
         * Ways to find other components
         */
        short sdno;                     /* subdisk number */
        short driveno;                  /* drive number */
};

/*
 * A group of requests built to satisfy an I/O
 * transfer on a single plex.
 */
struct rqgroup {
        struct rqgroup *next;           /* pointer to next group */
        struct request *rq;             /* pointer to the request */
        short count;                    /* number of requests in this group */
        short active;                   /* and number active */
        short plexno;                   /* index of plex */
        int badsdno;                    /* index of bad subdisk or -1 */
        enum xferinfo flags;            /* description of transfer */
        struct rangelock *lock;         /* lock for this transfer */
        vinum_off_t lockbase;           /* and lock address */
        struct rqelement rqe[0];        /* and the elements of this request */
};

/*
 * Describe one high-level request and the
 * work we have to do to satisfy it.
 */
struct request {
        struct bio *bio;                /* pointer to the high-level request */
        enum xferinfo flags;
        union {
            int volno;                  /* volume index */
            int plexno;                 /* or plex index */
        } volplex;
        int error;                      /* current error indication */
        int sdno;                       /* reviving subdisk     */
                                        /* (XFR_REVIVECONFLICT) */
        short isplex;                   /* set if this is a plex request */
        short active;                   /* number of subrequests still active */
        struct rqgroup *rqg;            /* ptr to the first group of requests */
        struct rqgroup *lrqg;           /* and to the last group of requests */
        struct request *next;           /* link of waiting requests */
};

/*
 * Extended buffer header for subdisk I/O.  Includes
 * a pointer to the user I/O request.
 */
struct sdbuf {
        struct buf b;                   /* our buffer */
        struct bio *bio;                /* and pointer to parent */
        short driveno;                  /* drive index */
        short sdno;                     /* and subdisk index */
};

/*
 * Values returned by rqe and friends.  Be careful
 * with these: they are in order of increasing
 * seriousness.  Some routines check for
 * > REQUEST_RECOVERED to indicate a failed request. XXX
 */
enum requeststatus {
        REQUEST_OK,             /* request built OK */
        REQUEST_RECOVERED,      /* request OK, but involves RAID5 recovery */
        REQUEST_DEGRADED,       /* parts of request failed */
        REQUEST_EOF,            /* parts of request failed: outside plex */
        REQUEST_DOWN,           /* all of request failed: subdisk(s) down */
        REQUEST_ENOMEM          /* all of request failed: ran out of memory */
};

#ifdef VINUMDEBUG

/*
 * Trace entry for request info (DEBUG_LASTREQS)
 */
enum rqinfo_type {
        loginfo_unused,         /* never been used */
        loginfo_user_bp,        /* this is the bp when strategy is called */
        loginfo_user_bpl,       /* and this is the bp at launch time */
        loginfo_rqe,            /* user RQE */
        loginfo_iodone,         /* iodone */
        loginfo_raid5_data,     /* write RAID-5 data block */
        loginfo_raid5_parity,   /* write RAID-5 parity block */
        loginfo_sdio,           /* subdisk I/O */
        loginfo_sdiol,          /* subdisk I/O launch */
        loginfo_sdiodone,       /* subdisk iodone */
        loginfo_lockwait,       /* wait for range lock */
        loginfo_lock,           /* lock range */
        loginfo_unlock,         /* unlock range */
};

/*
 * Info to pass to logrq
 */
union rqinfou {
        struct bio *bio;
        struct rqelement *rqe;          /* addr of request, for correlation */
        struct rangelock *lockinfo;
};

struct rqinfo {
        enum rqinfo_type type;          /* kind of event */
        struct timeval timestamp;       /* time it happened */
        struct bio *bio;                /* point to user buffer */
        int devmajor;                   /* major and minor device info */
        int devminor;
        union {
                struct buf b;           /* yup, the *whole* buffer header */
                struct bio bio;
                struct rqelement rqe;   /* and the whole rqe */
                struct rangelock lockinfo;
        } info;
};

#define RQINFO_SIZE 128         /* number of info slots in buffer */

void logrq(enum rqinfo_type type, union rqinfou info, struct bio *ubio);

#endif

/* Structures for the daemon */

/*
 * Types of request to the daemon
 */
enum daemonrq {
        daemonrq_none,          /* dummy to catch bugs */
        daemonrq_ioerror,       /* error occurred on I/O */
        daemonrq_saveconfig,    /* save configuration */
        daemonrq_return,        /* return to userland */
        daemonrq_ping,          /* show sign of life */
        daemonrq_init,          /* initialize a plex */
        daemonrq_revive,        /* revive a subdisk */
        daemonrq_closedrive,    /* close a drive */
};

/*
 * Info field for daemon requests and the request information
 */
union daemoninfo {
        struct request *rq;     /* for daemonrq_ioerror */
        struct sd *sd;          /* for daemonrq_revive */
        struct plex *plex;      /* for daemonrq_init */
        struct drive *drive;    /* for daemonrq_closedrive */
        int nothing;            /* for passing NULL */
};

struct daemonq {
        struct daemonq *next;   /* pointer to next element in queue */
        enum daemonrq type;     /* type of request */
        int privateinuse;       /* private element, being used */
        union daemoninfo info;  /* and the request information */
};

void queue_daemon_request(enum daemonrq type, union daemoninfo info);

extern int daemon_options;

enum daemon_option {
        daemon_verbose = 1,     /* talk about what we're doing */
        daemon_stopped = 2,
        daemon_noupdate = 4,    /* don't update the disk config, for recovery */
};

void freerq(struct request *rq);
void unlockrange(int plexno, struct rangelock *);