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