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