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/* Struct & Defines to support sense information. */
 257
 258/* The following struct is returned in sensebuf field in uiscmdrsp_scsi.  It is
 259 * initialized in exactly the manner that is recommended in Windows (hence the
 260 * odd values).
 261 * When set, these fields will have the following values:
 262 * ErrorCode = 0x70             indicates current error
 263 * Valid = 1                    indicates sense info is valid
 264 * SenseKey                     contains sense key as defined by SCSI specs.
 265 * AdditionalSenseCode          contains sense key as defined by SCSI specs.
 266 * AdditionalSenseCodeQualifier contains qualifier to sense code as defined by
 267 *                              scsi docs.
 268 * AdditionalSenseLength        contains will be sizeof(sense_data)-8=10.
 269 */
 270struct sense_data {
 271        u8 errorcode:7;
 272        u8 valid:1;
 273        u8 segment_number;
 274        u8 sense_key:4;
 275        u8 reserved:1;
 276        u8 incorrect_length:1;
 277        u8 end_of_media:1;
 278        u8 file_mark:1;
 279        u8 information[4];
 280        u8 additional_sense_length;
 281        u8 command_specific_information[4];
 282        u8 additional_sense_code;
 283        u8 additional_sense_code_qualifier;
 284        u8 fru_code;
 285        u8 sense_key_specific[3];
 286} __packed;
 287
 288struct net_pkt_xmt {
 289        int len;        /* full length of data in the packet */
 290        int num_frags;  /* number of fragments in frags containing data */
 291        struct phys_info frags[MAX_PHYS_INFO];  /* physical page information */
 292        char ethhdr[ETH_HEADER_SIZE];   /* the ethernet header  */
 293        struct {
 294                /* these are needed for csum at uisnic end */
 295                u8 valid;       /* 1 = struct is valid - else ignore */
 296                u8 hrawoffv;    /* 1 = hwrafoff is valid */
 297                u8 nhrawoffv;   /* 1 = nhwrafoff is valid */
 298                u16 protocol;   /* specifies packet protocol */
 299                u32 csum;       /* value used to set skb->csum at IOPart */
 300                u32 hrawoff;    /* value used to set skb->h.raw at IOPart */
 301                /* hrawoff points to the start of the TRANSPORT LAYER HEADER */
 302                u32 nhrawoff;   /* value used to set skb->nh.raw at IOPart */
 303                /* nhrawoff points to the start of the NETWORK LAYER HEADER */
 304        } lincsum;
 305
 306            /* **** NOTE ****
 307             * The full packet is described in frags but the ethernet header is
 308             * separately kept in ethhdr so that uisnic doesn't have "MAP" the
 309             * guest memory to get to the header. uisnic needs ethhdr to
 310             * determine how to route the packet.
 311             */
 312} __packed;
 313
 314struct net_pkt_xmtdone {
 315        u32 xmt_done_result;    /* result of NET_XMIT */
 316} __packed;
 317
 318/* RCVPOST_BUF_SIZe must be at most page_size(4096) - cache_line_size (64) The
 319 * reason is because dev_skb_alloc which is used to generate RCV_POST skbs in
 320 * virtnic requires that there is "overhead" in the buffer, and pads 16 bytes. I
 321 * prefer to use 1 full cache line size for "overhead" so that transfers are
 322 * better.  IOVM requires that a buffer be represented by 1 phys_info structure
 323 * which can only cover page_size.
 324 */
 325#define RCVPOST_BUF_SIZE 4032
 326#define MAX_NET_RCV_CHAIN \
 327        ((ETH_MAX_MTU + ETH_HEADER_SIZE + RCVPOST_BUF_SIZE - 1) \
 328        / RCVPOST_BUF_SIZE)
 329
 330struct net_pkt_rcvpost {
 331            /* rcv buf size must be large enough to include ethernet data len +
 332             * ethernet header len - we are choosing 2K because it is guaranteed
 333             * to be describable
 334             */
 335            struct phys_info frag;      /* physical page information for the */
 336                                        /* single fragment 2K rcv buf */
 337            u64 unique_num;
 338            /* unique_num ensure that receive posts are returned to */
 339            /* the Adapter which we sent them originally. */
 340} __packed;
 341
 342struct net_pkt_rcv {
 343        /* the number of receive buffers that can be chained  */
 344        /* is based on max mtu and size of each rcv buf */
 345        u32 rcv_done_len;       /* length of received data */
 346        u8 numrcvbufs;          /* number of receive buffers that contain the */
 347        /* incoming data; guest end MUST chain these together. */
 348        void *rcvbuf[MAX_NET_RCV_CHAIN];        /* list of chained rcvbufs */
 349        /* each entry is a receive buffer provided by NET_RCV_POST. */
 350        /* NOTE: first rcvbuf in the chain will also be provided in net.buf. */
 351        u64 unique_num;
 352        u32 rcvs_dropped_delta;
 353} __packed;
 354
 355struct net_pkt_enbdis {
 356        void *context;
 357        u16 enable;             /* 1 = enable, 0 = disable */
 358} __packed;
 359
 360struct net_pkt_macaddr {
 361        void *context;
 362        u8 macaddr[MAX_MACADDR_LEN];    /* 6 bytes */
 363} __packed;
 364
 365/* cmd rsp packet used for VNIC network traffic  */
 366struct uiscmdrsp_net {
 367        enum net_types type;
 368        void *buf;
 369        union {
 370                struct net_pkt_xmt xmt;         /* used for NET_XMIT */
 371                struct net_pkt_xmtdone xmtdone; /* used for NET_XMIT_DONE */
 372                struct net_pkt_rcvpost rcvpost; /* used for NET_RCV_POST */
 373                struct net_pkt_rcv rcv;         /* used for NET_RCV */
 374                struct net_pkt_enbdis enbdis;   /* used for NET_RCV_ENBDIS, */
 375                                                /* NET_RCV_ENBDIS_ACK,  */
 376                                                /* NET_RCV_PROMSIC, */
 377                                                /* and NET_CONNECT_STATUS */
 378                struct net_pkt_macaddr macaddr;
 379        };
 380} __packed;
 381
 382struct uiscmdrsp_scsitaskmgmt {
 383        enum task_mgmt_types tasktype;
 384
 385            /* the type of task */
 386        struct uisscsi_dest vdest;
 387
 388            /* the vdisk for which this task mgmt is generated */
 389        u64 handle;
 390
 391            /* This is a handle that the guest has saved off for its own use.
 392             * Its value is preserved by iopart & returned as is in the task
 393             * mgmt rsp.
 394             */
 395        u64 notify_handle;
 396
 397           /* For linux guests, this is a pointer to wait_queue_head that a
 398            * thread is waiting on to see if the taskmgmt command has completed.
 399            * When the rsp is received by guest, the thread receiving the
 400            * response uses this to notify the thread waiting for taskmgmt
 401            * command completion.  Its value is preserved by iopart & returned
 402            * as is in the task mgmt rsp.
 403            */
 404        u64 notifyresult_handle;
 405
 406            /* this is a handle to location in guest where the result of the
 407             * taskmgmt command (result field) is to saved off when the response
 408             * is handled.  Its value is preserved by iopart & returned as is in
 409             * the task mgmt rsp.
 410             */
 411        char result;
 412
 413            /* result of taskmgmt command - set by IOPart - values are: */
 414#define TASK_MGMT_FAILED  0
 415} __packed;
 416
 417/* Used by uissd to send disk add/remove notifications to Guest */
 418/* Note that the vHba pointer is not used by the Client/Guest side. */
 419struct uiscmdrsp_disknotify {
 420        u8 add;                 /* 0-remove, 1-add */
 421        void *v_hba;            /* channel info to route msg */
 422        u32 channel, id, lun;   /* SCSI Path of Disk to added or removed */
 423} __packed;
 424
 425/* The following is used by virthba/vSCSI to send the Acquire/Release commands
 426 * to the IOVM.
 427 */
 428struct uiscmdrsp_vdiskmgmt {
 429        enum vdisk_mgmt_types vdisktype;
 430
 431            /* the type of task */
 432        struct uisscsi_dest vdest;
 433
 434            /* the vdisk for which this task mgmt is generated */
 435        u64 handle;
 436
 437            /* This is a handle that the guest has saved off for its own use.
 438             * Its value is preserved by iopart & returned as is in the task
 439             * mgmt rsp.
 440             */
 441        u64 notify_handle;
 442
 443            /* For linux guests, this is a pointer to wait_queue_head that a
 444             * thread is waiting on to see if the tskmgmt command has completed.
 445             * When the rsp is received by guest, the thread receiving the
 446             * response uses this to notify the thread waiting for taskmgmt
 447             * command completion.  Its value is preserved by iopart & returned
 448             * as is in the task mgmt rsp.
 449             */
 450        u64 notifyresult_handle;
 451
 452            /* this is a handle to location in guest where the result of the
 453             * taskmgmt command (result field) is to saved off when the response
 454             * is handled.  Its value is preserved by iopart & returned as is in
 455             * the task mgmt rsp.
 456             */
 457        char result;
 458
 459            /* result of taskmgmt command - set by IOPart - values are: */
 460#define VDISK_MGMT_FAILED  0
 461} __packed;
 462
 463/* keeping cmd & rsp info in one structure for now cmd rsp packet for scsi */
 464struct uiscmdrsp {
 465        char cmdtype;
 466
 467/* describes what type of information is in the struct */
 468#define CMD_SCSI_TYPE           1
 469#define CMD_NET_TYPE            2
 470#define CMD_SCSITASKMGMT_TYPE   3
 471#define CMD_NOTIFYGUEST_TYPE    4
 472#define CMD_VDISKMGMT_TYPE      5
 473        union {
 474                struct uiscmdrsp_scsi scsi;
 475                struct uiscmdrsp_net net;
 476                struct uiscmdrsp_scsitaskmgmt scsitaskmgmt;
 477                struct uiscmdrsp_disknotify disknotify;
 478                struct uiscmdrsp_vdiskmgmt vdiskmgmt;
 479        };
 480        void *private_data;     /* send the response when the cmd is */
 481                                /* done (scsi & scsittaskmgmt). */
 482        struct uiscmdrsp *next; /* General Purpose Queue Link */
 483        struct uiscmdrsp *activeQ_next; /* Used to track active commands */
 484        struct uiscmdrsp *activeQ_prev; /* Used to track active commands */
 485} __packed;
 486
 487struct iochannel_vhba {
 488        struct vhba_wwnn wwnn;          /* 8 bytes */
 489        struct vhba_config_max max;     /* 20 bytes */
 490} __packed;                             /* total = 28 bytes */
 491struct iochannel_vnic {
 492        u8 macaddr[6];                  /* 6 bytes */
 493        u32 num_rcv_bufs;               /* 4 bytes */
 494        u32 mtu;                        /* 4 bytes */
 495        uuid_le zone_uuid;              /* 16 bytes */
 496} __packed;
 497/* This is just the header of the IO channel.  It is assumed that directly after
 498 * this header there is a large region of memory which contains the command and
 499 * response queues as specified in cmd_q and rsp_q SIGNAL_QUEUE_HEADERS.
 500 */
 501struct spar_io_channel_protocol {
 502        struct channel_header channel_header;
 503        struct signal_queue_header cmd_q;
 504        struct signal_queue_header rsp_q;
 505        union {
 506                struct iochannel_vhba vhba;
 507                struct iochannel_vnic vnic;
 508        } __packed;
 509
 510#define MAX_CLIENTSTRING_LEN 1024
 511        /* client_string is NULL termimated so holds max -1 bytes */
 512         u8 client_string[MAX_CLIENTSTRING_LEN];
 513} __packed;
 514
 515/* INLINE functions for initializing and accessing I/O data channels */
 516#define SIZEOF_PROTOCOL (COVER(sizeof(struct spar_io_channel_protocol), 64))
 517#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64))
 518
 519#define MIN_IO_CHANNEL_SIZE COVER(SIZEOF_PROTOCOL + \
 520                                  2 * MIN_NUMSIGNALS * SIZEOF_CMDRSP, 4096)
 521
 522/*
 523 * INLINE function for expanding a guest's pfn-off-size into multiple 4K page
 524 * pfn-off-size entires.
 525 */
 526
 527/* use 4K page sizes when we it comes to passing page information between */
 528/* Guest and IOPartition. */
 529#define PI_PAGE_SIZE  0x1000
 530#define PI_PAGE_MASK  0x0FFF
 531
 532/* returns next non-zero index on success or zero on failure (i.e. out of
 533 * room)
 534 */
 535static inline  u16
 536add_physinfo_entries(u64 inp_pfn, u16 inp_off, u32 inp_len, u16 index,
 537                     u16 max_pi_arr_entries, struct phys_info pi_arr[])
 538{
 539        u32 len;
 540        u16 i, firstlen;
 541
 542        firstlen = PI_PAGE_SIZE - inp_off;
 543        if (inp_len <= firstlen) {
 544                /* the input entry spans only one page - add as is */
 545                if (index >= max_pi_arr_entries)
 546                        return 0;
 547                pi_arr[index].pi_pfn = inp_pfn;
 548                pi_arr[index].pi_off = (u16)inp_off;
 549                pi_arr[index].pi_len = (u16)inp_len;
 550                return index + 1;
 551        }
 552
 553        /* this entry spans multiple pages */
 554        for (len = inp_len, i = 0; len;
 555                len -= pi_arr[index + i].pi_len, i++) {
 556                if (index + i >= max_pi_arr_entries)
 557                        return 0;
 558                pi_arr[index + i].pi_pfn = inp_pfn + i;
 559                if (i == 0) {
 560                        pi_arr[index].pi_off = inp_off;
 561                        pi_arr[index].pi_len = firstlen;
 562                } else {
 563                        pi_arr[index + i].pi_off = 0;
 564                        pi_arr[index + i].pi_len =
 565                            (u16)MINNUM(len, (u32)PI_PAGE_SIZE);
 566                }
 567        }
 568        return index + i;
 569}
 570
 571#endif                          /* __IOCHANNEL_H__ */
 572