/* 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 #include "vmcallinterface.h" #define _ULTRA_CONTROLVM_CHANNEL_INLINE_ #include #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 SPAR_VHBA_CHANNEL_OK_CLIENT(ch) \ (spar_check_channel_client(ch, spar_vhba_channel_protocol_uuid, \ "vhba", MIN_IO_CHANNEL_SIZE, \ ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID, \ ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE)) #define SPAR_VNIC_CHANNEL_OK_CLIENT(ch) \ (spar_check_channel_client(ch, spar_vnic_channel_protocol_uuid, \ "vnic", MIN_IO_CHANNEL_SIZE, \ ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID, \ ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE)) /* * 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 */ enum net_types { 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 */ }; #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 */ enum task_mgmt_types { TASK_MGMT_ABORT_TASK = 1, TASK_MGMT_BUS_RESET, TASK_MGMT_LUN_RESET, TASK_MGMT_TARGET_RESET, }; /* various types of vdisk mgmt commands */ enum vdisk_mgmt_types { VDISK_MGMT_ACQUIRE = 1, VDISK_MGMT_RELEASE, }; /* 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 segment_number; u8 sense_key:4; u8 reserved:1; u8 incorrect_length:1; u8 end_of_media:1; u8 file_mark:1; u8 information[4]; u8 additional_sense_length; u8 command_specific_information[4]; u8 additional_sense_code; u8 additional_sense_code_qualifier; u8 fru_code; u8 sense_key_specific[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 unique_num; /* 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 unique_num; u32 rcvs_dropped_delta; }; 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 { enum 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 { enum 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 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 *v_hba; /* 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 { enum 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 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 cmd_q and rsp_q SIGNAL_QUEUE_HEADERS. */ struct spar_io_channel_protocol { struct channel_header channel_header; struct signal_queue_header cmd_q; struct signal_queue_header rsp_q; 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 zone_uuid; /* 16 */ } vnic; /* total 30 */ }; #define MAX_CLIENTSTRING_LEN 1024 u8 client_string[MAX_CLIENTSTRING_LEN];/* NULL terminated - so holds * max - 1 bytes */ }; #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 SIZEOF_PROTOCOL (COVER(sizeof(struct spar_io_channel_protocol), 64)) #define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64)) #define MIN_IO_CHANNEL_SIZE COVER(SIZEOF_PROTOCOL + \ 2 * MIN_NUMSIGNALS * SIZEOF_CMDRSP, 4096) /* * 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__ */