aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/unisys/common-spar/include/channels/iochannel.h
blob: a95add766fc3ce2659a3e25edd77e90713634858 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
/* Copyright (C) 2010 - 2013 UNISYS CORPORATION */
/* All rights reserved. */
#ifndef __IOCHANNEL_H__
#define __IOCHANNEL_H__

/*
* Everything needed for IOPart-GuestPart communication is define in
* this file.  Note: Everything is OS-independent because this file is
* used by Windows, Linux and possible EFI drivers.  */


/*
* Communication flow between the IOPart and GuestPart uses the channel headers
* channel state.  The following states are currently being used:
*       UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED
*
* additional states will be used later.  No locking is needed to switch between
* states due to the following rules:
*
*      1.  IOPart is only the only partition allowed to change from UNIT
*      2.  IOPart is only the only partition allowed to change from
*		CHANNEL_ATTACHING
*      3.  GuestPart is only the only partition allowed to change from
*		CHANNEL_ATTACHED
*
* The state changes are the following: IOPart sees the channel is in UNINIT,
*        UNINIT -> CHANNEL_ATTACHING (performed only by IOPart)
*        CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart)
*        CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart)
*/

#include <linux/uuid.h>

#include "commontypes.h"
#include "vmcallinterface.h"

#define _ULTRA_CONTROLVM_CHANNEL_INLINE_
#include <linux/dma-direction.h>
#include "controlvmchannel.h"
#include "vbuschannel.h"
#undef _ULTRA_CONTROLVM_CHANNEL_INLINE_
#include "channel.h"

/*
 * CHANNEL Guids
 */

#include "channel_guid.h"

#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
#define ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE
#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE \
	ULTRA_CHANNEL_PROTOCOL_SIGNATURE

/* Must increment these whenever you insert or delete fields within this channel
* struct.  Also increment whenever you change the meaning of fields within this
* channel struct so as to break pre-existing software.  Note that you can
* usually add fields to the END of the channel struct withOUT needing to
* increment this. */
#define ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID 2
#define ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID 2
#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID 1

#define ULTRA_VHBA_CHANNEL_OK_CLIENT(pChannel, logCtx)			\
	(ULTRA_check_channel_client(pChannel, UltraVhbaChannelProtocolGuid, \
				    "vhba", MIN_IO_CHANNEL_SIZE,	\
				    ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID, \
				    ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE, \
				    __FILE__, __LINE__, logCtx))
#define ULTRA_VHBA_CHANNEL_OK_SERVER(actualBytes, logCtx)		\
	(ULTRA_check_channel_server(UltraVhbaChannelProtocolGuid,	\
				    "vhba", MIN_IO_CHANNEL_SIZE, actualBytes, \
				    __FILE__, __LINE__, logCtx))
#define ULTRA_VNIC_CHANNEL_OK_CLIENT(pChannel, logCtx)			\
	(ULTRA_check_channel_client(pChannel, UltraVnicChannelProtocolGuid, \
				    "vnic", MIN_IO_CHANNEL_SIZE,	\
				    ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID, \
				    ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE, \
				    __FILE__, __LINE__, logCtx))
#define ULTRA_VNIC_CHANNEL_OK_SERVER(actualBytes, logCtx)		\
	(ULTRA_check_channel_server(UltraVnicChannelProtocolGuid,	\
				    "vnic", MIN_IO_CHANNEL_SIZE, actualBytes, \
				    __FILE__, __LINE__, logCtx))
#define ULTRA_VSWITCH_CHANNEL_OK_CLIENT(pChannel, logCtx)		\
	(ULTRA_check_channel_client(pChannel, UltraVswitchChannelProtocolGuid, \
				    "vswitch", MIN_IO_CHANNEL_SIZE,	\
				    ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID, \
				    ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE, \
				    __FILE__, __LINE__, logCtx))
#define ULTRA_VSWITCH_CHANNEL_OK_SERVER(actualBytes, logCtx)          \
	(ULTRA_check_channel_server(UltraVswitchChannelProtocolGuid,	\
				    "vswitch", MIN_IO_CHANNEL_SIZE,	\
				    actualBytes,		    \
				    __FILE__, __LINE__, logCtx))
/*
* Everything necessary to handle SCSI & NIC traffic between Guest Partition and
* IO Partition is defined below.  */


/*
* Defines and enums.
*/

#define MINNUM(a, b) (((a) < (b)) ? (a) : (b))
#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b))

/* these define the two queues per data channel between iopart and
 * ioguestparts */
#define IOCHAN_TO_IOPART 0 /* used by ioguestpart to 'insert' signals to
			    * iopart */
#define IOCHAN_FROM_GUESTPART 0 /* used by iopart to 'remove' signals from
				 * ioguestpart - same queue as previous queue */

#define IOCHAN_TO_GUESTPART 1 /* used by iopart to 'insert' signals to
			       * ioguestpart */
#define IOCHAN_FROM_IOPART 1 /* used by ioguestpart to 'remove' signals from
			      * iopart - same queue as previous queue */

/* these define the two queues per control channel between controlpart and "its"
 * guests, which includes the iopart  */
#define CTRLCHAN_TO_CTRLGUESTPART 0 /* used by ctrlguestpart to 'insert' signals
				     * to ctrlpart */
#define CTLRCHAN_FROM_CTRLPART 0 /* used by ctrlpart to 'remove' signals from
				  * ctrlquestpart - same queue as previous
				  * queue */

#define CTRLCHAN_TO_CTRLPART 1 /* used by ctrlpart to 'insert' signals to
				* ctrlguestpart */
#define CTRLCHAN_FROM_CTRLGUESTPART 1 /* used by ctrguestpart to 'remove'
				       * signals from ctrlpart - same queue as
				       * previous queue */

/* these define the Event & Ack queues per control channel Events are generated
* by CTRLGUESTPART and sent to CTRLPART; Acks are generated by CTRLPART and sent
* to CTRLGUESTPART. */
#define CTRLCHAN_EVENT_TO_CTRLPART 2 /* used by ctrlguestpart to 'insert' Events
				      * to ctrlpart */
#define CTRLCHAN_EVENT_FROM_CTRLGUESTPART 2 /* used by ctrlpart to 'remove'
					     * Events from ctrlguestpart */

#define CTRLCHAN_ACK_TO_CTRLGUESTPART 3	/* used by ctrlpart to 'insert' Acks to
					 * ctrlguestpart */
#define CTRLCHAN_ACK_FROM_CTRLPART 3 /* used by ctrlguestpart to 'remove' Events
				      * from ctrlpart */

/* size of cdb - i.e., scsi cmnd */
#define MAX_CMND_SIZE 16

#define MAX_SENSE_SIZE 64

#define MAX_PHYS_INFO 64

/* Because GuestToGuestCopy is limited to 4KiB segments, and we have limited the
* Emulex Driver to 256 scatter list segments via the lpfc_sg_seg_cnt parameter
* to 256, the maximum I/O size is limited to 256 * 4 KiB = 1 MB */
#define MAX_IO_SIZE   (1024*1024)	/* 1 MB */

/* NOTE 1: lpfc defines its support for segments in
* #define LPFC_SG_SEG_CNT 64
*
* NOTE 2: In Linux, frags array in skb is currently allocated to be
* MAX_SKB_FRAGS size, which is 18 which is smaller than MAX_PHYS_INFO for
* now.  */

#ifndef MAX_SERIAL_NUM
#define MAX_SERIAL_NUM		32
#endif				/* MAX_SERIAL_NUM */

#define MAX_SCSI_BUSES		1
#define MAX_SCSI_TARGETS	8
#define MAX_SCSI_LUNS		16
#define MAX_SCSI_FROM_HOST	0xFFFFFFFF	/* Indicator to use Physical HBA
						 * SCSI Host value */

/* various types of network packets that can be sent in cmdrsp */
typedef enum { NET_RCV_POST = 0,	/* submit buffer to hold receiving
					 * incoming packet */
	/* virtnic -> uisnic */
	NET_RCV,		/* incoming packet received */
	/* uisnic -> virtpci */
	NET_XMIT,		/* for outgoing net packets      */
	/* virtnic -> uisnic */
	NET_XMIT_DONE,		/* outgoing packet xmitted */
	/* uisnic -> virtpci */
	NET_RCV_ENBDIS,		/* enable/disable packet reception */
	/* virtnic -> uisnic */
	NET_RCV_ENBDIS_ACK,	/* acknowledge enable/disable packet
				 * reception */
	/* uisnic -> virtnic */
	NET_RCV_PROMISC,	/* enable/disable promiscuous mode */
	/* virtnic -> uisnic */
	NET_CONNECT_STATUS,	/* indicate the loss or restoration of a network
				 * connection */
	/* uisnic -> virtnic */
	NET_MACADDR,		/* indicates the client has requested to update
				 * its MAC addr */
	NET_MACADDR_ACK,	/* MAC address  */

} NET_TYPES;

#define		ETH_HEADER_SIZE 14	/* size of ethernet header */

#define		ETH_MIN_DATA_SIZE 46	/* minimum eth data size */
#define		ETH_MIN_PACKET_SIZE (ETH_HEADER_SIZE + ETH_MIN_DATA_SIZE)

#define     ETH_DEF_DATA_SIZE 1500	/* default data size */
#define     ETH_DEF_PACKET_SIZE (ETH_HEADER_SIZE + ETH_DEF_DATA_SIZE)

#define		ETH_MAX_MTU 16384	/* maximum data size */

#ifndef MAX_MACADDR_LEN
#define MAX_MACADDR_LEN 6	/* number of bytes in MAC address */
#endif				/* MAX_MACADDR_LEN */

#define ETH_IS_LOCALLY_ADMINISTERED(Address) \
	(((u8 *) (Address))[0] & ((u8) 0x02))
#define NIC_VENDOR_ID 0x0008000B

/* various types of scsi task mgmt commands  */
typedef enum { TASK_MGMT_ABORT_TASK =
	    1, TASK_MGMT_BUS_RESET, TASK_MGMT_LUN_RESET,
	    TASK_MGMT_TARGET_RESET,
} TASK_MGMT_TYPES;

/* various types of vdisk mgmt commands  */
typedef enum { VDISK_MGMT_ACQUIRE = 1, VDISK_MGMT_RELEASE,
} VDISK_MGMT_TYPES;

/* this is used in the vdest field  */
#define VDEST_ALL 0xFFFF

#define MIN_NUMSIGNALS 64
#define MAX_NUMSIGNALS 4096

/* MAX_NET_RCV_BUF specifies the number of rcv buffers that are created by each
* guest's virtnic and posted to uisnic.  Uisnic, for each channel, keeps the rcv
* buffers posted and uses them to receive data on behalf of the guest's virtnic.
* NOTE: the num_rcv_bufs is configurable for each VNIC. So the following is
* simply an upperlimit on what each VNIC can provide.  Setting it to half of the
* NUMSIGNALS to prevent queue full deadlocks */
#define MAX_NET_RCV_BUFS (MIN_NUMSIGNALS / 2)

/*
 * structs with pragma pack  */


/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */
/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */

#pragma pack(push, 1)

struct guest_phys_info {
	U64 address;
	U64 length;
};

#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info))

struct uisscsi_dest {
	U32 channel;		/* channel == bus number */
	U32 id;			/* id == target number */
	U32 lun;		/* lun == logical unit number */
};

struct vhba_wwnn {
	U32 wwnn1;
	U32 wwnn2;
};

/* WARNING: Values stired in this structure must contain maximum counts (not
 * maximum values). */
struct vhba_config_max {	/* 20 bytes */
	U32 max_channel;	/* maximum channel for devices attached to this
				 * bus */
	U32 max_id;		/* maximum SCSI ID for devices attached to this
				 * bus */
	U32 max_lun;		/* maximum SCSI LUN for devices attached to this
				 * bus */
	U32 cmd_per_lun;	/* maximum number of outstanding commands per
				 * lun that are allowed at one time */
	U32 max_io_size;	/* maximum io size for devices attached to this
				 * bus */
	/* max io size is often determined by the resource of the hba. e.g */
	/* max scatter gather list length * page size / sector size */
};

struct uiscmdrsp_scsi {
	void *scsicmd;		/* the handle to the cmd that was received -
				 * send it back as is in the rsp packet.  */
	u8 cmnd[MAX_CMND_SIZE];	/* the cdb for the command */
	U32 bufflen;		/* length of data to be transferred out or in */
	u16 guest_phys_entries;	/* Number of entries in scatter-gather (sg)
				 * list */
	struct guest_phys_info gpi_list[MAX_PHYS_INFO];	/* physical address
							 * information for each
							 * fragment */
	enum dma_data_direction  data_dir; /* direction of the data, if any */
	struct uisscsi_dest vdest;	/* identifies the virtual hba, id,
					 * channel, lun to which cmd was sent */

	    /* the following fields are needed to queue the rsp back to cmd
	     * originator */
	int linuxstat;		/* the original Linux status - for use by linux
				 * vdisk code */
	u8 scsistat;		/* the scsi status */
	u8 addlstat;		/* non-scsi status - covers cases like timeout
				 * needed by windows guests */
#define ADDL_RESET		1
#define ADDL_TIMEOUT		2
#define ADDL_INTERNAL_ERROR	3
#define ADDL_SEL_TIMEOUT	4
#define ADDL_CMD_TIMEOUT	5
#define ADDL_BAD_TARGET		6
#define ADDL_RETRY		7

	/* the following fields are need to determine the result of command */
	 u8 sensebuf[MAX_SENSE_SIZE];	/* sense info in case cmd failed; */
	/* it holds the sense_data struct; */
	/* see that struct for details. */
	void *vdisk; /* contains pointer to the vdisk so that we can clean up
		      * when the IO completes. */
	int no_disk_result;	/* used to return no disk inquiry result */
	/* when no_disk_result is set to 1,  */
	/* scsi.scsistat is SAM_STAT_GOOD */
	/* scsi.addlstat is 0 */
	/* scsi.linuxstat is SAM_STAT_GOOD */
	/* That is, there is NO error. */
};

/*
* Defines to support sending correct inquiry result when no disk is
* configured.  */

/* From SCSI SPC2 -
 *
 * If the target is not capable of supporting a device on this logical unit, the
 * device server shall set this field to 7Fh (PERIPHERAL QUALIFIER set to 011b
 * and PERIPHERAL DEVICE TYPE set to 1Fh).
 *
 *The device server is capable of supporting the specified peripheral device
 *type on this logical unit. However, the physical device is not currently
 *connected to this logical unit.
 */

#define DEV_NOT_PRESENT 0x7f	/* old name - compatibility */
#define DEV_NOT_CAPABLE 0x7f	/* peripheral qualifier of 0x3  */
    /* peripheral type of 0x1f */
    /* specifies no device but target present */

#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 /* peripheral qualifier of 0x1 */
    /* peripheral type of 0 - disk */
    /* specifies device capable, but not present */

#define DEV_PROC_CAPABLE_NOT_PRESENT 0x23 /* peripheral qualifier of 0x1 */
    /* peripheral type of 3 - processor */
    /* specifies device capable, but not present */

#define DEV_HISUPPORT 0x10;	/* HiSup = 1; shows support for report luns */
    /* must be returned for lun 0. */

/* NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length
* in buf[4] some linux code accesses bytes beyond 5 to retrieve vendor, product
* & revision.  Yikes! So let us always send back 36 bytes, the minimum for
* inquiry result. */
#define NO_DISK_INQUIRY_RESULT_LEN 36

#define MIN_INQUIRY_RESULT_LEN 5 /* we need at least 5 bytes minimum for inquiry
				  * result */

/* SCSI device version for no disk inquiry result */
#define SCSI_SPC2_VER 4		/* indicates SCSI SPC2 (SPC3 is 5) */

/* Windows and Linux want different things for a non-existent lun. So, we'll let
 * caller pass in the peripheral qualifier and type.
 * NOTE:[4] SCSI returns (n-4); so we return length-1-4 or length-5. */

#define SET_NO_DISK_INQUIRY_RESULT(buf, len, lun, lun0notpresent, notpresent) \
	do {								\
		MEMSET(buf, 0,						\
		       MINNUM(len,					\
			      (unsigned int) NO_DISK_INQUIRY_RESULT_LEN)); \
		buf[2] = (u8) SCSI_SPC2_VER;				\
		if (lun == 0) {						\
			buf[0] = (u8) lun0notpresent;			\
			buf[3] = (u8) DEV_HISUPPORT;			\
		} else							\
			buf[0] = (u8) notpresent;			\
		buf[4] = (u8) (						\
			MINNUM(len,					\
			       (unsigned int) NO_DISK_INQUIRY_RESULT_LEN) - 5);	\
		if (len >= NO_DISK_INQUIRY_RESULT_LEN) {		\
			buf[8] = 'D';					\
			buf[9] = 'E';					\
			buf[10] = 'L';					\
			buf[11] = 'L';					\
			buf[16] = 'P';					\
			buf[17] = 'S';					\
			buf[18] = 'E';					\
			buf[19] = 'U';					\
			buf[20] = 'D';					\
			buf[21] = 'O';					\
			buf[22] = ' ';					\
			buf[23] = 'D';					\
			buf[24] = 'E';					\
			buf[25] = 'V';					\
			buf[26] = 'I';					\
			buf[27] = 'C';					\
			buf[28] = 'E';					\
			buf[30] = ' ';					\
			buf[31] = '.';					\
		}							\
	} while (0)


/*
* Struct & Defines to support sense information.
*/


/* The following struct is returned in sensebuf field in uiscmdrsp_scsi.  It is
* initialized in exactly the manner that is recommended in Windows (hence the
* odd values).
* When set, these fields will have the following values:
* ErrorCode = 0x70		indicates current error
* Valid = 1			indicates sense info is valid
* SenseKey			contains sense key as defined by SCSI specs.
* AdditionalSenseCode		contains sense key as defined by SCSI specs.
* AdditionalSenseCodeQualifier	contains qualifier to sense code as defined by
*				scsi docs.
* AdditionalSenseLength		contains will be sizeof(sense_data)-8=10.
*/
struct sense_data {
	u8 ErrorCode:7;
	u8 Valid:1;
	u8 SegmentNumber;
	u8 SenseKey:4;
	u8 Reserved:1;
	u8 IncorrectLength:1;
	u8 EndOfMedia:1;
	u8 FileMark:1;
	u8 Information[4];
	u8 AdditionalSenseLength;
	u8 CommandSpecificInformation[4];
	u8 AdditionalSenseCode;
	u8 AdditionalSenseCodeQualifier;
	u8 FieldReplaceableUnitCode;
	u8 SenseKeySpecific[3];
};

/* some SCSI ADSENSE codes */
#ifndef SCSI_ADSENSE_LUN_NOT_READY
#define SCSI_ADSENSE_LUN_NOT_READY 0x04
#endif	/*  */
#ifndef SCSI_ADSENSE_ILLEGAL_COMMAND
#define SCSI_ADSENSE_ILLEGAL_COMMAND 0x20
#endif	/*  */
#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK
#endif	/*  */
#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK
#define SCSI_ADSENSE_ILLEGAL_BLOCK  0x21
#endif	/*  */
#ifndef SCSI_ADSENSE_INVALID_CDB
#define SCSI_ADSENSE_INVALID_CDB    0x24
#endif	/*  */
#ifndef SCSI_ADSENSE_INVALID_LUN
#define SCSI_ADSENSE_INVALID_LUN    0x25
#endif	/*  */
#ifndef SCSI_ADWRITE_PROTECT
#define SCSI_ADWRITE_PROTECT        0x27
#endif	/*  */
#ifndef SCSI_ADSENSE_MEDIUM_CHANGED
#define SCSI_ADSENSE_MEDIUM_CHANGED 0x28
#endif	/*  */
#ifndef SCSI_ADSENSE_BUS_RESET
#define SCSI_ADSENSE_BUS_RESET      0x29
#endif	/*  */
#ifndef SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 0x3a
#endif	/*  */

struct net_pkt_xmt {
	int len;	/* full length of data in the packet */
	int num_frags;	/* number of fragments in frags containing data */
	struct phys_info frags[MAX_PHYS_INFO];	/* physical page information for
						 * each fragment */
	char ethhdr[ETH_HEADER_SIZE];	/* the ethernet header  */
	struct {

		    /* these are needed for csum at uisnic end */
		u8 valid;	/* 1 = rest of this struct is valid - else
				 * ignore */
		u8 hrawoffv;	/* 1 = hwrafoff is valid */
		u8 nhrawoffv;	/* 1 = nhwrafoff is valid */
		u16 protocol;	/* specifies packet protocol */
		U32 csum;	/* value used to set skb->csum at IOPart */
		U32 hrawoff;	/* value used to set skb->h.raw at IOPart */
		/* hrawoff points to the start of the TRANSPORT LAYER HEADER */
		U32 nhrawoff;	/* value used to set skb->nh.raw at IOPart */
		/* nhrawoff points to the start of the NETWORK LAYER HEADER */
	} lincsum;

	    /* **** NOTE ****
	     * The full packet is described in frags but the ethernet header is
	     * separately kept in ethhdr so that uisnic doesn't have "MAP" the
	     * guest memory to get to the header. uisnic needs ethhdr to
	     * determine how to route the packet.
	     */
};

struct net_pkt_xmtdone {
	U32 xmt_done_result;	/* result of NET_XMIT */
#define XMIT_SUCCESS 0
#define XMIT_FAILED 1
};

/* RCVPOST_BUF_SIZe must be at most page_size(4096) - cache_line_size (64) The
* reason is because dev_skb_alloc which is used to generate RCV_POST skbs in
* virtnic requires that there is "overhead" in the buffer, and pads 16 bytes.  I
* prefer to use 1 full cache line size for "overhead" so that transfers are
* better.  IOVM requires that a buffer be represented by 1 phys_info structure
* which can only cover page_size. */
#define RCVPOST_BUF_SIZE 4032
#define MAX_NET_RCV_CHAIN \
	((ETH_MAX_MTU+ETH_HEADER_SIZE + RCVPOST_BUF_SIZE-1) / RCVPOST_BUF_SIZE)

struct net_pkt_rcvpost {
	    /* rcv buf size must be large enough to include ethernet data len +
	    * ethernet header len - we are choosing 2K because it is guaranteed
	    * to be describable */
	    struct phys_info frag;	/* physical page information for the
					 * single fragment 2K rcv buf */
	    U64 UniqueNum;		/* This is used to make sure that
					 * receive posts are returned to  */
	    /* the Adapter which sent them origonally. */
};

struct net_pkt_rcv {

	/* the number of receive buffers that can be chained  */
	/* is based on max mtu and size of each rcv buf */
	U32 rcv_done_len;	/* length of received data */
	u8 numrcvbufs;		/* number of receive buffers that contain the */
	/* incoming data; guest end MUST chain these together. */
	void *rcvbuf[MAX_NET_RCV_CHAIN];	/* the list of receive buffers
						 * that must be chained; */
	/* each entry is a receive buffer provided by NET_RCV_POST. */
	/* NOTE: first rcvbuf in the chain will also be provided in net.buf. */
	U64 UniqueNum;
	U32 RcvsDroppedDelta;
};

struct net_pkt_enbdis {
	void *context;
	u16 enable;		/* 1 = enable, 0 = disable */
};

struct net_pkt_macaddr {
	void *context;
	u8 macaddr[MAX_MACADDR_LEN];	/* 6 bytes */
};

/* cmd rsp packet used for VNIC network traffic  */
struct uiscmdrsp_net {
	NET_TYPES type;
	void *buf;
	union {
		struct net_pkt_xmt xmt;	/* used for NET_XMIT */
		struct net_pkt_xmtdone xmtdone;	/* used for NET_XMIT_DONE */
		struct net_pkt_rcvpost rcvpost;	/* used for NET_RCV_POST */
		struct net_pkt_rcv rcv;	/* used for NET_RCV */
		struct net_pkt_enbdis enbdis;	/* used for NET_RCV_ENBDIS, */
		/* NET_RCV_ENBDIS_ACK,  */
		/* NET_RCV_PROMSIC, */
		/* and NET_CONNECT_STATUS */
		struct net_pkt_macaddr macaddr;
	};
};

struct uiscmdrsp_scsitaskmgmt {
	TASK_MGMT_TYPES tasktype;

	    /* the type of task */
	struct uisscsi_dest vdest;

	    /* the vdisk for which this task mgmt is generated */
	void *scsicmd;

	    /* This is some handle that the guest has saved off for its own use.
	    * Its value is preserved by iopart & returned as is in the task mgmt
	    * rsp. */
	void *notify;

	    /* For linux guests, this is a pointer to wait_queue_head that a
	    * thread is waiting on to see if the taskmgmt command has completed.
	    * For windows guests, this is a pointer to a location that a waiting
	    * thread is testing to see if the taskmgmt command has completed.
	    * When the rsp is received by guest, the thread receiving the
	    * response uses this to notify the the thread waiting for taskmgmt
	    * command completion.  Its value is preserved by iopart & returned
	    * as is in the task mgmt rsp. */
	void *notifyresult;

	    /* this is a handle to location in guest where the result of the
	    * taskmgmt command (result field) is to saved off when the response
	    * is handled.  Its value is preserved by iopart & returned as is in
	    * the task mgmt rsp. */
	char result;

	    /* result of taskmgmt command - set by IOPart - values are: */
#define TASK_MGMT_FAILED  0
#define TASK_MGMT_SUCCESS 1
};

/* The following is used by uissd to send disk add/remove notifications to
 * Guest */
/* Note that the vHba pointer is not used by the Client/Guest side. */
struct uiscmdrsp_disknotify {
	u8 add;		/* 0-remove, 1-add */
	void *vHba;		/* Pointer to vhba_info for channel info to
				 * route msg */
	U32 channel, id, lun;	/* SCSI Path of Disk to added or removed */
};

/* The following is used by virthba/vSCSI to send the Acquire/Release commands
* to the IOVM.  */
struct uiscmdrsp_vdiskmgmt {
	VDISK_MGMT_TYPES vdisktype;

	    /* the type of task */
	struct uisscsi_dest vdest;

	    /* the vdisk for which this task mgmt is generated */
	void *scsicmd;

	    /* This is some handle that the guest has saved off for its own use.
	    * Its value is preserved by iopart & returned as is in the task mgmt
	    * rsp. */
	void *notify;

	    /* For linux guests, this is a pointer to wait_queue_head that a
	    * thread is waiting on to see if the taskmgmt command has completed.
	    * For windows guests, this is a pointer to a location that a waiting
	    * thread is testing to see if the taskmgmt command has completed.
	    * When the rsp is received by guest, the thread receiving the
	    * response uses this to notify the the thread waiting for taskmgmt
	    * command completion.  Its value is preserved by iopart & returned
	    * as is in the task mgmt rsp. */
	void *notifyresult;

	    /* this is a handle to location in guest where the result of the
	    * taskmgmt command (result field) is to saved off when the response
	    * is handled.  Its value is preserved by iopart & returned as is in
	    * the task mgmt rsp. */
	char result;

	    /* result of taskmgmt command - set by IOPart - values are: */
#define VDISK_MGMT_FAILED  0
#define VDISK_MGMT_SUCCESS 1
};

/* keeping cmd & rsp info in one structure for now cmd rsp packet for scsi */
struct uiscmdrsp {
	char cmdtype;

	    /* describes what type of information is in the struct */
#define CMD_SCSI_TYPE		1
#define CMD_NET_TYPE		2
#define CMD_SCSITASKMGMT_TYPE	3
#define CMD_NOTIFYGUEST_TYPE	4
#define CMD_VDISKMGMT_TYPE	5
	union {
		struct uiscmdrsp_scsi scsi;
		struct uiscmdrsp_net net;
		struct uiscmdrsp_scsitaskmgmt scsitaskmgmt;
		struct uiscmdrsp_disknotify disknotify;
		struct uiscmdrsp_vdiskmgmt vdiskmgmt;
	};
	void *private_data;	/* used to send the response when the cmd is
				 * done (scsi & scsittaskmgmt).  */
	struct uiscmdrsp *next;	/* General Purpose Queue Link */
	struct uiscmdrsp *activeQ_next;	/* Used to track active commands */
	struct uiscmdrsp *activeQ_prev;	/* Used to track active commands  */
};

/* This is just the header of the IO channel.  It is assumed that directly after
* this header there is a large region of memory which contains the command and
* response queues as specified in cmdQ and rspQ SIGNAL_QUEUE_HEADERS. */
typedef struct _ULTRA_IO_CHANNEL_PROTOCOL {
	CHANNEL_HEADER ChannelHeader;
	SIGNAL_QUEUE_HEADER cmdQ;
	SIGNAL_QUEUE_HEADER rspQ;
	union {
		struct {
			struct vhba_wwnn wwnn;	/* 8 bytes */
			struct vhba_config_max max;	/* 20 bytes */
		} vhba;		/* 28 */
		struct {
			u8 macaddr[MAX_MACADDR_LEN];	/* 6 bytes */
			U32 num_rcv_bufs;	/* 4 */
			U32 mtu;	/* 4 */
			uuid_le zoneGuid;	/* 16 */
		} vnic;		/* total     30 */
	};

#define MAX_CLIENTSTRING_LEN 1024
	 u8 clientString[MAX_CLIENTSTRING_LEN];	/* NULL terminated - so holds
						 * max - 1 bytes */
} ULTRA_IO_CHANNEL_PROTOCOL;

#pragma pack(pop)
/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */

/* define offsets to members of struct uiscmdrsp */
#define OFFSET_CMDTYPE OFFSETOF(struct uiscmdrsp, cmdtype)
#define OFFSET_SCSI OFFSETOF(struct uiscmdrsp, scsi)
#define OFFSET_NET OFFSETOF(struct uiscmdrsp, net)
#define OFFSET_SCSITASKMGMT OFFSETOF(struct uiscmdrsp, scsitaskmgmt)
#define OFFSET_NEXT OFFSETOF(struct uiscmdrsp, next)

/* define offsets to members of struct uiscmdrsp_net */
#define OFFSET_TYPE OFFSETOF(struct uiscmdrsp_net, type)
#define OFFSET_BUF OFFSETOF(struct uiscmdrsp_net, buf)
#define OFFSET_XMT OFFSETOF(struct uiscmdrsp_net, xmt)
#define OFFSET_XMT_DONE_RESULT OFFSETOF(struct uiscmdrsp_net, xmtdone)
#define OFFSET_RCVPOST OFFSETOF(struct uiscmdrsp_net, rcvpost)
#define OFFSET_RCV_DONE_LEN OFFSETOF(struct uiscmdrsp_net, rcv)
#define OFFSET_ENBDIS OFFSETOF(struct uiscmdrsp_net, enbdis)

/* define offsets to members of struct net_pkt_rcvpost */
#define OFFSET_TOTALLEN OFFSETOF(struct net_pkt_rcvpost, totallen)
#define	OFFSET_FRAG OFFSETOF(struct net_pkt_rcvpost, frag)

/*
* INLINE functions for initializing and accessing I/O data channels
*/


#define NUMSIGNALS(x, q) (((ULTRA_IO_CHANNEL_PROTOCOL *)(x))->q.MaxSignalSlots)
#define SIZEOF_PROTOCOL (COVER(sizeof(ULTRA_IO_CHANNEL_PROTOCOL), 64))
#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64))

#define IO_CHANNEL_SIZE(x) COVER(SIZEOF_PROTOCOL + \
				 (NUMSIGNALS(x, cmdQ) + \
				  NUMSIGNALS(x, rspQ)) * SIZEOF_CMDRSP, 4096)
#define MIN_IO_CHANNEL_SIZE COVER(SIZEOF_PROTOCOL + \
				  2 * MIN_NUMSIGNALS * SIZEOF_CMDRSP, 4096)
#ifdef __GNUC__
/* These defines should only ever be used in service partitons */
/* because they rely on the size of uiscmdrsp */
#define QSLOTSFROMBYTES(bytes) (((bytes-SIZEOF_PROTOCOL)/2)/SIZEOF_CMDRSP)
#define QSIZEFROMBYTES(bytes) (QSLOTSFROMBYTES(bytes)*SIZEOF_CMDRSP)
#define SignalQInit(x)						\
	do {							\
		x->cmdQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size);	\
		x->cmdQ.oSignalBase = SIZEOF_PROTOCOL -			\
			OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ);	\
		x->cmdQ.SignalSize = SIZEOF_CMDRSP;			\
		x->cmdQ.MaxSignalSlots =				\
			QSLOTSFROMBYTES(x->ChannelHeader.Size);		\
		x->cmdQ.MaxSignals = x->cmdQ.MaxSignalSlots - 1;	\
		x->rspQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size);	\
		x->rspQ.oSignalBase =					\
			(SIZEOF_PROTOCOL + x->cmdQ.Size) -		\
			OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, rspQ);	\
		x->rspQ.SignalSize = SIZEOF_CMDRSP;			\
		x->rspQ.MaxSignalSlots =				\
			QSLOTSFROMBYTES(x->ChannelHeader.Size);		\
		x->rspQ.MaxSignals = x->rspQ.MaxSignalSlots - 1;	\
		x->ChannelHeader.oChannelSpace =			\
			OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ);	\
	} while (0)

#define INIT_CLIENTSTRING(chan, type, clientStr, clientStrLen)	\
	do {								\
		if (clientStr) {					\
			chan->ChannelHeader.oClientString =		\
				OFFSETOF(type, clientString);		\
			MEMCPY(chan->clientString, clientStr,		\
			       MINNUM(clientStrLen,			\
				      (U32) (MAX_CLIENTSTRING_LEN - 1))); \
			chan->clientString[MINNUM(clientStrLen,		\
						  (U32) (MAX_CLIENTSTRING_LEN \
							 - 1))]		\
				= '\0';					\
		}							\
		else							\
			if (clientStrLen > 0)				\
				return 0;				\
	} while (0)


#define ULTRA_IO_CHANNEL_SERVER_READY(x, chanId, logCtx) \
	ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, CHANNELSRV_READY, \
					logCtx);

#define ULTRA_IO_CHANNEL_SERVER_NOTREADY(x, chanId, logCtx)	\
	ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, \
					CHANNELSRV_UNINITIALIZED, logCtx);

static inline int ULTRA_VHBA_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x,
					      struct vhba_wwnn *wwnn,
					      struct vhba_config_max *max,
					      unsigned char *clientStr,
					      U32 clientStrLen, U64 bytes)  {
	MEMSET(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL));
	x->ChannelHeader.VersionId = ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID;
	x->ChannelHeader.Signature = ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE;
	x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED;
	x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader);
	x->ChannelHeader.Size = COVER(bytes, 4096);
	x->ChannelHeader.Type = UltraVhbaChannelProtocolGuid;
	x->ChannelHeader.ZoneGuid = NULL_UUID_LE;
	x->vhba.wwnn = *wwnn;
	x->vhba.max = *max;
	INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr,
			  clientStrLen);
	SignalQInit(x);
	if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) ||
	     (x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) {
		return 0;
	}
	if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) ||
	     (x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) {
		return 0;
	}
	return 1;
}

static inline void ULTRA_VHBA_set_max(ULTRA_IO_CHANNEL_PROTOCOL *x,
				      struct vhba_config_max *max)  {
	x->vhba.max = *max;
}

static inline int ULTRA_VNIC_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x,
						 unsigned char *macaddr,
						 U32 num_rcv_bufs, U32 mtu,
						 uuid_le zoneGuid,
						 unsigned char *clientStr,
						 U32 clientStrLen,
						 U64 bytes)  {
	MEMSET(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL));
	x->ChannelHeader.VersionId = ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID;
	x->ChannelHeader.Signature = ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE;
	x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED;
	x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader);
	x->ChannelHeader.Size = COVER(bytes, 4096);
	x->ChannelHeader.Type = UltraVnicChannelProtocolGuid;
	x->ChannelHeader.ZoneGuid = NULL_UUID_LE;
	MEMCPY(x->vnic.macaddr, macaddr, MAX_MACADDR_LEN);
	x->vnic.num_rcv_bufs = num_rcv_bufs;
	x->vnic.mtu = mtu;
	x->vnic.zoneGuid = zoneGuid;
	INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr,
			   clientStrLen);
	SignalQInit(x);
	if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) ||
	     (x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) {
		return 0;
	}
	if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) ||
	     (x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) {
		return 0;
	}
	return 1;
}

#endif	/* __GNUC__ */

/*
* INLINE function for expanding a guest's pfn-off-size into multiple 4K page
* pfn-off-size entires.
*/


/* we deal with 4K page sizes when we it comes to passing page information
 * between */
/* Guest and IOPartition. */
#define PI_PAGE_SIZE  0x1000
#define PI_PAGE_MASK  0x0FFF
#define PI_PAGE_SHIFT 12

/* returns next non-zero index on success or zero on failure (i.e. out of
 * room)
 */
static INLINE  u16
add_physinfo_entries(U32 inp_pfn,	/* input - specifies the pfn to be used
					 * to add entries */
		     u16 inp_off,	/* input - specifies the off to be used
					 * to add entries */
		     U32 inp_len,	/* input - specifies the len to be used
					 * to add entries */
		     u16 index,		/* input - index in array at which new
					 * entries are added */
		     u16 max_pi_arr_entries,	/* input - specifies the maximum
						 * entries pi_arr can hold */
		     struct phys_info pi_arr[]) /* input & output - array to
						  * which entries are added */
{
	U32 len;
	u16 i, firstlen;

	firstlen = PI_PAGE_SIZE - inp_off;
	if (inp_len <= firstlen) {

		/* the input entry spans only one page - add as is */
		if (index >= max_pi_arr_entries)
			return 0;
		pi_arr[index].pi_pfn = inp_pfn;
		pi_arr[index].pi_off = (u16) inp_off;
		pi_arr[index].pi_len = (u16) inp_len;
		    return index + 1;
	}

	    /* this entry spans multiple pages */
	    for (len = inp_len, i = 0; len;
		 len -= pi_arr[index + i].pi_len, i++) {
		if (index + i >= max_pi_arr_entries)
			return 0;
		pi_arr[index + i].pi_pfn = inp_pfn + i;
		if (i == 0) {
			pi_arr[index].pi_off = inp_off;
			pi_arr[index].pi_len = firstlen;
		}

		else {
			pi_arr[index + i].pi_off = 0;
			pi_arr[index + i].pi_len =
			    (u16) MINNUM(len, (U32) PI_PAGE_SIZE);
		}

	}
	return index + i;
}

#endif				/* __IOCHANNEL_H__ */