/* $NetBSD: isp_tpublic.h,v 1.21 2021/12/12 13:05:14 andvar Exp $ */
/*-
*  Copyright (c) 1997-2008 by Matthew Jacob
*  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 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 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.
*/
/*
* Host Adapter Public Target Interface Structures && Routines
*/
/*
* A note about terminology:
*
*  "Inner Layer" means this driver (isp and the isp_tpublic API).
*
*    This module includes the both generic and platform specific pieces.
*
*  "Outer Layer" means another (external) module.
*
*    This is an additional module that actually implements SCSI target command
*    decode and is the recipient of incoming commands and the source of the
*    disposition for them.
*/

#ifndef    _ISP_TPUBLIC_H
#define    _ISP_TPUBLIC_H    1
/*
* Include general target definitions
*/
#include "isp_target.h"

/*
* Action codes set by the Inner Layer for the outer layer to figure out what to do with.
*/
typedef enum {
   QOUT_HBA_REG=0,     /* the argument is a pointer to a hba_register_t */
   QOUT_ENABLE,        /* the argument is a pointer to a enadis_t */
   QOUT_DISABLE,       /* the argument is a pointer to a enadis_t */
   QOUT_TMD_START,     /* the argument is a pointer to a tmd_cmd_t */
   QOUT_TMD_DONE,      /* the argument is a pointer to a tmd_xact_t */
   QOUT_NOTIFY,        /* the argument is a pointer to a notify_t */
   QOUT_HBA_UNREG      /* the argument is a pointer to a hba_register_t */
} tact_e;

/*
* Action codes set by the outer layer for the
* inner layer to figure out what to do with.
*/
typedef enum {
   QIN_HBA_REG=99,     /* the argument is a pointer to a hba_register_t */
   QIN_GETINFO,        /* the argument is a pointer to a info_t */
   QIN_SETINFO,        /* the argument is a pointer to a info_t */
   QIN_GETDLIST,       /* the argument is a pointer to a fc_dlist_t */
   QIN_ENABLE,         /* the argument is a pointer to a enadis_t */
   QIN_DISABLE,        /* the argument is a pointer to a enadis_t */
   QIN_TMD_CONT,       /* the argument is a pointer to a tmd_xact_t */
   QIN_TMD_FIN,        /* the argument is a pointer to a tmd_cmd_t */
   QIN_NOTIFY_ACK,     /* the argument is a pointer to a notify_t */
   QIN_HBA_UNREG,      /* the argument is a pointer to a hba_register_t */
} qact_e;

/*
* This structure is used to register to the outer layer the
* binding of an HBA identifier, driver name and instance and the
* lun width capabilities of this inner layer. It's up to each
* platform to figure out how it wants to actually implement this.
* A typical sequence would be for the MD layer to find some external
* module's entry point and start by sending a QOUT_HBA_REG with info
* filled in, and the external module to call back with a QIN_HBA_REG
* that passes back the corresponding information.
*
* The r_version tag defines the version of this API.
*/
#define    QR_VERSION    20
typedef struct {
   /* NB: structure tags from here to r_version must never change */
   void *                  r_identity;
   void                    (*r_action)(qact_e, void *);
   char                    r_name[8];
   int                     r_inst;
   int                     r_version;
   uint32_t                r_locator;
   uint32_t                r_nchannels;
   enum { R_FC, R_SPI }    r_type;
   void *                  r_private;
} hba_register_t;

/*
* An information structure that is used to get or set per-channel transport layer parameters.
*/
typedef struct {
   void *                  i_identity;
   enum { I_FC, I_SPI }    i_type;
   int                     i_channel;
   int                     i_error;
   union {
       struct {
           uint64_t    wwnn_nvram;
           uint64_t    wwpn_nvram;
           uint64_t    wwnn;
           uint64_t    wwpn;
       } fc;
       struct {
           int         iid;
       } spi;
   }                       i_id;
} info_t;

/*
* An information structure to return a list of logged in WWPNs. FC specific.
*/
typedef struct {
   void *                  d_identity;
   int                     d_channel;
   int                     d_error;
   int                     d_count;
   uint64_t *              d_wwpns;
} fc_dlist_t;

/*
* Lun ENABLE/DISABLE
*
* A word about ENABLE/DISABLE: the argument is a pointer to a enadis_t
* with en_hba, en_chan and en_lun filled out. We used to have an iid
* and target pair, but this just gets silly so we made initiator id
* and target id something you set, once, elsewhere.
*
* If an error occurs in either enabling or disabling the described lun
* en_error is set with an appropriate non-zero value.
*/
typedef struct {
   void *          en_private;     /* for outer layer usage */
   void *          en_hba;         /* HBA tag */
   uint16_t        en_lun;         /* logical unit */
   uint16_t        en_chan;        /* channel on card */
   int             en_error;
} enadis_t;



/*
* Data Transaction
*
* A tmd_xact_t is a structure used to describe a transaction within
* an overall command. It used to be part of the overall command,
* but it became desirable to allow for multiple simultaneous
* transfers for a command to happen. Generally these structures
* define data to be moved (along with the relative offset within
* the overall command) with the last structure containing status
* and sense (if needed) as well.
*
* The td_cmd tag points back to the owning command.
*
* The td_data tag points to the (platform specific) data descriptor.
*
* The td_lprivate is for use by the Inner Layer for private usage.
*
* The td_xfrlen says whether this transaction is moving data- if nonzero.
*
* The td_offset states what the relative offset within the comamnd the
* data transfer will start at. It is undefined if td_xfrlen is zero.
*
* The td_error flag will note any errors that occurred during an attempt
* to start this transaction. The inner layer is responsible for setting
* this.
*
* The td_hflags tag is set by the outer layer to indicate how the inner
* layer is supposed to treat this transaction.
*
* The td_lflags tag is set by the inner layer to indicate whether this
* transaction sent status and/or sense. Note that (much as it hurts),
* this API allows the inner layer to *fail* to send sense even if asked
* to- that is, AUTOSENSE is not a requirement of this API and the outer
* layer has to be prepared for this (unlikely) eventuality.
*/

typedef struct tmd_cmd tmd_cmd_t;
typedef struct tmd_xact {
   tmd_cmd_t *         td_cmd;                 /* cross-ref to tmd_cmd_t */
   void *              td_data;                /* data descriptor */
   void *              td_lprivate;            /* private for lower layer */
   uint32_t            td_xfrlen;              /* size of this data load */
   uint32_t            td_offset;              /* offset for this data load */
   int                 td_error;               /* error with this transfer */
   uint8_t             td_hflags;              /* flags set by caller */
   uint8_t             td_lflags;              /* flags set by callee */
} tmd_xact_t;

#define TDFH_STSVALID   0x01    /* status is valid - include it */
#define TDFH_SNSVALID   0x02    /* sense data (from outer layer) good - include it */
#define TDFH_DATA_IN    0x04    /* target (us) -> initiator (them) */
#define TDFH_DATA_OUT   0x08    /* initiator (them) -> target (us) */
#define TDFH_DATA_MASK  0x0C    /* mask to cover data direction */
#define TDFH_PRIVATE    0xF0    /* private outer layer usage */

#define TDFL_SENTSTATUS 0x01    /* this transaction sent status */
#define TDFL_SENTSENSE  0x02    /* this transaction sent sense data */
#define TDFL_ERROR      0x04    /* this transaction had an error */
#define TDFL_SYNCERROR  0x08    /* ... and didn't even start because of it */
#define TDFL_PRIVATE    0xF0    /* private inner layer usage */

/*
* The command structure below the SCSI Command structure that is
* is the whole point of this API. After a LUN is (or LUNS are)
* enabled, initiators who send commands addressed to the port,
* channel and lun that have been enabled cause an interrupt which
* causes the chip to receive the command and present it to the
* inner layer. The inner layer allocates one of this command
* structures and copies relevant information to it and sends it
* to the outer layer with the action QOUT_TMD_START.
*
* The outer layer is then responsible for command decode and is responsible
* for sending any transactions back (via a QIN_TMD_CONT) to the inner layer
* that (optionally) moves data and then sends closing status.
*
* The outer layer, when informed of the status of the final transaction
* then releases this structure by sending it back to the inner layer
* with the action QOUT_TMD_FIN.
*
* The structure tag meanings are as described below.
*
* The cd_hba tag is a tag that uniquely identifies the HBA this target
* mode command is coming from. The outer layer has to pass this back
* unchanged to avoid chaos. It is identical to the r_identity tag used
* by the inner layer to register with the outer layer.
*
* The cd_iid, cd_channel, cd_tgt and cd_lun tags are used to identify the
* the initiator who sent us a command, the channel on the this particular
* hardware port we arrived on (for multiple channel devices), the target we
* claim to be, and the lun on that target.
*
* The cd_tagval field is a tag that uniquely describes this tag. It may
* or may not have any correspondence to an underying hardware tag. The
* outer layer must pass this back unchanged or chaos will result.
*
* The tag cd_totlen is the total data amount expected to be moved
* for this command. This will be set to non-zero for transports
* that know this value from the transport level (e.g., Fibre Channel).
* If it shows up in the outer layers set to zero, the total data length
* must be inferred from the CDB.
*
* The tag cd_moved is the total amount of data moved so far. It is the
* responsibility of the inner layer to set this for every transaction and
* to keep track of it so that transport level residuals may be correctly
* set.
*
* The cd_cdb contains storage for the passed in SCSI command.
*
* The cd_tagtype field specifies what kind of command tag type, if
* any, has been sent with this command.
*
* The tag cd_flags has some junk flags set but mostly has flags reserved for outer layer use.
*
* The tags cd_sense and cd_scsi_status are self-explanatory.
*
* The cd_xact tag is the first or only transaction structure related to this command.
*
* The tag cd_lreserved, cd_hreserved are scratch areas for use for the outer and inner layers respectively.
*
*/

#ifndef TMD_CDBLEN
#define TMD_CDBLEN       16
#endif
#ifndef TMD_SENSELEN
#define TMD_SENSELEN     18
#endif
#ifndef QCDS
#define QCDS             (sizeof (uint64_t))
#endif
#ifndef TMD_PRIV_LO
#define TMD_PRIV_LO 4
#endif
#ifndef TMD_PRIV_HI
#define TMD_PRIV_HI 4
#endif

struct tmd_cmd {
   void *              cd_hba;     /* HBA tag */
   uint64_t            cd_iid;     /* initiator ID */
   uint64_t            cd_tgt;     /* target id */
   uint64_t            cd_tagval;  /* tag value */
   uint8_t             cd_lun[8];  /* logical unit */
   uint32_t            cd_totlen;  /* total data load */
   uint32_t            cd_moved;   /* total data moved so far */
   uint16_t            cd_channel; /* channel index */
   uint16_t            cd_flags;   /* flags */
   uint16_t            cd_req_cnt; /* how many tmd_xact_t's are active */
   uint8_t             cd_cdb[TMD_CDBLEN];
   uint8_t             cd_tagtype; /* tag type */
   uint8_t             cd_scsi_status;
   uint8_t             cd_sense[TMD_SENSELEN];
   tmd_xact_t          cd_xact;    /* first or only transaction */
   union {
       void *          ptrs[QCDS / sizeof (void *)];       /* (assume) one pointer */
       uint64_t        llongs[QCDS / sizeof (uint64_t)];   /* one long long */
       uint32_t        longs[QCDS / sizeof (uint32_t)];    /* two longs */
       uint16_t        shorts[QCDS / sizeof (uint16_t)];   /* four shorts */
       uint8_t         bytes[QCDS];                        /* eight bytes */
   } cd_lreserved[TMD_PRIV_LO], cd_hreserved[TMD_PRIV_HI];
};

#define CDF_NODISC      0x0001  /* disconnects disabled */
#define CDF_DATA_IN     0x0002  /* target (us) -> initiator (them) */
#define CDF_DATA_OUT    0x0004  /* initiator (them) -> target (us) */
#define CDF_BIDIR       0x0006  /* bidirectional data */
#define CDF_SNSVALID    0x0008  /* sense is set on incoming command */
#define CDF_PRIVATE     0xff00  /* available for private use in outer layer */

/* defined tags */
#define CD_UNTAGGED     0
#define CD_SIMPLE_TAG   1
#define CD_ORDERED_TAG  2
#define CD_HEAD_TAG     3
#define CD_ACA_TAG      4

#ifndef    TMD_SIZE
#define    TMD_SIZE     (sizeof (tmd_cmd_t))
#endif

#define L0LUN_TO_FLATLUN(lptr)              ((((lptr)[0] & 0x3f) << 8) | ((lptr)[1]))
#define FLATLUN_TO_L0LUN(lptr, lun)                 \
   (lptr)[1] = lun & 0xff;                         \
   if (sizeof (lun) == 1) {                        \
       (lptr)[0] = 0;                              \
   } else {                                        \
       uint16_t nl = lun;                          \
       if (nl == LUN_ANY) {                        \
           (lptr)[0] = (nl >> 8) & 0xff;           \
       } else if (nl < 256) {                      \
           (lptr)[0] = 0;                          \
       } else {                                    \
           (lptr)[0] = 0x40 | ((nl >> 8) & 0x3f);  \
       }                                           \
   }                                               \
   memset(&(lptr)[2], 0, 6)

/*
* Inner Layer Handler Function.
*
* The inner layer target handler function (the outer layer calls this)
* should be prototyped like so:
*
*    void target_action(qact_e, void *arg)
*
* The outer layer target handler function (the inner layer calls this)
* should be prototyped like:
*
*    void scsi_target_handler(tact_e, void *arg)
*/

#endif    /* _ISP_TPUBLIC_H */
/*
* vim:ts=4:sw=4:expandtab
*/