/*      $NetBSD: iopvar.h,v 1.24 2012/10/27 17:18:17 chs Exp $  */

/*-
* Copyright (c) 2000, 2001, 2002, 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Andrew Doran.
*
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/

#ifndef _I2O_IOPVAR_H_
#define _I2O_IOPVAR_H_

#include <sys/mutex.h>
#include <sys/condvar.h>

/*
* Transfer descriptor.
*/
struct iop_xfer {
       bus_dmamap_t    ix_map;
       u_int           ix_size;
       u_int           ix_flags;
};
#define IX_IN                   0x0001  /* Data transfer from IOP */
#define IX_OUT                  0x0002  /* Data transfer to IOP */

/*
* Message wrapper.
*/
struct iop_msg {
       SLIST_ENTRY(iop_msg)    im_chain;       /* Next free message */
       u_int                   im_flags;       /* Control flags */
       u_int                   im_tctx;        /* Transaction context */
       void                    *im_dvcontext;  /* Un*x device context */
       struct i2o_reply        *im_rb;         /* Reply buffer */
       kcondvar_t              im_cv;          /* Notifier */
       u_int                   im_reqstatus;   /* Status from reply */
       u_int                   im_detstatus;   /* Detailed status code */
       struct iop_xfer         im_xfer[IOP_MAX_MSG_XFERS];
};
#define IM_SYSMASK              0x00ff
#define IM_REPLIED              0x0001  /* Message has been replied to */
#define IM_ALLOCED              0x0002  /* This message wrapper is allocated */
#define IM_SGLOFFADJ            0x0004  /* S/G list offset adjusted */
#define IM_FAIL                 0x0008  /* Transaction error returned */

#define IM_USERMASK             0xff00
#define IM_WAIT                 0x0100  /* Wait (sleep) for completion */
#define IM_POLL                 0x0200  /* Wait (poll) for completion */
#define IM_NOSTATUS             0x0400  /* Don't check status if waiting */
#define IM_POLL_INTR            0x0800  /* Do send interrupt when polling */

struct iop_initiator {
       LIST_ENTRY(iop_initiator) ii_list;
       LIST_ENTRY(iop_initiator) ii_hash;

       void    (*ii_intr)(device_t, struct iop_msg *, void *);
       int     (*ii_reconfig)(device_t);
       void    (*ii_adjqparam)(device_t, int);

       device_t ii_dv;
       kcondvar_t ii_cv;
       int     ii_flags;
       int     ii_ictx;                /* Initiator context */
       int     ii_tid;
};
#define II_NOTCTX       0x0001  /* No transaction context */
#define II_CONFIGURED   0x0002  /* Already configured */
#define II_UTILITY      0x0004  /* Utility initiator (not a real device) */

#define IOP_ICTX        0
#define IOP_INIT_CODE   0x80

/*
* Parameter group op (for async parameter retrievals).
*/
struct iop_pgop {
       struct  i2o_param_op_list_header olh;
       struct  i2o_param_op_all_template oat;
} __packed;

/*
* Per-IOP context.
*/
struct iop_softc {
       device_t        sc_dev;         /* Generic device data */
       bus_space_handle_t sc_ioh;      /* Bus space handle */
       bus_space_tag_t sc_iot;         /* Bus space tag */
       bus_dma_tag_t   sc_dmat;        /* Bus DMA tag */
       bus_space_handle_t sc_msg_ioh;  /* Message queue bus space handle */
       bus_space_tag_t sc_msg_iot;     /* Message queue bus space tag */
       void            *sc_ih;         /* Interrupt handler cookie */

       struct iop_msg  *sc_ims;        /* Message wrappers */
       SLIST_HEAD(, iop_msg) sc_im_freelist; /* Free wrapper list */
       kmutex_t        sc_intrlock;    /* Interrupt level lock */

       bus_dmamap_t    sc_rep_dmamap;  /* Reply frames DMA map */
       int             sc_rep_size;    /* Reply frames size */
       bus_addr_t      sc_rep_phys;    /* Reply frames PA */
       void *          sc_rep;         /* Reply frames VA */

       int             sc_maxib;       /* Max inbound (-> IOP) queue depth */
       int             sc_maxob;       /* Max outbound (<- IOP) queue depth */
       int             sc_curib;       /* Current inbound queue depth */
       int             sc_framesize;   /* Max msg frame size in bytes */

       struct i2o_hrt  *sc_hrt;        /* Hardware resource table */
       struct iop_tidmap *sc_tidmap;   /* TID map (per-LCT-entry flags) */
       struct i2o_lct  *sc_lct;        /* Logical configuration table */
       int             sc_nlctent;     /* Number of LCT entries */
       int             sc_flags;       /* IOP-wide flags */
       u_int32_t       sc_chgind;      /* Configuration change indicator */
       kmutex_t        sc_conflock;    /* Configuration lock */
       kcondvar_t      sc_confcv;      /* Configuration CV */
       lwp_t           *sc_reconf_thread;/* Auto reconfiguration process */
       LIST_HEAD(, iop_initiator) sc_iilist;/* Initiator list */
       int             sc_nii;         /* Total number of initiators */
       int             sc_nuii;        /* Number of utility initiators */

       struct iop_initiator sc_eventii;/* IOP event handler */
       bus_dmamap_t    sc_scr_dmamap;  /* Scratch DMA map */
       bus_dma_segment_t sc_scr_seg[1];/* Scratch DMA segment */
       void *          sc_scr;         /* Scratch memory VA */

       bus_space_tag_t sc_bus_memt;    /* Parent bus memory tag */
       bus_space_tag_t sc_bus_iot;     /* Parent but I/O tag */
       bus_addr_t      sc_memaddr;     /* Register window address */
       bus_size_t      sc_memsize;     /* Register window size */
       int             sc_pcibus;      /* PCI bus number */
       int             sc_pcidev;      /* PCI device number */

       struct i2o_status sc_status;    /* Last retrieved status record */
};
#define IOP_OPEN                0x01    /* Device interface open */
#define IOP_HAVESTATUS          0x02    /* Successfully retrieved status */
#define IOP_ONLINE              0x04    /* Can use ioctl interface */

struct iop_attach_args {
       int     ia_class;               /* device class */
       int     ia_tid;                 /* target ID */
};

void    iop_init(struct iop_softc *, const char *);
int     iop_intr(void *);
int     iop_lct_get(struct iop_softc *);
int     iop_print_ident(struct iop_softc *, int);
int     iop_post(struct iop_softc *, u_int32_t *);
int     iop_reconfigure(struct iop_softc *, u_int);
int     iop_status_get(struct iop_softc *, int);
int     iop_simple_cmd(struct iop_softc *, int, int, int, int, int);
void    iop_strvis(struct iop_softc *, const char *, int, char *, int);

void    iop_initiator_register(struct iop_softc *, struct iop_initiator *);
void    iop_initiator_unregister(struct iop_softc *, struct iop_initiator *);

struct  iop_msg *iop_msg_alloc(struct iop_softc *, int);
void    iop_msg_free(struct iop_softc *, struct iop_msg *);
int     iop_msg_map(struct iop_softc *, struct iop_msg *, u_int32_t *, void *,
                   int, int, struct proc *);
int     iop_msg_map_bio(struct iop_softc *, struct iop_msg *, u_int32_t *,
                       void *, int, int);
int     iop_msg_post(struct iop_softc *, struct iop_msg *, void *, int);
void    iop_msg_unmap(struct iop_softc *, struct iop_msg *);

int     iop_field_get_all(struct iop_softc *, int, int, void *, int,
                         struct iop_initiator *);
int     iop_field_set(struct iop_softc *, int, int, void *, int, int);
int     iop_table_add_row(struct iop_softc *, int, int, void *, int, int);
int     iop_table_clear(struct iop_softc *, int, int);
int     iop_table_del_row(struct iop_softc *, int, int, int);
int     iop_table_get_row(struct iop_softc *, int, int, void *, int, int);

int     iop_util_abort(struct iop_softc *, struct iop_initiator *, int, int,
                     int);
int     iop_util_claim(struct iop_softc *, struct iop_initiator *, int, int);
int     iop_util_eventreg(struct iop_softc *, struct iop_initiator *, int);

#endif  /* !_I2O_IOPVAR_H_ */