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