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