Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 | /* Copyright (C) 2010 - 2013 UNISYS CORPORATION */
/* All rights reserved. */
#ifndef __IOCHANNEL_H__
#define __IOCHANNEL_H__
/*
* Everything needed for IOPart-GuestPart communication is define in
* this file. Note: Everything is OS-independent because this file is
* used by Windows, Linux and possible EFI drivers. */
/*
* Communication flow between the IOPart and GuestPart uses the channel headers
* channel state. The following states are currently being used:
* UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED
*
* additional states will be used later. No locking is needed to switch between
* states due to the following rules:
*
* 1. IOPart is only the only partition allowed to change from UNIT
* 2. IOPart is only the only partition allowed to change from
* CHANNEL_ATTACHING
* 3. GuestPart is only the only partition allowed to change from
* CHANNEL_ATTACHED
*
* The state changes are the following: IOPart sees the channel is in UNINIT,
* UNINIT -> CHANNEL_ATTACHING (performed only by IOPart)
* CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart)
* CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart)
*/
#include <linux/uuid.h>
#include "vmcallinterface.h"
#define _ULTRA_CONTROLVM_CHANNEL_INLINE_
#include <linux/dma-direction.h>
#include "controlvmchannel.h"
#include "vbuschannel.h"
#undef _ULTRA_CONTROLVM_CHANNEL_INLINE_
#include "channel.h"
/*
* CHANNEL Guids
*/
#include "channel_guid.h"
#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
#define ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE \
ULTRA_CHANNEL_PROTOCOL_SIGNATURE
/* Must increment these whenever you insert or delete fields within this channel
* struct. Also increment whenever you change the meaning of fields within this
* channel struct so as to break pre-existing software. Note that you can
* usually add fields to the END of the channel struct withOUT needing to
* increment this. */
#define ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID 2
#define ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID 2
#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID 1
#define ULTRA_VHBA_CHANNEL_OK_CLIENT(pChannel, logCtx) \
(ULTRA_check_channel_client(pChannel, UltraVhbaChannelProtocolGuid, \
"vhba", MIN_IO_CHANNEL_SIZE, \
ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID, \
ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE, \
__FILE__, __LINE__, logCtx))
#define ULTRA_VHBA_CHANNEL_OK_SERVER(actualBytes, logCtx) \
(ULTRA_check_channel_server(UltraVhbaChannelProtocolGuid, \
"vhba", MIN_IO_CHANNEL_SIZE, actualBytes, \
__FILE__, __LINE__, logCtx))
#define ULTRA_VNIC_CHANNEL_OK_CLIENT(pChannel, logCtx) \
(ULTRA_check_channel_client(pChannel, UltraVnicChannelProtocolGuid, \
"vnic", MIN_IO_CHANNEL_SIZE, \
ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID, \
ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE, \
__FILE__, __LINE__, logCtx))
#define ULTRA_VNIC_CHANNEL_OK_SERVER(actualBytes, logCtx) \
(ULTRA_check_channel_server(UltraVnicChannelProtocolGuid, \
"vnic", MIN_IO_CHANNEL_SIZE, actualBytes, \
__FILE__, __LINE__, logCtx))
#define ULTRA_VSWITCH_CHANNEL_OK_CLIENT(pChannel, logCtx) \
(ULTRA_check_channel_client(pChannel, UltraVswitchChannelProtocolGuid, \
"vswitch", MIN_IO_CHANNEL_SIZE, \
ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID, \
ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE, \
__FILE__, __LINE__, logCtx))
#define ULTRA_VSWITCH_CHANNEL_OK_SERVER(actualBytes, logCtx) \
(ULTRA_check_channel_server(UltraVswitchChannelProtocolGuid, \
"vswitch", MIN_IO_CHANNEL_SIZE, \
actualBytes, \
__FILE__, __LINE__, logCtx))
/*
* Everything necessary to handle SCSI & NIC traffic between Guest Partition and
* IO Partition is defined below. */
/*
* Defines and enums.
*/
#define MINNUM(a, b) (((a) < (b)) ? (a) : (b))
#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b))
/* these define the two queues per data channel between iopart and
* ioguestparts */
#define IOCHAN_TO_IOPART 0 /* used by ioguestpart to 'insert' signals to
* iopart */
#define IOCHAN_FROM_GUESTPART 0 /* used by iopart to 'remove' signals from
* ioguestpart - same queue as previous queue */
#define IOCHAN_TO_GUESTPART 1 /* used by iopart to 'insert' signals to
* ioguestpart */
#define IOCHAN_FROM_IOPART 1 /* used by ioguestpart to 'remove' signals from
* iopart - same queue as previous queue */
/* these define the two queues per control channel between controlpart and "its"
* guests, which includes the iopart */
#define CTRLCHAN_TO_CTRLGUESTPART 0 /* used by ctrlguestpart to 'insert' signals
* to ctrlpart */
#define CTLRCHAN_FROM_CTRLPART 0 /* used by ctrlpart to 'remove' signals from
* ctrlquestpart - same queue as previous
* queue */
#define CTRLCHAN_TO_CTRLPART 1 /* used by ctrlpart to 'insert' signals to
* ctrlguestpart */
#define CTRLCHAN_FROM_CTRLGUESTPART 1 /* used by ctrguestpart to 'remove'
* signals from ctrlpart - same queue as
* previous queue */
/* these define the Event & Ack queues per control channel Events are generated
* by CTRLGUESTPART and sent to CTRLPART; Acks are generated by CTRLPART and sent
* to CTRLGUESTPART. */
#define CTRLCHAN_EVENT_TO_CTRLPART 2 /* used by ctrlguestpart to 'insert' Events
* to ctrlpart */
#define CTRLCHAN_EVENT_FROM_CTRLGUESTPART 2 /* used by ctrlpart to 'remove'
* Events from ctrlguestpart */
#define CTRLCHAN_ACK_TO_CTRLGUESTPART 3 /* used by ctrlpart to 'insert' Acks to
* ctrlguestpart */
#define CTRLCHAN_ACK_FROM_CTRLPART 3 /* used by ctrlguestpart to 'remove' Events
* from ctrlpart */
/* size of cdb - i.e., scsi cmnd */
#define MAX_CMND_SIZE 16
#define MAX_SENSE_SIZE 64
#define MAX_PHYS_INFO 64
/* Because GuestToGuestCopy is limited to 4KiB segments, and we have limited the
* Emulex Driver to 256 scatter list segments via the lpfc_sg_seg_cnt parameter
* to 256, the maximum I/O size is limited to 256 * 4 KiB = 1 MB */
#define MAX_IO_SIZE (1024*1024) /* 1 MB */
/* NOTE 1: lpfc defines its support for segments in
* #define LPFC_SG_SEG_CNT 64
*
* NOTE 2: In Linux, frags array in skb is currently allocated to be
* MAX_SKB_FRAGS size, which is 18 which is smaller than MAX_PHYS_INFO for
* now. */
#ifndef MAX_SERIAL_NUM
#define MAX_SERIAL_NUM 32
#endif /* MAX_SERIAL_NUM */
#define MAX_SCSI_BUSES 1
#define MAX_SCSI_TARGETS 8
#define MAX_SCSI_LUNS 16
#define MAX_SCSI_FROM_HOST 0xFFFFFFFF /* Indicator to use Physical HBA
* SCSI Host value */
/* various types of network packets that can be sent in cmdrsp */
typedef enum { NET_RCV_POST = 0, /* submit buffer to hold receiving
* incoming packet */
/* virtnic -> uisnic */
NET_RCV, /* incoming packet received */
/* uisnic -> virtpci */
NET_XMIT, /* for outgoing net packets */
/* virtnic -> uisnic */
NET_XMIT_DONE, /* outgoing packet xmitted */
/* uisnic -> virtpci */
NET_RCV_ENBDIS, /* enable/disable packet reception */
/* virtnic -> uisnic */
NET_RCV_ENBDIS_ACK, /* acknowledge enable/disable packet
* reception */
/* uisnic -> virtnic */
NET_RCV_PROMISC, /* enable/disable promiscuous mode */
/* virtnic -> uisnic */
NET_CONNECT_STATUS, /* indicate the loss or restoration of a network
* connection */
/* uisnic -> virtnic */
NET_MACADDR, /* indicates the client has requested to update
* its MAC addr */
NET_MACADDR_ACK, /* MAC address */
} NET_TYPES;
#define ETH_HEADER_SIZE 14 /* size of ethernet header */
#define ETH_MIN_DATA_SIZE 46 /* minimum eth data size */
#define ETH_MIN_PACKET_SIZE (ETH_HEADER_SIZE + ETH_MIN_DATA_SIZE)
#define ETH_DEF_DATA_SIZE 1500 /* default data size */
#define ETH_DEF_PACKET_SIZE (ETH_HEADER_SIZE + ETH_DEF_DATA_SIZE)
#define ETH_MAX_MTU 16384 /* maximum data size */
#ifndef MAX_MACADDR_LEN
#define MAX_MACADDR_LEN 6 /* number of bytes in MAC address */
#endif /* MAX_MACADDR_LEN */
#define ETH_IS_LOCALLY_ADMINISTERED(Address) \
(((u8 *) (Address))[0] & ((u8) 0x02))
#define NIC_VENDOR_ID 0x0008000B
/* various types of scsi task mgmt commands */
typedef enum { TASK_MGMT_ABORT_TASK =
1, TASK_MGMT_BUS_RESET, TASK_MGMT_LUN_RESET,
TASK_MGMT_TARGET_RESET,
} TASK_MGMT_TYPES;
/* various types of vdisk mgmt commands */
typedef enum { VDISK_MGMT_ACQUIRE = 1, VDISK_MGMT_RELEASE,
} VDISK_MGMT_TYPES;
/* this is used in the vdest field */
#define VDEST_ALL 0xFFFF
#define MIN_NUMSIGNALS 64
#define MAX_NUMSIGNALS 4096
/* MAX_NET_RCV_BUF specifies the number of rcv buffers that are created by each
* guest's virtnic and posted to uisnic. Uisnic, for each channel, keeps the rcv
* buffers posted and uses them to receive data on behalf of the guest's virtnic.
* NOTE: the num_rcv_bufs is configurable for each VNIC. So the following is
* simply an upperlimit on what each VNIC can provide. Setting it to half of the
* NUMSIGNALS to prevent queue full deadlocks */
#define MAX_NET_RCV_BUFS (MIN_NUMSIGNALS / 2)
/*
* structs with pragma pack */
/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */
#pragma pack(push, 1)
struct guest_phys_info {
u64 address;
u64 length;
};
#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info))
struct uisscsi_dest {
u32 channel; /* channel == bus number */
u32 id; /* id == target number */
u32 lun; /* lun == logical unit number */
};
struct vhba_wwnn {
u32 wwnn1;
u32 wwnn2;
};
/* WARNING: Values stired in this structure must contain maximum counts (not
* maximum values). */
struct vhba_config_max { /* 20 bytes */
u32 max_channel; /* maximum channel for devices attached to this
* bus */
u32 max_id; /* maximum SCSI ID for devices attached to this
* bus */
u32 max_lun; /* maximum SCSI LUN for devices attached to this
* bus */
u32 cmd_per_lun; /* maximum number of outstanding commands per
* lun that are allowed at one time */
u32 max_io_size; /* maximum io size for devices attached to this
* bus */
/* max io size is often determined by the resource of the hba. e.g */
/* max scatter gather list length * page size / sector size */
};
struct uiscmdrsp_scsi {
void *scsicmd; /* the handle to the cmd that was received -
* send it back as is in the rsp packet. */
u8 cmnd[MAX_CMND_SIZE]; /* the cdb for the command */
u32 bufflen; /* length of data to be transferred out or in */
u16 guest_phys_entries; /* Number of entries in scatter-gather (sg)
* list */
struct guest_phys_info gpi_list[MAX_PHYS_INFO]; /* physical address
* information for each
* fragment */
enum dma_data_direction data_dir; /* direction of the data, if any */
struct uisscsi_dest vdest; /* identifies the virtual hba, id,
* channel, lun to which cmd was sent */
/* the following fields are needed to queue the rsp back to cmd
* originator */
int linuxstat; /* the original Linux status - for use by linux
* vdisk code */
u8 scsistat; /* the scsi status */
u8 addlstat; /* non-scsi status - covers cases like timeout
* needed by windows guests */
#define ADDL_RESET 1
#define ADDL_TIMEOUT 2
#define ADDL_INTERNAL_ERROR 3
#define ADDL_SEL_TIMEOUT 4
#define ADDL_CMD_TIMEOUT 5
#define ADDL_BAD_TARGET 6
#define ADDL_RETRY 7
/* the following fields are need to determine the result of command */
u8 sensebuf[MAX_SENSE_SIZE]; /* sense info in case cmd failed; */
/* it holds the sense_data struct; */
/* see that struct for details. */
void *vdisk; /* contains pointer to the vdisk so that we can clean up
* when the IO completes. */
int no_disk_result; /* used to return no disk inquiry result */
/* when no_disk_result is set to 1, */
/* scsi.scsistat is SAM_STAT_GOOD */
/* scsi.addlstat is 0 */
/* scsi.linuxstat is SAM_STAT_GOOD */
/* That is, there is NO error. */
};
/*
* Defines to support sending correct inquiry result when no disk is
* configured. */
/* From SCSI SPC2 -
*
* If the target is not capable of supporting a device on this logical unit, the
* device server shall set this field to 7Fh (PERIPHERAL QUALIFIER set to 011b
* and PERIPHERAL DEVICE TYPE set to 1Fh).
*
*The device server is capable of supporting the specified peripheral device
*type on this logical unit. However, the physical device is not currently
*connected to this logical unit.
*/
#define DEV_NOT_PRESENT 0x7f /* old name - compatibility */
#define DEV_NOT_CAPABLE 0x7f /* peripheral qualifier of 0x3 */
/* peripheral type of 0x1f */
/* specifies no device but target present */
#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 /* peripheral qualifier of 0x1 */
/* peripheral type of 0 - disk */
/* specifies device capable, but not present */
#define DEV_PROC_CAPABLE_NOT_PRESENT 0x23 /* peripheral qualifier of 0x1 */
/* peripheral type of 3 - processor */
/* specifies device capable, but not present */
#define DEV_HISUPPORT 0x10; /* HiSup = 1; shows support for report luns */
/* must be returned for lun 0. */
/* NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length
* in buf[4] some linux code accesses bytes beyond 5 to retrieve vendor, product
* & revision. Yikes! So let us always send back 36 bytes, the minimum for
* inquiry result. */
#define NO_DISK_INQUIRY_RESULT_LEN 36
#define MIN_INQUIRY_RESULT_LEN 5 /* we need at least 5 bytes minimum for inquiry
* result */
/* SCSI device version for no disk inquiry result */
#define SCSI_SPC2_VER 4 /* indicates SCSI SPC2 (SPC3 is 5) */
/* Windows and Linux want different things for a non-existent lun. So, we'll let
* caller pass in the peripheral qualifier and type.
* NOTE:[4] SCSI returns (n-4); so we return length-1-4 or length-5. */
#define SET_NO_DISK_INQUIRY_RESULT(buf, len, lun, lun0notpresent, notpresent) \
do { \
memset(buf, 0, \
MINNUM(len, \
(unsigned int) NO_DISK_INQUIRY_RESULT_LEN)); \
buf[2] = (u8) SCSI_SPC2_VER; \
if (lun == 0) { \
buf[0] = (u8) lun0notpresent; \
buf[3] = (u8) DEV_HISUPPORT; \
} else \
buf[0] = (u8) notpresent; \
buf[4] = (u8) ( \
MINNUM(len, \
(unsigned int) NO_DISK_INQUIRY_RESULT_LEN) - 5); \
if (len >= NO_DISK_INQUIRY_RESULT_LEN) { \
buf[8] = 'D'; \
buf[9] = 'E'; \
buf[10] = 'L'; \
buf[11] = 'L'; \
buf[16] = 'P'; \
buf[17] = 'S'; \
buf[18] = 'E'; \
buf[19] = 'U'; \
buf[20] = 'D'; \
buf[21] = 'O'; \
buf[22] = ' '; \
buf[23] = 'D'; \
buf[24] = 'E'; \
buf[25] = 'V'; \
buf[26] = 'I'; \
buf[27] = 'C'; \
buf[28] = 'E'; \
buf[30] = ' '; \
buf[31] = '.'; \
} \
} while (0)
/*
* Struct & Defines to support sense information.
*/
/* The following struct is returned in sensebuf field in uiscmdrsp_scsi. It is
* initialized in exactly the manner that is recommended in Windows (hence the
* odd values).
* When set, these fields will have the following values:
* ErrorCode = 0x70 indicates current error
* Valid = 1 indicates sense info is valid
* SenseKey contains sense key as defined by SCSI specs.
* AdditionalSenseCode contains sense key as defined by SCSI specs.
* AdditionalSenseCodeQualifier contains qualifier to sense code as defined by
* scsi docs.
* AdditionalSenseLength contains will be sizeof(sense_data)-8=10.
*/
struct sense_data {
u8 ErrorCode:7;
u8 Valid:1;
u8 SegmentNumber;
u8 SenseKey:4;
u8 Reserved:1;
u8 IncorrectLength:1;
u8 EndOfMedia:1;
u8 FileMark:1;
u8 Information[4];
u8 AdditionalSenseLength;
u8 CommandSpecificInformation[4];
u8 AdditionalSenseCode;
u8 AdditionalSenseCodeQualifier;
u8 FieldReplaceableUnitCode;
u8 SenseKeySpecific[3];
};
/* some SCSI ADSENSE codes */
#ifndef SCSI_ADSENSE_LUN_NOT_READY
#define SCSI_ADSENSE_LUN_NOT_READY 0x04
#endif /* */
#ifndef SCSI_ADSENSE_ILLEGAL_COMMAND
#define SCSI_ADSENSE_ILLEGAL_COMMAND 0x20
#endif /* */
#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK
#endif /* */
#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK
#define SCSI_ADSENSE_ILLEGAL_BLOCK 0x21
#endif /* */
#ifndef SCSI_ADSENSE_INVALID_CDB
#define SCSI_ADSENSE_INVALID_CDB 0x24
#endif /* */
#ifndef SCSI_ADSENSE_INVALID_LUN
#define SCSI_ADSENSE_INVALID_LUN 0x25
#endif /* */
#ifndef SCSI_ADWRITE_PROTECT
#define SCSI_ADWRITE_PROTECT 0x27
#endif /* */
#ifndef SCSI_ADSENSE_MEDIUM_CHANGED
#define SCSI_ADSENSE_MEDIUM_CHANGED 0x28
#endif /* */
#ifndef SCSI_ADSENSE_BUS_RESET
#define SCSI_ADSENSE_BUS_RESET 0x29
#endif /* */
#ifndef SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 0x3a
#endif /* */
struct net_pkt_xmt {
int len; /* full length of data in the packet */
int num_frags; /* number of fragments in frags containing data */
struct phys_info frags[MAX_PHYS_INFO]; /* physical page information for
* each fragment */
char ethhdr[ETH_HEADER_SIZE]; /* the ethernet header */
struct {
/* these are needed for csum at uisnic end */
u8 valid; /* 1 = rest of this struct is valid - else
* ignore */
u8 hrawoffv; /* 1 = hwrafoff is valid */
u8 nhrawoffv; /* 1 = nhwrafoff is valid */
u16 protocol; /* specifies packet protocol */
u32 csum; /* value used to set skb->csum at IOPart */
u32 hrawoff; /* value used to set skb->h.raw at IOPart */
/* hrawoff points to the start of the TRANSPORT LAYER HEADER */
u32 nhrawoff; /* value used to set skb->nh.raw at IOPart */
/* nhrawoff points to the start of the NETWORK LAYER HEADER */
} lincsum;
/* **** NOTE ****
* The full packet is described in frags but the ethernet header is
* separately kept in ethhdr so that uisnic doesn't have "MAP" the
* guest memory to get to the header. uisnic needs ethhdr to
* determine how to route the packet.
*/
};
struct net_pkt_xmtdone {
u32 xmt_done_result; /* result of NET_XMIT */
#define XMIT_SUCCESS 0
#define XMIT_FAILED 1
};
/* RCVPOST_BUF_SIZe must be at most page_size(4096) - cache_line_size (64) The
* reason is because dev_skb_alloc which is used to generate RCV_POST skbs in
* virtnic requires that there is "overhead" in the buffer, and pads 16 bytes. I
* prefer to use 1 full cache line size for "overhead" so that transfers are
* better. IOVM requires that a buffer be represented by 1 phys_info structure
* which can only cover page_size. */
#define RCVPOST_BUF_SIZE 4032
#define MAX_NET_RCV_CHAIN \
((ETH_MAX_MTU+ETH_HEADER_SIZE + RCVPOST_BUF_SIZE-1) / RCVPOST_BUF_SIZE)
struct net_pkt_rcvpost {
/* rcv buf size must be large enough to include ethernet data len +
* ethernet header len - we are choosing 2K because it is guaranteed
* to be describable */
struct phys_info frag; /* physical page information for the
* single fragment 2K rcv buf */
u64 UniqueNum; /* This is used to make sure that
* receive posts are returned to */
/* the Adapter which sent them origonally. */
};
struct net_pkt_rcv {
/* the number of receive buffers that can be chained */
/* is based on max mtu and size of each rcv buf */
u32 rcv_done_len; /* length of received data */
u8 numrcvbufs; /* number of receive buffers that contain the */
/* incoming data; guest end MUST chain these together. */
void *rcvbuf[MAX_NET_RCV_CHAIN]; /* the list of receive buffers
* that must be chained; */
/* each entry is a receive buffer provided by NET_RCV_POST. */
/* NOTE: first rcvbuf in the chain will also be provided in net.buf. */
u64 UniqueNum;
u32 RcvsDroppedDelta;
};
struct net_pkt_enbdis {
void *context;
u16 enable; /* 1 = enable, 0 = disable */
};
struct net_pkt_macaddr {
void *context;
u8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */
};
/* cmd rsp packet used for VNIC network traffic */
struct uiscmdrsp_net {
NET_TYPES type;
void *buf;
union {
struct net_pkt_xmt xmt; /* used for NET_XMIT */
struct net_pkt_xmtdone xmtdone; /* used for NET_XMIT_DONE */
struct net_pkt_rcvpost rcvpost; /* used for NET_RCV_POST */
struct net_pkt_rcv rcv; /* used for NET_RCV */
struct net_pkt_enbdis enbdis; /* used for NET_RCV_ENBDIS, */
/* NET_RCV_ENBDIS_ACK, */
/* NET_RCV_PROMSIC, */
/* and NET_CONNECT_STATUS */
struct net_pkt_macaddr macaddr;
};
};
struct uiscmdrsp_scsitaskmgmt {
TASK_MGMT_TYPES tasktype;
/* the type of task */
struct uisscsi_dest vdest;
/* the vdisk for which this task mgmt is generated */
void *scsicmd;
/* This is some handle that the guest has saved off for its own use.
* Its value is preserved by iopart & returned as is in the task mgmt
* rsp. */
void *notify;
/* For linux guests, this is a pointer to wait_queue_head that a
* thread is waiting on to see if the taskmgmt command has completed.
* For windows guests, this is a pointer to a location that a waiting
* thread is testing to see if the taskmgmt command has completed.
* When the rsp is received by guest, the thread receiving the
* response uses this to notify the the thread waiting for taskmgmt
* command completion. Its value is preserved by iopart & returned
* as is in the task mgmt rsp. */
void *notifyresult;
/* this is a handle to location in guest where the result of the
* taskmgmt command (result field) is to saved off when the response
* is handled. Its value is preserved by iopart & returned as is in
* the task mgmt rsp. */
char result;
/* result of taskmgmt command - set by IOPart - values are: */
#define TASK_MGMT_FAILED 0
#define TASK_MGMT_SUCCESS 1
};
/* The following is used by uissd to send disk add/remove notifications to
* Guest */
/* Note that the vHba pointer is not used by the Client/Guest side. */
struct uiscmdrsp_disknotify {
u8 add; /* 0-remove, 1-add */
void *vHba; /* Pointer to vhba_info for channel info to
* route msg */
u32 channel, id, lun; /* SCSI Path of Disk to added or removed */
};
/* The following is used by virthba/vSCSI to send the Acquire/Release commands
* to the IOVM. */
struct uiscmdrsp_vdiskmgmt {
VDISK_MGMT_TYPES vdisktype;
/* the type of task */
struct uisscsi_dest vdest;
/* the vdisk for which this task mgmt is generated */
void *scsicmd;
/* This is some handle that the guest has saved off for its own use.
* Its value is preserved by iopart & returned as is in the task mgmt
* rsp. */
void *notify;
/* For linux guests, this is a pointer to wait_queue_head that a
* thread is waiting on to see if the taskmgmt command has completed.
* For windows guests, this is a pointer to a location that a waiting
* thread is testing to see if the taskmgmt command has completed.
* When the rsp is received by guest, the thread receiving the
* response uses this to notify the the thread waiting for taskmgmt
* command completion. Its value is preserved by iopart & returned
* as is in the task mgmt rsp. */
void *notifyresult;
/* this is a handle to location in guest where the result of the
* taskmgmt command (result field) is to saved off when the response
* is handled. Its value is preserved by iopart & returned as is in
* the task mgmt rsp. */
char result;
/* result of taskmgmt command - set by IOPart - values are: */
#define VDISK_MGMT_FAILED 0
#define VDISK_MGMT_SUCCESS 1
};
/* keeping cmd & rsp info in one structure for now cmd rsp packet for scsi */
struct uiscmdrsp {
char cmdtype;
/* describes what type of information is in the struct */
#define CMD_SCSI_TYPE 1
#define CMD_NET_TYPE 2
#define CMD_SCSITASKMGMT_TYPE 3
#define CMD_NOTIFYGUEST_TYPE 4
#define CMD_VDISKMGMT_TYPE 5
union {
struct uiscmdrsp_scsi scsi;
struct uiscmdrsp_net net;
struct uiscmdrsp_scsitaskmgmt scsitaskmgmt;
struct uiscmdrsp_disknotify disknotify;
struct uiscmdrsp_vdiskmgmt vdiskmgmt;
};
void *private_data; /* used to send the response when the cmd is
* done (scsi & scsittaskmgmt). */
struct uiscmdrsp *next; /* General Purpose Queue Link */
struct uiscmdrsp *activeQ_next; /* Used to track active commands */
struct uiscmdrsp *activeQ_prev; /* Used to track active commands */
};
/* This is just the header of the IO channel. It is assumed that directly after
* this header there is a large region of memory which contains the command and
* response queues as specified in cmdQ and rspQ SIGNAL_QUEUE_HEADERS. */
typedef struct _ULTRA_IO_CHANNEL_PROTOCOL {
CHANNEL_HEADER ChannelHeader;
SIGNAL_QUEUE_HEADER cmdQ;
SIGNAL_QUEUE_HEADER rspQ;
union {
struct {
struct vhba_wwnn wwnn; /* 8 bytes */
struct vhba_config_max max; /* 20 bytes */
} vhba; /* 28 */
struct {
u8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */
u32 num_rcv_bufs; /* 4 */
u32 mtu; /* 4 */
uuid_le zoneGuid; /* 16 */
} vnic; /* total 30 */
};
#define MAX_CLIENTSTRING_LEN 1024
u8 clientString[MAX_CLIENTSTRING_LEN]; /* NULL terminated - so holds
* max - 1 bytes */
} ULTRA_IO_CHANNEL_PROTOCOL;
#pragma pack(pop)
/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */
/* define offsets to members of struct uiscmdrsp */
#define OFFSET_CMDTYPE offsetof(struct uiscmdrsp, cmdtype)
#define OFFSET_SCSI offsetof(struct uiscmdrsp, scsi)
#define OFFSET_NET offsetof(struct uiscmdrsp, net)
#define OFFSET_SCSITASKMGMT offsetof(struct uiscmdrsp, scsitaskmgmt)
#define OFFSET_NEXT offsetof(struct uiscmdrsp, next)
/* define offsets to members of struct uiscmdrsp_net */
#define OFFSET_TYPE offsetof(struct uiscmdrsp_net, type)
#define OFFSET_BUF offsetof(struct uiscmdrsp_net, buf)
#define OFFSET_XMT offsetof(struct uiscmdrsp_net, xmt)
#define OFFSET_XMT_DONE_RESULT offsetof(struct uiscmdrsp_net, xmtdone)
#define OFFSET_RCVPOST offsetof(struct uiscmdrsp_net, rcvpost)
#define OFFSET_RCV_DONE_LEN offsetof(struct uiscmdrsp_net, rcv)
#define OFFSET_ENBDIS offsetof(struct uiscmdrsp_net, enbdis)
/* define offsets to members of struct net_pkt_rcvpost */
#define OFFSET_TOTALLEN offsetof(struct net_pkt_rcvpost, totallen)
#define OFFSET_FRAG offsetof(struct net_pkt_rcvpost, frag)
/*
* INLINE functions for initializing and accessing I/O data channels
*/
#define NUMSIGNALS(x, q) (((ULTRA_IO_CHANNEL_PROTOCOL *)(x))->q.MaxSignalSlots)
#define SIZEOF_PROTOCOL (COVER(sizeof(ULTRA_IO_CHANNEL_PROTOCOL), 64))
#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64))
#define IO_CHANNEL_SIZE(x) COVER(SIZEOF_PROTOCOL + \
(NUMSIGNALS(x, cmdQ) + \
NUMSIGNALS(x, rspQ)) * SIZEOF_CMDRSP, 4096)
#define MIN_IO_CHANNEL_SIZE COVER(SIZEOF_PROTOCOL + \
2 * MIN_NUMSIGNALS * SIZEOF_CMDRSP, 4096)
#ifdef __GNUC__
/* These defines should only ever be used in service partitons */
/* because they rely on the size of uiscmdrsp */
#define QSLOTSFROMBYTES(bytes) (((bytes-SIZEOF_PROTOCOL)/2)/SIZEOF_CMDRSP)
#define QSIZEFROMBYTES(bytes) (QSLOTSFROMBYTES(bytes)*SIZEOF_CMDRSP)
#define SignalQInit(x) \
do { \
x->cmdQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size); \
x->cmdQ.oSignalBase = SIZEOF_PROTOCOL - \
offsetof(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ); \
x->cmdQ.SignalSize = SIZEOF_CMDRSP; \
x->cmdQ.MaxSignalSlots = \
QSLOTSFROMBYTES(x->ChannelHeader.Size); \
x->cmdQ.MaxSignals = x->cmdQ.MaxSignalSlots - 1; \
x->rspQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size); \
x->rspQ.oSignalBase = \
(SIZEOF_PROTOCOL + x->cmdQ.Size) - \
offsetof(ULTRA_IO_CHANNEL_PROTOCOL, rspQ); \
x->rspQ.SignalSize = SIZEOF_CMDRSP; \
x->rspQ.MaxSignalSlots = \
QSLOTSFROMBYTES(x->ChannelHeader.Size); \
x->rspQ.MaxSignals = x->rspQ.MaxSignalSlots - 1; \
x->ChannelHeader.oChannelSpace = \
offsetof(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ); \
} while (0)
#define INIT_CLIENTSTRING(chan, type, clientStr, clientStrLen) \
do { \
if (clientStr) { \
chan->ChannelHeader.oClientString = \
offsetof(type, clientString); \
memcpy(chan->clientString, clientStr, \
MINNUM(clientStrLen, \
(u32) (MAX_CLIENTSTRING_LEN - 1))); \
chan->clientString[MINNUM(clientStrLen, \
(u32) (MAX_CLIENTSTRING_LEN \
- 1))] \
= '\0'; \
} \
else \
if (clientStrLen > 0) \
return 0; \
} while (0)
#define ULTRA_IO_CHANNEL_SERVER_READY(x, chanId, logCtx) \
ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, CHANNELSRV_READY, \
logCtx)
#define ULTRA_IO_CHANNEL_SERVER_NOTREADY(x, chanId, logCtx) \
ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, \
CHANNELSRV_UNINITIALIZED, logCtx)
static inline int ULTRA_VHBA_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x,
struct vhba_wwnn *wwnn,
struct vhba_config_max *max,
unsigned char *clientStr,
u32 clientStrLen, u64 bytes) {
memset(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL));
x->ChannelHeader.VersionId = ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID;
x->ChannelHeader.Signature = ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE;
x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED;
x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader);
x->ChannelHeader.Size = COVER(bytes, 4096);
x->ChannelHeader.Type = UltraVhbaChannelProtocolGuid;
x->ChannelHeader.ZoneGuid = NULL_UUID_LE;
x->vhba.wwnn = *wwnn;
x->vhba.max = *max;
INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr,
clientStrLen);
SignalQInit(x);
if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) ||
(x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) {
return 0;
}
if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) ||
(x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) {
return 0;
}
return 1;
}
static inline void ULTRA_VHBA_set_max(ULTRA_IO_CHANNEL_PROTOCOL *x,
struct vhba_config_max *max) {
x->vhba.max = *max;
}
static inline int ULTRA_VNIC_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x,
unsigned char *macaddr,
u32 num_rcv_bufs, u32 mtu,
uuid_le zoneGuid,
unsigned char *clientStr,
u32 clientStrLen,
u64 bytes) {
memset(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL));
x->ChannelHeader.VersionId = ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID;
x->ChannelHeader.Signature = ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE;
x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED;
x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader);
x->ChannelHeader.Size = COVER(bytes, 4096);
x->ChannelHeader.Type = UltraVnicChannelProtocolGuid;
x->ChannelHeader.ZoneGuid = NULL_UUID_LE;
memcpy(x->vnic.macaddr, macaddr, MAX_MACADDR_LEN);
x->vnic.num_rcv_bufs = num_rcv_bufs;
x->vnic.mtu = mtu;
x->vnic.zoneGuid = zoneGuid;
INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr,
clientStrLen);
SignalQInit(x);
if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) ||
(x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) {
return 0;
}
if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) ||
(x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) {
return 0;
}
return 1;
}
#endif /* __GNUC__ */
/*
* INLINE function for expanding a guest's pfn-off-size into multiple 4K page
* pfn-off-size entires.
*/
/* we deal with 4K page sizes when we it comes to passing page information
* between */
/* Guest and IOPartition. */
#define PI_PAGE_SIZE 0x1000
#define PI_PAGE_MASK 0x0FFF
#define PI_PAGE_SHIFT 12
/* returns next non-zero index on success or zero on failure (i.e. out of
* room)
*/
static inline u16
add_physinfo_entries(u32 inp_pfn, /* input - specifies the pfn to be used
* to add entries */
u16 inp_off, /* input - specifies the off to be used
* to add entries */
u32 inp_len, /* input - specifies the len to be used
* to add entries */
u16 index, /* input - index in array at which new
* entries are added */
u16 max_pi_arr_entries, /* input - specifies the maximum
* entries pi_arr can hold */
struct phys_info pi_arr[]) /* input & output - array to
* which entries are added */
{
u32 len;
u16 i, firstlen;
firstlen = PI_PAGE_SIZE - inp_off;
if (inp_len <= firstlen) {
/* the input entry spans only one page - add as is */
if (index >= max_pi_arr_entries)
return 0;
pi_arr[index].pi_pfn = inp_pfn;
pi_arr[index].pi_off = (u16) inp_off;
pi_arr[index].pi_len = (u16) inp_len;
return index + 1;
}
/* this entry spans multiple pages */
for (len = inp_len, i = 0; len;
len -= pi_arr[index + i].pi_len, i++) {
if (index + i >= max_pi_arr_entries)
return 0;
pi_arr[index + i].pi_pfn = inp_pfn + i;
if (i == 0) {
pi_arr[index].pi_off = inp_off;
pi_arr[index].pi_len = firstlen;
}
else {
pi_arr[index + i].pi_off = 0;
pi_arr[index + i].pi_len =
(u16) MINNUM(len, (u32) PI_PAGE_SIZE);
}
}
return index + i;
}
#endif /* __IOCHANNEL_H__ */
|