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