linux/drivers/staging/unisys/include/iochannel.h
<<
>>
Prefs
   1/* Copyright (C) 2010 - 2013 UNISYS CORPORATION */
   2/* All rights reserved. */
   3#ifndef __IOCHANNEL_H__
   4#define __IOCHANNEL_H__
   5
   6/*
   7 * Everything needed for IOPart-GuestPart communication is define in
   8 * this file.  Note: Everything is OS-independent because this file is
   9 * used by Windows, Linux and possible EFI drivers.
  10 */
  11
  12/*
  13 * Communication flow between the IOPart and GuestPart uses the channel headers
  14 * channel state.  The following states are currently being used:
  15 *       UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED
  16 *
  17 * additional states will be used later.  No locking is needed to switch between
  18 * states due to the following rules:
  19 *
  20 *      1.  IOPart is only the only partition allowed to change from UNIT
  21 *      2.  IOPart is only the only partition allowed to change from
  22 *              CHANNEL_ATTACHING
  23 *      3.  GuestPart is only the only partition allowed to change from
  24 *              CHANNEL_ATTACHED
  25 *
  26 * The state changes are the following: IOPart sees the channel is in UNINIT,
  27 *        UNINIT -> CHANNEL_ATTACHING (performed only by IOPart)
  28 *        CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart)
  29 *        CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart)
  30 */
  31
  32#include <linux/uuid.h>
  33
  34#include <linux/dma-direction.h>
  35#include "channel.h"
  36#include "channel_guid.h"
  37
  38#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
  39#define ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
  40#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE \
  41        ULTRA_CHANNEL_PROTOCOL_SIGNATURE
  42
  43/* Must increment these whenever you insert or delete fields within this channel
  44 * struct.  Also increment whenever you change the meaning of fields within this
  45 * channel struct so as to break pre-existing software.  Note that you can
  46 * usually add fields to the END of the channel struct withOUT needing to
  47 * increment this.
  48 */
  49#define ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID 2
  50#define ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID 2
  51#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID 1
  52
  53#define SPAR_VHBA_CHANNEL_OK_CLIENT(ch)                 \
  54        (spar_check_channel_client(ch, spar_vhba_channel_protocol_uuid, \
  55                                   "vhba", MIN_IO_CHANNEL_SIZE, \
  56                                   ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID, \
  57                                   ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE))
  58
  59#define SPAR_VNIC_CHANNEL_OK_CLIENT(ch)                 \
  60        (spar_check_channel_client(ch, spar_vnic_channel_protocol_uuid, \
  61                                   "vnic", MIN_IO_CHANNEL_SIZE, \
  62                                   ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID, \
  63                                   ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE))
  64
  65/*
  66 * Everything necessary to handle SCSI & NIC traffic between Guest Partition and
  67 * IO Partition is defined below.
  68 */
  69
  70/* Defines and enums. */
  71#define MINNUM(a, b) (((a) < (b)) ? (a) : (b))
  72#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b))
  73
  74/* define the two queues per data channel between iopart and ioguestparts */
  75/* used by ioguestpart to 'insert' signals to iopart */
  76#define IOCHAN_TO_IOPART 0
  77/* used by ioguestpart to 'remove' signals from iopart, same previous queue */
  78#define IOCHAN_FROM_IOPART 1
  79
  80/* size of cdb - i.e., scsi cmnd */
  81#define MAX_CMND_SIZE 16
  82
  83#define MAX_SENSE_SIZE 64
  84
  85#define MAX_PHYS_INFO 64
  86
  87/* various types of network packets that can be sent in cmdrsp */
  88enum net_types {
  89        NET_RCV_POST = 0,       /* submit buffer to hold receiving
  90                                 * incoming packet
  91                                 */
  92        /* virtnic -> uisnic */
  93        NET_RCV,                /* incoming packet received */
  94        /* uisnic -> virtpci */
  95        NET_XMIT,               /* for outgoing net packets */
  96        /* virtnic -> uisnic */
  97        NET_XMIT_DONE,          /* outgoing packet xmitted */
  98        /* uisnic -> virtpci */
  99        NET_RCV_ENBDIS,         /* enable/disable packet reception */
 100        /* virtnic -> uisnic */
 101        NET_RCV_ENBDIS_ACK,     /* acknowledge enable/disable packet */
 102                                /* reception */
 103        /* uisnic -> virtnic */
 104        NET_RCV_PROMISC,        /* enable/disable promiscuous mode */
 105        /* virtnic -> uisnic */
 106        NET_CONNECT_STATUS,     /* indicate the loss or restoration of a network
 107                                 * connection
 108                                 */
 109        /* uisnic -> virtnic */
 110        NET_MACADDR,            /* indicates the client has requested to update
 111                                 * its MAC addr
 112                                 */
 113        NET_MACADDR_ACK,        /* MAC address */
 114
 115};
 116
 117#define         ETH_HEADER_SIZE 14      /* size of ethernet header */
 118
 119#define         ETH_MIN_DATA_SIZE 46    /* minimum eth data size */
 120#define         ETH_MIN_PACKET_SIZE (ETH_HEADER_SIZE + ETH_MIN_DATA_SIZE)
 121
 122#define         ETH_MAX_MTU 16384       /* maximum data size */
 123
 124#ifndef MAX_MACADDR_LEN
 125#define MAX_MACADDR_LEN 6       /* number of bytes in MAC address */
 126#endif                          /* MAX_MACADDR_LEN */
 127
 128/* various types of scsi task mgmt commands  */
 129enum task_mgmt_types {
 130        TASK_MGMT_ABORT_TASK = 1,
 131        TASK_MGMT_BUS_RESET,
 132        TASK_MGMT_LUN_RESET,
 133        TASK_MGMT_TARGET_RESET,
 134};
 135
 136/* various types of vdisk mgmt commands  */
 137enum vdisk_mgmt_types {
 138        VDISK_MGMT_ACQUIRE = 1,
 139        VDISK_MGMT_RELEASE,
 140};
 141
 142struct phys_info {
 143        u64 pi_pfn;
 144        u16 pi_off;
 145        u16 pi_len;
 146} __packed;
 147
 148#define MIN_NUMSIGNALS 64
 149
 150/* structs with pragma pack  */
 151
 152struct guest_phys_info {
 153        u64 address;
 154        u64 length;
 155} __packed;
 156
 157#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info))
 158
 159struct uisscsi_dest {
 160        u32 channel;            /* channel == bus number */
 161        u32 id;                 /* id == target number */
 162        u32 lun;                /* lun == logical unit number */
 163} __packed;
 164
 165struct vhba_wwnn {
 166        u32 wwnn1;
 167        u32 wwnn2;
 168} __packed;
 169
 170/* WARNING: Values stired in this structure must contain maximum counts (not
 171 * maximum values).
 172 */
 173struct vhba_config_max {/* 20 bytes */
 174        u32 max_channel;/* maximum channel for devices attached to this bus */
 175        u32 max_id;     /* maximum SCSI ID for devices attached to bus */
 176        u32 max_lun;    /* maximum SCSI LUN for devices attached to bus */
 177        u32 cmd_per_lun;/* maximum number of outstanding commands per LUN */
 178        u32 max_io_size;/* maximum io size for devices attached to this bus */
 179        /* max io size is often determined by the resource of the hba. e.g */
 180        /* max scatter gather list length * page size / sector size */
 181} __packed;
 182
 183struct uiscmdrsp_scsi {
 184        u64 handle;             /* the handle to the cmd that was received */
 185                                /* send it back as is in the rsp packet.  */
 186        u8 cmnd[MAX_CMND_SIZE]; /* the cdb for the command */
 187        u32 bufflen;            /* length of data to be transferred out or in */
 188        u16 guest_phys_entries; /* Number of entries in scatter-gather list */
 189        struct guest_phys_info gpi_list[MAX_PHYS_INFO]; /* physical address
 190                                                         * information for each
 191                                                         * fragment
 192                                                         */
 193        enum dma_data_direction  data_dir; /* direction of the data, if any */
 194        struct uisscsi_dest vdest;      /* identifies the virtual hba, id, */
 195                                        /* channel, lun to which cmd was sent */
 196
 197        /* Needed to queue the rsp back to cmd originator */
 198        int linuxstat;          /* original Linux status used by linux vdisk */
 199        u8 scsistat;            /* the scsi status */
 200        u8 addlstat;            /* non-scsi status */
 201#define ADDL_SEL_TIMEOUT        4
 202
 203        /* the following fields are need to determine the result of command */
 204         u8 sensebuf[MAX_SENSE_SIZE];   /* sense info in case cmd failed; */
 205        /* it holds the sense_data struct; */
 206        /* see that struct for details. */
 207        void *vdisk; /* pointer to the vdisk to clean up when IO completes. */
 208        int no_disk_result;
 209        /* used to return no disk inquiry result
 210         * when no_disk_result is set to 1,
 211         * scsi.scsistat is SAM_STAT_GOOD
 212         * scsi.addlstat is 0
 213         * scsi.linuxstat is SAM_STAT_GOOD
 214         * That is, there is NO error.
 215         */
 216} __packed;
 217
 218/* Defines to support sending correct inquiry result when no disk is
 219 * configured.
 220 */
 221
 222/* From SCSI SPC2 -
 223 *
 224 * If the target is not capable of supporting a device on this logical unit, the
 225 * device server shall set this field to 7Fh (PERIPHERAL QUALIFIER set to 011b
 226 * and PERIPHERAL DEVICE TYPE set to 1Fh).
 227 *
 228 *The device server is capable of supporting the specified peripheral device
 229 *type on this logical unit. However, the physical device is not currently
 230 *connected to this logical unit.
 231 */
 232
 233#define DEV_NOT_CAPABLE 0x7f    /* peripheral qualifier of 0x3  */
 234                                /* peripheral type of 0x1f */
 235                                /* specifies no device but target present */
 236
 237#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 /* peripheral qualifier of 0x1 */
 238    /* peripheral type of 0 - disk */
 239    /* specifies device capable, but not present */
 240
 241#define DEV_HISUPPORT 0x10      /* HiSup = 1; shows support for report luns */
 242                                /* must be returned for lun 0. */
 243
 244/* NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length
 245 * in buf[4] some linux code accesses bytes beyond 5 to retrieve vendor, product
 246 * & revision.  Yikes! So let us always send back 36 bytes, the minimum for
 247 * inquiry result.
 248 */
 249#define NO_DISK_INQUIRY_RESULT_LEN 36
 250
 251#define MIN_INQUIRY_RESULT_LEN 5 /* 5 bytes minimum for inquiry result */
 252
 253/* SCSI device version for no disk inquiry result */
 254#define SCSI_SPC2_VER 4         /* indicates SCSI SPC2 (SPC3 is 5) */
 255
 256/* Windows and Linux want different things for a non-existent lun. So, we'll let
 257 * caller pass in the peripheral qualifier and type.
 258 * NOTE:[4] SCSI returns (n-4); so we return length-1-4 or length-5.
 259 */
 260
 261#define SET_NO_DISK_INQUIRY_RESULT(buf, len, lun, lun0notpresent, notpresent) \
 262        do {                                                            \
 263                memset(buf, 0,                                          \
 264                       MINNUM(len,                                      \
 265                              (unsigned int)NO_DISK_INQUIRY_RESULT_LEN)); \
 266                buf[2] = (u8)SCSI_SPC2_VER;                             \
 267                if (lun == 0) {                                         \
 268                        buf[0] = (u8)lun0notpresent;                    \
 269                        buf[3] = (u8)DEV_HISUPPORT;                     \
 270                } else                                                  \
 271                        buf[0] = (u8)notpresent;                        \
 272                buf[4] = (u8)(                                          \
 273                        MINNUM(len,                                     \
 274                               (unsigned int)NO_DISK_INQUIRY_RESULT_LEN) - 5);\
 275                if (len >= NO_DISK_INQUIRY_RESULT_LEN) {                \
 276                        buf[8] = 'D';                                   \
 277                        buf[9] = 'E';                                   \
 278                        buf[10] = 'L';                                  \
 279                        buf[11] = 'L';                                  \
 280                        buf[16] = 'P';                                  \
 281                        buf[17] = 'S';                                  \
 282                        buf[18] = 'E';                                  \
 283                        buf[19] = 'U';                                  \
 284                        buf[20] = 'D';                                  \
 285                        buf[21] = 'O';                                  \
 286                        buf[22] = ' ';                                  \
 287                        buf[23] = 'D';                                  \
 288                        buf[24] = 'E';                                  \
 289                        buf[25] = 'V';                                  \
 290                        buf[26] = 'I';                                  \
 291                        buf[27] = 'C';                                  \
 292                        buf[28] = 'E';                                  \
 293                        buf[30] = ' ';                                  \
 294                        buf[31] = '.';                                  \
 295                }                                                       \
 296        } while (0)
 297
 298/* Struct & Defines to support sense information. */
 299
 300/* The following struct is returned in sensebuf field in uiscmdrsp_scsi.  It is
 301 * initialized in exactly the manner that is recommended in Windows (hence the
 302 * odd values).
 303 * When set, these fields will have the following values:
 304 * ErrorCode = 0x70             indicates current error
 305 * Valid = 1                    indicates sense info is valid
 306 * SenseKey                     contains sense key as defined by SCSI specs.
 307 * AdditionalSenseCode          contains sense key as defined by SCSI specs.
 308 * AdditionalSenseCodeQualifier contains qualifier to sense code as defined by
 309 *                              scsi docs.
 310 * AdditionalSenseLength        contains will be sizeof(sense_data)-8=10.
 311 */
 312struct sense_data {
 313        u8 errorcode:7;
 314        u8 valid:1;
 315        u8 segment_number;
 316        u8 sense_key:4;
 317        u8 reserved:1;
 318        u8 incorrect_length:1;
 319        u8 end_of_media:1;
 320        u8 file_mark:1;
 321        u8 information[4];
 322        u8 additional_sense_length;
 323        u8 command_specific_information[4];
 324        u8 additional_sense_code;
 325        u8 additional_sense_code_qualifier;
 326        u8 fru_code;
 327        u8 sense_key_specific[3];
 328} __packed;
 329
 330struct net_pkt_xmt {
 331        int len;        /* full length of data in the packet */
 332        int num_frags;  /* number of fragments in frags containing data */
 333        struct phys_info frags[MAX_PHYS_INFO];  /* physical page information */
 334        char ethhdr[ETH_HEADER_SIZE];   /* the ethernet header  */
 335        struct {
 336                /* these are needed for csum at uisnic end */
 337                u8 valid;       /* 1 = struct is valid - else ignore */
 338                u8 hrawoffv;    /* 1 = hwrafoff is valid */
 339                u8 nhrawoffv;   /* 1 = nhwrafoff is valid */
 340                u16 protocol;   /* specifies packet protocol */
 341                u32 csum;       /* value used to set skb->csum at IOPart */
 342                u32 hrawoff;    /* value used to set skb->h.raw at IOPart */
 343                /* hrawoff points to the start of the TRANSPORT LAYER HEADER */
 344                u32 nhrawoff;   /* value used to set skb->nh.raw at IOPart */
 345                /* nhrawoff points to the start of the NETWORK LAYER HEADER */
 346        } lincsum;
 347
 348            /* **** NOTE ****
 349             * The full packet is described in frags but the ethernet header is
 350             * separately kept in ethhdr so that uisnic doesn't have "MAP" the
 351             * guest memory to get to the header. uisnic needs ethhdr to
 352             * determine how to route the packet.
 353             */
 354} __packed;
 355
 356struct net_pkt_xmtdone {
 357        u32 xmt_done_result;    /* result of NET_XMIT */
 358} __packed;
 359
 360/* RCVPOST_BUF_SIZe must be at most page_size(4096) - cache_line_size (64) The
 361 * reason is because dev_skb_alloc which is used to generate RCV_POST skbs in
 362 * virtnic requires that there is "overhead" in the buffer, and pads 16 bytes. I
 363 * prefer to use 1 full cache line size for "overhead" so that transfers are
 364 * better.  IOVM requires that a buffer be represented by 1 phys_info structure
 365 * which can only cover page_size.
 366 */
 367#define RCVPOST_BUF_SIZE 4032
 368#define MAX_NET_RCV_CHAIN \
 369        ((ETH_MAX_MTU + ETH_HEADER_SIZE + RCVPOST_BUF_SIZE - 1) \
 370        / RCVPOST_BUF_SIZE)
 371
 372struct net_pkt_rcvpost {
 373            /* rcv buf size must be large enough to include ethernet data len +
 374             * ethernet header len - we are choosing 2K because it is guaranteed
 375             * to be describable
 376             */
 377            struct phys_info frag;      /* physical page information for the */
 378                                        /* single fragment 2K rcv buf */
 379            u64 unique_num;
 380            /* unique_num ensure that receive posts are returned to */
 381            /* the Adapter which we sent them originally. */
 382} __packed;
 383
 384struct net_pkt_rcv {
 385        /* the number of receive buffers that can be chained  */
 386        /* is based on max mtu and size of each rcv buf */
 387        u32 rcv_done_len;       /* length of received data */
 388        u8 numrcvbufs;          /* number of receive buffers that contain the */
 389        /* incoming data; guest end MUST chain these together. */
 390        void *rcvbuf[MAX_NET_RCV_CHAIN];        /* list of chained rcvbufs */
 391        /* each entry is a receive buffer provided by NET_RCV_POST. */
 392        /* NOTE: first rcvbuf in the chain will also be provided in net.buf. */
 393        u64 unique_num;
 394        u32 rcvs_dropped_delta;
 395} __packed;
 396
 397struct net_pkt_enbdis {
 398        void *context;
 399        u16 enable;             /* 1 = enable, 0 = disable */
 400} __packed;
 401
 402struct net_pkt_macaddr {
 403        void *context;
 404        u8 macaddr[MAX_MACADDR_LEN];    /* 6 bytes */
 405} __packed;
 406
 407/* cmd rsp packet used for VNIC network traffic  */
 408struct uiscmdrsp_net {
 409        enum net_types type;
 410        void *buf;
 411        union {
 412                struct net_pkt_xmt xmt;         /* used for NET_XMIT */
 413                struct net_pkt_xmtdone xmtdone; /* used for NET_XMIT_DONE */
 414                struct net_pkt_rcvpost rcvpost; /* used for NET_RCV_POST */
 415                struct net_pkt_rcv rcv;         /* used for NET_RCV */
 416                struct net_pkt_enbdis enbdis;   /* used for NET_RCV_ENBDIS, */
 417                                                /* NET_RCV_ENBDIS_ACK,  */
 418                                                /* NET_RCV_PROMSIC, */
 419                                                /* and NET_CONNECT_STATUS */
 420                struct net_pkt_macaddr macaddr;
 421        };
 422} __packed;
 423
 424struct uiscmdrsp_scsitaskmgmt {
 425        enum task_mgmt_types tasktype;
 426
 427            /* the type of task */
 428        struct uisscsi_dest vdest;
 429
 430            /* the vdisk for which this task mgmt is generated */
 431        u64 handle;
 432
 433            /* This is a handle that the guest has saved off for its own use.
 434             * Its value is preserved by iopart & returned as is in the task
 435             * mgmt rsp.
 436             */
 437        u64 notify_handle;
 438
 439           /* For linux guests, this is a pointer to wait_queue_head that a
 440            * thread is waiting on to see if the taskmgmt command has completed.
 441            * When the rsp is received by guest, the thread receiving the
 442            * response uses this to notify the thread waiting for taskmgmt
 443            * command completion.  Its value is preserved by iopart & returned
 444            * as is in the task mgmt rsp.
 445            */
 446        u64 notifyresult_handle;
 447
 448            /* this is a handle to location in guest where the result of the
 449             * taskmgmt command (result field) is to saved off when the response
 450             * is handled.  Its value is preserved by iopart & returned as is in
 451             * the task mgmt rsp.
 452             */
 453        char result;
 454
 455            /* result of taskmgmt command - set by IOPart - values are: */
 456#define TASK_MGMT_FAILED  0
 457} __packed;
 458
 459/* Used by uissd to send disk add/remove notifications to Guest */
 460/* Note that the vHba pointer is not used by the Client/Guest side. */
 461struct uiscmdrsp_disknotify {
 462        u8 add;                 /* 0-remove, 1-add */
 463        void *v_hba;            /* channel info to route msg */
 464        u32 channel, id, lun;   /* SCSI Path of Disk to added or removed */
 465} __packed;
 466
 467/* The following is used by virthba/vSCSI to send the Acquire/Release commands
 468 * to the IOVM.
 469 */
 470struct uiscmdrsp_vdiskmgmt {
 471        enum vdisk_mgmt_types vdisktype;
 472
 473            /* the type of task */
 474        struct uisscsi_dest vdest;
 475
 476            /* the vdisk for which this task mgmt is generated */
 477        u64 handle;
 478
 479            /* This is a handle that the guest has saved off for its own use.
 480             * Its value is preserved by iopart & returned as is in the task
 481             * mgmt rsp.
 482             */
 483        u64 notify_handle;
 484
 485            /* For linux guests, this is a pointer to wait_queue_head that a
 486             * thread is waiting on to see if the tskmgmt command has completed.
 487             * When the rsp is received by guest, the thread receiving the
 488             * response uses this to notify the thread waiting for taskmgmt
 489             * command completion.  Its value is preserved by iopart & returned
 490             * as is in the task mgmt rsp.
 491             */
 492        u64 notifyresult_handle;
 493
 494            /* this is a handle to location in guest where the result of the
 495             * taskmgmt command (result field) is to saved off when the response
 496             * is handled.  Its value is preserved by iopart & returned as is in
 497             * the task mgmt rsp.
 498             */
 499        char result;
 500
 501            /* result of taskmgmt command - set by IOPart - values are: */
 502#define VDISK_MGMT_FAILED  0
 503} __packed;
 504
 505/* keeping cmd & rsp info in one structure for now cmd rsp packet for scsi */
 506struct uiscmdrsp {
 507        char cmdtype;
 508
 509/* describes what type of information is in the struct */
 510#define CMD_SCSI_TYPE           1
 511#define CMD_NET_TYPE            2
 512#define CMD_SCSITASKMGMT_TYPE   3
 513#define CMD_NOTIFYGUEST_TYPE    4
 514#define CMD_VDISKMGMT_TYPE      5
 515        union {
 516                struct uiscmdrsp_scsi scsi;
 517                struct uiscmdrsp_net net;
 518                struct uiscmdrsp_scsitaskmgmt scsitaskmgmt;
 519                struct uiscmdrsp_disknotify disknotify;
 520                struct uiscmdrsp_vdiskmgmt vdiskmgmt;
 521        };
 522        void *private_data;     /* send the response when the cmd is */
 523                                /* done (scsi & scsittaskmgmt). */
 524        struct uiscmdrsp *next; /* General Purpose Queue Link */
 525        struct uiscmdrsp *activeQ_next; /* Used to track active commands */
 526        struct uiscmdrsp *activeQ_prev; /* Used to track active commands */
 527} __packed;
 528
 529struct iochannel_vhba {
 530        struct vhba_wwnn wwnn;          /* 8 bytes */
 531        struct vhba_config_max max;     /* 20 bytes */
 532} __packed;                             /* total = 28 bytes */
 533struct iochannel_vnic {
 534        u8 macaddr[6];                  /* 6 bytes */
 535        u32 num_rcv_bufs;               /* 4 bytes */
 536        u32 mtu;                        /* 4 bytes */
 537        uuid_le zone_uuid;              /* 16 bytes */
 538} __packed;
 539/* This is just the header of the IO channel.  It is assumed that directly after
 540 * this header there is a large region of memory which contains the command and
 541 * response queues as specified in cmd_q and rsp_q SIGNAL_QUEUE_HEADERS.
 542 */
 543struct spar_io_channel_protocol {
 544        struct channel_header channel_header;
 545        struct signal_queue_header cmd_q;
 546        struct signal_queue_header rsp_q;
 547        union {
 548                struct iochannel_vhba vhba;
 549                struct iochannel_vnic vnic;
 550        } __packed;
 551
 552#define MAX_CLIENTSTRING_LEN 1024
 553        /* client_string is NULL termimated so holds max -1 bytes */
 554         u8 client_string[MAX_CLIENTSTRING_LEN];
 555} __packed;
 556
 557/* INLINE functions for initializing and accessing I/O data channels */
 558#define SIZEOF_PROTOCOL (COVER(sizeof(struct spar_io_channel_protocol), 64))
 559#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64))
 560
 561#define MIN_IO_CHANNEL_SIZE COVER(SIZEOF_PROTOCOL + \
 562                                  2 * MIN_NUMSIGNALS * SIZEOF_CMDRSP, 4096)
 563
 564/*
 565 * INLINE function for expanding a guest's pfn-off-size into multiple 4K page
 566 * pfn-off-size entires.
 567 */
 568
 569/* use 4K page sizes when we it comes to passing page information between */
 570/* Guest and IOPartition. */
 571#define PI_PAGE_SIZE  0x1000
 572#define PI_PAGE_MASK  0x0FFF
 573
 574/* returns next non-zero index on success or zero on failure (i.e. out of
 575 * room)
 576 */
 577static inline  u16
 578add_physinfo_entries(u64 inp_pfn, u16 inp_off, u32 inp_len, u16 index,
 579                     u16 max_pi_arr_entries, struct phys_info pi_arr[])
 580{
 581        u32 len;
 582        u16 i, firstlen;
 583
 584        firstlen = PI_PAGE_SIZE - inp_off;
 585        if (inp_len <= firstlen) {
 586                /* the input entry spans only one page - add as is */
 587                if (index >= max_pi_arr_entries)
 588                        return 0;
 589                pi_arr[index].pi_pfn = inp_pfn;
 590                pi_arr[index].pi_off = (u16)inp_off;
 591                pi_arr[index].pi_len = (u16)inp_len;
 592                return index + 1;
 593        }
 594
 595        /* this entry spans multiple pages */
 596        for (len = inp_len, i = 0; len;
 597                len -= pi_arr[index + i].pi_len, i++) {
 598                if (index + i >= max_pi_arr_entries)
 599                        return 0;
 600                pi_arr[index + i].pi_pfn = inp_pfn + i;
 601                if (i == 0) {
 602                        pi_arr[index].pi_off = inp_off;
 603                        pi_arr[index].pi_len = firstlen;
 604                } else {
 605                        pi_arr[index + i].pi_off = 0;
 606                        pi_arr[index + i].pi_len =
 607                            (u16)MINNUM(len, (u32)PI_PAGE_SIZE);
 608                }
 609        }
 610        return index + i;
 611}
 612
 613#endif                          /* __IOCHANNEL_H__ */
 614