NetBSD/sys/dev/ic/isp_tpublic.h

376 lines
15 KiB
C

/* $NetBSD: isp_tpublic.h,v 1.18 2009/06/25 23:44:02 mjacob 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 isp_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 isp_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 capapbilities 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
* responsibilty 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 be prototyped like so:
*
* void target_action(qact_e, void *arg)
*
* The outer layer target handler function (the inner layer calls this)
* should be be prototyped like:
*
* void scsi_target_handler(tact_e, void *arg)
*/
#endif /* _ISP_TPUBLIC_H */
/*
* vim:ts=4:sw=4:expandtab
*/