#ifndef FREEBSD_NVME_IOCTL_H
#define FREEBSD_NVME_IOCTL_H

/*-
 * Copyright (C) 2012-2013 Intel Corporation
 * All rights reserved.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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.
 *
 * $FreeBSD$
 */


#include <sys/param.h>

#ifdef __cplusplus
extern "C" {
#endif

#define NVME_PASSTHROUGH_CMD    _IOWR('n', 0, struct nvme_pt_command)

#if __FreeBSD_version < 1100110

#define NVME_STATUS_GET_SC(st)  (st.sc)
#define NVME_STATUS_GET_SCT(st)  (st.sct)


struct nvme_command
{
        /* dword 0 */
        uint16_t opc    :  8;   /* opcode */
        uint16_t fuse   :  2;   /* fused operation */
        uint16_t rsvd1  :  6;
        uint16_t cid;           /* command identifier */

        /* dword 1 */
        uint32_t nsid;          /* namespace identifier */

        /* dword 2-3 */
        uint32_t rsvd2;
        uint32_t rsvd3;

        /* dword 4-5 */
        uint64_t mptr;          /* metadata pointer */

        /* dword 6-7 */
        uint64_t prp1;          /* prp entry 1 */

        /* dword 8-9 */
        uint64_t prp2;          /* prp entry 2 */

        /* dword 10-15 */
        uint32_t cdw10;         /* command-specific */
        uint32_t cdw11;         /* command-specific */
        uint32_t cdw12;         /* command-specific */
        uint32_t cdw13;         /* command-specific */
        uint32_t cdw14;         /* command-specific */
        uint32_t cdw15;         /* command-specific */
} __packed;

struct nvme_status {

        uint16_t p      :  1;   /* phase tag */
        uint16_t sc     :  8;   /* status code */
        uint16_t sct    :  3;   /* status code type */
        uint16_t rsvd2  :  2;
        uint16_t m      :  1;   /* more */
        uint16_t dnr    :  1;   /* do not retry */
} __packed;

struct nvme_completion {

        /* dword 0 */
        uint32_t                cdw0;   /* command-specific */

        /* dword 1 */
        uint32_t                rsvd1;

        /* dword 2 */
        uint16_t                sqhd;   /* submission queue head pointer */
        uint16_t                sqid;   /* submission queue identifier */

        /* dword 3 */
        uint16_t                cid;    /* command identifier */
        struct nvme_status      status;
} __packed;

struct nvme_pt_command {

        /*
         * cmd is used to specify a passthrough command to a controller or
         *  namespace.
         *
         * The following fields from cmd may be specified by the caller:
         *      * opc  (opcode)
         *      * nsid (namespace id) - for admin commands only
         *      * cdw10-cdw15
         *
         * Remaining fields must be set to 0 by the caller.
         */
        struct nvme_command     cmd;

        /*
         * cpl returns completion status for the passthrough command
         *  specified by cmd.
         *
         * The following fields will be filled out by the driver, for
         *  consumption by the caller:
         *      * cdw0
         *      * status (except for phase)
         *
         * Remaining fields will be set to 0 by the driver.
         */
        struct nvme_completion  cpl;

        /* buf is the data buffer associated with this passthrough command. */
        void *                  buf;

        /*
         * len is the length of the data buffer associated with this
         *  passthrough command.
         */
        uint32_t                len;

        /*
         * is_read = 1 if the passthrough command will read data into the
         *  supplied buffer from the controller.
         *
         * is_read = 0 if the passthrough command will write data from the
         *  supplied buffer to the controller.
         */
        uint32_t                is_read;

        /*
         * driver_lock is used by the driver only.  It must be set to 0
         *  by the caller.
         */
        struct mtx *            driver_lock;
};
#else		/* not    __FreeBSD_version < 1100110 */
#include <dev/nvme/nvme.h>
#endif		/* __FreeBSD_version < 1100110 */

#ifndef nvme_completion_is_error
#define nvme_completion_is_error(cpl)                                   \
        ((cpl)->status.sc != 0 || (cpl)->status.sct != 0)
#endif

#define NVME_CTRLR_PREFIX       "/dev/nvme"
#define NVME_NS_PREFIX          "ns"

#ifdef __cplusplus
}
#endif

#endif          /* for FREEBSD_NVME_IOCTL_H */
