root/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*******************************************************************************
 * IBM Virtual SCSI Target Driver
 * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
 *                         Santiago Leon (santil@us.ibm.com) IBM Corp.
 *                         Linda Xie (lxie@us.ibm.com) IBM Corp.
 *
 * Copyright (C) 2005-2011 FUJITA Tomonori <tomof@acm.org>
 * Copyright (C) 2010 Nicholas A. Bellinger <nab@kernel.org>
 * Copyright (C) 2016 Bryant G. Ly <bryantly@linux.vnet.ibm.com> IBM Corp.
 *
 * Authors: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
 * Authors: Michael Cyr <mikecyr@linux.vnet.ibm.com>
 *
 ****************************************************************************/

#ifndef __H_IBMVSCSI_TGT
#define __H_IBMVSCSI_TGT

#include <linux/interrupt.h>
#include "libsrp.h"

#define SYS_ID_NAME_LEN         64
#define PARTITION_NAMELEN       96
#define IBMVSCSIS_NAMELEN       32

#define MSG_HI  0
#define MSG_LOW 1

#define MAX_CMD_Q_PAGES       4
#define CRQ_PER_PAGE          (PAGE_SIZE / sizeof(struct viosrp_crq))
/* in terms of number of elements */
#define DEFAULT_CMD_Q_SIZE    CRQ_PER_PAGE
#define MAX_CMD_Q_SIZE        (DEFAULT_CMD_Q_SIZE * MAX_CMD_Q_PAGES)

#define SRP_VIOLATION           0x102  /* general error code */

/*
 * SRP buffer formats defined as of 16.a supported by this driver.
 */
#define SUPPORTED_FORMATS  ((SRP_DATA_DESC_DIRECT << 1) | \
                            (SRP_DATA_DESC_INDIRECT << 1))

#define SCSI_LUN_ADDR_METHOD_FLAT       1

struct dma_window {
        u32 liobn;      /* Unique per vdevice */
        u64 tce_base;   /* Physical location of the TCE table */
        u64 tce_size;   /* Size of the TCE table in bytes */
};

struct target_dds {
        u64 unit_id;                /* 64 bit will force alignment */
#define NUM_DMA_WINDOWS 2
#define LOCAL  0
#define REMOTE 1
        struct dma_window  window[NUM_DMA_WINDOWS];

        /* root node property "ibm,partition-no" */
        uint partition_num;
        char partition_name[PARTITION_NAMELEN];
};

#define MAX_NUM_PORTS        1
#define MAX_H_COPY_RDMA      (128 * 1024)

#define MAX_EYE   64

/* Return codes */
#define ADAPT_SUCCESS            0L
/* choose error codes that do not conflict with PHYP */
#define ERROR                   -40L

struct format_code {
        u8 reserved;
        u8 buffers;
};

struct client_info {
#define SRP_VERSION "16.a"
        char srp_version[8];
        /* root node property ibm,partition-name */
        char partition_name[PARTITION_NAMELEN];
        /* root node property ibm,partition-no */
        u32 partition_number;
        /* initially 1 */
        u32 mad_version;
        u32 os_type;
};

/*
 * Changing this constant changes the number of seconds to wait before
 * considering the client will never service its queue again.
 */
#define SECONDS_TO_CONSIDER_FAILED 30
/*
 * These constants set the polling period used to determine if the client
 * has freed at least one element in the response queue.
 */
#define WAIT_SECONDS 1
#define WAIT_NANO_SECONDS 5000
#define MAX_TIMER_POPS ((1000000 / WAIT_NANO_SECONDS) * \
                        SECONDS_TO_CONSIDER_FAILED)
/*
 * general purpose timer control block
 * which can be used for multiple functions
 */
struct timer_cb {
        struct hrtimer timer;
        /*
         * how long has it been since the client
         * serviced the queue. The variable is incrmented
         * in the service_wait_q routine and cleared
         * in send messages
         */
        int timer_pops;
        /* the timer is started */
        bool started;
};

struct cmd_queue {
        /* kva */
        struct viosrp_crq *base_addr;
        dma_addr_t crq_token;
        /* used to maintain index */
        uint mask;
        /* current element */
        uint index;
        int size;
};

#define SCSOLNT_RESP_SHIFT      1
#define UCSOLNT_RESP_SHIFT      2

#define SCSOLNT         BIT(SCSOLNT_RESP_SHIFT)
#define UCSOLNT         BIT(UCSOLNT_RESP_SHIFT)

enum cmd_type {
        SCSI_CDB        = 0x01,
        TASK_MANAGEMENT = 0x02,
        /* MAD or addressed to port 0 */
        ADAPTER_MAD     = 0x04,
        UNSET_TYPE      = 0x08,
};

struct iu_rsp {
        u8 format;
        u8 sol_not;
        u16 len;
        /* tag is just to help client identify cmd, so don't translate be/le */
        u64 tag;
};

struct ibmvscsis_cmd {
        struct list_head list;
        /* Used for TCM Core operations */
        struct se_cmd se_cmd;
        struct iu_entry *iue;
        struct iu_rsp rsp;
        struct work_struct work;
        struct scsi_info *adapter;
        struct ibmvscsis_cmd *abort_cmd;
        /* Sense buffer that will be mapped into outgoing status */
        unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
        u64 init_time;
#define CMD_FAST_FAIL   BIT(0)
#define DELAY_SEND      BIT(1)
        u32 flags;
        char type;
};

struct ibmvscsis_nexus {
        struct se_session *se_sess;
};

struct ibmvscsis_tport {
        /* SCSI protocol the tport is providing */
        u8 tport_proto_id;
        /* ASCII formatted WWPN for SRP Target port */
        char tport_name[IBMVSCSIS_NAMELEN];
        /* Returned by ibmvscsis_make_tport() */
        struct se_wwn tport_wwn;
        /* Returned by ibmvscsis_make_tpg() */
        struct se_portal_group se_tpg;
        /* ibmvscsis port target portal group tag for TCM */
        u16 tport_tpgt;
        /* Pointer to TCM session for I_T Nexus */
        struct ibmvscsis_nexus *ibmv_nexus;
        bool enabled;
        bool releasing;
};

struct scsi_info {
        struct list_head list;
        char eye[MAX_EYE];

        /* commands waiting for space on repsonse queue */
        struct list_head waiting_rsp;
#define NO_QUEUE                    0x00
#define WAIT_ENABLED                0X01
#define WAIT_CONNECTION             0x04
        /* have established a connection */
#define CONNECTED                   0x08
        /* at least one port is processing SRP IU */
#define SRP_PROCESSING              0x10
        /* remove request received */
#define UNCONFIGURING               0x20
        /* disconnect by letting adapter go idle, no error */
#define WAIT_IDLE                   0x40
        /* disconnecting to clear an error */
#define ERR_DISCONNECT              0x80
        /* disconnect to clear error state, then come back up */
#define ERR_DISCONNECT_RECONNECT    0x100
        /* disconnected after clearing an error */
#define ERR_DISCONNECTED            0x200
        /* A series of errors caused unexpected errors */
#define UNDEFINED                   0x400
        u16  state;
        int fast_fail;
        struct target_dds dds;
        char *cmd_pool;
        /* list of free commands */
        struct list_head free_cmd;
        /* command elements ready for scheduler */
        struct list_head schedule_q;
        /* commands sent to TCM */
        struct list_head active_q;
        caddr_t *map_buf;
        /* ioba of map buffer */
        dma_addr_t map_ioba;
        /* allowable number of outstanding SRP requests */
        int request_limit;
        /* extra credit */
        int credit;
        /* outstanding transactions against credit limit */
        int debit;

        /* allow only one outstanding mad request */
#define PROCESSING_MAD                0x00002
        /* Waiting to go idle */
#define WAIT_FOR_IDLE                 0x00004
        /* H_REG_CRQ called */
#define CRQ_CLOSED                    0x00010
        /* detected that client has failed */
#define CLIENT_FAILED                 0x00040
        /* detected that transport event occurred */
#define TRANS_EVENT                   0x00080
        /* don't attempt to send anything to the client */
#define RESPONSE_Q_DOWN               0x00100
        /* request made to schedule disconnect handler */
#define SCHEDULE_DISCONNECT           0x00400
        /* disconnect handler is scheduled */
#define DISCONNECT_SCHEDULED          0x00800
        /* remove function is sleeping */
#define CFG_SLEEPING                  0x01000
        /* Register for Prepare for Suspend Transport Events */
#define PREP_FOR_SUSPEND_ENABLED      0x02000
        /* Prepare for Suspend event sent */
#define PREP_FOR_SUSPEND_PENDING      0x04000
        /* Resume from Suspend event sent */
#define PREP_FOR_SUSPEND_ABORTED      0x08000
        /* Prepare for Suspend event overwrote another CRQ entry */
#define PREP_FOR_SUSPEND_OVERWRITE    0x10000
        u32 flags;
        /* adapter lock */
        spinlock_t intr_lock;
        /* information needed to manage command queue */
        struct cmd_queue cmd_q;
        /* used in hcall to copy response back into srp buffer */
        u64  empty_iu_id;
        /* used in crq, to tag what iu the response is for */
        u64  empty_iu_tag;
        uint new_state;
        uint resume_state;
        /* control block for the response queue timer */
        struct timer_cb rsp_q_timer;
        /* keep last client to enable proper accounting */
        struct client_info client_data;
        /* what can this client do */
        u32 client_cap;
        /*
         * The following two fields capture state and flag changes that
         * can occur when the lock is given up.  In the orginal design,
         * the lock was held during calls into phyp;
         * however, phyp did not meet PAPR architecture.  This is
         * a work around.
         */
        u16  phyp_acr_state;
        u32 phyp_acr_flags;

        struct workqueue_struct *work_q;
        struct completion wait_idle;
        struct completion unconfig;
        struct device dev;
        struct vio_dev *dma_dev;
        struct srp_target target;
        struct ibmvscsis_tport tport;
        struct tasklet_struct work_task;
        struct work_struct proc_work;
};

/*
 * Provide a constant that allows software to detect the adapter is
 * disconnecting from the client from one of several states.
 */
#define IS_DISCONNECTING (UNCONFIGURING | ERR_DISCONNECT_RECONNECT | \
                          ERR_DISCONNECT)

/*
 * Provide a constant that can be used with interrupt handling that
 * essentially lets the interrupt handler know that all requests should
 * be thrown out,
 */
#define DONT_PROCESS_STATE (IS_DISCONNECTING | UNDEFINED | \
                            ERR_DISCONNECTED  | WAIT_IDLE)

/*
 * If any of these flag bits are set then do not allow the interrupt
 * handler to schedule the off level handler.
 */
#define BLOCK (DISCONNECT_SCHEDULED)

/* State and transition events that stop the interrupt handler */
#define TARGET_STOP(VSCSI) (long)(((VSCSI)->state & DONT_PROCESS_STATE) | \
                                  ((VSCSI)->flags & BLOCK))

#define PREP_FOR_SUSPEND_FLAGS  (PREP_FOR_SUSPEND_ENABLED | \
                                 PREP_FOR_SUSPEND_PENDING | \
                                 PREP_FOR_SUSPEND_ABORTED | \
                                 PREP_FOR_SUSPEND_OVERWRITE)

/* flag bit that are not reset during disconnect */
#define PRESERVE_FLAG_FIELDS (PREP_FOR_SUSPEND_FLAGS)

#define vio_iu(IUE) ((union viosrp_iu *)((IUE)->sbuf->buf))

#define READ_CMD(cdb)   (((cdb)[0] & 0x1F) == 8)
#define WRITE_CMD(cdb)  (((cdb)[0] & 0x1F) == 0xA)

#ifndef H_GET_PARTNER_INFO
#define H_GET_PARTNER_INFO              0x0000000000000008LL
#endif
#ifndef H_ENABLE_PREPARE_FOR_SUSPEND
#define H_ENABLE_PREPARE_FOR_SUSPEND    0x000000000000001DLL
#endif
#ifndef H_READY_FOR_SUSPEND
#define H_READY_FOR_SUSPEND             0x000000000000001ELL
#endif


#define h_copy_rdma(l, sa, sb, da, db) \
                plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db)
#define h_vioctl(u, o, a, u1, u2, u3, u4) \
                plpar_hcall_norets(H_VIOCTL, u, o, a, u1, u2)
#define h_reg_crq(ua, tok, sz) \
                plpar_hcall_norets(H_REG_CRQ, ua, tok, sz)
#define h_free_crq(ua) \
                plpar_hcall_norets(H_FREE_CRQ, ua)
#define h_send_crq(ua, d1, d2) \
                plpar_hcall_norets(H_SEND_CRQ, ua, d1, d2)

#endif