cregit-Linux how code gets into the kernel

Release 4.11 drivers/staging/unisys/include/iochannel.h

/* Copyright (C) 2010 - 2016 UNISYS CORPORATION */
/* All rights reserved. */
#ifndef __IOCHANNEL_H__

#define __IOCHANNEL_H__

/*
 * Everything needed for IOPart-GuestPart communication is define in
 * this file. Note: Everything is OS-independent because this file is
 * used by Windows, Linux and possible EFI drivers.
 */

/*
 * Communication flow between the IOPart and GuestPart uses the channel headers
 * channel state. The following states are currently being used:
 *       UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED
 *
 * Additional states will be used later. No locking is needed to switch between
 * states due to the following rules:
 *
 *      1.  IOPart is only the only partition allowed to change from UNIT
 *      2.  IOPart is only the only partition allowed to change from
 *              CHANNEL_ATTACHING
 *      3.  GuestPart is only the only partition allowed to change from
 *              CHANNEL_ATTACHED
 *
 * The state changes are the following: IOPart sees the channel is in UNINIT,
 *        UNINIT -> CHANNEL_ATTACHING (performed only by IOPart)
 *        CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart)
 *        CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart)
 */

#include <linux/uuid.h>

#include <linux/dma-direction.h>
#include "channel.h"


#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE

#define ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE

#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE \
	ULTRA_CHANNEL_PROTOCOL_SIGNATURE

/*
 * Must increment these whenever you insert or delete fields within this channel
 * struct. Also increment whenever you change the meaning of fields within this
 * channel struct so as to break pre-existing software. Note that you can
 * usually add fields to the END of the channel struct without needing to
 * increment this.
 */

#define ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID 2

#define ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID 2

#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID 1


#define SPAR_VHBA_CHANNEL_OK_CLIENT(ch)			\
	(spar_check_channel_client(ch, spar_vhba_channel_protocol_uuid, \
                                   "vhba", MIN_IO_CHANNEL_SIZE, \
                                   ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID, \
                                   ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE))


#define SPAR_VNIC_CHANNEL_OK_CLIENT(ch)			\
	(spar_check_channel_client(ch, spar_vnic_channel_protocol_uuid, \
                                   "vnic", MIN_IO_CHANNEL_SIZE, \
                                   ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID, \
                                   ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE))

/*
 * Everything necessary to handle SCSI & NIC traffic between Guest Partition and
 * IO Partition is defined below.
 */

/* Defines and enums. */

#define MINNUM(a, b) (((a) < (b)) ? (a) : (b))

#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b))

/* Define the two queues per data channel between iopart and ioguestparts. */
/* Used by ioguestpart to 'insert' signals to iopart. */

#define IOCHAN_TO_IOPART 0
/* Used by ioguestpart to 'remove' signals from iopart, same previous queue. */

#define IOCHAN_FROM_IOPART 1

/* Size of cdb - i.e., SCSI cmnd */

#define MAX_CMND_SIZE 16


#define MAX_SENSE_SIZE 64


#define MAX_PHYS_INFO 64

/* Various types of network packets that can be sent in cmdrsp. */

enum net_types {
	
NET_RCV_POST = 0,	/*
                                 * Submit buffer to hold receiving
                                 * incoming packet
                                 */
	/* visornic -> uisnic */
	
NET_RCV,		/* incoming packet received */
	/* uisnic -> virtpci */
	
NET_XMIT,		/* for outgoing net packets */
	/* visornic -> uisnic */
	
NET_XMIT_DONE,		/* outgoing packet xmitted */
	/* uisnic -> virtpci */
	
NET_RCV_ENBDIS,		/* enable/disable packet reception */
	/* visornic -> uisnic */
	
NET_RCV_ENBDIS_ACK,	/* acknowledge enable/disable packet */
				/* reception */
	/* uisnic -> visornic */
	
NET_RCV_PROMISC,	/* enable/disable promiscuous mode */
	/* visornic -> uisnic */
	
NET_CONNECT_STATUS,	/*
                                 * indicate the loss or restoration of a network
                                 * connection
                                 */
	/* uisnic -> visornic */
	
NET_MACADDR,		/*
                                 * Indicates the client has requested to update
                                 * it's MAC address
                                 */
	
NET_MACADDR_ACK,	/* MAC address acknowledge */

};


#define ETH_MIN_DATA_SIZE 46	
/* minimum eth data size */

#define ETH_MIN_PACKET_SIZE (ETH_HLEN + ETH_MIN_DATA_SIZE)


#define VISOR_ETH_MAX_MTU 16384	
/* maximum data size */

#ifndef MAX_MACADDR_LEN

#define MAX_MACADDR_LEN 6	
/* number of bytes in MAC address */
#endif

/* Various types of scsi task mgmt commands. */

enum task_mgmt_types {
	
TASK_MGMT_ABORT_TASK = 1,
	
TASK_MGMT_BUS_RESET,
	
TASK_MGMT_LUN_RESET,
	
TASK_MGMT_TARGET_RESET,
};

/* Various types of vdisk mgmt commands. */

enum vdisk_mgmt_types {
	
VDISK_MGMT_ACQUIRE = 1,
	
VDISK_MGMT_RELEASE,
};


struct phys_info {
	
u64 pi_pfn;
	
u16 pi_off;
	
u16 pi_len;
} 
__packed;


#define MIN_NUMSIGNALS 64

/* Structs with pragma pack. */


struct guest_phys_info {
	
u64 address;
	
u64 length;
} 
__packed;


#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info))


struct uisscsi_dest {
	
u32 channel;	/* channel == bus number */
	
u32 id;		/* id == target number */
	
u32 lun;	/* lun == logical unit number */
} 
__packed;


struct vhba_wwnn {
	
u32 wwnn1;
	
u32 wwnn2;
} 
__packed;

/*
 * WARNING: Values stired in this structure must contain maximum counts (not
 * maximum values).
 */

struct vhba_config_max {/* 20 bytes */
	
u32 max_channel;/* maximum channel for devices attached to this bus */
	
u32 max_id;	/* maximum SCSI ID for devices attached to bus */
	
u32 max_lun;	/* maximum SCSI LUN for devices attached to bus */
	
u32 cmd_per_lun;/* maximum number of outstanding commands per LUN */
	
u32 max_io_size;/* maximum io size for devices attached to this bus */
	/* max io size is often determined by the resource of the hba. e.g */
	/* max scatter gather list length * page size / sector size */
} 
__packed;


struct uiscmdrsp_scsi {
	
u64 handle;		/* the handle to the cmd that was received */
				/* send it back as is in the rsp packet.  */
	
u8 cmnd[MAX_CMND_SIZE];	/* the cdb for the command */
	
u32 bufflen;		/* length of data to be transferred out or in */
	
u16 guest_phys_entries;	/* Number of entries in scatter-gather list */
	
struct guest_phys_info gpi_list[MAX_PHYS_INFO];	/* physical address
                                                         * information for each
                                                         * fragment
                                                         */
	
enum dma_data_direction data_dir; /* direction of the data, if any */
	
struct uisscsi_dest vdest;	/* identifies the virtual hba, id, */
					/* channel, lun to which cmd was sent */

	/* Needed to queue the rsp back to cmd originator. */
	
int linuxstat;		/* original Linux status used by Linux vdisk */
	
u8 scsistat;		/* the scsi status */
	
u8 addlstat;		/* non-scsi status */

#define ADDL_SEL_TIMEOUT	4

	/* The following fields are need to determine the result of command. */
	 
u8 sensebuf[MAX_SENSE_SIZE];	/* sense info in case cmd failed; */
	/* sensebuf holds the sense_data struct; */
	/* See sense_data struct for more details. */
	
void *vdisk; /* Pointer to the vdisk to clean up when IO completes. */
	
int no_disk_result;
	/*
         * Used to return no disk inquiry result
         * when no_disk_result is set to 1,
         * scsi.scsistat is SAM_STAT_GOOD
         * scsi.addlstat is 0
         * scsi.linuxstat is SAM_STAT_GOOD
         * That is, there is NO error.
         */
} 
__packed;

/*
 * Defines to support sending correct inquiry result when no disk is
 * configured.
 */

/*
 * From SCSI SPC2 -
 *
 * If the target is not capable of supporting a device on this logical unit, the
 * device server shall set this field to 7Fh (PERIPHERAL QUALIFIER set to 011b
 * and PERIPHERAL DEVICE TYPE set to 1Fh).
 *
 * The device server is capable of supporting the specified peripheral device
 * type on this logical unit. However, the physical device is not currently
 * connected to this logical unit.
 */


#define DEV_NOT_CAPABLE 0x7f	
/*
                                 * peripheral qualifier of 0x3
                                 * peripheral type of 0x1f
                                 * specifies no device but target present
                                 */


#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20	
/* peripheral qualifier of 0x1
                                                 * peripheral type of 0 - disk
                                                 * Specifies device capable, but
                                                 * not present
                                                 */


#define DEV_HISUPPORT 0x10	
/*
                                 * HiSup = 1; shows support for report luns
                                 * must be returned for lun 0.
                                 */

/*
 * NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length
 * in buf[4] some Linux code accesses bytes beyond 5 to retrieve vendor, product
 * and revision. Yikes! So let us always send back 36 bytes, the minimum for
 * inquiry result.
 */

#define NO_DISK_INQUIRY_RESULT_LEN 36


#define MIN_INQUIRY_RESULT_LEN 5 
/* 5 bytes minimum for inquiry result */

/* SCSI device version for no disk inquiry result */

#define SCSI_SPC2_VER 4	
/* indicates SCSI SPC2 (SPC3 is 5) */

/* Struct and Defines to support sense information. */

/*
 * The following struct is returned in sensebuf field in uiscmdrsp_scsi. It is
 * initialized in exactly the manner that is recommended in Windows (hence the
 * odd values).
 * When set, these fields will have the following values:
 * ErrorCode = 0x70             indicates current error
 * Valid = 1                    indicates sense info is valid
 * SenseKey                     contains sense key as defined by SCSI specs.
 * AdditionalSenseCode          contains sense key as defined by SCSI specs.
 * AdditionalSenseCodeQualifier contains qualifier to sense code as defined by
 *                              scsi docs.
 * AdditionalSenseLength        contains will be sizeof(sense_data)-8=10.
 */

struct sense_data {
	
u8 errorcode:7;
	
u8 valid:1;
	
u8 segment_number;
	
u8 sense_key:4;
	
u8 reserved:1;
	
u8 incorrect_length:1;
	
u8 end_of_media:1;
	
u8 file_mark:1;
	
u8 information[4];
	
u8 additional_sense_length;
	
u8 command_specific_information[4];
	
u8 additional_sense_code;
	
u8 additional_sense_code_qualifier;
	
u8 fru_code;
	
u8 sense_key_specific[3];
} 
__packed;


struct net_pkt_xmt {
	
int len;	/* full length of data in the packet */
	
int num_frags;	/* number of fragments in frags containing data */
	
struct phys_info frags[MAX_PHYS_INFO];	/* physical page information */
	
char ethhdr[ETH_HLEN];	/* the ethernet header  */
	struct {
		/* These are needed for csum at uisnic end */
		
u8 valid;	/* 1 = struct is valid - else ignore */
		
u8 hrawoffv;	/* 1 = hwrafoff is valid */
		
u8 nhrawoffv;	/* 1 = nhwrafoff is valid */
		
u16 protocol;	/* specifies packet protocol */
		
u32 csum;	/* value used to set skb->csum at IOPart */
		
u32 hrawoff;	/* value used to set skb->h.raw at IOPart */
		/* hrawoff points to the start of the TRANSPORT LAYER HEADER */
		
u32 nhrawoff;	/* value used to set skb->nh.raw at IOPart */
		/* nhrawoff points to the start of the NETWORK LAYER HEADER */
	} 
lincsum;

	    /*
             * NOTE:
             * The full packet is described in frags but the ethernet header is
             * separately kept in ethhdr so that uisnic doesn't have "MAP" the
             * guest memory to get to the header. uisnic needs ethhdr to
             * determine how to route the packet.
             */
} 
__packed;


struct net_pkt_xmtdone {
	
u32 xmt_done_result; /* result of NET_XMIT */
} 
__packed;

/*
 * RCVPOST_BUF_SIZE must be at most page_size(4096) - cache_line_size (64) The
 * reason is because dev_skb_alloc which is used to generate RCV_POST skbs in
 * visornic requires that there is "overhead" in the buffer, and pads 16 bytes.
 * Use 1 full cache line size for "overhead" so that transfers are optimized.
 * IOVM requires that a buffer be represented by 1 phys_info structure
 * which can only cover page_size.
 */

#define RCVPOST_BUF_SIZE 4032

#define MAX_NET_RCV_CHAIN \
	((VISOR_ETH_MAX_MTU + ETH_HLEN + RCVPOST_BUF_SIZE - 1) \
        / RCVPOST_BUF_SIZE)

/*
 * rcv buf size must be large enough to include ethernet data len + ethernet
 * header len - we are choosing 2K because it is guaranteed to be describable.
 */

struct net_pkt_rcvpost {
	/* Physical page information for the single fragment 2K rcv buf */
	
struct phys_info frag;

	/*
         * Ensures that receive posts are returned to the adapter which we sent
         * them from originally.
         */
	
u64 unique_num;

} 
__packed;

/*
 * The number of rcvbuf that can be chained is based on max mtu and size of each
 * rcvbuf.
 */

struct net_pkt_rcv {
	
u32 rcv_done_len; /* length of received data */

	/*
         * numrcvbufs: contain the incoming data; guest side MUST chain these
         * together.
         */
	
u8 numrcvbufs;

	
void *rcvbuf[MAX_NET_RCV_CHAIN]; /* list of chained rcvbufs */

	/* Each entry is a receive buffer provided by NET_RCV_POST. */
	/* NOTE: first rcvbuf in the chain will also be provided in net.buf. */
	
u64 unique_num;
	
u32 rcvs_dropped_delta;
} 
__packed;


struct net_pkt_enbdis {
	
void *context;
	
u16 enable; /* 1 = enable, 0 = disable */
} 
__packed;


struct net_pkt_macaddr {
	
void *context;
	
u8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */
} 
__packed;

/* cmd rsp packet used for VNIC network traffic  */

struct uiscmdrsp_net {
	
enum net_types type;
	
void *buf;
	union {
		
struct net_pkt_xmt xmt;		/* used for NET_XMIT */
		
struct net_pkt_xmtdone xmtdone;	/* used for NET_XMIT_DONE */
		
struct net_pkt_rcvpost rcvpost;	/* used for NET_RCV_POST */
		
struct net_pkt_rcv rcv;		/* used for NET_RCV */
		
struct net_pkt_enbdis enbdis;	/* used for NET_RCV_ENBDIS, */
						/* NET_RCV_ENBDIS_ACK,  */
						/* NET_RCV_PROMSIC, */
						/* and NET_CONNECT_STATUS */
		
struct net_pkt_macaddr macaddr;
	};
} 
__packed;


struct uiscmdrsp_scsitaskmgmt {
	/* The type of task. */
	
enum task_mgmt_types tasktype;

	/* The vdisk for which this task mgmt is generated. */
	
struct uisscsi_dest vdest;

	/*
         * This is a handle that the guest has saved off for its own use.
         * The handle value is preserved by iopart and returned as in task
         * mgmt rsp.
         */
	
u64 handle;

	/*
         * For Linux guests, this is a pointer to wait_queue_head that a
         * thread is waiting on to see if the taskmgmt command has completed.
         * When the rsp is received by guest, the thread receiving the
         * response uses this to notify the thread waiting for taskmgmt
         * command completion. It's value is preserved by iopart and returned
         * as in the task mgmt rsp.
         */
	
u64 notify_handle;

	/*
         * This is a handle to the location in the guest where the result of
         * the taskmgmt command (result field) is saved to when the response
         * is handled. It's value is preserved by iopart and returned as in
         * the task mgmt rsp.
         */
	
u64 notifyresult_handle;

	/* Result of taskmgmt command - set by IOPart - values are: */
	
char result;


#define TASK_MGMT_FAILED  0
} 
__packed;

/* Used by uissd to send disk add/remove notifications to Guest. */
/* Note that the vHba pointer is not used by the Client/Guest side. */

struct uiscmdrsp_disknotify {
	
u8 add;			/* 0-remove, 1-add */
	
void *v_hba;		/* channel info to route msg */
	


u32 channel, id, lun;	/* SCSI Path of Disk to added or removed */
} 
__packed;

/*
 * The following is used by virthba/vSCSI to send the Acquire/Release commands
 * to the IOVM.
 */

struct uiscmdrsp_vdiskmgmt {
	/* The type of task */
	
enum vdisk_mgmt_types vdisktype;

	/* The vdisk for which this task mgmt is generated */
	
struct uisscsi_dest vdest;

	/*
         * This is a handle that the guest has saved off for its own use. It's
         * value is preserved by iopart and returned as in the task mgmt rsp.
         */
	
u64 handle;

	/*
         * For Linux guests, this is a pointer to wait_queue_head that a
         * thread is waiting on to see if the tskmgmt command has completed.
         * When the rsp is received by guest, the thread receiving the
         * response uses this to notify the thread waiting for taskmgmt
         * command completion. It's value is preserved by iopart and returned
         * as in the task mgmt rsp.
         */
	
u64 notify_handle;

	/*
         * Handle to the location in guest where the result of the
         * taskmgmt command (result field) is saved to when the response
         * is handled. It's value is preserved by iopart and returned as in
         * the task mgmt rsp.
         */
	
u64 notifyresult_handle;

	/* Result of taskmgmt command - set by IOPart - values are: */
	
char result;
} 
__packed;

/* Keeping cmd and rsp info in one structure for now cmd rsp packet for SCSI */

struct uiscmdrsp {
	
char cmdtype;

/* Describes what type of information is in the struct */

#define CMD_SCSI_TYPE		1

#define CMD_NET_TYPE		2

#define CMD_SCSITASKMGMT_TYPE	3

#define CMD_NOTIFYGUEST_TYPE	4

#define CMD_VDISKMGMT_TYPE	5
	union {
		
struct uiscmdrsp_scsi scsi;
		
struct uiscmdrsp_net net;
		
struct uiscmdrsp_scsitaskmgmt scsitaskmgmt;
		
struct uiscmdrsp_disknotify disknotify;
		
struct uiscmdrsp_vdiskmgmt vdiskmgmt;
	};
	/* Send the response when the cmd is done (scsi and scsittaskmgmt). */
	
void *private_data;
	
struct uiscmdrsp *next;	/* General Purpose Queue Link */
	
struct uiscmdrsp *activeQ_next;	/* Pointer to the nextactive commands */
	
struct uiscmdrsp *activeQ_prev;	/* Pointer to the prevactive commands */
} 
__packed;


struct iochannel_vhba {
	
struct vhba_wwnn wwnn;		/* 8 bytes */
	
struct vhba_config_max max;	/* 20 bytes */
} 
__packed;				
/* total = 28 bytes */

struct iochannel_vnic {
	
u8 macaddr[6];			/* 6 bytes */
	
u32 num_rcv_bufs;		/* 4 bytes */
	
u32 mtu;			/* 4 bytes */
	
uuid_le zone_uuid;		/* 16 bytes */
} 
__packed;
/*
 * This is just the header of the IO channel. It is assumed that directly after
 * this header there is a large region of memory which contains the command and
 * response queues as specified in cmd_q and rsp_q SIGNAL_QUEUE_HEADERS.
 */

struct spar_io_channel_protocol {
	
struct channel_header channel_header;
	
struct signal_queue_header cmd_q;
	
struct signal_queue_header rsp_q;
	union {
		
struct iochannel_vhba vhba;
		
struct iochannel_vnic vnic;
	} 
__packed;


#define MAX_CLIENTSTRING_LEN 1024
	/* client_string is NULL termimated so holds max-1 bytes */
	 
u8 client_string[MAX_CLIENTSTRING_LEN];
} 
__packed;

/* INLINE functions for initializing and accessing I/O data channels. */

#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64))

/* Use 4K page sizes when passing page info between Guest and IOPartition. */

#define PI_PAGE_SIZE  0x1000

#define PI_PAGE_MASK  0x0FFF

/* Returns next non-zero index on success or 0 on failure (i.e. out of room). */

static inline u16 add_physinfo_entries(u64 inp_pfn, u16 inp_off, u32 inp_len, u16 index, u16 max_pi_arr_entries, struct phys_info pi_arr[]) { u32 len; u16 i, firstlen; firstlen = PI_PAGE_SIZE - inp_off; if (inp_len <= firstlen) { /* The input entry spans only one page - add as is. */ if (index >= max_pi_arr_entries) return 0; pi_arr[index].pi_pfn = inp_pfn; pi_arr[index].pi_off = (u16)inp_off; pi_arr[index].pi_len = (u16)inp_len; return index + 1; } /* This entry spans multiple pages. */ for (len = inp_len, i = 0; len; len -= pi_arr[index + i].pi_len, i++) { if (index + i >= max_pi_arr_entries) return 0; pi_arr[index + i].pi_pfn = inp_pfn + i; if (i == 0) { pi_arr[index].pi_off = inp_off; pi_arr[index].pi_len = firstlen; } else { pi_arr[index + i].pi_off = 0; pi_arr[index + i].pi_len = (u16)MINNUM(len, (u32)PI_PAGE_SIZE); } } return index + i; }

Contributors

PersonTokensPropCommitsCommitProp
Ken Cox20293.09%116.67%
Benjamin Romer125.53%350.00%
Erik Arfvidson20.92%116.67%
David Kershner10.46%116.67%
Total217100.00%6100.00%

#endif /* __IOCHANNEL_H__ */

Overall Contributors

PersonTokensPropCommitsCommitProp
Ken Cox89875.15%26.90%
Benjamin Romer1109.21%1758.62%
Erik Arfvidson998.28%310.34%
David Kershner836.95%517.24%
Jarod Wilson40.33%13.45%
Yeliz Taneroglu10.08%13.45%
Total1195100.00%29100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.