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