summaryrefslogtreecommitdiff
path: root/drivers/scsi/elx/efct/efct_hw.h
blob: 7440461a58c8b9567c5f613494ce775c6f5058b0 (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
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
 */

#ifndef _EFCT_HW_H
#define _EFCT_HW_H

#include "../libefc_sli/sli4.h"

/*
 * EFCT PCI IDs
 */
#define EFCT_VENDOR_ID			0x10df
/* LightPulse 16Gb x 4 FC (lancer-g6) */
#define EFCT_DEVICE_LANCER_G6		0xe307
/* LightPulse 32Gb x 4 FC (lancer-g7) */
#define EFCT_DEVICE_LANCER_G7		0xf407

/*Default RQ entries len used by driver*/
#define EFCT_HW_RQ_ENTRIES_MIN		512
#define EFCT_HW_RQ_ENTRIES_DEF		1024
#define EFCT_HW_RQ_ENTRIES_MAX		4096

/*Defines the size of the RQ buffers used for each RQ*/
#define EFCT_HW_RQ_SIZE_HDR             128
#define EFCT_HW_RQ_SIZE_PAYLOAD         1024

/*Define the maximum number of multi-receive queues*/
#define EFCT_HW_MAX_MRQS		8

/*
 * Define count of when to set the WQEC bit in a submitted
 * WQE, causing a consummed/released completion to be posted.
 */
#define EFCT_HW_WQEC_SET_COUNT		32

/*Send frame timeout in seconds*/
#define EFCT_HW_SEND_FRAME_TIMEOUT	10

/*
 * FDT Transfer Hint value, reads greater than this value
 * will be segmented to implement fairness. A value of zero disables
 * the feature.
 */
#define EFCT_HW_FDT_XFER_HINT		8192

#define EFCT_HW_TIMECHECK_ITERATIONS	100
#define EFCT_HW_MAX_NUM_MQ		1
#define EFCT_HW_MAX_NUM_RQ		32
#define EFCT_HW_MAX_NUM_EQ		16
#define EFCT_HW_MAX_NUM_WQ		32
#define EFCT_HW_DEF_NUM_EQ		1

#define OCE_HW_MAX_NUM_MRQ_PAIRS	16

#define EFCT_HW_MQ_DEPTH		128
#define EFCT_HW_EQ_DEPTH		1024

/*
 * A CQ will be assinged to each WQ
 * (CQ must have 2X entries of the WQ for abort
 * processing), plus a separate one for each RQ PAIR and one for MQ
 */
#define EFCT_HW_MAX_NUM_CQ \
	((EFCT_HW_MAX_NUM_WQ * 2) + 1 + (OCE_HW_MAX_NUM_MRQ_PAIRS * 2))

#define EFCT_HW_Q_HASH_SIZE		128
#define EFCT_HW_RQ_HEADER_SIZE		128
#define EFCT_HW_RQ_HEADER_INDEX		0

#define EFCT_HW_REQUE_XRI_REGTAG	65534

/* Options for efct_hw_command() */
enum efct_cmd_opts {
	/* command executes synchronously and busy-waits for completion */
	EFCT_CMD_POLL,
	/* command executes asynchronously. Uses callback */
	EFCT_CMD_NOWAIT,
};

enum efct_hw_reset {
	EFCT_HW_RESET_FUNCTION,
	EFCT_HW_RESET_FIRMWARE,
	EFCT_HW_RESET_MAX
};

enum efct_hw_topo {
	EFCT_HW_TOPOLOGY_AUTO,
	EFCT_HW_TOPOLOGY_NPORT,
	EFCT_HW_TOPOLOGY_LOOP,
	EFCT_HW_TOPOLOGY_NONE,
	EFCT_HW_TOPOLOGY_MAX
};

/* pack fw revision values into a single uint64_t */
#define HW_FWREV(a, b, c, d) (((uint64_t)(a) << 48) | ((uint64_t)(b) << 32) \
			| ((uint64_t)(c) << 16) | ((uint64_t)(d)))

#define EFCT_FW_VER_STR(a, b, c, d) (#a "." #b "." #c "." #d)

enum efct_hw_io_type {
	EFCT_HW_ELS_REQ,
	EFCT_HW_ELS_RSP,
	EFCT_HW_FC_CT,
	EFCT_HW_FC_CT_RSP,
	EFCT_HW_BLS_ACC,
	EFCT_HW_BLS_RJT,
	EFCT_HW_IO_TARGET_READ,
	EFCT_HW_IO_TARGET_WRITE,
	EFCT_HW_IO_TARGET_RSP,
	EFCT_HW_IO_DNRX_REQUEUE,
	EFCT_HW_IO_MAX,
};

enum efct_hw_io_state {
	EFCT_HW_IO_STATE_FREE,
	EFCT_HW_IO_STATE_INUSE,
	EFCT_HW_IO_STATE_WAIT_FREE,
	EFCT_HW_IO_STATE_WAIT_SEC_HIO,
};

#define EFCT_TARGET_WRITE_SKIPS	1
#define EFCT_TARGET_READ_SKIPS	2

struct efct_hw;
struct efct_io;

#define EFCT_CMD_CTX_POOL_SZ	32
/**
 * HW command context.
 * Stores the state for the asynchronous commands sent to the hardware.
 */
struct efct_command_ctx {
	struct list_head	list_entry;
	int (*cb)(struct efct_hw *hw, int status, u8 *mqe, void *arg);
	void			*arg;	/* Argument for callback */
	/* buffer holding command / results */
	u8			buf[SLI4_BMBX_SIZE];
	void			*ctx;	/* upper layer context */
};

struct efct_hw_sgl {
	uintptr_t		addr;
	size_t			len;
};

union efct_hw_io_param_u {
	struct sli_bls_params bls;
	struct sli_els_params els;
	struct sli_ct_params fc_ct;
	struct sli_fcp_tgt_params fcp_tgt;
};

/* WQ steering mode */
enum efct_hw_wq_steering {
	EFCT_HW_WQ_STEERING_CLASS,
	EFCT_HW_WQ_STEERING_REQUEST,
	EFCT_HW_WQ_STEERING_CPU,
};

/* HW wqe object */
struct efct_hw_wqe {
	struct list_head	list_entry;
	bool			abort_wqe_submit_needed;
	bool			send_abts;
	u32			id;
	u32			abort_reqtag;
	u8			*wqebuf;
};

struct efct_hw_io;
/* Typedef for HW "done" callback */
typedef int (*efct_hw_done_t)(struct efct_hw_io *, u32 len, int status,
			      u32 ext, void *ul_arg);

/**
 * HW IO object.
 *
 * Stores the per-IO information necessary
 * for both SLI and efct.
 * @ref:		reference counter for hw io object
 * @state:		state of IO: free, busy, wait_free
 * @list_entry		used for busy, wait_free, free lists
 * @wqe			Work queue object, with link for pending
 * @hw			pointer back to hardware context
 * @xfer_rdy		transfer ready data
 * @type		IO type
 * @xbusy		Exchange is active in FW
 * @abort_in_progress	if TRUE, abort is in progress
 * @status_saved	if TRUE, latched status should be returned
 * @wq_class		WQ class if steering mode is Class
 * @reqtag		request tag for this HW IO
 * @wq			WQ assigned to the exchange
 * @done		Function called on IO completion
 * @arg			argument passed to IO done callback
 * @abort_done		Function called on abort completion
 * @abort_arg		argument passed to abort done callback
 * @wq_steering		WQ steering mode request
 * @saved_status	Saved status
 * @saved_len		Status length
 * @saved_ext		Saved extended status
 * @eq			EQ on which this HIO came up
 * @sge_offset		SGE data offset
 * @def_sgl_count	Count of SGEs in default SGL
 * @abort_reqtag	request tag for an abort of this HW IO
 * @indicator		Exchange indicator
 * @def_sgl		default SGL
 * @sgl			pointer to current active SGL
 * @sgl_count		count of SGEs in io->sgl
 * @first_data_sge	index of first data SGE
 * @n_sge		number of active SGEs
 */
struct efct_hw_io {
	struct kref		ref;
	enum efct_hw_io_state	state;
	void			(*release)(struct kref *arg);
	struct list_head	list_entry;
	struct efct_hw_wqe	wqe;

	struct efct_hw		*hw;
	struct efc_dma		xfer_rdy;
	u16			type;
	bool			xbusy;
	bool			abort_in_progress;
	bool			status_saved;
	u8			wq_class;
	u16			reqtag;

	struct hw_wq		*wq;
	efct_hw_done_t		done;
	void			*arg;
	efct_hw_done_t		abort_done;
	void			*abort_arg;

	enum efct_hw_wq_steering wq_steering;

	u32			saved_status;
	u32			saved_len;
	u32			saved_ext;

	struct hw_eq		*eq;
	u32			sge_offset;
	u32			def_sgl_count;
	u32			abort_reqtag;
	u32			indicator;
	struct efc_dma		def_sgl;
	struct efc_dma		*sgl;
	u32			sgl_count;
	u32			first_data_sge;
	u32			n_sge;
};

enum efct_hw_port {
	EFCT_HW_PORT_INIT,
	EFCT_HW_PORT_SHUTDOWN,
};

/* Node group rpi reference */
struct efct_hw_rpi_ref {
	atomic_t rpi_count;
	atomic_t rpi_attached;
};

enum efct_hw_link_stat {
	EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT,
	EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT,
	EFCT_HW_LINK_STAT_LOSS_OF_SIGNAL_COUNT,
	EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT,
	EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT,
	EFCT_HW_LINK_STAT_CRC_COUNT,
	EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_TIMEOUT_COUNT,
	EFCT_HW_LINK_STAT_ELASTIC_BUFFER_OVERRUN_COUNT,
	EFCT_HW_LINK_STAT_ARB_TIMEOUT_COUNT,
	EFCT_HW_LINK_STAT_ADVERTISED_RCV_B2B_CREDIT,
	EFCT_HW_LINK_STAT_CURR_RCV_B2B_CREDIT,
	EFCT_HW_LINK_STAT_ADVERTISED_XMIT_B2B_CREDIT,
	EFCT_HW_LINK_STAT_CURR_XMIT_B2B_CREDIT,
	EFCT_HW_LINK_STAT_RCV_EOFA_COUNT,
	EFCT_HW_LINK_STAT_RCV_EOFDTI_COUNT,
	EFCT_HW_LINK_STAT_RCV_EOFNI_COUNT,
	EFCT_HW_LINK_STAT_RCV_SOFF_COUNT,
	EFCT_HW_LINK_STAT_RCV_DROPPED_NO_AER_COUNT,
	EFCT_HW_LINK_STAT_RCV_DROPPED_NO_RPI_COUNT,
	EFCT_HW_LINK_STAT_RCV_DROPPED_NO_XRI_COUNT,
	EFCT_HW_LINK_STAT_MAX,
};

enum efct_hw_host_stat {
	EFCT_HW_HOST_STAT_TX_KBYTE_COUNT,
	EFCT_HW_HOST_STAT_RX_KBYTE_COUNT,
	EFCT_HW_HOST_STAT_TX_FRAME_COUNT,
	EFCT_HW_HOST_STAT_RX_FRAME_COUNT,
	EFCT_HW_HOST_STAT_TX_SEQ_COUNT,
	EFCT_HW_HOST_STAT_RX_SEQ_COUNT,
	EFCT_HW_HOST_STAT_TOTAL_EXCH_ORIG,
	EFCT_HW_HOST_STAT_TOTAL_EXCH_RESP,
	EFCT_HW_HOSY_STAT_RX_P_BSY_COUNT,
	EFCT_HW_HOST_STAT_RX_F_BSY_COUNT,
	EFCT_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_RQ_BUF_COUNT,
	EFCT_HW_HOST_STAT_EMPTY_RQ_TIMEOUT_COUNT,
	EFCT_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_XRI_COUNT,
	EFCT_HW_HOST_STAT_EMPTY_XRI_POOL_COUNT,
	EFCT_HW_HOST_STAT_MAX,
};

enum efct_hw_state {
	EFCT_HW_STATE_UNINITIALIZED,
	EFCT_HW_STATE_QUEUES_ALLOCATED,
	EFCT_HW_STATE_ACTIVE,
	EFCT_HW_STATE_RESET_IN_PROGRESS,
	EFCT_HW_STATE_TEARDOWN_IN_PROGRESS,
};

struct efct_hw_link_stat_counts {
	u8		overflow;
	u32		counter;
};

struct efct_hw_host_stat_counts {
	u32		counter;
};

/* Structure used for the hash lookup of queue IDs */
struct efct_queue_hash {
	bool		in_use;
	u16		id;
	u16		index;
};

/* WQ callback object */
struct hw_wq_callback {
	u16		instance_index;	/* use for request tag */
	void (*callback)(void *arg, u8 *cqe, int status);
	void		*arg;
	struct list_head list_entry;
};

struct reqtag_pool {
	spinlock_t lock;	/* pool lock */
	struct hw_wq_callback *tags[U16_MAX];
	struct list_head freelist;
};

struct efct_hw_config {
	u32		n_eq;
	u32		n_cq;
	u32		n_mq;
	u32		n_rq;
	u32		n_wq;
	u32		n_io;
	u32		n_sgl;
	u32		speed;
	u32		topology;
	/* size of the buffers for first burst */
	u32		rq_default_buffer_size;
	u8		esoc;
	/* MRQ RQ selection policy */
	u8		rq_selection_policy;
	/* RQ quanta if rq_selection_policy == 2 */
	u8		rr_quanta;
	u32		filter_def[SLI4_CMD_REG_FCFI_NUM_RQ_CFG];
};

struct efct_hw {
	struct efct		*os;
	struct sli4		sli;
	u16			ulp_start;
	u16			ulp_max;
	u32			dump_size;
	enum efct_hw_state	state;
	bool			hw_setup_called;
	u8			sliport_healthcheck;
	u16			fcf_indicator;

	/* HW configuration */
	struct efct_hw_config	config;

	/* calculated queue sizes for each type */
	u32			num_qentries[SLI4_QTYPE_MAX];

	/* Storage for SLI queue objects */
	struct sli4_queue	wq[EFCT_HW_MAX_NUM_WQ];
	struct sli4_queue	rq[EFCT_HW_MAX_NUM_RQ];
	u16			hw_rq_lookup[EFCT_HW_MAX_NUM_RQ];
	struct sli4_queue	mq[EFCT_HW_MAX_NUM_MQ];
	struct sli4_queue	cq[EFCT_HW_MAX_NUM_CQ];
	struct sli4_queue	eq[EFCT_HW_MAX_NUM_EQ];

	/* HW queue */
	u32			eq_count;
	u32			cq_count;
	u32			mq_count;
	u32			wq_count;
	u32			rq_count;
	u32			cmd_head_count;
	struct list_head	eq_list;

	struct efct_queue_hash	cq_hash[EFCT_HW_Q_HASH_SIZE];
	struct efct_queue_hash	rq_hash[EFCT_HW_Q_HASH_SIZE];
	struct efct_queue_hash	wq_hash[EFCT_HW_Q_HASH_SIZE];

	/* Storage for HW queue objects */
	struct hw_wq		*hw_wq[EFCT_HW_MAX_NUM_WQ];
	struct hw_rq		*hw_rq[EFCT_HW_MAX_NUM_RQ];
	struct hw_mq		*hw_mq[EFCT_HW_MAX_NUM_MQ];
	struct hw_cq		*hw_cq[EFCT_HW_MAX_NUM_CQ];
	struct hw_eq		*hw_eq[EFCT_HW_MAX_NUM_EQ];
	/* count of hw_rq[] entries */
	u32			hw_rq_count;
	/* count of multirq RQs */
	u32			hw_mrq_count;

	struct hw_wq		**wq_cpu_array;

	/* Sequence objects used in incoming frame processing */
	struct efc_hw_sequence	*seq_pool;

	/* Maintain an ordered, linked list of outstanding HW commands. */
	struct mutex            bmbx_lock;
	spinlock_t		cmd_lock;
	struct list_head	cmd_head;
	struct list_head	cmd_pending;
	mempool_t		*cmd_ctx_pool;
	mempool_t		*mbox_rqst_pool;

	struct sli4_link_event	link;

	/* pointer array of IO objects */
	struct efct_hw_io	**io;
	/* array of WQE buffs mapped to IO objects */
	u8			*wqe_buffs;

	/* IO lock to synchronize list access */
	spinlock_t		io_lock;
	/* List of IO objects in use */
	struct list_head	io_inuse;
	/* List of IO objects waiting to be freed */
	struct list_head	io_wait_free;
	/* List of IO objects available for allocation */
	struct list_head	io_free;

	struct efc_dma		loop_map;

	struct efc_dma		xfer_rdy;

	struct efc_dma		rnode_mem;

	atomic_t		io_alloc_failed_count;

	/* stat: wq sumbit count */
	u32			tcmd_wq_submit[EFCT_HW_MAX_NUM_WQ];
	/* stat: wq complete count */
	u32			tcmd_wq_complete[EFCT_HW_MAX_NUM_WQ];

	atomic_t		send_frame_seq_id;
	struct reqtag_pool	*wq_reqtag_pool;
};

enum efct_hw_io_count_type {
	EFCT_HW_IO_INUSE_COUNT,
	EFCT_HW_IO_FREE_COUNT,
	EFCT_HW_IO_WAIT_FREE_COUNT,
	EFCT_HW_IO_N_TOTAL_IO_COUNT,
};

/* HW queue data structures */
struct hw_eq {
	struct list_head	list_entry;
	enum sli4_qtype		type;
	u32			instance;
	u32			entry_count;
	u32			entry_size;
	struct efct_hw		*hw;
	struct sli4_queue	*queue;
	struct list_head	cq_list;
	u32			use_count;
};

struct hw_cq {
	struct list_head	list_entry;
	enum sli4_qtype		type;
	u32			instance;
	u32			entry_count;
	u32			entry_size;
	struct hw_eq		*eq;
	struct sli4_queue	*queue;
	struct list_head	q_list;
	u32			use_count;
};

struct hw_q {
	struct list_head	list_entry;
	enum sli4_qtype		type;
};

struct hw_mq {
	struct list_head	list_entry;
	enum sli4_qtype		type;
	u32			instance;

	u32			entry_count;
	u32			entry_size;
	struct hw_cq		*cq;
	struct sli4_queue	*queue;

	u32			use_count;
};

struct hw_wq {
	struct list_head	list_entry;
	enum sli4_qtype		type;
	u32			instance;
	struct efct_hw		*hw;

	u32			entry_count;
	u32			entry_size;
	struct hw_cq		*cq;
	struct sli4_queue	*queue;
	u32			class;

	/* WQ consumed */
	u32			wqec_set_count;
	u32			wqec_count;
	u32			free_count;
	u32			total_submit_count;
	struct list_head	pending_list;

	/* HW IO allocated for use with Send Frame */
	struct efct_hw_io	*send_frame_io;

	/* Stats */
	u32			use_count;
	u32			wq_pending_count;
};

struct hw_rq {
	struct list_head	list_entry;
	enum sli4_qtype		type;
	u32			instance;

	u32			entry_count;
	u32			use_count;
	u32			hdr_entry_size;
	u32			first_burst_entry_size;
	u32			data_entry_size;
	bool			is_mrq;
	u32			base_mrq_id;

	struct hw_cq		*cq;

	u8			filter_mask;
	struct sli4_queue	*hdr;
	struct sli4_queue	*first_burst;
	struct sli4_queue	*data;

	struct efc_hw_rq_buffer	*hdr_buf;
	struct efc_hw_rq_buffer	*fb_buf;
	struct efc_hw_rq_buffer	*payload_buf;
	/* RQ tracker for this RQ */
	struct efc_hw_sequence	**rq_tracker;
};

struct efct_hw_send_frame_context {
	struct efct_hw		*hw;
	struct hw_wq_callback	*wqcb;
	struct efct_hw_wqe	wqe;
	void (*callback)(int status, void *arg);
	void			*arg;

	/* General purpose elements */
	struct efc_hw_sequence	*seq;
	struct efc_dma		payload;
};

struct efct_hw_grp_hdr {
	u32			size;
	__be32			magic_number;
	u32			word2;
	u8			rev_name[128];
	u8			date[12];
	u8			revision[32];
};

static inline int
efct_hw_get_link_speed(struct efct_hw *hw) {
	return hw->link.speed;
}

int
efct_hw_setup(struct efct_hw *hw, void *os, struct pci_dev *pdev);
int efct_hw_init(struct efct_hw *hw);
int
efct_hw_parse_filter(struct efct_hw *hw, void *value);
int
efct_hw_init_queues(struct efct_hw *hw);
int
efct_hw_map_wq_cpu(struct efct_hw *hw);
uint64_t
efct_get_wwnn(struct efct_hw *hw);
uint64_t
efct_get_wwpn(struct efct_hw *hw);

#endif /* __EFCT_H__ */