sli4.c revision 331766
1/*-
2 * Copyright (c) 2017 Broadcom. All rights reserved.
3 * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 *    this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 *    this list of conditions and the following disclaimer in the documentation
13 *    and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * $FreeBSD: head/sys/dev/ocs_fc/sli4.c 331766 2018-03-30 15:28:25Z ken $
32 */
33
34/**
35 * @defgroup sli SLI-4 Base APIs
36 */
37
38/**
39 * @file
40 * All common (i.e. transport-independent) SLI-4 functions are implemented
41 * in this file.
42 */
43
44#include "sli4.h"
45
46#if defined(OCS_INCLUDE_DEBUG)
47#include "ocs_utils.h"
48#endif
49
50#define SLI4_BMBX_DELAY_US 1000 /* 1 ms */
51#define SLI4_INIT_PORT_DELAY_US 10000 /* 10 ms */
52
53static int32_t sli_fw_init(sli4_t *);
54static int32_t sli_fw_term(sli4_t *);
55static int32_t sli_sliport_control(sli4_t *sli4, uint32_t endian);
56static int32_t sli_cmd_fw_deinitialize(sli4_t *, void *, size_t);
57static int32_t sli_cmd_fw_initialize(sli4_t *, void *, size_t);
58static int32_t sli_queue_doorbell(sli4_t *, sli4_queue_t *);
59static uint8_t sli_queue_entry_is_valid(sli4_queue_t *, uint8_t *, uint8_t);
60
61const uint8_t sli4_fw_initialize[] = {
62	0xff, 0x12, 0x34, 0xff,
63	0xff, 0x56, 0x78, 0xff,
64};
65
66const uint8_t sli4_fw_deinitialize[] = {
67	0xff, 0xaa, 0xbb, 0xff,
68	0xff, 0xcc, 0xdd, 0xff,
69};
70
71typedef struct {
72	uint32_t rev_id;
73	uint32_t family;	/* generation */
74	sli4_asic_type_e type;
75	sli4_asic_rev_e rev;
76} sli4_asic_entry_t;
77
78sli4_asic_entry_t sli4_asic_table[] = {
79	{	0x00,	1,	SLI4_ASIC_TYPE_BE3,	SLI4_ASIC_REV_A0},
80	{	0x01,	1,	SLI4_ASIC_TYPE_BE3,	SLI4_ASIC_REV_A1},
81	{	0x02,	1,	SLI4_ASIC_TYPE_BE3,	SLI4_ASIC_REV_A2},
82	{	0x00,	4,	SLI4_ASIC_TYPE_SKYHAWK,	SLI4_ASIC_REV_A0},
83	{	0x00,	2,	SLI4_ASIC_TYPE_SKYHAWK,	SLI4_ASIC_REV_A0},
84	{	0x10,	1,	SLI4_ASIC_TYPE_BE3,	SLI4_ASIC_REV_B0},
85	{	0x10,	0x04,	SLI4_ASIC_TYPE_SKYHAWK,	SLI4_ASIC_REV_B0},
86	{	0x11,	0x04,	SLI4_ASIC_TYPE_SKYHAWK,	SLI4_ASIC_REV_B1},
87	{	0x0,	0x0a,	SLI4_ASIC_TYPE_LANCER,	SLI4_ASIC_REV_A0},
88	{	0x10,	0x0b,	SLI4_ASIC_TYPE_LANCER,	SLI4_ASIC_REV_B0},
89	{	0x30,	0x0b,	SLI4_ASIC_TYPE_LANCER,	SLI4_ASIC_REV_D0},
90	{	0x3,	0x0b,	SLI4_ASIC_TYPE_LANCERG6,SLI4_ASIC_REV_A3},
91	{	0x0,	0x0c,	SLI4_ASIC_TYPE_LANCERG6,SLI4_ASIC_REV_A0},
92	{	0x1,	0x0c,	SLI4_ASIC_TYPE_LANCERG6,SLI4_ASIC_REV_A1},
93	{	0x3,	0x0c,	SLI4_ASIC_TYPE_LANCERG6,SLI4_ASIC_REV_A3},
94
95	{	0x00,	0x05,	SLI4_ASIC_TYPE_CORSAIR,	SLI4_ASIC_REV_A0},
96};
97
98/*
99 * @brief Convert queue type enum (SLI_QTYPE_*) into a string.
100 */
101const char *SLI_QNAME[] = {
102	"Event Queue",
103	"Completion Queue",
104	"Mailbox Queue",
105	"Work Queue",
106	"Receive Queue",
107	"Undefined"
108};
109
110/**
111 * @brief Define the mapping of registers to their BAR and offset.
112 *
113 * @par Description
114 * Although SLI-4 specification defines a common set of registers, their locations
115 * (both BAR and offset) depend on the interface type. This array maps a register
116 * enum to an array of BAR/offset pairs indexed by the interface type. For
117 * example, to access the bootstrap mailbox register on an interface type 0
118 * device, code can refer to the offset using regmap[SLI4_REG_BMBX][0].offset.
119 *
120 * @b Note: A value of UINT32_MAX for either the register set (rset) or offset (off)
121 * indicates an invalid mapping.
122 */
123const sli4_reg_t regmap[SLI4_REG_MAX][SLI4_MAX_IF_TYPES] = {
124	/* SLI4_REG_BMBX */
125	{
126		{ 2, SLI4_BMBX_REG }, { 0, SLI4_BMBX_REG }, { 0, SLI4_BMBX_REG }, { 0, SLI4_BMBX_REG },
127	},
128	/* SLI4_REG_EQCQ_DOORBELL */
129	{
130		{ 2, SLI4_EQCQ_DOORBELL_REG }, { 0, SLI4_EQCQ_DOORBELL_REG },
131		{ 0, SLI4_EQCQ_DOORBELL_REG }, { 0, SLI4_EQCQ_DOORBELL_REG },
132	},
133	/* SLI4_REG_FCOE_RQ_DOORBELL */
134	{
135		{ 2, SLI4_RQ_DOORBELL_REG }, { 0, SLI4_RQ_DOORBELL_REG },
136		{ 0, SLI4_RQ_DOORBELL_REG }, { UINT32_MAX, UINT32_MAX },
137	},
138	/* SLI4_REG_IO_WQ_DOORBELL */
139	{
140		{ 2, SLI4_IO_WQ_DOORBELL_REG }, { 0, SLI4_IO_WQ_DOORBELL_REG }, { 0, SLI4_IO_WQ_DOORBELL_REG }, { UINT32_MAX, UINT32_MAX },
141	},
142	/* SLI4_REG_MQ_DOORBELL */
143	{
144		{ 2, SLI4_MQ_DOORBELL_REG }, { 0, SLI4_MQ_DOORBELL_REG },
145		{ 0, SLI4_MQ_DOORBELL_REG }, { 0, SLI4_MQ_DOORBELL_REG },
146	},
147	/* SLI4_REG_PHYSDEV_CONTROL */
148	{
149		{ UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { 0, SLI4_PHSDEV_CONTROL_REG_23 }, { 0, SLI4_PHSDEV_CONTROL_REG_23 },
150	},
151	/* SLI4_REG_SLIPORT_CONTROL */
152	{
153		{ UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { 0, SLI4_SLIPORT_CONTROL_REG }, { UINT32_MAX, UINT32_MAX },
154	},
155	/* SLI4_REG_SLIPORT_ERROR1 */
156	{
157		{ UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { 0, SLI4_SLIPORT_ERROR1 }, { UINT32_MAX, UINT32_MAX },
158	},
159	/* SLI4_REG_SLIPORT_ERROR2 */
160	{
161		{ UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { 0, SLI4_SLIPORT_ERROR2 }, { UINT32_MAX, UINT32_MAX },
162	},
163	/* SLI4_REG_SLIPORT_SEMAPHORE */
164	{
165		{ 1, SLI4_PORT_SEMAPHORE_REG_0 },  { 0, SLI4_PORT_SEMAPHORE_REG_1 },
166		{ 0, SLI4_PORT_SEMAPHORE_REG_23 }, { 0, SLI4_PORT_SEMAPHORE_REG_23 },
167	},
168	/* SLI4_REG_SLIPORT_STATUS */
169	{
170		{ UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { 0, SLI4_PORT_STATUS_REG_23 }, { 0, SLI4_PORT_STATUS_REG_23 },
171	},
172	/* SLI4_REG_UERR_MASK_HI */
173	{
174		{ 0, SLI4_UERR_MASK_HIGH_REG }, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX },
175	},
176	/* SLI4_REG_UERR_MASK_LO */
177	{
178		{ 0, SLI4_UERR_MASK_LOW_REG }, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX },
179	},
180	/* SLI4_REG_UERR_STATUS_HI */
181	{
182		{ 0, SLI4_UERR_STATUS_HIGH_REG }, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX },
183	},
184	/* SLI4_REG_UERR_STATUS_LO */
185	{
186		{ 0, SLI4_UERR_STATUS_LOW_REG }, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX },
187	},
188	/* SLI4_REG_SW_UE_CSR1 */
189	{
190		{ 1, SLI4_SW_UE_CSR1}, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX },
191	},
192	/* SLI4_REG_SW_UE_CSR2 */
193	{
194		{ 1, SLI4_SW_UE_CSR2}, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX }, { UINT32_MAX, UINT32_MAX },
195	},
196};
197
198/**
199 * @brief Read the given SLI register.
200 *
201 * @param sli Pointer to the SLI context.
202 * @param reg Register name enum.
203 *
204 * @return Returns the register value.
205 */
206uint32_t
207sli_reg_read(sli4_t *sli, sli4_regname_e reg)
208{
209	const sli4_reg_t	*r = &(regmap[reg][sli->if_type]);
210
211	if ((UINT32_MAX == r->rset) || (UINT32_MAX == r->off)) {
212		ocs_log_err(sli->os, "regname %d not defined for if_type %d\n", reg, sli->if_type);
213		return UINT32_MAX;
214	}
215
216	return ocs_reg_read32(sli->os, r->rset, r->off);
217}
218
219/**
220 * @brief Write the value to the given SLI register.
221 *
222 * @param sli Pointer to the SLI context.
223 * @param reg Register name enum.
224 * @param val Value to write.
225 *
226 * @return None.
227 */
228void
229sli_reg_write(sli4_t *sli, sli4_regname_e reg, uint32_t val)
230{
231	const sli4_reg_t	*r = &(regmap[reg][sli->if_type]);
232
233	if ((UINT32_MAX == r->rset) || (UINT32_MAX == r->off)) {
234		ocs_log_err(sli->os, "regname %d not defined for if_type %d\n", reg, sli->if_type);
235		return;
236	}
237
238	ocs_reg_write32(sli->os, r->rset, r->off, val);
239}
240
241/**
242 * @brief Check if the SLI_INTF register is valid.
243 *
244 * @param val 32-bit SLI_INTF register value.
245 *
246 * @return Returns 0 on success, or a non-zero value on failure.
247 */
248static uint8_t
249sli_intf_valid_check(uint32_t val)
250{
251	return ((val >> SLI4_INTF_VALID_SHIFT) & SLI4_INTF_VALID_MASK) != SLI4_INTF_VALID;
252}
253
254/**
255 * @brief Retrieve the SLI revision level.
256 *
257 * @param val 32-bit SLI_INTF register value.
258 *
259 * @return Returns the SLI revision level.
260 */
261static uint8_t
262sli_intf_sli_revision(uint32_t val)
263{
264	return ((val >> SLI4_INTF_SLI_REVISION_SHIFT) & SLI4_INTF_SLI_REVISION_MASK);
265}
266
267static uint8_t
268sli_intf_sli_family(uint32_t val)
269{
270	return ((val >> SLI4_INTF_SLI_FAMILY_SHIFT) & SLI4_INTF_SLI_FAMILY_MASK);
271}
272
273/**
274 * @brief Retrieve the SLI interface type.
275 *
276 * @param val 32-bit SLI_INTF register value.
277 *
278 * @return Returns the SLI interface type.
279 */
280static uint8_t
281sli_intf_if_type(uint32_t val)
282{
283	return ((val >> SLI4_INTF_IF_TYPE_SHIFT) & SLI4_INTF_IF_TYPE_MASK);
284}
285
286/**
287 * @brief Retrieve PCI revision ID.
288 *
289 * @param val 32-bit PCI CLASS_REVISION register value.
290 *
291 * @return Returns the PCI revision ID.
292 */
293static uint8_t
294sli_pci_rev_id(uint32_t val)
295{
296	return ((val >> SLI4_PCI_REV_ID_SHIFT) & SLI4_PCI_REV_ID_MASK);
297}
298
299/**
300 * @brief retrieve SLI ASIC generation
301 *
302 * @param val 32-bit SLI_ASIC_ID register value
303 *
304 * @return SLI ASIC generation
305 */
306static uint8_t
307sli_asic_gen(uint32_t val)
308{
309	return ((val >> SLI4_ASIC_GEN_SHIFT) & SLI4_ASIC_GEN_MASK);
310}
311
312/**
313 * @brief Wait for the bootstrap mailbox to report "ready".
314 *
315 * @param sli4 SLI context pointer.
316 * @param msec Number of milliseconds to wait.
317 *
318 * @return Returns 0 if BMBX is ready, or non-zero otherwise (i.e. time out occurred).
319 */
320static int32_t
321sli_bmbx_wait(sli4_t *sli4, uint32_t msec)
322{
323	uint32_t	val = 0;
324
325	do {
326		ocs_udelay(SLI4_BMBX_DELAY_US);
327		val = sli_reg_read(sli4, SLI4_REG_BMBX);
328		msec--;
329	} while(msec && !(val & SLI4_BMBX_RDY));
330
331	return(!(val & SLI4_BMBX_RDY));
332}
333
334/**
335 * @brief Write bootstrap mailbox.
336 *
337 * @param sli4 SLI context pointer.
338 *
339 * @return Returns 0 if command succeeded, or non-zero otherwise.
340 */
341static int32_t
342sli_bmbx_write(sli4_t *sli4)
343{
344	uint32_t	val = 0;
345
346	/* write buffer location to bootstrap mailbox register */
347	ocs_dma_sync(&sli4->bmbx, OCS_DMASYNC_PREWRITE);
348	val = SLI4_BMBX_WRITE_HI(sli4->bmbx.phys);
349	sli_reg_write(sli4, SLI4_REG_BMBX, val);
350
351	if (sli_bmbx_wait(sli4, SLI4_BMBX_DELAY_US)) {
352		ocs_log_crit(sli4->os, "BMBX WRITE_HI failed\n");
353		return -1;
354	}
355	val = SLI4_BMBX_WRITE_LO(sli4->bmbx.phys);
356	sli_reg_write(sli4, SLI4_REG_BMBX, val);
357
358	/* wait for SLI Port to set ready bit */
359	return sli_bmbx_wait(sli4, SLI4_BMBX_TIMEOUT_MSEC/*XXX*/);
360}
361
362#if defined(OCS_INCLUDE_DEBUG)
363/**
364 * @ingroup sli
365 * @brief Dump BMBX mailbox command.
366 *
367 * @par Description
368 * Convenience function for dumping BMBX mailbox commands. Takes
369 * into account which mailbox command is given since SLI_CONFIG
370 * commands are special.
371 *
372 * @b Note: This function takes advantage of
373 * the one-command-at-a-time nature of the BMBX to be able to
374 * display non-embedded SLI_CONFIG commands. This will not work
375 * for mailbox commands on the MQ. Luckily, all current non-emb
376 * mailbox commands go through the BMBX.
377 *
378 * @param sli4 SLI context pointer.
379 * @param mbx Pointer to mailbox command to dump.
380 * @param prefix Prefix for dump label.
381 *
382 * @return None.
383 */
384static void
385sli_dump_bmbx_command(sli4_t *sli4, void *mbx, const char *prefix)
386{
387	uint32_t size = 0;
388	char label[64];
389	uint32_t i;
390	/* Mailbox diagnostic logging */
391	sli4_mbox_command_header_t *hdr = (sli4_mbox_command_header_t *)mbx;
392
393	if (!ocs_debug_is_enabled(OCS_DEBUG_ENABLE_MQ_DUMP)) {
394		return;
395	}
396
397	if (hdr->command == SLI4_MBOX_COMMAND_SLI_CONFIG) {
398		sli4_cmd_sli_config_t *sli_config = (sli4_cmd_sli_config_t *)hdr;
399		sli4_req_hdr_t	*sli_config_hdr;
400		if (sli_config->emb) {
401			ocs_snprintf(label, sizeof(label), "%s (emb)", prefix);
402
403			/*  if embedded, dump entire command */
404			sli_config_hdr = (sli4_req_hdr_t *)sli_config->payload.embed;
405			size = sizeof(*sli_config) - sizeof(sli_config->payload) +
406				sli_config_hdr->request_length + (4*sizeof(uint32_t));
407			ocs_dump32(OCS_DEBUG_ENABLE_MQ_DUMP, sli4->os, label,
408				   (uint8_t *)sli4->bmbx.virt, size);
409		} else {
410			sli4_sli_config_pmd_t *pmd;
411			ocs_snprintf(label, sizeof(label), "%s (non-emb hdr)", prefix);
412
413			/* if non-embedded, break up into two parts: SLI_CONFIG hdr
414			   and the payload(s) */
415			size = sizeof(*sli_config) - sizeof(sli_config->payload) + (12 * sli_config->pmd_count);
416			ocs_dump32(OCS_DEBUG_ENABLE_MQ_DUMP, sli4->os, label,
417				   (uint8_t *)sli4->bmbx.virt, size);
418
419			/* as sanity check, make sure first PMD matches what was saved */
420			pmd = &sli_config->payload.mem;
421			if ((pmd->address_high == ocs_addr32_hi(sli4->bmbx_non_emb_pmd->phys)) &&
422			    (pmd->address_low == ocs_addr32_lo(sli4->bmbx_non_emb_pmd->phys))) {
423				for (i = 0; i < sli_config->pmd_count; i++, pmd++) {
424					sli_config_hdr = sli4->bmbx_non_emb_pmd->virt;
425					ocs_snprintf(label, sizeof(label), "%s (non-emb pay[%d])",
426						     prefix, i);
427					ocs_dump32(OCS_DEBUG_ENABLE_MQ_DUMP, sli4->os, label,
428						   (uint8_t *)sli4->bmbx_non_emb_pmd->virt,
429						   sli_config_hdr->request_length + (4*sizeof(uint32_t)));
430				}
431			} else {
432				ocs_log_debug(sli4->os, "pmd addr does not match pmd:%x %x (%x %x)\n",
433					pmd->address_high, pmd->address_low,
434					ocs_addr32_hi(sli4->bmbx_non_emb_pmd->phys),
435					ocs_addr32_lo(sli4->bmbx_non_emb_pmd->phys));
436			}
437
438		}
439	} else {
440		/* not an SLI_CONFIG command, just display first 64 bytes, like we do
441		   for MQEs */
442		size = 64;
443		ocs_dump32(OCS_DEBUG_ENABLE_MQ_DUMP, sli4->os, prefix,
444			   (uint8_t *)mbx, size);
445	}
446}
447#endif
448
449/**
450 * @ingroup sli
451 * @brief Submit a command to the bootstrap mailbox and check the status.
452 *
453 * @param sli4 SLI context pointer.
454 *
455 * @return Returns 0 on success, or a non-zero value on failure.
456 */
457int32_t
458sli_bmbx_command(sli4_t *sli4)
459{
460	void *cqe = (uint8_t *)sli4->bmbx.virt + SLI4_BMBX_SIZE;
461
462#if defined(OCS_INCLUDE_DEBUG)
463	sli_dump_bmbx_command(sli4, sli4->bmbx.virt, "bmbx cmd");
464#endif
465
466	if (sli_fw_error_status(sli4) > 0) {
467		ocs_log_crit(sli4->os, "Chip is in an error state - Mailbox "
468			"command rejected status=%#x error1=%#x error2=%#x\n",
469			sli_reg_read(sli4, SLI4_REG_SLIPORT_STATUS),
470			sli_reg_read(sli4, SLI4_REG_SLIPORT_ERROR1),
471			sli_reg_read(sli4, SLI4_REG_SLIPORT_ERROR2));
472		return -1;
473	}
474
475	if (sli_bmbx_write(sli4)) {
476		ocs_log_crit(sli4->os, "bootstrap mailbox write fail phys=%p reg=%#x\n",
477			(void*)sli4->bmbx.phys,
478			sli_reg_read(sli4, SLI4_REG_BMBX));
479		return -1;
480	}
481
482	/* check completion queue entry status */
483	ocs_dma_sync(&sli4->bmbx, OCS_DMASYNC_POSTREAD);
484	if (((sli4_mcqe_t *)cqe)->val) {
485#if defined(OCS_INCLUDE_DEBUG)
486		sli_dump_bmbx_command(sli4, sli4->bmbx.virt, "bmbx cmpl");
487        ocs_dump32(OCS_DEBUG_ENABLE_CQ_DUMP, sli4->os, "bmbx cqe", cqe, sizeof(sli4_mcqe_t));
488#endif
489		return sli_cqe_mq(cqe);
490	} else {
491		ocs_log_err(sli4->os, "invalid or wrong type\n");
492		return -1;
493	}
494}
495
496/****************************************************************************
497 * Messages
498 */
499
500/**
501 * @ingroup sli
502 * @brief Write a CONFIG_LINK command to the provided buffer.
503 *
504 * @param sli4 SLI context pointer.
505 * @param buf Virtual pointer to the destination buffer.
506 * @param size Buffer size, in bytes.
507 *
508 * @return Returns the number of bytes written.
509 */
510int32_t
511sli_cmd_config_link(sli4_t *sli4, void *buf, size_t size)
512{
513	sli4_cmd_config_link_t	*config_link = buf;
514
515	ocs_memset(buf, 0, size);
516
517	config_link->hdr.command = SLI4_MBOX_COMMAND_CONFIG_LINK;
518
519	/* Port interprets zero in a field as "use default value" */
520
521	return sizeof(sli4_cmd_config_link_t);
522}
523
524/**
525 * @ingroup sli
526 * @brief Write a DOWN_LINK command to the provided buffer.
527 *
528 * @param sli4 SLI context pointer.
529 * @param buf Virtual pointer to the destination buffer.
530 * @param size Buffer size, in bytes.
531 *
532 * @return Returns the number of bytes written.
533 */
534int32_t
535sli_cmd_down_link(sli4_t *sli4, void *buf, size_t size)
536{
537	sli4_mbox_command_header_t	*hdr = buf;
538
539	ocs_memset(buf, 0, size);
540
541	hdr->command = SLI4_MBOX_COMMAND_DOWN_LINK;
542
543	/* Port interprets zero in a field as "use default value" */
544
545	return sizeof(sli4_mbox_command_header_t);
546}
547
548/**
549 * @ingroup sli
550 * @brief Write a DUMP Type 4 command to the provided buffer.
551 *
552 * @param sli4 SLI context pointer.
553 * @param buf Virtual pointer to the destination buffer.
554 * @param size Buffer size, in bytes.
555 * @param wki The well known item ID.
556 *
557 * @return Returns the number of bytes written.
558 */
559int32_t
560sli_cmd_dump_type4(sli4_t *sli4, void *buf, size_t size, uint16_t wki)
561{
562	sli4_cmd_dump4_t	*cmd = buf;
563
564	ocs_memset(buf, 0, size);
565
566	cmd->hdr.command = SLI4_MBOX_COMMAND_DUMP;
567	cmd->type = 4;
568	cmd->wki_selection = wki;
569	return sizeof(sli4_cmd_dump4_t);
570}
571
572/**
573 * @ingroup sli
574 * @brief Write a COMMON_READ_TRANSCEIVER_DATA command.
575 *
576 * @param sli4 SLI context.
577 * @param buf Destination buffer for the command.
578 * @param size Buffer size, in bytes.
579 * @param page_num The page of SFP data to retrieve (0xa0 or 0xa2).
580 * @param dma DMA structure from which the data will be copied.
581 *
582 * @note This creates a Version 0 message.
583 *
584 * @return Returns the number of bytes written.
585 */
586int32_t
587sli_cmd_common_read_transceiver_data(sli4_t *sli4, void *buf, size_t size, uint32_t page_num,
588				     ocs_dma_t *dma)
589{
590	sli4_req_common_read_transceiver_data_t *req = NULL;
591	uint32_t	sli_config_off = 0;
592	uint32_t	payload_size;
593
594	if (dma == NULL) {
595		/* Payload length must accommodate both request and response */
596		payload_size = max(sizeof(sli4_req_common_read_transceiver_data_t),
597				   sizeof(sli4_res_common_read_transceiver_data_t));
598	} else {
599		payload_size = dma->size;
600	}
601
602	if (sli4->port_type == SLI4_PORT_TYPE_FC) {
603		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size, dma);
604	}
605
606	if (dma == NULL) {
607		req = (sli4_req_common_read_transceiver_data_t *)((uint8_t *)buf + sli_config_off);
608	} else {
609		req = (sli4_req_common_read_transceiver_data_t *)dma->virt;
610		ocs_memset(req, 0, dma->size);
611	}
612
613	req->hdr.opcode = SLI4_OPC_COMMON_READ_TRANSCEIVER_DATA;
614	req->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
615	req->hdr.request_length = payload_size - sizeof(sli4_req_hdr_t);
616
617	req->page_number = page_num;
618	req->port = sli4->physical_port;
619
620	return(sli_config_off + sizeof(sli4_req_common_read_transceiver_data_t));
621}
622
623/**
624 * @ingroup sli
625 * @brief Write a READ_LINK_STAT command to the provided buffer.
626 *
627 * @param sli4 SLI context pointer.
628 * @param buf Virtual pointer to the destination buffer.
629 * @param size Buffer size, in bytes.
630 * @param req_ext_counters If TRUE, then the extended counters will be requested.
631 * @param clear_overflow_flags If TRUE, then overflow flags will be cleared.
632 * @param clear_all_counters If TRUE, the counters will be cleared.
633 *
634 * @return Returns the number of bytes written.
635 */
636int32_t
637sli_cmd_read_link_stats(sli4_t *sli4, void *buf, size_t size,
638			uint8_t req_ext_counters,
639			uint8_t clear_overflow_flags,
640			uint8_t clear_all_counters)
641{
642	sli4_cmd_read_link_stats_t	*cmd = buf;
643
644	ocs_memset(buf, 0, size);
645
646	cmd->hdr.command = SLI4_MBOX_COMMAND_READ_LNK_STAT;
647	cmd->rec = req_ext_counters;
648	cmd->clrc = clear_all_counters;
649	cmd->clof = clear_overflow_flags;
650	return sizeof(sli4_cmd_read_link_stats_t);
651}
652
653/**
654 * @ingroup sli
655 * @brief Write a READ_STATUS command to the provided buffer.
656 *
657 * @param sli4 SLI context pointer.
658 * @param buf Virtual pointer to the destination buffer.
659 * @param size Buffer size, in bytes.
660 * @param clear_counters If TRUE, the counters will be cleared.
661 *
662 * @return Returns the number of bytes written.
663 */
664int32_t
665sli_cmd_read_status(sli4_t *sli4, void *buf, size_t size,
666			uint8_t clear_counters)
667{
668	sli4_cmd_read_status_t	*cmd = buf;
669
670	ocs_memset(buf, 0, size);
671
672	cmd->hdr.command = SLI4_MBOX_COMMAND_READ_STATUS;
673	cmd->cc = clear_counters;
674	return sizeof(sli4_cmd_read_status_t);
675}
676
677/**
678 * @brief Write a FW_DEINITIALIZE command to the provided buffer.
679 *
680 * @param sli4 SLI context pointer.
681 * @param buf Virtual pointer to the destination buffer.
682 * @param size Buffer size, in bytes.
683 *
684 * @return Returns the number of bytes written.
685 */
686static int32_t
687sli_cmd_fw_deinitialize(sli4_t *sli4, void *buf, size_t size)
688{
689
690	ocs_memset(buf, 0, size);
691	ocs_memcpy(buf, sli4_fw_deinitialize, sizeof(sli4_fw_deinitialize));
692
693	return sizeof(sli4_fw_deinitialize);
694}
695
696/**
697 * @brief Write a FW_INITIALIZE command to the provided buffer.
698 *
699 * @param sli4 SLI context pointer.
700 * @param buf Virtual pointer to the destination buffer.
701 * @param size Buffer size, in bytes.
702 *
703 * @return Returns the number of bytes written.
704 */
705static int32_t
706sli_cmd_fw_initialize(sli4_t *sli4, void *buf, size_t size)
707{
708
709	ocs_memset(buf, 0, size);
710	ocs_memcpy(buf, sli4_fw_initialize, sizeof(sli4_fw_initialize));
711
712	return sizeof(sli4_fw_initialize);
713}
714
715/**
716 * @ingroup sli
717 * @brief Write an INIT_LINK command to the provided buffer.
718 *
719 * @param sli4 SLI context pointer.
720 * @param buf Virtual pointer to the destination buffer.
721 * @param size Buffer size, in bytes.
722 * @param speed Link speed.
723 * @param reset_alpa For native FC, this is the selective reset AL_PA
724 *
725 * @return Returns the number of bytes written.
726 */
727int32_t
728sli_cmd_init_link(sli4_t *sli4, void *buf, size_t size, uint32_t speed, uint8_t reset_alpa)
729{
730	sli4_cmd_init_link_t	*init_link = buf;
731
732	ocs_memset(buf, 0, size);
733
734	init_link->hdr.command = SLI4_MBOX_COMMAND_INIT_LINK;
735
736	/* Most fields only have meaning for FC links */
737	if (sli4->config.topology != SLI4_READ_CFG_TOPO_FCOE) {
738		init_link->selective_reset_al_pa = reset_alpa;
739		init_link->link_flags.loopback = FALSE;
740
741		init_link->link_speed_selection_code = speed;
742		switch (speed) {
743		case FC_LINK_SPEED_1G:
744		case FC_LINK_SPEED_2G:
745		case FC_LINK_SPEED_4G:
746		case FC_LINK_SPEED_8G:
747		case FC_LINK_SPEED_16G:
748		case FC_LINK_SPEED_32G:
749			init_link->link_flags.fixed_speed = TRUE;
750			break;
751		case FC_LINK_SPEED_10G:
752			ocs_log_test(sli4->os, "unsupported FC speed %d\n", speed);
753			return 0;
754		}
755
756		switch (sli4->config.topology) {
757		case SLI4_READ_CFG_TOPO_FC:
758			/* Attempt P2P but failover to FC-AL */
759			init_link->link_flags.enable_topology_failover = TRUE;
760
761			if (sli_get_asic_type(sli4) == SLI4_ASIC_TYPE_LANCER)
762				init_link->link_flags.topology = SLI4_INIT_LINK_F_FCAL_FAIL_OVER;
763			else
764				init_link->link_flags.topology = SLI4_INIT_LINK_F_P2P_FAIL_OVER;
765
766			break;
767		case SLI4_READ_CFG_TOPO_FC_AL:
768			init_link->link_flags.topology = SLI4_INIT_LINK_F_FCAL_ONLY;
769			if ((init_link->link_speed_selection_code == FC_LINK_SPEED_16G) ||
770			    (init_link->link_speed_selection_code == FC_LINK_SPEED_32G)) {
771				ocs_log_test(sli4->os, "unsupported FC-AL speed %d\n", speed);
772				return 0;
773			}
774			break;
775		case SLI4_READ_CFG_TOPO_FC_DA:
776			init_link->link_flags.topology = FC_TOPOLOGY_P2P;
777			break;
778		default:
779			ocs_log_test(sli4->os, "unsupported topology %#x\n", sli4->config.topology);
780			return 0;
781		}
782
783		init_link->link_flags.unfair = FALSE;
784		init_link->link_flags.skip_lirp_lilp = FALSE;
785		init_link->link_flags.gen_loop_validity_check = FALSE;
786		init_link->link_flags.skip_lisa = FALSE;
787		init_link->link_flags.select_hightest_al_pa = FALSE;
788	}
789
790	return sizeof(sli4_cmd_init_link_t);
791}
792
793/**
794 * @ingroup sli
795 * @brief Write an INIT_VFI command to the provided buffer.
796 *
797 * @param sli4 SLI context pointer.
798 * @param buf Virtual pointer to the destination buffer.
799 * @param size Buffer size, in bytes.
800 * @param vfi VFI
801 * @param fcfi FCFI
802 * @param vpi VPI (Set to -1 if unused.)
803 *
804 * @return Returns the number of bytes written.
805 */
806int32_t
807sli_cmd_init_vfi(sli4_t *sli4, void *buf, size_t size, uint16_t vfi,
808		uint16_t fcfi, uint16_t vpi)
809{
810	sli4_cmd_init_vfi_t	*init_vfi = buf;
811
812	ocs_memset(buf, 0, size);
813
814	init_vfi->hdr.command = SLI4_MBOX_COMMAND_INIT_VFI;
815
816	init_vfi->vfi = vfi;
817	init_vfi->fcfi = fcfi;
818
819	/*
820	 * If the VPI is valid, initialize it at the same time as
821	 * the VFI
822	 */
823	if (0xffff != vpi) {
824		init_vfi->vp  = TRUE;
825		init_vfi->vpi = vpi;
826	}
827
828	return sizeof(sli4_cmd_init_vfi_t);
829}
830
831/**
832 * @ingroup sli
833 * @brief Write an INIT_VPI command to the provided buffer.
834 *
835 * @param sli4 SLI context pointer.
836 * @param buf Virtual pointer to the destination buffer.
837 * @param size Buffer size, in bytes.
838 * @param vpi VPI allocated.
839 * @param vfi VFI associated with this VPI.
840 *
841 * @return Returns the number of bytes written.
842 */
843int32_t
844sli_cmd_init_vpi(sli4_t *sli4, void *buf, size_t size, uint16_t vpi, uint16_t vfi)
845{
846	sli4_cmd_init_vpi_t	*init_vpi = buf;
847
848	ocs_memset(buf, 0, size);
849
850	init_vpi->hdr.command = SLI4_MBOX_COMMAND_INIT_VPI;
851	init_vpi->vpi = vpi;
852	init_vpi->vfi = vfi;
853
854	return sizeof(sli4_cmd_init_vpi_t);
855}
856
857/**
858 * @ingroup sli
859 * @brief Write a POST_XRI command to the provided buffer.
860 *
861 * @param sli4 SLI context pointer.
862 * @param buf Virtual pointer to the destination buffer.
863 * @param size Buffer size, in bytes.
864 * @param xri_base Starting XRI value for range of XRI given to SLI Port.
865 * @param xri_count Number of XRIs provided to the SLI Port.
866 *
867 * @return Returns the number of bytes written.
868 */
869int32_t
870sli_cmd_post_xri(sli4_t *sli4, void *buf, size_t size,  uint16_t xri_base, uint16_t xri_count)
871{
872	sli4_cmd_post_xri_t	*post_xri = buf;
873
874	ocs_memset(buf, 0, size);
875
876	post_xri->hdr.command = SLI4_MBOX_COMMAND_POST_XRI;
877	post_xri->xri_base = xri_base;
878	post_xri->xri_count = xri_count;
879
880	if (sli4->config.auto_xfer_rdy == 0) {
881		post_xri->enx = TRUE;
882		post_xri->val = TRUE;
883	}
884
885	return sizeof(sli4_cmd_post_xri_t);
886}
887
888/**
889 * @ingroup sli
890 * @brief Write a RELEASE_XRI command to the provided buffer.
891 *
892 * @param sli4 SLI context pointer.
893 * @param buf Virtual pointer to the destination buffer.
894 * @param size Buffer size, in bytes.
895 * @param num_xri The number of XRIs to be released.
896 *
897 * @return Returns the number of bytes written.
898 */
899int32_t
900sli_cmd_release_xri(sli4_t *sli4, void *buf, size_t size,  uint8_t num_xri)
901{
902	sli4_cmd_release_xri_t	*release_xri = buf;
903
904	ocs_memset(buf, 0, size);
905
906	release_xri->hdr.command = SLI4_MBOX_COMMAND_RELEASE_XRI;
907	release_xri->xri_count = num_xri;
908
909	return sizeof(sli4_cmd_release_xri_t);
910}
911
912/**
913 * @brief Write a READ_CONFIG command to the provided buffer.
914 *
915 * @param sli4 SLI context pointer.
916 * @param buf Virtual pointer to the destination buffer.
917 * @param size Buffer size, in bytes
918 *
919 * @return Returns the number of bytes written.
920 */
921static int32_t
922sli_cmd_read_config(sli4_t *sli4, void *buf, size_t size)
923{
924	sli4_cmd_read_config_t	*read_config = buf;
925
926	ocs_memset(buf, 0, size);
927
928	read_config->hdr.command = SLI4_MBOX_COMMAND_READ_CONFIG;
929
930	return sizeof(sli4_cmd_read_config_t);
931}
932
933/**
934 * @brief Write a READ_NVPARMS command to the provided buffer.
935 *
936 * @param sli4 SLI context pointer.
937 * @param buf Virtual pointer to the destination buffer.
938 * @param size Buffer size, in bytes.
939 *
940 * @return Returns the number of bytes written.
941 */
942int32_t
943sli_cmd_read_nvparms(sli4_t *sli4, void *buf, size_t size)
944{
945	sli4_cmd_read_nvparms_t	*read_nvparms = buf;
946
947	ocs_memset(buf, 0, size);
948
949	read_nvparms->hdr.command = SLI4_MBOX_COMMAND_READ_NVPARMS;
950
951	return sizeof(sli4_cmd_read_nvparms_t);
952}
953
954/**
955 * @brief Write a WRITE_NVPARMS command to the provided buffer.
956 *
957 * @param sli4 SLI context pointer.
958 * @param buf Virtual pointer to the destination buffer.
959 * @param size Buffer size, in bytes.
960 * @param wwpn WWPN to write - pointer to array of 8 uint8_t.
961 * @param wwnn WWNN to write - pointer to array of 8 uint8_t.
962 * @param hard_alpa Hard ALPA to write.
963 * @param preferred_d_id  Preferred D_ID to write.
964 *
965 * @return Returns the number of bytes written.
966 */
967int32_t
968sli_cmd_write_nvparms(sli4_t *sli4, void *buf, size_t size, uint8_t *wwpn, uint8_t *wwnn, uint8_t hard_alpa,
969		uint32_t preferred_d_id)
970{
971	sli4_cmd_write_nvparms_t	*write_nvparms = buf;
972
973	ocs_memset(buf, 0, size);
974
975	write_nvparms->hdr.command = SLI4_MBOX_COMMAND_WRITE_NVPARMS;
976	ocs_memcpy(write_nvparms->wwpn, wwpn, 8);
977	ocs_memcpy(write_nvparms->wwnn, wwnn, 8);
978	write_nvparms->hard_alpa = hard_alpa;
979	write_nvparms->preferred_d_id = preferred_d_id;
980
981	return sizeof(sli4_cmd_write_nvparms_t);
982}
983
984/**
985 * @brief Write a READ_REV command to the provided buffer.
986 *
987 * @param sli4 SLI context pointer.
988 * @param buf Virtual pointer to the destination buffer.
989 * @param size Buffer size, in bytes.
990 * @param vpd Pointer to the buffer.
991 *
992 * @return Returns the number of bytes written.
993 */
994static int32_t
995sli_cmd_read_rev(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *vpd)
996{
997	sli4_cmd_read_rev_t	*read_rev = buf;
998
999	ocs_memset(buf, 0, size);
1000
1001	read_rev->hdr.command = SLI4_MBOX_COMMAND_READ_REV;
1002
1003	if (vpd && vpd->size) {
1004		read_rev->vpd = TRUE;
1005
1006		read_rev->available_length = vpd->size;
1007
1008		read_rev->physical_address_low  = ocs_addr32_lo(vpd->phys);
1009		read_rev->physical_address_high = ocs_addr32_hi(vpd->phys);
1010	}
1011
1012	return sizeof(sli4_cmd_read_rev_t);
1013}
1014
1015/**
1016 * @ingroup sli
1017 * @brief Write a READ_SPARM64 command to the provided buffer.
1018 *
1019 * @param sli4 SLI context pointer.
1020 * @param buf Virtual pointer to the destination buffer.
1021 * @param size Buffer size, in bytes.
1022 * @param dma DMA buffer for the service parameters.
1023 * @param vpi VPI used to determine the WWN.
1024 *
1025 * @return Returns the number of bytes written.
1026 */
1027int32_t
1028sli_cmd_read_sparm64(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma,
1029		uint16_t vpi)
1030{
1031	sli4_cmd_read_sparm64_t	*read_sparm64 = buf;
1032
1033	ocs_memset(buf, 0, size);
1034
1035	if (SLI4_READ_SPARM64_VPI_SPECIAL == vpi) {
1036		ocs_log_test(sli4->os, "special VPI not supported!!!\n");
1037		return -1;
1038	}
1039
1040	if (!dma || !dma->phys) {
1041		ocs_log_test(sli4->os, "bad DMA buffer\n");
1042		return -1;
1043	}
1044
1045	read_sparm64->hdr.command = SLI4_MBOX_COMMAND_READ_SPARM64;
1046
1047	read_sparm64->bde_64.bde_type = SLI4_BDE_TYPE_BDE_64;
1048	read_sparm64->bde_64.buffer_length = dma->size;
1049	read_sparm64->bde_64.u.data.buffer_address_low  = ocs_addr32_lo(dma->phys);
1050	read_sparm64->bde_64.u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
1051
1052	read_sparm64->vpi = vpi;
1053
1054	return sizeof(sli4_cmd_read_sparm64_t);
1055}
1056
1057/**
1058 * @ingroup sli
1059 * @brief Write a READ_TOPOLOGY command to the provided buffer.
1060 *
1061 * @param sli4 SLI context pointer.
1062 * @param buf Virtual pointer to the destination buffer.
1063 * @param size Buffer size, in bytes.
1064 * @param dma DMA buffer for loop map (optional).
1065 *
1066 * @return Returns the number of bytes written.
1067 */
1068int32_t
1069sli_cmd_read_topology(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma)
1070{
1071	sli4_cmd_read_topology_t *read_topo = buf;
1072
1073	ocs_memset(buf, 0, size);
1074
1075	read_topo->hdr.command = SLI4_MBOX_COMMAND_READ_TOPOLOGY;
1076
1077	if (dma && dma->size) {
1078		if (dma->size < SLI4_MIN_LOOP_MAP_BYTES) {
1079			ocs_log_test(sli4->os, "loop map buffer too small %jd\n",
1080					dma->size);
1081			return 0;
1082		}
1083
1084		ocs_memset(dma->virt, 0, dma->size);
1085
1086		read_topo->bde_loop_map.bde_type = SLI4_BDE_TYPE_BDE_64;
1087		read_topo->bde_loop_map.buffer_length = dma->size;
1088		read_topo->bde_loop_map.u.data.buffer_address_low  = ocs_addr32_lo(dma->phys);
1089		read_topo->bde_loop_map.u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
1090	}
1091
1092	return sizeof(sli4_cmd_read_topology_t);
1093}
1094
1095/**
1096 * @ingroup sli
1097 * @brief Write a REG_FCFI command to the provided buffer.
1098 *
1099 * @param sli4 SLI context pointer.
1100 * @param buf Virtual pointer to the destination buffer.
1101 * @param size Buffer size, in bytes.
1102 * @param index FCF index returned by READ_FCF_TABLE.
1103 * @param rq_cfg RQ_ID/R_CTL/TYPE routing information
1104 * @param vlan_id VLAN ID tag.
1105 *
1106 * @return Returns the number of bytes written.
1107 */
1108int32_t
1109sli_cmd_reg_fcfi(sli4_t *sli4, void *buf, size_t size, uint16_t index, sli4_cmd_rq_cfg_t rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG], uint16_t vlan_id)
1110{
1111	sli4_cmd_reg_fcfi_t	*reg_fcfi = buf;
1112	uint32_t		i;
1113
1114	ocs_memset(buf, 0, size);
1115
1116	reg_fcfi->hdr.command = SLI4_MBOX_COMMAND_REG_FCFI;
1117
1118	reg_fcfi->fcf_index = index;
1119
1120	for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
1121		switch(i) {
1122		case 0:	reg_fcfi->rq_id_0 = rq_cfg[0].rq_id; break;
1123		case 1:	reg_fcfi->rq_id_1 = rq_cfg[1].rq_id; break;
1124		case 2:	reg_fcfi->rq_id_2 = rq_cfg[2].rq_id; break;
1125		case 3:	reg_fcfi->rq_id_3 = rq_cfg[3].rq_id; break;
1126		}
1127		reg_fcfi->rq_cfg[i].r_ctl_mask = rq_cfg[i].r_ctl_mask;
1128		reg_fcfi->rq_cfg[i].r_ctl_match = rq_cfg[i].r_ctl_match;
1129		reg_fcfi->rq_cfg[i].type_mask = rq_cfg[i].type_mask;
1130		reg_fcfi->rq_cfg[i].type_match = rq_cfg[i].type_match;
1131	}
1132
1133	if (vlan_id) {
1134		reg_fcfi->vv = TRUE;
1135		reg_fcfi->vlan_tag = vlan_id;
1136	}
1137
1138	return sizeof(sli4_cmd_reg_fcfi_t);
1139}
1140
1141/**
1142 * @brief Write REG_FCFI_MRQ to provided command buffer
1143 *
1144 * @param sli4 SLI context pointer.
1145 * @param buf Virtual pointer to the destination buffer.
1146 * @param size Buffer size, in bytes.
1147 * @param fcf_index FCF index returned by READ_FCF_TABLE.
1148 * @param vlan_id VLAN ID tag.
1149 * @param rr_quant Round robin quanta if RQ selection policy is 2
1150 * @param rq_selection_policy RQ selection policy
1151 * @param num_rqs Array of count of RQs per filter
1152 * @param rq_ids Array of RQ ids per filter
1153 * @param rq_cfg RQ_ID/R_CTL/TYPE routing information
1154 *
1155 * @return returns 0 for success, a negative error code value for failure.
1156 */
1157int32_t
1158sli_cmd_reg_fcfi_mrq(sli4_t *sli4, void *buf, size_t size, uint8_t mode,
1159		     uint16_t fcf_index, uint16_t vlan_id, uint8_t rq_selection_policy,
1160		     uint8_t mrq_bit_mask, uint16_t num_mrqs,
1161		     sli4_cmd_rq_cfg_t rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG])
1162{
1163	sli4_cmd_reg_fcfi_mrq_t	*reg_fcfi_mrq = buf;
1164	uint32_t i;
1165
1166	ocs_memset(buf, 0, size);
1167
1168	reg_fcfi_mrq->hdr.command = SLI4_MBOX_COMMAND_REG_FCFI_MRQ;
1169	if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE) {
1170		reg_fcfi_mrq->fcf_index = fcf_index;
1171		if (vlan_id) {
1172			reg_fcfi_mrq->vv = TRUE;
1173			reg_fcfi_mrq->vlan_tag = vlan_id;
1174		}
1175		goto done;
1176	}
1177
1178	reg_fcfi_mrq->mode = mode;
1179	for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
1180		reg_fcfi_mrq->rq_cfg[i].r_ctl_mask = rq_cfg[i].r_ctl_mask;
1181		reg_fcfi_mrq->rq_cfg[i].r_ctl_match = rq_cfg[i].r_ctl_match;
1182		reg_fcfi_mrq->rq_cfg[i].type_mask = rq_cfg[i].type_mask;
1183		reg_fcfi_mrq->rq_cfg[i].type_match = rq_cfg[i].type_match;
1184
1185		switch(i) {
1186		case 3:	reg_fcfi_mrq->rq_id_3 = rq_cfg[i].rq_id; break;
1187		case 2:	reg_fcfi_mrq->rq_id_2 = rq_cfg[i].rq_id; break;
1188		case 1:	reg_fcfi_mrq->rq_id_1 = rq_cfg[i].rq_id; break;
1189		case 0:	reg_fcfi_mrq->rq_id_0 = rq_cfg[i].rq_id; break;
1190		}
1191	}
1192
1193	reg_fcfi_mrq->rq_selection_policy = rq_selection_policy;
1194	reg_fcfi_mrq->mrq_filter_bitmask = mrq_bit_mask;
1195	reg_fcfi_mrq->num_mrq_pairs = num_mrqs;
1196done:
1197	return sizeof(sli4_cmd_reg_fcfi_mrq_t);
1198}
1199
1200/**
1201 * @ingroup sli
1202 * @brief Write a REG_RPI command to the provided buffer.
1203 *
1204 * @param sli4 SLI context pointer.
1205 * @param buf Virtual pointer to the destination buffer.
1206 * @param size Buffer size, in bytes.
1207 * @param nport_id Remote F/N_Port_ID.
1208 * @param rpi Previously-allocated Remote Port Indicator.
1209 * @param vpi Previously-allocated Virtual Port Indicator.
1210 * @param dma DMA buffer that contains the remote port's service parameters.
1211 * @param update Boolean indicating an update to an existing RPI (TRUE)
1212 * or a new registration (FALSE).
1213 *
1214 * @return Returns the number of bytes written.
1215 */
1216int32_t
1217sli_cmd_reg_rpi(sli4_t *sli4, void *buf, size_t size, uint32_t nport_id, uint16_t rpi,
1218			uint16_t vpi, ocs_dma_t *dma, uint8_t update,  uint8_t enable_t10_pi)
1219{
1220	sli4_cmd_reg_rpi_t *reg_rpi = buf;
1221
1222	ocs_memset(buf, 0, size);
1223
1224	reg_rpi->hdr.command = SLI4_MBOX_COMMAND_REG_RPI;
1225
1226	reg_rpi->rpi = rpi;
1227	reg_rpi->remote_n_port_id = nport_id;
1228	reg_rpi->upd = update;
1229	reg_rpi->etow = enable_t10_pi;
1230
1231	reg_rpi->bde_64.bde_type = SLI4_BDE_TYPE_BDE_64;
1232	reg_rpi->bde_64.buffer_length = SLI4_REG_RPI_BUF_LEN;
1233	reg_rpi->bde_64.u.data.buffer_address_low  = ocs_addr32_lo(dma->phys);
1234	reg_rpi->bde_64.u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
1235
1236	reg_rpi->vpi = vpi;
1237
1238	return sizeof(sli4_cmd_reg_rpi_t);
1239}
1240
1241/**
1242 * @ingroup sli
1243 * @brief Write a REG_VFI command to the provided buffer.
1244 *
1245 * @param sli4 SLI context pointer.
1246 * @param buf Virtual pointer to the destination buffer.
1247 * @param size Buffer size, in bytes.
1248 * @param domain Pointer to the domain object.
1249 *
1250 * @return Returns the number of bytes written.
1251 */
1252int32_t
1253sli_cmd_reg_vfi(sli4_t *sli4, void *buf, size_t size, ocs_domain_t *domain)
1254{
1255	sli4_cmd_reg_vfi_t	*reg_vfi = buf;
1256
1257	if (!sli4 || !buf || !domain) {
1258		return 0;
1259	}
1260
1261	ocs_memset(buf, 0, size);
1262
1263	reg_vfi->hdr.command = SLI4_MBOX_COMMAND_REG_VFI;
1264
1265	reg_vfi->vfi = domain->indicator;
1266
1267	reg_vfi->fcfi = domain->fcf_indicator;
1268
1269	/* TODO contents of domain->dma only valid if topo == FABRIC */
1270	reg_vfi->sparm.bde_type = SLI4_BDE_TYPE_BDE_64;
1271	reg_vfi->sparm.buffer_length = 0x70;
1272	reg_vfi->sparm.u.data.buffer_address_low  = ocs_addr32_lo(domain->dma.phys);
1273	reg_vfi->sparm.u.data.buffer_address_high = ocs_addr32_hi(domain->dma.phys);
1274
1275	reg_vfi->e_d_tov = sli4->config.e_d_tov;
1276	reg_vfi->r_a_tov = sli4->config.r_a_tov;
1277
1278	reg_vfi->vp = TRUE;
1279	reg_vfi->vpi = domain->sport->indicator;
1280	ocs_memcpy(reg_vfi->wwpn, &domain->sport->sli_wwpn, sizeof(reg_vfi->wwpn));
1281	reg_vfi->local_n_port_id = domain->sport->fc_id;
1282
1283	return sizeof(sli4_cmd_reg_vfi_t);
1284}
1285
1286/**
1287 * @ingroup sli
1288 * @brief Write a REG_VPI command to the provided buffer.
1289 *
1290 * @param sli4 SLI context pointer.
1291 * @param buf Virtual pointer to the destination buffer.
1292 * @param size Buffer size, in bytes.
1293 * @param sport Point to SLI Port object.
1294 * @param update Boolean indicating whether to update the existing VPI (true)
1295 * or create a new VPI (false).
1296 *
1297 * @return Returns the number of bytes written.
1298 */
1299int32_t
1300sli_cmd_reg_vpi(sli4_t *sli4, void *buf, size_t size, ocs_sli_port_t *sport, uint8_t update)
1301{
1302	sli4_cmd_reg_vpi_t	*reg_vpi = buf;
1303
1304	if (!sli4 || !buf || !sport) {
1305		return 0;
1306	}
1307
1308	ocs_memset(buf, 0, size);
1309
1310	reg_vpi->hdr.command = SLI4_MBOX_COMMAND_REG_VPI;
1311
1312	reg_vpi->local_n_port_id = sport->fc_id;
1313	reg_vpi->upd = update != 0;
1314	ocs_memcpy(reg_vpi->wwpn, &sport->sli_wwpn, sizeof(reg_vpi->wwpn));
1315	reg_vpi->vpi = sport->indicator;
1316	reg_vpi->vfi = sport->domain->indicator;
1317
1318	return sizeof(sli4_cmd_reg_vpi_t);
1319}
1320
1321/**
1322 * @brief Write a REQUEST_FEATURES command to the provided buffer.
1323 *
1324 * @param sli4 SLI context pointer.
1325 * @param buf Virtual pointer to the destination buffer.
1326 * @param size Buffer size, in bytes.
1327 * @param mask Features to request.
1328 * @param query Use feature query mode (does not change FW).
1329 *
1330 * @return Returns the number of bytes written.
1331 */
1332static int32_t
1333sli_cmd_request_features(sli4_t *sli4, void *buf, size_t size, sli4_features_t mask, uint8_t query)
1334{
1335	sli4_cmd_request_features_t *features = buf;
1336
1337	ocs_memset(buf, 0, size);
1338
1339	features->hdr.command = SLI4_MBOX_COMMAND_REQUEST_FEATURES;
1340
1341	if (query) {
1342		features->qry = TRUE;
1343	}
1344	features->command.dword = mask.dword;
1345
1346	return sizeof(sli4_cmd_request_features_t);
1347}
1348
1349/**
1350 * @ingroup sli
1351 * @brief Write a SLI_CONFIG command to the provided buffer.
1352 *
1353 * @param sli4 SLI context pointer.
1354 * @param buf Virtual pointer to the destination buffer.
1355 * @param size Buffer size, in bytes.
1356 * @param length Length in bytes of attached command.
1357 * @param dma DMA buffer for non-embedded commands.
1358 *
1359 * @return Returns the number of bytes written.
1360 */
1361int32_t
1362sli_cmd_sli_config(sli4_t *sli4, void *buf, size_t size, uint32_t length, ocs_dma_t *dma)
1363{
1364	sli4_cmd_sli_config_t	*sli_config = NULL;
1365
1366	if ((length > sizeof(sli_config->payload.embed)) && (dma == NULL)) {
1367		ocs_log_test(sli4->os, "length(%d) > payload(%ld)\n",
1368				length, sizeof(sli_config->payload.embed));
1369		return -1;
1370	}
1371
1372	sli_config = buf;
1373
1374	ocs_memset(buf, 0, size);
1375
1376	sli_config->hdr.command = SLI4_MBOX_COMMAND_SLI_CONFIG;
1377	if (NULL == dma) {
1378		sli_config->emb = TRUE;
1379		sli_config->payload_length = length;
1380	} else {
1381		sli_config->emb = FALSE;
1382
1383		sli_config->pmd_count = 1;
1384
1385		sli_config->payload.mem.address_low = ocs_addr32_lo(dma->phys);
1386		sli_config->payload.mem.address_high = ocs_addr32_hi(dma->phys);
1387		sli_config->payload.mem.length = dma->size;
1388		sli_config->payload_length = dma->size;
1389#if defined(OCS_INCLUDE_DEBUG)
1390		/* save pointer to DMA for BMBX dumping purposes */
1391		sli4->bmbx_non_emb_pmd = dma;
1392#endif
1393
1394	}
1395
1396	return offsetof(sli4_cmd_sli_config_t, payload.embed);
1397}
1398
1399/**
1400 * @brief Initialize SLI Port control register.
1401 *
1402 * @param sli4 SLI context pointer.
1403 * @param endian Endian value to write.
1404 *
1405 * @return Returns 0 on success, or a negative error code value on failure.
1406 */
1407
1408static int32_t
1409sli_sliport_control(sli4_t *sli4, uint32_t endian)
1410{
1411	uint32_t iter;
1412	int32_t rc;
1413
1414	rc = -1;
1415
1416	/* Initialize port, endian */
1417	sli_reg_write(sli4, SLI4_REG_SLIPORT_CONTROL, endian | SLI4_SLIPORT_CONTROL_IP);
1418
1419	for (iter = 0; iter < 3000; iter ++) {
1420		ocs_udelay(SLI4_INIT_PORT_DELAY_US);
1421		if (sli_fw_ready(sli4) == 1) {
1422			rc = 0;
1423			break;
1424		}
1425	}
1426
1427	if (rc != 0) {
1428		ocs_log_crit(sli4->os, "port failed to become ready after initialization\n");
1429	}
1430
1431	return rc;
1432}
1433
1434/**
1435 * @ingroup sli
1436 * @brief Write a UNREG_FCFI command to the provided buffer.
1437 *
1438 * @param sli4 SLI context pointer.
1439 * @param buf Virtual pointer to the destination buffer.
1440 * @param size Buffer size, in bytes.
1441 * @param indicator Indicator value.
1442 *
1443 * @return Returns the number of bytes written.
1444 */
1445int32_t
1446sli_cmd_unreg_fcfi(sli4_t *sli4, void *buf, size_t size, uint16_t indicator)
1447{
1448	sli4_cmd_unreg_fcfi_t	*unreg_fcfi = buf;
1449
1450	if (!sli4 || !buf) {
1451		return 0;
1452	}
1453
1454	ocs_memset(buf, 0, size);
1455
1456	unreg_fcfi->hdr.command = SLI4_MBOX_COMMAND_UNREG_FCFI;
1457
1458	unreg_fcfi->fcfi = indicator;
1459
1460	return sizeof(sli4_cmd_unreg_fcfi_t);
1461}
1462
1463/**
1464 * @ingroup sli
1465 * @brief Write an UNREG_RPI command to the provided buffer.
1466 *
1467 * @param sli4 SLI context pointer.
1468 * @param buf Virtual pointer to the destination buffer.
1469 * @param size Buffer size, in bytes.
1470 * @param indicator Indicator value.
1471 * @param which Type of unregister, such as node, port, domain, or FCF.
1472 * @param fc_id FC address.
1473 *
1474 * @return Returns the number of bytes written.
1475 */
1476int32_t
1477sli_cmd_unreg_rpi(sli4_t *sli4, void *buf, size_t size, uint16_t indicator, sli4_resource_e which,
1478		uint32_t fc_id)
1479{
1480	sli4_cmd_unreg_rpi_t	*unreg_rpi = buf;
1481	uint8_t		index_indicator = 0;
1482
1483	if (!sli4 || !buf) {
1484		return 0;
1485	}
1486
1487	ocs_memset(buf, 0, size);
1488
1489	unreg_rpi->hdr.command = SLI4_MBOX_COMMAND_UNREG_RPI;
1490
1491	switch (which) {
1492	case SLI_RSRC_FCOE_RPI:
1493		index_indicator = SLI4_UNREG_RPI_II_RPI;
1494		if (fc_id != UINT32_MAX) {
1495			unreg_rpi->dp = TRUE;
1496			unreg_rpi->destination_n_port_id = fc_id & 0x00ffffff;
1497		}
1498		break;
1499	case SLI_RSRC_FCOE_VPI:
1500		index_indicator = SLI4_UNREG_RPI_II_VPI;
1501		break;
1502	case SLI_RSRC_FCOE_VFI:
1503		index_indicator = SLI4_UNREG_RPI_II_VFI;
1504		break;
1505	case SLI_RSRC_FCOE_FCFI:
1506		index_indicator = SLI4_UNREG_RPI_II_FCFI;
1507		break;
1508	default:
1509		ocs_log_test(sli4->os, "unknown type %#x\n", which);
1510		return 0;
1511	}
1512
1513	unreg_rpi->ii = index_indicator;
1514	unreg_rpi->index = indicator;
1515
1516	return sizeof(sli4_cmd_unreg_rpi_t);
1517}
1518
1519/**
1520 * @ingroup sli
1521 * @brief Write an UNREG_VFI command to the provided buffer.
1522 *
1523 * @param sli4 SLI context pointer.
1524 * @param buf Virtual pointer to the destination buffer.
1525 * @param size Buffer size, in bytes.
1526 * @param domain Pointer to the domain object
1527 * @param which Type of unregister, such as domain, FCFI, or everything.
1528 *
1529 * @return Returns the number of bytes written.
1530 */
1531int32_t
1532sli_cmd_unreg_vfi(sli4_t *sli4, void *buf, size_t size, ocs_domain_t *domain, uint32_t which)
1533{
1534	sli4_cmd_unreg_vfi_t	*unreg_vfi = buf;
1535
1536	if (!sli4 || !buf || !domain) {
1537		return 0;
1538	}
1539
1540	ocs_memset(buf, 0, size);
1541
1542	unreg_vfi->hdr.command = SLI4_MBOX_COMMAND_UNREG_VFI;
1543	switch (which) {
1544	case SLI4_UNREG_TYPE_DOMAIN:
1545		unreg_vfi->index = domain->indicator;
1546		break;
1547	case SLI4_UNREG_TYPE_FCF:
1548		unreg_vfi->index = domain->fcf_indicator;
1549		break;
1550	case SLI4_UNREG_TYPE_ALL:
1551		unreg_vfi->index = UINT16_MAX;
1552		break;
1553	default:
1554		return 0;
1555	}
1556
1557	if (SLI4_UNREG_TYPE_DOMAIN != which) {
1558		unreg_vfi->ii = SLI4_UNREG_VFI_II_FCFI;
1559	}
1560
1561	return sizeof(sli4_cmd_unreg_vfi_t);
1562}
1563
1564/**
1565 * @ingroup sli
1566 * @brief Write an UNREG_VPI command to the provided buffer.
1567 *
1568 * @param sli4 SLI context pointer.
1569 * @param buf Virtual pointer to the destination buffer.
1570 * @param size Buffer size, in bytes.
1571 * @param indicator Indicator value.
1572 * @param which Type of unregister: port, domain, FCFI, everything
1573 *
1574 * @return Returns the number of bytes written.
1575 */
1576int32_t
1577sli_cmd_unreg_vpi(sli4_t *sli4, void *buf, size_t size, uint16_t indicator, uint32_t which)
1578{
1579	sli4_cmd_unreg_vpi_t	*unreg_vpi = buf;
1580
1581	if (!sli4 || !buf) {
1582		return 0;
1583	}
1584
1585	ocs_memset(buf, 0, size);
1586
1587	unreg_vpi->hdr.command = SLI4_MBOX_COMMAND_UNREG_VPI;
1588	unreg_vpi->index = indicator;
1589	switch (which) {
1590	case SLI4_UNREG_TYPE_PORT:
1591		unreg_vpi->ii = SLI4_UNREG_VPI_II_VPI;
1592		break;
1593	case SLI4_UNREG_TYPE_DOMAIN:
1594		unreg_vpi->ii = SLI4_UNREG_VPI_II_VFI;
1595		break;
1596	case SLI4_UNREG_TYPE_FCF:
1597		unreg_vpi->ii = SLI4_UNREG_VPI_II_FCFI;
1598		break;
1599	case SLI4_UNREG_TYPE_ALL:
1600		unreg_vpi->index = UINT16_MAX;	/* override indicator */
1601		unreg_vpi->ii = SLI4_UNREG_VPI_II_FCFI;
1602		break;
1603	default:
1604		return 0;
1605	}
1606
1607	return sizeof(sli4_cmd_unreg_vpi_t);
1608}
1609
1610
1611/**
1612 * @ingroup sli
1613 * @brief Write an CONFIG_AUTO_XFER_RDY command to the provided buffer.
1614 *
1615 * @param sli4 SLI context pointer.
1616 * @param buf Virtual pointer to the destination buffer.
1617 * @param size Buffer size, in bytes.
1618 * @param max_burst_len if the write FCP_DL is less than this size,
1619 * then the SLI port will generate the auto XFER_RDY.
1620 *
1621 * @return Returns the number of bytes written.
1622 */
1623int32_t
1624sli_cmd_config_auto_xfer_rdy(sli4_t *sli4, void *buf, size_t size, uint32_t max_burst_len)
1625{
1626	sli4_cmd_config_auto_xfer_rdy_t	*req = buf;
1627
1628	if (!sli4 || !buf) {
1629		return 0;
1630	}
1631
1632	ocs_memset(buf, 0, size);
1633
1634	req->hdr.command = SLI4_MBOX_COMMAND_CONFIG_AUTO_XFER_RDY;
1635	req->max_burst_len = max_burst_len;
1636
1637	return sizeof(sli4_cmd_config_auto_xfer_rdy_t);
1638}
1639
1640/**
1641 * @ingroup sli
1642 * @brief Write an CONFIG_AUTO_XFER_RDY_HP command to the provided buffer.
1643 *
1644 * @param sli4 SLI context pointer.
1645 * @param buf Virtual pointer to the destination buffer.
1646 * @param size Buffer size, in bytes.
1647 * @param max_burst_len if the write FCP_DL is less than this size,
1648 * @param esoc enable start offset computation,
1649 * @param block_size block size,
1650 * then the SLI port will generate the auto XFER_RDY.
1651 *
1652 * @return Returns the number of bytes written.
1653 */
1654int32_t
1655sli_cmd_config_auto_xfer_rdy_hp(sli4_t *sli4, void *buf, size_t size, uint32_t max_burst_len,
1656                                                uint32_t esoc, uint32_t block_size )
1657{
1658        sli4_cmd_config_auto_xfer_rdy_hp_t      *req = buf;
1659
1660        if (!sli4 || !buf) {
1661                return 0;
1662        }
1663
1664        ocs_memset(buf, 0, size);
1665
1666        req->hdr.command = SLI4_MBOX_COMMAND_CONFIG_AUTO_XFER_RDY_HP;
1667        req->max_burst_len = max_burst_len;
1668        req->esoc = esoc;
1669        req->block_size = block_size;
1670        return sizeof(sli4_cmd_config_auto_xfer_rdy_hp_t);
1671}
1672
1673/**
1674 * @brief Write a COMMON_FUNCTION_RESET command.
1675 *
1676 * @param sli4 SLI context.
1677 * @param buf Destination buffer for the command.
1678 * @param size Buffer size, in bytes.
1679 *
1680 * @return Returns the number of bytes written.
1681 */
1682static int32_t
1683sli_cmd_common_function_reset(sli4_t *sli4, void *buf, size_t size)
1684{
1685	sli4_req_common_function_reset_t *reset = NULL;
1686	uint32_t	sli_config_off = 0;
1687
1688	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
1689		uint32_t payload_size;
1690
1691		/* Payload length must accommodate both request and response */
1692		payload_size = max(sizeof(sli4_req_common_function_reset_t),
1693				sizeof(sli4_res_common_function_reset_t));
1694
1695		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
1696				NULL);
1697	}
1698	reset = (sli4_req_common_function_reset_t *)((uint8_t *)buf + sli_config_off);
1699
1700	reset->hdr.opcode = SLI4_OPC_COMMON_FUNCTION_RESET;
1701	reset->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
1702
1703	return(sli_config_off + sizeof(sli4_req_common_function_reset_t));
1704}
1705
1706/**
1707 * @brief Write a COMMON_CREATE_CQ command.
1708 *
1709 * @param sli4 SLI context.
1710 * @param buf Destination buffer for the command.
1711 * @param size Buffer size, in bytes.
1712 * @param qmem DMA memory for the queue.
1713 * @param eq_id Associated EQ_ID
1714 * @param ignored This parameter carries the ULP which is only used for WQ and RQs
1715 *
1716 * @note This creates a Version 0 message.
1717 *
1718 * @return Returns the number of bytes written.
1719 */
1720static int32_t
1721sli_cmd_common_create_cq(sli4_t *sli4, void *buf, size_t size,
1722		ocs_dma_t *qmem, uint16_t eq_id, uint16_t ignored)
1723{
1724	sli4_req_common_create_cq_v0_t	*cqv0 = NULL;
1725	sli4_req_common_create_cq_v2_t	*cqv2 = NULL;
1726	uint32_t	sli_config_off = 0;
1727	uint32_t	p;
1728	uintptr_t	addr;
1729	uint32_t	if_type = sli4->if_type;
1730	uint32_t	page_bytes = 0;
1731	uint32_t	num_pages = 0;
1732	uint32_t 	cmd_size = 0;
1733	uint32_t	page_size = 0;
1734	uint32_t	n_cqe = 0;
1735
1736	/* First calculate number of pages and the mailbox cmd length */
1737	switch (if_type)
1738	{
1739	case SLI4_IF_TYPE_BE3_SKH_PF:
1740		page_bytes = SLI_PAGE_SIZE;
1741		num_pages = sli_page_count(qmem->size, page_bytes);
1742		cmd_size = sizeof(sli4_req_common_create_cq_v0_t) + (8 * num_pages);
1743		break;
1744	case SLI4_IF_TYPE_LANCER_FC_ETH:
1745		n_cqe = qmem->size / SLI4_CQE_BYTES;
1746		switch (n_cqe) {
1747		case 256:
1748		case 512:
1749		case 1024:
1750		case 2048:
1751			page_size = 1;
1752			break;
1753		case 4096:
1754			page_size = 2;
1755			break;
1756		default:
1757			return 0;
1758		}
1759		page_bytes = page_size * SLI_PAGE_SIZE;
1760		num_pages = sli_page_count(qmem->size, page_bytes);
1761		cmd_size = sizeof(sli4_req_common_create_cq_v2_t) + (8 * num_pages);
1762		break;
1763	default:
1764		ocs_log_test(sli4->os, "unsupported IF_TYPE %d\n", if_type);
1765		return -1;
1766	}
1767
1768
1769	/* now that we have the mailbox command size, we can set SLI_CONFIG fields */
1770	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
1771		uint32_t payload_size;
1772
1773		/* Payload length must accommodate both request and response */
1774		payload_size = max((size_t)cmd_size, sizeof(sli4_res_common_create_queue_t));
1775
1776		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
1777				NULL);
1778	}
1779
1780	switch (if_type)
1781	{
1782	case SLI4_IF_TYPE_BE3_SKH_PF:
1783		cqv0 = (sli4_req_common_create_cq_v0_t *)((uint8_t *)buf + sli_config_off);
1784		cqv0->hdr.opcode = SLI4_OPC_COMMON_CREATE_CQ;
1785		cqv0->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
1786		cqv0->hdr.version = 0;
1787		cqv0->hdr.request_length = cmd_size - sizeof(sli4_req_hdr_t);
1788
1789		/* valid values for number of pages: 1, 2, 4 (sec 4.4.3) */
1790		cqv0->num_pages = num_pages;
1791		switch (cqv0->num_pages) {
1792		case 1:
1793			cqv0->cqecnt = SLI4_CQ_CNT_256;
1794			break;
1795		case 2:
1796			cqv0->cqecnt = SLI4_CQ_CNT_512;
1797			break;
1798		case 4:
1799			cqv0->cqecnt = SLI4_CQ_CNT_1024;
1800			break;
1801		default:
1802			ocs_log_test(sli4->os, "num_pages %d not valid\n", cqv0->num_pages);
1803			return -1;
1804		}
1805		cqv0->evt = TRUE;
1806		cqv0->valid = TRUE;
1807		/* TODO cq->nodelay = ???; */
1808		/* TODO cq->clswm = ???; */
1809		cqv0->arm = FALSE;
1810		cqv0->eq_id = eq_id;
1811
1812		for (p = 0, addr = qmem->phys;
1813				p < cqv0->num_pages;
1814				p++, addr += page_bytes) {
1815			cqv0->page_physical_address[p].low = ocs_addr32_lo(addr);
1816			cqv0->page_physical_address[p].high = ocs_addr32_hi(addr);
1817		}
1818
1819		break;
1820	case SLI4_IF_TYPE_LANCER_FC_ETH:
1821	{
1822		cqv2 = (sli4_req_common_create_cq_v2_t *)((uint8_t *)buf + sli_config_off);
1823		cqv2->hdr.opcode = SLI4_OPC_COMMON_CREATE_CQ;
1824		cqv2->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
1825		cqv2->hdr.version = 2;
1826		cqv2->hdr.request_length = cmd_size - sizeof(sli4_req_hdr_t);
1827
1828		cqv2->page_size = page_size;
1829
1830		/* valid values for number of pages: 1, 2, 4, 8 (sec 4.4.3) */
1831		cqv2->num_pages = num_pages;
1832		if (!cqv2->num_pages || (cqv2->num_pages > SLI4_COMMON_CREATE_CQ_V2_MAX_PAGES)) {
1833			return 0;
1834		}
1835
1836		switch (cqv2->num_pages) {
1837		case 1:
1838			cqv2->cqecnt = SLI4_CQ_CNT_256;
1839			break;
1840		case 2:
1841			cqv2->cqecnt = SLI4_CQ_CNT_512;
1842			break;
1843		case 4:
1844			cqv2->cqecnt = SLI4_CQ_CNT_1024;
1845			break;
1846		case 8:
1847			cqv2->cqecnt = SLI4_CQ_CNT_LARGE;
1848			cqv2->cqe_count = n_cqe;
1849			break;
1850		default:
1851			ocs_log_test(sli4->os, "num_pages %d not valid\n", cqv2->num_pages);
1852			return -1;
1853		}
1854
1855		cqv2->evt = TRUE;
1856		cqv2->valid = TRUE;
1857		/* TODO cq->nodelay = ???; */
1858		/* TODO cq->clswm = ???; */
1859		cqv2->arm = FALSE;
1860		cqv2->eq_id = eq_id;
1861
1862		for (p = 0, addr = qmem->phys;
1863				p < cqv2->num_pages;
1864				p++, addr += page_bytes) {
1865			cqv2->page_physical_address[p].low = ocs_addr32_lo(addr);
1866			cqv2->page_physical_address[p].high = ocs_addr32_hi(addr);
1867		}
1868	}
1869		break;
1870	default:
1871		ocs_log_test(sli4->os, "unsupported IF_TYPE %d\n", if_type);
1872		return -1;
1873	}
1874
1875	return (sli_config_off + cmd_size);
1876}
1877
1878/**
1879 * @brief Write a COMMON_DESTROY_CQ command.
1880 *
1881 * @param sli4 SLI context.
1882 * @param buf Destination buffer for the command.
1883 * @param size Buffer size, in bytes.
1884 * @param cq_id CQ ID
1885 *
1886 * @note This creates a Version 0 message.
1887 *
1888 * @return Returns the number of bytes written.
1889 */
1890static int32_t
1891sli_cmd_common_destroy_cq(sli4_t *sli4, void *buf, size_t size, uint16_t cq_id)
1892{
1893	sli4_req_common_destroy_cq_t	*cq = NULL;
1894	uint32_t	sli_config_off = 0;
1895
1896	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
1897		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
1898				/* Payload length must accommodate both request and response */
1899				max(sizeof(sli4_req_common_destroy_cq_t),
1900					sizeof(sli4_res_hdr_t)),
1901				NULL);
1902	}
1903	cq = (sli4_req_common_destroy_cq_t *)((uint8_t *)buf + sli_config_off);
1904
1905	cq->hdr.opcode = SLI4_OPC_COMMON_DESTROY_CQ;
1906	cq->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
1907	cq->hdr.request_length = sizeof(sli4_req_common_destroy_cq_t) -
1908					sizeof(sli4_req_hdr_t);
1909	cq->cq_id = cq_id;
1910
1911	return(sli_config_off + sizeof(sli4_req_common_destroy_cq_t));
1912}
1913
1914/**
1915 * @brief Write a COMMON_MODIFY_EQ_DELAY command.
1916 *
1917 * @param sli4 SLI context.
1918 * @param buf Destination buffer for the command.
1919 * @param size Buffer size, in bytes.
1920 * @param q Queue object array.
1921 * @param num_q Queue object array count.
1922 * @param shift Phase shift for staggering interrupts.
1923 * @param delay_mult Delay multiplier for limiting interrupt frequency.
1924 *
1925 * @return Returns the number of bytes written.
1926 */
1927static int32_t
1928sli_cmd_common_modify_eq_delay(sli4_t *sli4, void *buf, size_t size, sli4_queue_t *q, int num_q, uint32_t shift,
1929				uint32_t delay_mult)
1930{
1931	sli4_req_common_modify_eq_delay_t *modify_delay = NULL;
1932	uint32_t	sli_config_off = 0;
1933	int i;
1934
1935	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
1936		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
1937				/* Payload length must accommodate both request and response */
1938				max(sizeof(sli4_req_common_modify_eq_delay_t), sizeof(sli4_res_hdr_t)),
1939				NULL);
1940	}
1941
1942	modify_delay = (sli4_req_common_modify_eq_delay_t *)((uint8_t *)buf + sli_config_off);
1943
1944	modify_delay->hdr.opcode = SLI4_OPC_COMMON_MODIFY_EQ_DELAY;
1945	modify_delay->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
1946	modify_delay->hdr.request_length = sizeof(sli4_req_common_modify_eq_delay_t) -
1947					sizeof(sli4_req_hdr_t);
1948
1949	modify_delay->num_eq = num_q;
1950
1951	for (i = 0; i<num_q; i++) {
1952		modify_delay->eq_delay_record[i].eq_id = q[i].id;
1953		modify_delay->eq_delay_record[i].phase = shift;
1954		modify_delay->eq_delay_record[i].delay_multiplier = delay_mult;
1955	}
1956
1957	return(sli_config_off + sizeof(sli4_req_common_modify_eq_delay_t));
1958}
1959
1960/**
1961 * @brief Write a COMMON_CREATE_EQ command.
1962 *
1963 * @param sli4 SLI context.
1964 * @param buf Destination buffer for the command.
1965 * @param size Buffer size, in bytes.
1966 * @param qmem DMA memory for the queue.
1967 * @param ignored1 Ignored (used for consistency among queue creation functions).
1968 * @param ignored2 Ignored (used for consistency among queue creation functions).
1969 *
1970 * @note Other queue creation routines use the last parameter to pass in
1971 * the associated Q_ID and ULP. EQ doesn't have an associated queue or ULP,
1972 * so these parameters are ignored
1973 *
1974 * @note This creates a Version 0 message
1975 *
1976 * @return Returns the number of bytes written.
1977 */
1978static int32_t
1979sli_cmd_common_create_eq(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *qmem,
1980		uint16_t ignored1, uint16_t ignored2)
1981{
1982	sli4_req_common_create_eq_t	*eq = NULL;
1983	uint32_t	sli_config_off = 0;
1984	uint32_t	p;
1985	uintptr_t	addr;
1986
1987	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
1988		uint32_t payload_size;
1989
1990		/* Payload length must accommodate both request and response */
1991		payload_size = max(sizeof(sli4_req_common_create_eq_t),
1992				sizeof(sli4_res_common_create_queue_t));
1993
1994		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
1995				NULL);
1996	}
1997	eq = (sli4_req_common_create_eq_t *)((uint8_t *)buf + sli_config_off);
1998
1999	eq->hdr.opcode = SLI4_OPC_COMMON_CREATE_EQ;
2000	eq->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2001	eq->hdr.request_length = sizeof(sli4_req_common_create_eq_t) -
2002					sizeof(sli4_req_hdr_t);
2003	/* valid values for number of pages: 1, 2, 4 (sec 4.4.3) */
2004	eq->num_pages = qmem->size / SLI_PAGE_SIZE;
2005	switch (eq->num_pages) {
2006	case 1:
2007		eq->eqesz = SLI4_EQE_SIZE_4;
2008		eq->count = SLI4_EQ_CNT_1024;
2009		break;
2010	case 2:
2011		eq->eqesz = SLI4_EQE_SIZE_4;
2012		eq->count = SLI4_EQ_CNT_2048;
2013		break;
2014	case 4:
2015		eq->eqesz = SLI4_EQE_SIZE_4;
2016		eq->count = SLI4_EQ_CNT_4096;
2017		break;
2018	default:
2019		ocs_log_test(sli4->os, "num_pages %d not valid\n", eq->num_pages);
2020		return -1;
2021	}
2022	eq->valid = TRUE;
2023	eq->arm = FALSE;
2024	eq->delay_multiplier = 32;
2025
2026	for (p = 0, addr = qmem->phys;
2027			p < eq->num_pages;
2028			p++, addr += SLI_PAGE_SIZE) {
2029		eq->page_address[p].low = ocs_addr32_lo(addr);
2030		eq->page_address[p].high = ocs_addr32_hi(addr);
2031	}
2032
2033	return(sli_config_off + sizeof(sli4_req_common_create_eq_t));
2034}
2035
2036
2037/**
2038 * @brief Write a COMMON_DESTROY_EQ command.
2039 *
2040 * @param sli4 SLI context.
2041 * @param buf Destination buffer for the command.
2042 * @param size Buffer size, in bytes.
2043 * @param eq_id Queue ID to destroy.
2044 *
2045 * @note Other queue creation routines use the last parameter to pass in
2046 * the associated Q_ID. EQ doesn't have an associated queue so this
2047 * parameter is ignored.
2048 *
2049 * @note This creates a Version 0 message.
2050 *
2051 * @return Returns the number of bytes written.
2052 */
2053static int32_t
2054sli_cmd_common_destroy_eq(sli4_t *sli4, void *buf, size_t size, uint16_t eq_id)
2055{
2056	sli4_req_common_destroy_eq_t	*eq = NULL;
2057	uint32_t	sli_config_off = 0;
2058
2059	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2060		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2061				/* Payload length must accommodate both request and response */
2062				max(sizeof(sli4_req_common_destroy_eq_t),
2063					sizeof(sli4_res_hdr_t)),
2064				NULL);
2065	}
2066	eq = (sli4_req_common_destroy_eq_t *)((uint8_t *)buf + sli_config_off);
2067
2068	eq->hdr.opcode = SLI4_OPC_COMMON_DESTROY_EQ;
2069	eq->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2070	eq->hdr.request_length = sizeof(sli4_req_common_destroy_eq_t) -
2071					sizeof(sli4_req_hdr_t);
2072
2073	eq->eq_id = eq_id;
2074
2075	return(sli_config_off + sizeof(sli4_req_common_destroy_eq_t));
2076}
2077
2078/**
2079 * @brief Write a LOWLEVEL_SET_WATCHDOG command.
2080 *
2081 * @param sli4 SLI context.
2082 * @param buf Destination buffer for the command.
2083 * @param size Buffer size, in bytes.
2084 * @param timeout watchdog timer timeout in seconds
2085 *
2086 * @return void
2087 */
2088void
2089sli4_cmd_lowlevel_set_watchdog(sli4_t *sli4, void *buf, size_t size, uint16_t timeout)
2090{
2091
2092	sli4_req_lowlevel_set_watchdog_t *req = NULL;
2093	uint32_t	sli_config_off = 0;
2094
2095	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2096		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2097				/* Payload length must accommodate both request and response */
2098				max(sizeof(sli4_req_lowlevel_set_watchdog_t),
2099					sizeof(sli4_res_lowlevel_set_watchdog_t)),
2100				NULL);
2101	}
2102	req = (sli4_req_lowlevel_set_watchdog_t *)((uint8_t *)buf + sli_config_off);
2103
2104	req->hdr.opcode = SLI4_OPC_LOWLEVEL_SET_WATCHDOG;
2105	req->hdr.subsystem = SLI4_SUBSYSTEM_LOWLEVEL;
2106	req->hdr.request_length = sizeof(sli4_req_lowlevel_set_watchdog_t) - sizeof(sli4_req_hdr_t);
2107	req->watchdog_timeout = timeout;
2108
2109	return;
2110}
2111
2112static int32_t
2113sli_cmd_common_get_cntl_attributes(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma)
2114{
2115	sli4_req_hdr_t *hdr = NULL;
2116	uint32_t	sli_config_off = 0;
2117
2118	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2119		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2120				sizeof(sli4_req_hdr_t),
2121				dma);
2122	}
2123
2124	if (dma == NULL) {
2125		return 0;
2126	}
2127
2128	ocs_memset(dma->virt, 0, dma->size);
2129
2130	hdr = dma->virt;
2131
2132	hdr->opcode = SLI4_OPC_COMMON_GET_CNTL_ATTRIBUTES;
2133	hdr->subsystem = SLI4_SUBSYSTEM_COMMON;
2134	hdr->request_length = dma->size;
2135
2136	return(sli_config_off + sizeof(sli4_req_hdr_t));
2137}
2138
2139/**
2140 * @brief Write a COMMON_GET_CNTL_ADDL_ATTRIBUTES command.
2141 *
2142 * @param sli4 SLI context.
2143 * @param buf Destination buffer for the command.
2144 * @param size Buffer size, in bytes.
2145 * @param dma DMA structure from which the data will be copied.
2146 *
2147 * @note This creates a Version 0 message.
2148 *
2149 * @return Returns the number of bytes written.
2150 */
2151static int32_t
2152sli_cmd_common_get_cntl_addl_attributes(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma)
2153{
2154	sli4_req_hdr_t *hdr = NULL;
2155	uint32_t	sli_config_off = 0;
2156
2157	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2158		sli_config_off = sli_cmd_sli_config(sli4, buf, size, sizeof(sli4_req_hdr_t), dma);
2159	}
2160
2161	if (dma == NULL) {
2162		return 0;
2163	}
2164
2165	ocs_memset(dma->virt, 0, dma->size);
2166
2167	hdr = dma->virt;
2168
2169	hdr->opcode = SLI4_OPC_COMMON_GET_CNTL_ADDL_ATTRIBUTES;
2170	hdr->subsystem = SLI4_SUBSYSTEM_COMMON;
2171	hdr->request_length = dma->size;
2172
2173	return(sli_config_off + sizeof(sli4_req_hdr_t));
2174}
2175
2176/**
2177 * @brief Write a COMMON_CREATE_MQ_EXT command.
2178 *
2179 * @param sli4 SLI context.
2180 * @param buf Destination buffer for the command.
2181 * @param size Buffer size, in bytes.
2182 * @param qmem DMA memory for the queue.
2183 * @param cq_id Associated CQ_ID.
2184 * @param ignored This parameter carries the ULP which is only used for WQ and RQs
2185 *
2186 * @note This creates a Version 0 message.
2187 *
2188 * @return Returns the number of bytes written.
2189 */
2190static int32_t
2191sli_cmd_common_create_mq_ext(sli4_t *sli4, void *buf, size_t size,
2192			     ocs_dma_t *qmem, uint16_t cq_id, uint16_t ignored)
2193{
2194	sli4_req_common_create_mq_ext_t	*mq = NULL;
2195	uint32_t	sli_config_off = 0;
2196	uint32_t	p;
2197	uintptr_t	addr;
2198
2199	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2200		uint32_t payload_size;
2201
2202		/* Payload length must accommodate both request and response */
2203		payload_size = max(sizeof(sli4_req_common_create_mq_ext_t),
2204				sizeof(sli4_res_common_create_queue_t));
2205
2206		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
2207				NULL);
2208	}
2209	mq = (sli4_req_common_create_mq_ext_t *)((uint8_t *)buf + sli_config_off);
2210
2211	mq->hdr.opcode = SLI4_OPC_COMMON_CREATE_MQ_EXT;
2212	mq->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2213	mq->hdr.request_length = sizeof(sli4_req_common_create_mq_ext_t) -
2214					sizeof(sli4_req_hdr_t);
2215	/* valid values for number of pages: 1, 2, 4, 8 (sec 4.4.12) */
2216	mq->num_pages = qmem->size / SLI_PAGE_SIZE;
2217	switch (mq->num_pages) {
2218	case 1:
2219		mq->ring_size = SLI4_MQE_SIZE_16;
2220		break;
2221	case 2:
2222		mq->ring_size = SLI4_MQE_SIZE_32;
2223		break;
2224	case 4:
2225		mq->ring_size = SLI4_MQE_SIZE_64;
2226		break;
2227	case 8:
2228		mq->ring_size = SLI4_MQE_SIZE_128;
2229		break;
2230	default:
2231		ocs_log_test(sli4->os, "num_pages %d not valid\n", mq->num_pages);
2232		return -1;
2233	}
2234
2235	/* TODO break this down by sli4->config.topology */
2236	mq->async_event_bitmap = SLI4_ASYNC_EVT_FC_FCOE;
2237
2238	if (sli4->config.mq_create_version) {
2239		mq->cq_id_v1 = cq_id;
2240		mq->hdr.version = 1;
2241	}
2242	else {
2243		mq->cq_id_v0 = cq_id;
2244	}
2245	mq->val = TRUE;
2246
2247	for (p = 0, addr = qmem->phys;
2248			p < mq->num_pages;
2249			p++, addr += SLI_PAGE_SIZE) {
2250		mq->page_physical_address[p].low = ocs_addr32_lo(addr);
2251		mq->page_physical_address[p].high = ocs_addr32_hi(addr);
2252	}
2253
2254	return(sli_config_off + sizeof(sli4_req_common_create_mq_ext_t));
2255}
2256
2257/**
2258 * @brief Write a COMMON_DESTROY_MQ command.
2259 *
2260 * @param sli4 SLI context.
2261 * @param buf Destination buffer for the command.
2262 * @param size Buffer size, in bytes.
2263 * @param mq_id MQ ID
2264 *
2265 * @note This creates a Version 0 message.
2266 *
2267 * @return Returns the number of bytes written.
2268 */
2269static int32_t
2270sli_cmd_common_destroy_mq(sli4_t *sli4, void *buf, size_t size, uint16_t mq_id)
2271{
2272	sli4_req_common_destroy_mq_t	*mq = NULL;
2273	uint32_t	sli_config_off = 0;
2274
2275	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2276		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2277				/* Payload length must accommodate both request and response */
2278				max(sizeof(sli4_req_common_destroy_mq_t),
2279					sizeof(sli4_res_hdr_t)),
2280				NULL);
2281	}
2282	mq = (sli4_req_common_destroy_mq_t *)((uint8_t *)buf + sli_config_off);
2283
2284	mq->hdr.opcode = SLI4_OPC_COMMON_DESTROY_MQ;
2285	mq->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2286	mq->hdr.request_length = sizeof(sli4_req_common_destroy_mq_t) -
2287					sizeof(sli4_req_hdr_t);
2288
2289	mq->mq_id = mq_id;
2290
2291	return(sli_config_off + sizeof(sli4_req_common_destroy_mq_t));
2292}
2293
2294/**
2295 * @ingroup sli
2296 * @brief Write a COMMON_NOP command
2297 *
2298 * @param sli4 SLI context.
2299 * @param buf Destination buffer for the command.
2300 * @param size Buffer size, in bytes.
2301 * @param context NOP context value (passed to response, except on FC/FCoE).
2302 *
2303 * @return Returns the number of bytes written.
2304 */
2305int32_t
2306sli_cmd_common_nop(sli4_t *sli4, void *buf, size_t size, uint64_t context)
2307{
2308	sli4_req_common_nop_t *nop = NULL;
2309	uint32_t	sli_config_off = 0;
2310
2311	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2312		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2313				/* Payload length must accommodate both request and response */
2314				max(sizeof(sli4_req_common_nop_t), sizeof(sli4_res_common_nop_t)),
2315				NULL);
2316	}
2317
2318	nop = (sli4_req_common_nop_t *)((uint8_t *)buf + sli_config_off);
2319
2320	nop->hdr.opcode = SLI4_OPC_COMMON_NOP;
2321	nop->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2322	nop->hdr.request_length = 8;
2323
2324	ocs_memcpy(&nop->context, &context, sizeof(context));
2325
2326	return(sli_config_off + sizeof(sli4_req_common_nop_t));
2327}
2328
2329/**
2330 * @ingroup sli
2331 * @brief Write a COMMON_GET_RESOURCE_EXTENT_INFO command.
2332 *
2333 * @param sli4 SLI context.
2334 * @param buf Destination buffer for the command.
2335 * @param size Buffer size, in bytes.
2336 * @param rtype Resource type (for example, XRI, VFI, VPI, and RPI).
2337 *
2338 * @return Returns the number of bytes written.
2339 */
2340int32_t
2341sli_cmd_common_get_resource_extent_info(sli4_t *sli4, void *buf, size_t size, uint16_t rtype)
2342{
2343	sli4_req_common_get_resource_extent_info_t *extent = NULL;
2344	uint32_t	sli_config_off = 0;
2345
2346	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2347		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2348				sizeof(sli4_req_common_get_resource_extent_info_t),
2349				NULL);
2350	}
2351
2352	extent = (sli4_req_common_get_resource_extent_info_t *)((uint8_t *)buf + sli_config_off);
2353
2354	extent->hdr.opcode = SLI4_OPC_COMMON_GET_RESOURCE_EXTENT_INFO;
2355	extent->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2356	extent->hdr.request_length = 4;
2357
2358	extent->resource_type = rtype;
2359
2360	return(sli_config_off + sizeof(sli4_req_common_get_resource_extent_info_t));
2361}
2362
2363/**
2364 * @ingroup sli
2365 * @brief Write a COMMON_GET_SLI4_PARAMETERS command.
2366 *
2367 * @param sli4 SLI context.
2368 * @param buf Destination buffer for the command.
2369 * @param size Buffer size, in bytes.
2370 *
2371 * @return Returns the number of bytes written.
2372 */
2373int32_t
2374sli_cmd_common_get_sli4_parameters(sli4_t *sli4, void *buf, size_t size)
2375{
2376	sli4_req_hdr_t	*hdr = NULL;
2377	uint32_t	sli_config_off = 0;
2378
2379	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2380		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2381				sizeof(sli4_res_common_get_sli4_parameters_t),
2382				NULL);
2383	}
2384
2385	hdr = (sli4_req_hdr_t *)((uint8_t *)buf + sli_config_off);
2386
2387	hdr->opcode = SLI4_OPC_COMMON_GET_SLI4_PARAMETERS;
2388	hdr->subsystem = SLI4_SUBSYSTEM_COMMON;
2389	hdr->request_length = 0x50;
2390
2391	return(sli_config_off + sizeof(sli4_req_hdr_t));
2392}
2393
2394/**
2395 * @brief Write a COMMON_QUERY_FW_CONFIG command to the provided buffer.
2396 *
2397 * @param sli4 SLI context pointer.
2398 * @param buf Virtual pointer to destination buffer.
2399 * @param size Buffer size in bytes.
2400 *
2401 * @return Returns the number of bytes written
2402 */
2403static int32_t
2404sli_cmd_common_query_fw_config(sli4_t *sli4, void *buf, size_t size)
2405{
2406	sli4_req_common_query_fw_config_t   *fw_config;
2407	uint32_t	sli_config_off = 0;
2408	uint32_t payload_size;
2409
2410	/* Payload length must accommodate both request and response */
2411	payload_size = max(sizeof(sli4_req_common_query_fw_config_t),
2412			   sizeof(sli4_res_common_query_fw_config_t));
2413
2414	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2415		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2416				payload_size,
2417				NULL);
2418	}
2419
2420	fw_config = (sli4_req_common_query_fw_config_t*)((uint8_t*)buf + sli_config_off);
2421	fw_config->hdr.opcode	      = SLI4_OPC_COMMON_QUERY_FW_CONFIG;
2422	fw_config->hdr.subsystem      = SLI4_SUBSYSTEM_COMMON;
2423	fw_config->hdr.request_length = payload_size - sizeof(sli4_req_hdr_t);
2424	return sli_config_off + sizeof(sli4_req_common_query_fw_config_t);
2425}
2426
2427/**
2428 * @brief Write a COMMON_GET_PORT_NAME command to the provided buffer.
2429 *
2430 * @param sli4 SLI context pointer.
2431 * @param buf Virtual pointer to destination buffer.
2432 * @param size Buffer size in bytes.
2433 *
2434 * @note Function supports both version 0 and 1 forms of this command via
2435 * the IF_TYPE.
2436 *
2437 * @return Returns the number of bytes written.
2438 */
2439static int32_t
2440sli_cmd_common_get_port_name(sli4_t *sli4, void *buf, size_t size)
2441{
2442	sli4_req_common_get_port_name_t	*port_name;
2443	uint32_t	sli_config_off = 0;
2444	uint32_t	payload_size;
2445	uint8_t		version = 0;
2446	uint8_t		pt = 0;
2447
2448	/* Select command version according to IF_TYPE */
2449	switch (sli4->if_type) {
2450	case SLI4_IF_TYPE_BE3_SKH_PF:
2451	case SLI4_IF_TYPE_BE3_SKH_VF:
2452		version = 0;
2453		break;
2454	case SLI4_IF_TYPE_LANCER_FC_ETH:
2455	case SLI4_IF_TYPE_LANCER_RDMA:
2456		version = 1;
2457		break;
2458	default:
2459		ocs_log_test(sli4->os, "unsupported IF_TYPE %d\n", sli4->if_type);
2460		return 0;
2461	}
2462
2463	/* Payload length must accommodate both request and response */
2464	payload_size = max(sizeof(sli4_req_common_get_port_name_t),
2465			   sizeof(sli4_res_common_get_port_name_t));
2466
2467	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2468		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2469				payload_size,
2470				NULL);
2471
2472		pt = 1;
2473	}
2474
2475	port_name = (sli4_req_common_get_port_name_t *)((uint8_t *)buf + sli_config_off);
2476
2477	port_name->hdr.opcode		= SLI4_OPC_COMMON_GET_PORT_NAME;
2478	port_name->hdr.subsystem	= SLI4_SUBSYSTEM_COMMON;
2479	port_name->hdr.request_length	= sizeof(sli4_req_hdr_t) + (version * sizeof(uint32_t));
2480	port_name->hdr.version		= version;
2481
2482	/* Set the port type value (ethernet=0, FC=1) for V1 commands */
2483	if (version == 1) {
2484		port_name->pt = pt;
2485	}
2486
2487	return sli_config_off + port_name->hdr.request_length;
2488}
2489
2490
2491/**
2492 * @ingroup sli
2493 * @brief Write a COMMON_WRITE_OBJECT command.
2494 *
2495 * @param sli4 SLI context.
2496 * @param buf Destination buffer for the command.
2497 * @param size Buffer size, in bytes.
2498 * @param noc True if the object should be written but not committed to flash.
2499 * @param eof True if this is the last write for this object.
2500 * @param desired_write_length Number of bytes of data to write to the object.
2501 * @param offset Offset, in bytes, from the start of the object.
2502 * @param object_name Name of the object to write.
2503 * @param dma DMA structure from which the data will be copied.
2504 *
2505 * @return Returns the number of bytes written.
2506 */
2507int32_t
2508sli_cmd_common_write_object(sli4_t *sli4, void *buf, size_t size,
2509		uint16_t noc, uint16_t eof, uint32_t desired_write_length,
2510		uint32_t offset,
2511		char *object_name,
2512		ocs_dma_t *dma)
2513{
2514	sli4_req_common_write_object_t *wr_obj = NULL;
2515	uint32_t	sli_config_off = 0;
2516	sli4_bde_t *host_buffer;
2517
2518	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2519		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2520				sizeof (sli4_req_common_write_object_t) + sizeof (sli4_bde_t),
2521				NULL);
2522	}
2523
2524	wr_obj = (sli4_req_common_write_object_t *)((uint8_t *)buf + sli_config_off);
2525
2526	wr_obj->hdr.opcode = SLI4_OPC_COMMON_WRITE_OBJECT;
2527	wr_obj->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2528	wr_obj->hdr.request_length = sizeof(*wr_obj) - 4*sizeof(uint32_t) + sizeof(sli4_bde_t);
2529	wr_obj->hdr.timeout = 0;
2530	wr_obj->hdr.version = 0;
2531
2532	wr_obj->noc = noc;
2533	wr_obj->eof = eof;
2534	wr_obj->desired_write_length = desired_write_length;
2535	wr_obj->write_offset = offset;
2536	ocs_strncpy(wr_obj->object_name, object_name, sizeof(wr_obj->object_name));
2537	wr_obj->host_buffer_descriptor_count = 1;
2538
2539	host_buffer = (sli4_bde_t *)wr_obj->host_buffer_descriptor;
2540
2541	/* Setup to transfer xfer_size bytes to device */
2542	host_buffer->bde_type = SLI4_BDE_TYPE_BDE_64;
2543	host_buffer->buffer_length = desired_write_length;
2544	host_buffer->u.data.buffer_address_low = ocs_addr32_lo(dma->phys);
2545	host_buffer->u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
2546
2547
2548	return(sli_config_off + sizeof(sli4_req_common_write_object_t) + sizeof (sli4_bde_t));
2549}
2550
2551
2552/**
2553 * @ingroup sli
2554 * @brief Write a COMMON_DELETE_OBJECT command.
2555 *
2556 * @param sli4 SLI context.
2557 * @param buf Destination buffer for the command.
2558 * @param size Buffer size, in bytes.
2559 * @param object_name Name of the object to write.
2560 *
2561 * @return Returns the number of bytes written.
2562 */
2563int32_t
2564sli_cmd_common_delete_object(sli4_t *sli4, void *buf, size_t size,
2565		char *object_name)
2566{
2567	sli4_req_common_delete_object_t *del_obj = NULL;
2568	uint32_t	sli_config_off = 0;
2569
2570	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2571		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2572				sizeof (sli4_req_common_delete_object_t),
2573				NULL);
2574	}
2575
2576	del_obj = (sli4_req_common_delete_object_t *)((uint8_t *)buf + sli_config_off);
2577
2578	del_obj->hdr.opcode = SLI4_OPC_COMMON_DELETE_OBJECT;
2579	del_obj->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2580	del_obj->hdr.request_length = sizeof(*del_obj);
2581	del_obj->hdr.timeout = 0;
2582	del_obj->hdr.version = 0;
2583
2584	ocs_strncpy(del_obj->object_name, object_name, sizeof(del_obj->object_name));
2585	return(sli_config_off + sizeof(sli4_req_common_delete_object_t));
2586}
2587
2588/**
2589 * @ingroup sli
2590 * @brief Write a COMMON_READ_OBJECT command.
2591 *
2592 * @param sli4 SLI context.
2593 * @param buf Destination buffer for the command.
2594 * @param size Buffer size, in bytes.
2595 * @param desired_read_length Number of bytes of data to read from the object.
2596 * @param offset Offset, in bytes, from the start of the object.
2597 * @param object_name Name of the object to read.
2598 * @param dma DMA structure from which the data will be copied.
2599 *
2600 * @return Returns the number of bytes written.
2601 */
2602int32_t
2603sli_cmd_common_read_object(sli4_t *sli4, void *buf, size_t size,
2604		uint32_t desired_read_length,
2605		uint32_t offset,
2606		char *object_name,
2607		ocs_dma_t *dma)
2608{
2609	sli4_req_common_read_object_t *rd_obj = NULL;
2610	uint32_t	sli_config_off = 0;
2611	sli4_bde_t *host_buffer;
2612
2613	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2614		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2615				sizeof (sli4_req_common_read_object_t) + sizeof (sli4_bde_t),
2616				NULL);
2617	}
2618
2619	rd_obj = (sli4_req_common_read_object_t *)((uint8_t *)buf + sli_config_off);
2620
2621	rd_obj->hdr.opcode = SLI4_OPC_COMMON_READ_OBJECT;
2622	rd_obj->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2623	rd_obj->hdr.request_length = sizeof(*rd_obj) - 4*sizeof(uint32_t) + sizeof(sli4_bde_t);
2624	rd_obj->hdr.timeout = 0;
2625	rd_obj->hdr.version = 0;
2626
2627	rd_obj->desired_read_length = desired_read_length;
2628	rd_obj->read_offset = offset;
2629	ocs_strncpy(rd_obj->object_name, object_name, sizeof(rd_obj->object_name));
2630	rd_obj->host_buffer_descriptor_count = 1;
2631
2632	host_buffer = (sli4_bde_t *)rd_obj->host_buffer_descriptor;
2633
2634	/* Setup to transfer xfer_size bytes to device */
2635	host_buffer->bde_type = SLI4_BDE_TYPE_BDE_64;
2636	host_buffer->buffer_length = desired_read_length;
2637	if (dma != NULL) {
2638		host_buffer->u.data.buffer_address_low = ocs_addr32_lo(dma->phys);
2639		host_buffer->u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
2640	} else {
2641		host_buffer->u.data.buffer_address_low = 0;
2642		host_buffer->u.data.buffer_address_high = 0;
2643	}
2644
2645
2646	return(sli_config_off + sizeof(sli4_req_common_read_object_t) + sizeof (sli4_bde_t));
2647}
2648
2649/**
2650 * @ingroup sli
2651 * @brief Write a DMTF_EXEC_CLP_CMD command.
2652 *
2653 * @param sli4 SLI context.
2654 * @param buf Destination buffer for the command.
2655 * @param size Buffer size, in bytes.
2656 * @param cmd DMA structure that describes the buffer for the command.
2657 * @param resp DMA structure that describes the buffer for the response.
2658 *
2659 * @return Returns the number of bytes written.
2660 */
2661int32_t
2662sli_cmd_dmtf_exec_clp_cmd(sli4_t *sli4, void *buf, size_t size,
2663		ocs_dma_t *cmd,
2664		ocs_dma_t *resp)
2665{
2666	sli4_req_dmtf_exec_clp_cmd_t *clp_cmd = NULL;
2667	uint32_t	sli_config_off = 0;
2668
2669	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2670		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2671				sizeof (sli4_req_dmtf_exec_clp_cmd_t),
2672				NULL);
2673	}
2674
2675	clp_cmd = (sli4_req_dmtf_exec_clp_cmd_t*)((uint8_t *)buf + sli_config_off);
2676
2677	clp_cmd->hdr.opcode = SLI4_OPC_DMTF_EXEC_CLP_CMD;
2678	clp_cmd->hdr.subsystem = SLI4_SUBSYSTEM_DMTF;
2679	clp_cmd->hdr.request_length = sizeof(sli4_req_dmtf_exec_clp_cmd_t) -
2680					sizeof(sli4_req_hdr_t);
2681	clp_cmd->hdr.timeout = 0;
2682	clp_cmd->hdr.version = 0;
2683	clp_cmd->cmd_buf_length = cmd->size;
2684	clp_cmd->cmd_buf_addr_low = ocs_addr32_lo(cmd->phys);
2685	clp_cmd->cmd_buf_addr_high = ocs_addr32_hi(cmd->phys);
2686	clp_cmd->resp_buf_length = resp->size;
2687	clp_cmd->resp_buf_addr_low = ocs_addr32_lo(resp->phys);
2688	clp_cmd->resp_buf_addr_high = ocs_addr32_hi(resp->phys);
2689
2690	return(sli_config_off + sizeof(sli4_req_dmtf_exec_clp_cmd_t));
2691}
2692
2693/**
2694 * @ingroup sli
2695 * @brief Write a COMMON_SET_DUMP_LOCATION command.
2696 *
2697 * @param sli4 SLI context.
2698 * @param buf Destination buffer for the command.
2699 * @param size Buffer size, in bytes.
2700 * @param query Zero to set dump location, non-zero to query dump size
2701 * @param is_buffer_list Set to one if the buffer is a set of buffer descriptors or
2702 *                       set to 0 if the buffer is a contiguous dump area.
2703 * @param buffer DMA structure to which the dump will be copied.
2704 *
2705 * @return Returns the number of bytes written.
2706 */
2707int32_t
2708sli_cmd_common_set_dump_location(sli4_t *sli4, void *buf, size_t size,
2709				 uint8_t query, uint8_t is_buffer_list,
2710				 ocs_dma_t *buffer, uint8_t fdb)
2711{
2712	sli4_req_common_set_dump_location_t *set_dump_loc = NULL;
2713	uint32_t	sli_config_off = 0;
2714
2715	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2716		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2717				sizeof (sli4_req_common_set_dump_location_t),
2718				NULL);
2719	}
2720
2721	set_dump_loc = (sli4_req_common_set_dump_location_t *)((uint8_t *)buf + sli_config_off);
2722
2723	set_dump_loc->hdr.opcode = SLI4_OPC_COMMON_SET_DUMP_LOCATION;
2724	set_dump_loc->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2725	set_dump_loc->hdr.request_length = sizeof(sli4_req_common_set_dump_location_t) - sizeof(sli4_req_hdr_t);
2726	set_dump_loc->hdr.timeout = 0;
2727	set_dump_loc->hdr.version = 0;
2728
2729	set_dump_loc->blp = is_buffer_list;
2730	set_dump_loc->qry = query;
2731	set_dump_loc->fdb = fdb;
2732
2733	if (buffer) {
2734		set_dump_loc->buf_addr_low = ocs_addr32_lo(buffer->phys);
2735		set_dump_loc->buf_addr_high = ocs_addr32_hi(buffer->phys);
2736		set_dump_loc->buffer_length = buffer->len;
2737	} else {
2738		set_dump_loc->buf_addr_low = 0;
2739		set_dump_loc->buf_addr_high = 0;
2740		set_dump_loc->buffer_length = 0;
2741	}
2742
2743	return(sli_config_off + sizeof(sli4_req_common_set_dump_location_t));
2744}
2745
2746
2747/**
2748 * @ingroup sli
2749 * @brief Write a COMMON_SET_FEATURES command.
2750 *
2751 * @param sli4 SLI context.
2752 * @param buf Destination buffer for the command.
2753 * @param size Buffer size, in bytes.
2754 * @param feature Feature to set.
2755 * @param param_len Length of the parameter (must be a multiple of 4 bytes).
2756 * @param parameter Pointer to the parameter value.
2757 *
2758 * @return Returns the number of bytes written.
2759 */
2760int32_t
2761sli_cmd_common_set_features(sli4_t *sli4, void *buf, size_t size,
2762			    uint32_t feature,
2763			    uint32_t param_len,
2764			    void* parameter)
2765{
2766	sli4_req_common_set_features_t *cmd = NULL;
2767	uint32_t	sli_config_off = 0;
2768
2769	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2770		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2771				sizeof (sli4_req_common_set_features_t),
2772				NULL);
2773	}
2774
2775	cmd = (sli4_req_common_set_features_t *)((uint8_t *)buf + sli_config_off);
2776
2777	cmd->hdr.opcode = SLI4_OPC_COMMON_SET_FEATURES;
2778	cmd->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2779	cmd->hdr.request_length = sizeof(sli4_req_common_set_features_t) - sizeof(sli4_req_hdr_t);
2780	cmd->hdr.timeout = 0;
2781	cmd->hdr.version = 0;
2782
2783	cmd->feature = feature;
2784	cmd->param_len = param_len;
2785	ocs_memcpy(cmd->params, parameter, param_len);
2786
2787	return(sli_config_off + sizeof(sli4_req_common_set_features_t));
2788}
2789
2790/**
2791 * @ingroup sli
2792 * @brief Write a COMMON_COMMON_GET_PROFILE_CONFIG command.
2793 *
2794 * @param sli4 SLI context.
2795 * @param buf Destination buffer for the command.
2796 * @param size Buffer size in bytes.
2797 * @param dma DMA capable memory used to retrieve profile.
2798 *
2799 * @return Returns the number of bytes written.
2800 */
2801int32_t
2802sli_cmd_common_get_profile_config(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma)
2803{
2804        sli4_req_common_get_profile_config_t *req = NULL;
2805	uint32_t	sli_config_off = 0;
2806	uint32_t	payload_size;
2807
2808	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2809		sli_config_off = sli_cmd_sli_config(sli4, buf, size,
2810				sizeof (sli4_req_common_get_profile_config_t),
2811				dma);
2812	}
2813
2814	if (dma != NULL) {
2815		req = dma->virt;
2816		ocs_memset(req, 0, dma->size);
2817		payload_size = dma->size;
2818	} else {
2819		req = (sli4_req_common_get_profile_config_t *)((uint8_t *)buf + sli_config_off);
2820		payload_size = sizeof(sli4_req_common_get_profile_config_t);
2821	}
2822
2823        req->hdr.opcode = SLI4_OPC_COMMON_GET_PROFILE_CONFIG;
2824        req->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2825        req->hdr.request_length = payload_size - sizeof(sli4_req_hdr_t);
2826        req->hdr.version = 1;
2827
2828        return(sli_config_off + sizeof(sli4_req_common_get_profile_config_t));
2829}
2830
2831/**
2832 * @ingroup sli
2833 * @brief Write a COMMON_COMMON_SET_PROFILE_CONFIG command.
2834 *
2835 * @param sli4 SLI context.
2836 * @param buf Destination buffer for the command.
2837 * @param size Buffer size, in bytes.
2838 * @param dma DMA capable memory containing profile.
2839 * @param profile_id Profile ID to configure.
2840 * @param descriptor_count Number of descriptors in DMA buffer.
2841 * @param isap Implicit Set Active Profile value to use.
2842 *
2843 * @return Returns the number of bytes written.
2844 */
2845int32_t
2846sli_cmd_common_set_profile_config(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma,
2847		uint8_t profile_id, uint32_t descriptor_count, uint8_t isap)
2848{
2849        sli4_req_common_set_profile_config_t *req = NULL;
2850        uint32_t cmd_off = 0;
2851        uint32_t payload_size;
2852
2853	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2854		cmd_off = sli_cmd_sli_config(sli4, buf, size,
2855						    sizeof (sli4_req_common_set_profile_config_t),
2856						    dma);
2857	}
2858
2859	if (dma != NULL) {
2860		req = dma->virt;
2861		ocs_memset(req, 0, dma->size);
2862		payload_size = dma->size;
2863	} else {
2864		req = (sli4_req_common_set_profile_config_t *)((uint8_t *)buf + cmd_off);
2865		payload_size = sizeof(sli4_req_common_set_profile_config_t);
2866	}
2867
2868        req->hdr.opcode = SLI4_OPC_COMMON_SET_PROFILE_CONFIG;
2869        req->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2870        req->hdr.request_length = payload_size - sizeof(sli4_req_hdr_t);
2871        req->hdr.version = 1;
2872        req->profile_id = profile_id;
2873        req->desc_count = descriptor_count;
2874        req->isap = isap;
2875
2876        return(cmd_off + sizeof(sli4_req_common_set_profile_config_t));
2877}
2878
2879/**
2880 * @ingroup sli
2881 * @brief Write a COMMON_COMMON_GET_PROFILE_LIST command.
2882 *
2883 * @param sli4 SLI context.
2884 * @param buf Destination buffer for the command.
2885 * @param size Buffer size in bytes.
2886 * @param start_profile_index First profile index to return.
2887 * @param dma Buffer into which the list will be written.
2888 *
2889 * @return Returns the number of bytes written.
2890 */
2891int32_t
2892sli_cmd_common_get_profile_list(sli4_t *sli4, void *buf, size_t size,
2893                                   uint32_t start_profile_index, ocs_dma_t *dma)
2894{
2895        sli4_req_common_get_profile_list_t *req = NULL;
2896        uint32_t cmd_off = 0;
2897        uint32_t payload_size;
2898
2899	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2900		cmd_off = sli_cmd_sli_config(sli4, buf, size,
2901					     sizeof (sli4_req_common_get_profile_list_t),
2902					     dma);
2903	}
2904
2905	if (dma != NULL) {
2906		req = dma->virt;
2907		ocs_memset(req, 0, dma->size);
2908		payload_size = dma->size;
2909	} else {
2910		req = (sli4_req_common_get_profile_list_t *)((uint8_t *)buf + cmd_off);
2911		payload_size = sizeof(sli4_req_common_get_profile_list_t);
2912	}
2913
2914        req->hdr.opcode = SLI4_OPC_COMMON_GET_PROFILE_LIST;
2915        req->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2916        req->hdr.request_length = payload_size - sizeof(sli4_req_hdr_t);
2917        req->hdr.version = 0;
2918
2919        req->start_profile_index = start_profile_index;
2920
2921        return(cmd_off + sizeof(sli4_req_common_get_profile_list_t));
2922}
2923
2924/**
2925 * @ingroup sli
2926 * @brief Write a COMMON_COMMON_GET_ACTIVE_PROFILE command.
2927 *
2928 * @param sli4 SLI context.
2929 * @param buf Destination buffer for the command.
2930 * @param size Buffer size in bytes.
2931 *
2932 * @return Returns the number of bytes written.
2933 */
2934int32_t
2935sli_cmd_common_get_active_profile(sli4_t *sli4, void *buf, size_t size)
2936{
2937        sli4_req_common_get_active_profile_t *req = NULL;
2938        uint32_t cmd_off = 0;
2939        uint32_t payload_size;
2940
2941        /* Payload length must accommodate both request and response */
2942        payload_size = max(sizeof(sli4_req_common_get_active_profile_t),
2943                           sizeof(sli4_res_common_get_active_profile_t));
2944
2945	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2946		cmd_off = sli_cmd_sli_config(sli4, buf, size,
2947				payload_size,
2948				NULL);
2949	}
2950
2951        req = (sli4_req_common_get_active_profile_t *)
2952                ((uint8_t*)buf + cmd_off);
2953
2954        req->hdr.opcode = SLI4_OPC_COMMON_GET_ACTIVE_PROFILE;
2955        req->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2956        req->hdr.request_length = payload_size - sizeof(sli4_req_hdr_t);
2957        req->hdr.version = 0;
2958
2959        return(cmd_off + sizeof(sli4_req_common_get_active_profile_t));
2960}
2961
2962/**
2963 * @ingroup sli
2964 * @brief Write a COMMON_COMMON_SET_ACTIVE_PROFILE command.
2965 *
2966 * @param sli4 SLI context.
2967 * @param buf Destination buffer for the command.
2968 * @param size Buffer size in bytes.
2969 * @param fd If non-zero, set profile to factory default.
2970 * @param active_profile_id ID of new active profile.
2971 *
2972 * @return Returns the number of bytes written.
2973 */
2974int32_t
2975sli_cmd_common_set_active_profile(sli4_t *sli4, void *buf, size_t size,
2976                                  uint32_t fd, uint32_t active_profile_id)
2977{
2978        sli4_req_common_set_active_profile_t *req = NULL;
2979        uint32_t cmd_off = 0;
2980        uint32_t payload_size;
2981
2982        /* Payload length must accommodate both request and response */
2983        payload_size = max(sizeof(sli4_req_common_set_active_profile_t),
2984                           sizeof(sli4_res_common_set_active_profile_t));
2985
2986	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
2987		cmd_off = sli_cmd_sli_config(sli4, buf, size,
2988				payload_size,
2989				NULL);
2990	}
2991
2992        req = (sli4_req_common_set_active_profile_t *)
2993                ((uint8_t*)buf + cmd_off);
2994
2995        req->hdr.opcode = SLI4_OPC_COMMON_SET_ACTIVE_PROFILE;
2996        req->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
2997        req->hdr.request_length = payload_size - sizeof(sli4_req_hdr_t);
2998        req->hdr.version = 0;
2999        req->fd = fd;
3000        req->active_profile_id = active_profile_id;
3001
3002        return(cmd_off + sizeof(sli4_req_common_set_active_profile_t));
3003}
3004
3005/**
3006 * @ingroup sli
3007 * @brief Write a COMMON_GET_RECONFIG_LINK_INFO command.
3008 *
3009 * @param sli4 SLI context.
3010 * @param buf Destination buffer for the command.
3011 * @param size Buffer size in bytes.
3012 * @param dma Buffer to store the supported link configuration modes from the physical device.
3013 *
3014 * @return Returns the number of bytes written.
3015 */
3016int32_t
3017sli_cmd_common_get_reconfig_link_info(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma)
3018{
3019        sli4_req_common_get_reconfig_link_info_t *req = NULL;
3020        uint32_t cmd_off = 0;
3021        uint32_t payload_size;
3022
3023        /* Payload length must accommodate both request and response */
3024        payload_size = max(sizeof(sli4_req_common_get_reconfig_link_info_t),
3025                           sizeof(sli4_res_common_get_reconfig_link_info_t));
3026
3027	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
3028		cmd_off = sli_cmd_sli_config(sli4, buf, size,
3029				payload_size,
3030				dma);
3031	}
3032
3033	if (dma != NULL) {
3034		req = dma->virt;
3035		ocs_memset(req, 0, dma->size);
3036		payload_size = dma->size;
3037	} else {
3038		req = (sli4_req_common_get_reconfig_link_info_t *)((uint8_t *)buf + cmd_off);
3039		payload_size = sizeof(sli4_req_common_get_reconfig_link_info_t);
3040	}
3041
3042        req->hdr.opcode = SLI4_OPC_COMMON_GET_RECONFIG_LINK_INFO;
3043        req->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
3044        req->hdr.request_length = payload_size - sizeof(sli4_req_hdr_t);
3045        req->hdr.version = 0;
3046
3047        return(cmd_off + sizeof(sli4_req_common_get_reconfig_link_info_t));
3048}
3049
3050/**
3051 * @ingroup sli
3052 * @brief Write a COMMON_SET_RECONFIG_LINK_ID command.
3053 *
3054 * @param sli4 SLI context.
3055 * @param buf destination buffer for the command.
3056 * @param size buffer size in bytes.
3057 * @param fd If non-zero, set link config to factory default.
3058 * @param active_link_config_id ID of new active profile.
3059 * @param dma Buffer to assign the link configuration mode that is to become active from the physical device.
3060 *
3061 * @return Returns the number of bytes written.
3062 */
3063int32_t
3064sli_cmd_common_set_reconfig_link_id(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma,
3065                                  uint32_t fd, uint32_t active_link_config_id)
3066{
3067        sli4_req_common_set_reconfig_link_id_t *req = NULL;
3068        uint32_t cmd_off = 0;
3069        uint32_t payload_size;
3070
3071        /* Payload length must accommodate both request and response */
3072        payload_size = max(sizeof(sli4_req_common_set_reconfig_link_id_t),
3073                           sizeof(sli4_res_common_set_reconfig_link_id_t));
3074
3075	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
3076		cmd_off = sli_cmd_sli_config(sli4, buf, size,
3077				payload_size,
3078				NULL);
3079	}
3080
3081		if (dma != NULL) {
3082		req = dma->virt;
3083		ocs_memset(req, 0, dma->size);
3084		payload_size = dma->size;
3085	} else {
3086		req = (sli4_req_common_set_reconfig_link_id_t *)((uint8_t *)buf + cmd_off);
3087		payload_size = sizeof(sli4_req_common_set_reconfig_link_id_t);
3088	}
3089
3090        req->hdr.opcode = SLI4_OPC_COMMON_SET_RECONFIG_LINK_ID;
3091        req->hdr.subsystem = SLI4_SUBSYSTEM_COMMON;
3092        req->hdr.request_length = payload_size - sizeof(sli4_req_hdr_t);
3093        req->hdr.version = 0;
3094        req->fd = fd;
3095        req->next_link_config_id = active_link_config_id;
3096
3097        return(cmd_off + sizeof(sli4_req_common_set_reconfig_link_id_t));
3098}
3099
3100
3101/**
3102 * @ingroup sli
3103 * @brief Check the mailbox/queue completion entry.
3104 *
3105 * @param buf Pointer to the MCQE.
3106 *
3107 * @return Returns 0 on success, or a non-zero value on failure.
3108 */
3109int32_t
3110sli_cqe_mq(void *buf)
3111{
3112	sli4_mcqe_t	*mcqe = buf;
3113
3114	/*
3115	 * Firmware can split mbx completions into two MCQEs: first with only
3116	 * the "consumed" bit set and a second with the "complete" bit set.
3117	 * Thus, ignore MCQE unless "complete" is set.
3118	 */
3119	if (!mcqe->cmp) {
3120		return -2;
3121	}
3122
3123	if (mcqe->completion_status) {
3124		ocs_log_debug(NULL, "bad status (cmpl=%#x ext=%#x con=%d cmp=%d ae=%d val=%d)\n",
3125				mcqe->completion_status,
3126				mcqe->extended_status,
3127				mcqe->con,
3128				mcqe->cmp,
3129				mcqe->ae,
3130				mcqe->val);
3131	}
3132
3133	return mcqe->completion_status;
3134}
3135
3136/**
3137 * @ingroup sli
3138 * @brief Check the asynchronous event completion entry.
3139 *
3140 * @param sli4 SLI context.
3141 * @param buf Pointer to the ACQE.
3142 *
3143 * @return Returns 0 on success, or a non-zero value on failure.
3144 */
3145int32_t
3146sli_cqe_async(sli4_t *sli4, void *buf)
3147{
3148	sli4_acqe_t	*acqe = buf;
3149	int32_t		rc = -1;
3150
3151	if (!sli4 || !buf) {
3152		ocs_log_err(NULL, "bad parameter sli4=%p buf=%p\n", sli4, buf);
3153		return -1;
3154	}
3155
3156	switch (acqe->event_code) {
3157	case SLI4_ACQE_EVENT_CODE_LINK_STATE:
3158		rc = sli_fc_process_link_state(sli4, buf);
3159		break;
3160	case SLI4_ACQE_EVENT_CODE_FCOE_FIP:
3161		rc = sli_fc_process_fcoe(sli4, buf);
3162		break;
3163	case SLI4_ACQE_EVENT_CODE_GRP_5:
3164		/*TODO*/ocs_log_debug(sli4->os, "ACQE GRP5\n");
3165		break;
3166	case SLI4_ACQE_EVENT_CODE_SLI_PORT_EVENT:
3167        ocs_log_debug(sli4->os,"ACQE SLI Port, type=0x%x, data1,2=0x%08x,0x%08x\n",
3168		acqe->event_type, acqe->event_data[0], acqe->event_data[1]);
3169#if defined(OCS_INCLUDE_DEBUG)
3170		ocs_dump32(OCS_DEBUG_ALWAYS, sli4->os, "acq", acqe, sizeof(*acqe));
3171#endif
3172		break;
3173	case SLI4_ACQE_EVENT_CODE_FC_LINK_EVENT:
3174		rc = sli_fc_process_link_attention(sli4, buf);
3175		break;
3176	default:
3177		/*TODO*/ocs_log_test(sli4->os, "ACQE unknown=%#x\n", acqe->event_code);
3178	}
3179
3180	return rc;
3181}
3182
3183/**
3184 * @brief Check the SLI_CONFIG response.
3185 *
3186 * @par Description
3187 * Function checks the SLI_CONFIG response and the payload status.
3188 *
3189 * @param buf Pointer to SLI_CONFIG response.
3190 *
3191 * @return Returns 0 on success, or a non-zero value on failure.
3192 */
3193static int32_t
3194sli_res_sli_config(void *buf)
3195{
3196	sli4_cmd_sli_config_t	*sli_config = buf;
3197
3198	if (!buf || (SLI4_MBOX_COMMAND_SLI_CONFIG != sli_config->hdr.command)) {
3199		ocs_log_err(NULL, "bad parameter buf=%p cmd=%#x\n", buf,
3200				buf ? sli_config->hdr.command : -1);
3201		return -1;
3202	}
3203
3204	if (sli_config->hdr.status) {
3205		return sli_config->hdr.status;
3206	}
3207
3208	if (sli_config->emb) {
3209		return sli_config->payload.embed[4];
3210	} else {
3211		ocs_log_test(NULL, "external buffers not supported\n");
3212		return -1;
3213	}
3214}
3215
3216/**
3217 * @brief Issue a COMMON_FUNCTION_RESET command.
3218 *
3219 * @param sli4 SLI context.
3220 *
3221 * @return Returns 0 on success, or a non-zero value on failure.
3222 */
3223static int32_t
3224sli_common_function_reset(sli4_t *sli4)
3225{
3226
3227	if (sli_cmd_common_function_reset(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE)) {
3228		if (sli_bmbx_command(sli4)) {
3229			ocs_log_crit(sli4->os, "bootstrap mailbox write fail (COM_FUNC_RESET)\n");
3230			return -1;
3231		}
3232		if (sli_res_sli_config(sli4->bmbx.virt)) {
3233			ocs_log_err(sli4->os, "bad status COM_FUNC_RESET\n");
3234			return -1;
3235		}
3236	} else {
3237		ocs_log_err(sli4->os, "bad COM_FUNC_RESET write\n");
3238		return -1;
3239	}
3240
3241	return 0;
3242}
3243
3244
3245/**
3246 * @brief check to see if the FW is ready.
3247 *
3248 * @par Description
3249 * Based on <i>SLI-4 Architecture Specification, Revision 4.x0-13 (2012).</i>.
3250 *
3251 * @param sli4 SLI context.
3252 * @param timeout_ms Time, in milliseconds, to wait for the port to be ready
3253 *  before failing.
3254 *
3255 * @return Returns TRUE for ready, or FALSE otherwise.
3256 */
3257static int32_t
3258sli_wait_for_fw_ready(sli4_t *sli4, uint32_t timeout_ms)
3259{
3260	uint32_t	iter = timeout_ms / (SLI4_INIT_PORT_DELAY_US / 1000);
3261	uint32_t	ready = FALSE;
3262
3263	do {
3264		iter--;
3265		ocs_udelay(SLI4_INIT_PORT_DELAY_US);
3266		if (sli_fw_ready(sli4) == 1) {
3267			ready = TRUE;
3268		}
3269	} while (!ready && (iter > 0));
3270
3271	return ready;
3272}
3273
3274/**
3275 * @brief Initialize the firmware.
3276 *
3277 * @par Description
3278 * Based on <i>SLI-4 Architecture Specification, Revision 4.x0-13 (2012).</i>.
3279 *
3280 * @param sli4 SLI context.
3281 *
3282 * @return Returns 0 on success, or a non-zero value on failure.
3283 */
3284static int32_t
3285sli_fw_init(sli4_t *sli4)
3286{
3287	uint32_t ready;
3288	uint32_t endian;
3289
3290	/*
3291	 * Is firmware ready for operation?
3292	 */
3293	ready = sli_wait_for_fw_ready(sli4, SLI4_FW_READY_TIMEOUT_MSEC);
3294	if (!ready) {
3295		ocs_log_crit(sli4->os, "FW status is NOT ready\n");
3296		return -1;
3297	}
3298
3299	/*
3300	 * Reset port to a known state
3301	 */
3302	switch (sli4->if_type) {
3303	case SLI4_IF_TYPE_BE3_SKH_PF:
3304	case SLI4_IF_TYPE_BE3_SKH_VF:
3305		/* No SLIPORT_CONTROL register so use command sequence instead */
3306		if (sli_bmbx_wait(sli4, SLI4_BMBX_DELAY_US)) {
3307			ocs_log_crit(sli4->os, "bootstrap mailbox not ready\n");
3308			return -1;
3309		}
3310
3311		if (sli_cmd_fw_initialize(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE)) {
3312			if (sli_bmbx_command(sli4)) {
3313				ocs_log_crit(sli4->os, "bootstrap mailbox write fail (FW_INIT)\n");
3314				return -1;
3315			}
3316		} else {
3317			ocs_log_crit(sli4->os, "bad FW_INIT write\n");
3318			return -1;
3319		}
3320
3321		if (sli_common_function_reset(sli4)) {
3322			ocs_log_err(sli4->os, "bad COM_FUNC_RESET write\n");
3323			return -1;
3324		}
3325		break;
3326	case SLI4_IF_TYPE_LANCER_FC_ETH:
3327#if BYTE_ORDER == LITTLE_ENDIAN
3328		endian = SLI4_SLIPORT_CONTROL_LITTLE_ENDIAN;
3329#else
3330		endian = SLI4_SLIPORT_CONTROL_BIG_ENDIAN;
3331#endif
3332
3333		if (sli_sliport_control(sli4, endian))
3334			return -1;
3335		break;
3336	default:
3337		ocs_log_test(sli4->os, "if_type %d not supported\n", sli4->if_type);
3338		return -1;
3339	}
3340
3341	return 0;
3342}
3343
3344/**
3345 * @brief Terminate the firmware.
3346 *
3347 * @param sli4 SLI context.
3348 *
3349 * @return Returns 0 on success, or a non-zero value on failure.
3350 */
3351static int32_t
3352sli_fw_term(sli4_t *sli4)
3353{
3354	uint32_t endian;
3355
3356	if (sli4->if_type == SLI4_IF_TYPE_BE3_SKH_PF ||
3357	    sli4->if_type == SLI4_IF_TYPE_BE3_SKH_VF) {
3358		/* No SLIPORT_CONTROL register so use command sequence instead */
3359		if (sli_bmbx_wait(sli4, SLI4_BMBX_DELAY_US)) {
3360			ocs_log_crit(sli4->os, "bootstrap mailbox not ready\n");
3361			return -1;
3362		}
3363
3364		if (sli_common_function_reset(sli4)) {
3365			ocs_log_err(sli4->os, "bad COM_FUNC_RESET write\n");
3366			return -1;
3367		}
3368
3369		if (sli_cmd_fw_deinitialize(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE)) {
3370			if (sli_bmbx_command(sli4)) {
3371				ocs_log_crit(sli4->os, "bootstrap mailbox write fail (FW_DEINIT)\n");
3372				return -1;
3373			}
3374		} else {
3375			ocs_log_test(sli4->os, "bad FW_DEINIT write\n");
3376			return -1;
3377		}
3378	} else {
3379#if BYTE_ORDER == LITTLE_ENDIAN
3380		endian = SLI4_SLIPORT_CONTROL_LITTLE_ENDIAN;
3381#else
3382		endian = SLI4_SLIPORT_CONTROL_BIG_ENDIAN;
3383#endif
3384		/* type 2 etc. use SLIPORT_CONTROL to initialize port */
3385		sli_sliport_control(sli4, endian);
3386	}
3387	return 0;
3388}
3389
3390/**
3391 * @brief Write the doorbell register associated with the queue object.
3392 *
3393 * @param sli4 SLI context.
3394 * @param q Queue object.
3395 *
3396 * @return Returns 0 on success, or a non-zero value on failure.
3397 */
3398static int32_t
3399sli_queue_doorbell(sli4_t *sli4, sli4_queue_t *q)
3400{
3401	uint32_t	val = 0;
3402
3403	switch (q->type) {
3404	case SLI_QTYPE_EQ:
3405		val = sli_eq_doorbell(q->n_posted, q->id, FALSE);
3406		ocs_reg_write32(sli4->os, q->doorbell_rset, q->doorbell_offset, val);
3407		break;
3408	case SLI_QTYPE_CQ:
3409		val = sli_cq_doorbell(q->n_posted, q->id, FALSE);
3410		ocs_reg_write32(sli4->os, q->doorbell_rset, q->doorbell_offset, val);
3411		break;
3412	case SLI_QTYPE_MQ:
3413		val = SLI4_MQ_DOORBELL(q->n_posted, q->id);
3414		ocs_reg_write32(sli4->os, q->doorbell_rset, q->doorbell_offset, val);
3415		break;
3416	case SLI_QTYPE_RQ:
3417	{
3418		uint32_t	n_posted = q->n_posted;
3419		/*
3420		 * FC/FCoE has different rules for Receive Queues. The host
3421		 * should only update the doorbell of the RQ-pair containing
3422		 * the headers since the header / payload RQs are treated
3423		 * as a matched unit.
3424		 */
3425		if (SLI4_PORT_TYPE_FC == sli4->port_type) {
3426			/*
3427			 * In RQ-pair, an RQ either contains the FC header
3428			 * (i.e. is_hdr == TRUE) or the payload.
3429			 *
3430			 * Don't ring doorbell for payload RQ
3431			 */
3432			if (!q->u.flag.is_hdr) {
3433				break;
3434			}
3435			/*
3436			 * Some RQ cannot be incremented one entry at a time. Instead,
3437			 * the driver collects a number of entries and updates the
3438			 * RQ in batches.
3439			 */
3440			if (q->u.flag.rq_batch) {
3441				if (((q->index + q->n_posted) % SLI4_QUEUE_RQ_BATCH)) {
3442					break;
3443				}
3444				n_posted = SLI4_QUEUE_RQ_BATCH;
3445			}
3446		}
3447
3448		val = SLI4_RQ_DOORBELL(n_posted, q->id);
3449		ocs_reg_write32(sli4->os, q->doorbell_rset, q->doorbell_offset, val);
3450		break;
3451	}
3452	case SLI_QTYPE_WQ:
3453		val = SLI4_WQ_DOORBELL(q->n_posted, q->index, q->id);
3454		ocs_reg_write32(sli4->os, q->doorbell_rset, q->doorbell_offset, val);
3455		break;
3456	default:
3457		ocs_log_test(sli4->os, "bad queue type %d\n", q->type);
3458		return -1;
3459	}
3460
3461	return 0;
3462}
3463
3464static int32_t
3465sli_request_features(sli4_t *sli4, sli4_features_t *features, uint8_t query)
3466{
3467
3468	if (sli_cmd_request_features(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE,
3469				*features, query)) {
3470		sli4_cmd_request_features_t *req_features = sli4->bmbx.virt;
3471
3472		if (sli_bmbx_command(sli4)) {
3473			ocs_log_crit(sli4->os, "bootstrap mailbox write fail (REQUEST_FEATURES)\n");
3474			return -1;
3475		}
3476		if (req_features->hdr.status) {
3477			ocs_log_err(sli4->os, "REQUEST_FEATURES bad status %#x\n",
3478					req_features->hdr.status);
3479			return -1;
3480		}
3481		features->dword = req_features->response.dword;
3482	} else {
3483		ocs_log_err(sli4->os, "bad REQUEST_FEATURES write\n");
3484		return -1;
3485	}
3486
3487	return 0;
3488}
3489
3490/**
3491 * @brief Calculate max queue entries.
3492 *
3493 * @param sli4 SLI context.
3494 *
3495 * @return Returns 0 on success, or a non-zero value on failure.
3496 */
3497void
3498sli_calc_max_qentries(sli4_t *sli4)
3499{
3500	sli4_qtype_e q;
3501	uint32_t alloc_size, qentries, qentry_size;
3502
3503	for (q = SLI_QTYPE_EQ; q < SLI_QTYPE_MAX; q++) {
3504		sli4->config.max_qentries[q] = sli_convert_mask_to_count(sli4->config.count_method[q],
3505									 sli4->config.count_mask[q]);
3506	}
3507
3508	/* single, continguous DMA allocations will be called for each queue
3509	 * of size (max_qentries * queue entry size); since these can be large,
3510	 * check against the OS max DMA allocation size
3511	 */
3512	for (q = SLI_QTYPE_EQ; q < SLI_QTYPE_MAX; q++) {
3513		qentries = sli4->config.max_qentries[q];
3514		qentry_size = sli_get_queue_entry_size(sli4, q);
3515		alloc_size = qentries * qentry_size;
3516		if (alloc_size > ocs_max_dma_alloc(sli4->os, SLI_PAGE_SIZE)) {
3517			while (alloc_size > ocs_max_dma_alloc(sli4->os, SLI_PAGE_SIZE)) {
3518				/* cut the qentries in hwf until alloc_size <= max DMA alloc size */
3519				qentries >>= 1;
3520				alloc_size = qentries * qentry_size;
3521			}
3522			ocs_log_debug(sli4->os, "[%s]: max_qentries from %d to %d (max dma %d)\n",
3523				SLI_QNAME[q], sli4->config.max_qentries[q],
3524				qentries, ocs_max_dma_alloc(sli4->os, SLI_PAGE_SIZE));
3525			sli4->config.max_qentries[q] = qentries;
3526		}
3527	}
3528}
3529
3530/**
3531 * @brief Issue a FW_CONFIG mailbox command and store the results.
3532 *
3533 * @param sli4 SLI context.
3534 *
3535 * @return Returns 0 on success, or a non-zero value on failure.
3536 */
3537static int32_t
3538sli_query_fw_config(sli4_t *sli4)
3539{
3540	/*
3541	 * Read the device configuration
3542	 *
3543	 * Note: Only ulp0 fields contain values
3544	 */
3545	if (sli_cmd_common_query_fw_config(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE)) {
3546		sli4_res_common_query_fw_config_t   *fw_config =
3547			(sli4_res_common_query_fw_config_t *)
3548			(((uint8_t *)sli4->bmbx.virt) + offsetof(sli4_cmd_sli_config_t, payload.embed));
3549
3550		if (sli_bmbx_command(sli4)) {
3551			ocs_log_crit(sli4->os, "bootstrap mailbox write fail (QUERY_FW_CONFIG)\n");
3552			return -1;
3553		}
3554		if (fw_config->hdr.status) {
3555			ocs_log_err(sli4->os, "COMMON_QUERY_FW_CONFIG bad status %#x\n",
3556				fw_config->hdr.status);
3557			return -1;
3558		}
3559
3560		sli4->physical_port = fw_config->physical_port;
3561		sli4->config.dual_ulp_capable = ((fw_config->function_mode & SLI4_FUNCTION_MODE_DUA_MODE) == 0 ? 0 : 1);
3562		sli4->config.is_ulp_fc[0] = ((fw_config->ulp0_mode &
3563					      (SLI4_ULP_MODE_FCOE_INI |
3564					       SLI4_ULP_MODE_FCOE_TGT)) == 0 ? 0 : 1);
3565		sli4->config.is_ulp_fc[1] = ((fw_config->ulp1_mode &
3566					      (SLI4_ULP_MODE_FCOE_INI |
3567					       SLI4_ULP_MODE_FCOE_TGT)) == 0 ? 0 : 1);
3568
3569		if (sli4->config.dual_ulp_capable) {
3570			/*
3571			 * Lancer will not support this, so we use the values
3572			 * from the READ_CONFIG.
3573			 */
3574			if (sli4->config.is_ulp_fc[0] &&
3575			    sli4->config.is_ulp_fc[1]) {
3576				sli4->config.max_qcount[SLI_QTYPE_WQ] = fw_config->ulp0_toe_wq_total + fw_config->ulp1_toe_wq_total;
3577				sli4->config.max_qcount[SLI_QTYPE_RQ] = fw_config->ulp0_toe_defrq_total + fw_config->ulp1_toe_defrq_total;
3578			} else if (sli4->config.is_ulp_fc[0]) {
3579				sli4->config.max_qcount[SLI_QTYPE_WQ] = fw_config->ulp0_toe_wq_total;
3580				sli4->config.max_qcount[SLI_QTYPE_RQ] = fw_config->ulp0_toe_defrq_total;
3581			} else {
3582				sli4->config.max_qcount[SLI_QTYPE_WQ] = fw_config->ulp1_toe_wq_total;
3583				sli4->config.max_qcount[SLI_QTYPE_RQ] = fw_config->ulp1_toe_defrq_total;
3584			}
3585		}
3586	} else {
3587		ocs_log_err(sli4->os, "bad QUERY_FW_CONFIG write\n");
3588		return -1;
3589	}
3590	return 0;
3591}
3592
3593
3594static int32_t
3595sli_get_config(sli4_t *sli4)
3596{
3597	ocs_dma_t	get_cntl_addl_data;
3598
3599	/*
3600	 * Read the device configuration
3601	 */
3602	if (sli_cmd_read_config(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE)) {
3603		sli4_res_read_config_t	*read_config = sli4->bmbx.virt;
3604		uint32_t	i;
3605		uint32_t	total;
3606
3607		if (sli_bmbx_command(sli4)) {
3608			ocs_log_crit(sli4->os, "bootstrap mailbox write fail (READ_CONFIG)\n");
3609			return -1;
3610		}
3611		if (read_config->hdr.status) {
3612			ocs_log_err(sli4->os, "READ_CONFIG bad status %#x\n",
3613					read_config->hdr.status);
3614			return -1;
3615		}
3616
3617		sli4->config.has_extents = read_config->ext;
3618		if (FALSE == sli4->config.has_extents) {
3619			uint32_t	i = 0;
3620			uint32_t	*base = sli4->config.extent[0].base;
3621
3622			if (!base) {
3623				if (NULL == (base = ocs_malloc(sli4->os, SLI_RSRC_MAX * sizeof(uint32_t),
3624								OCS_M_ZERO | OCS_M_NOWAIT))) {
3625					ocs_log_err(sli4->os, "memory allocation failed for sli4_resource_t\n");
3626					return -1;
3627				}
3628			}
3629
3630			for (i = 0; i < SLI_RSRC_MAX; i++) {
3631				sli4->config.extent[i].number = 1;
3632				sli4->config.extent[i].n_alloc = 0;
3633				sli4->config.extent[i].base = &base[i];
3634			}
3635
3636			sli4->config.extent[SLI_RSRC_FCOE_VFI].base[0] = read_config->vfi_base;
3637			sli4->config.extent[SLI_RSRC_FCOE_VFI].size = read_config->vfi_count;
3638
3639			sli4->config.extent[SLI_RSRC_FCOE_VPI].base[0] = read_config->vpi_base;
3640			sli4->config.extent[SLI_RSRC_FCOE_VPI].size = read_config->vpi_count;
3641
3642			sli4->config.extent[SLI_RSRC_FCOE_RPI].base[0] = read_config->rpi_base;
3643			sli4->config.extent[SLI_RSRC_FCOE_RPI].size = read_config->rpi_count;
3644
3645			sli4->config.extent[SLI_RSRC_FCOE_XRI].base[0] = read_config->xri_base;
3646			sli4->config.extent[SLI_RSRC_FCOE_XRI].size = read_config->xri_count;
3647
3648			sli4->config.extent[SLI_RSRC_FCOE_FCFI].base[0] = 0;
3649			sli4->config.extent[SLI_RSRC_FCOE_FCFI].size = read_config->fcfi_count;
3650		} else {
3651			/* TODO extents*/
3652			;
3653		}
3654
3655		for (i = 0; i < SLI_RSRC_MAX; i++) {
3656			total = sli4->config.extent[i].number * sli4->config.extent[i].size;
3657			sli4->config.extent[i].use_map = ocs_bitmap_alloc(total);
3658			if (NULL == sli4->config.extent[i].use_map) {
3659				ocs_log_err(sli4->os, "bitmap memory allocation failed "
3660						"resource %d\n", i);
3661				return -1;
3662			}
3663			sli4->config.extent[i].map_size = total;
3664		}
3665
3666		sli4->config.topology = read_config->topology;
3667		switch (sli4->config.topology) {
3668		case SLI4_READ_CFG_TOPO_FCOE:
3669			ocs_log_debug(sli4->os, "FCoE\n");
3670			break;
3671		case SLI4_READ_CFG_TOPO_FC:
3672			ocs_log_debug(sli4->os, "FC (unknown)\n");
3673			break;
3674		case SLI4_READ_CFG_TOPO_FC_DA:
3675			ocs_log_debug(sli4->os, "FC (direct attach)\n");
3676			break;
3677		case SLI4_READ_CFG_TOPO_FC_AL:
3678			ocs_log_debug(sli4->os, "FC (arbitrated loop)\n");
3679			break;
3680		default:
3681			ocs_log_test(sli4->os, "bad topology %#x\n", sli4->config.topology);
3682		}
3683
3684		sli4->config.e_d_tov = read_config->e_d_tov;
3685		sli4->config.r_a_tov = read_config->r_a_tov;
3686
3687		sli4->config.link_module_type = read_config->lmt;
3688
3689		sli4->config.max_qcount[SLI_QTYPE_EQ] = read_config->eq_count;
3690		sli4->config.max_qcount[SLI_QTYPE_CQ] = read_config->cq_count;
3691		sli4->config.max_qcount[SLI_QTYPE_WQ] = read_config->wq_count;
3692		sli4->config.max_qcount[SLI_QTYPE_RQ] = read_config->rq_count;
3693
3694		/*
3695		 * READ_CONFIG doesn't give the max number of MQ. Applications
3696		 * will typically want 1, but we may need another at some future
3697		 * date. Dummy up a "max" MQ count here.
3698		 */
3699		sli4->config.max_qcount[SLI_QTYPE_MQ] = SLI_USER_MQ_COUNT;
3700	} else {
3701		ocs_log_err(sli4->os, "bad READ_CONFIG write\n");
3702		return -1;
3703	}
3704
3705	if (sli_cmd_common_get_sli4_parameters(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE)) {
3706		sli4_res_common_get_sli4_parameters_t	*parms = (sli4_res_common_get_sli4_parameters_t *)
3707			(((uint8_t *)sli4->bmbx.virt) + offsetof(sli4_cmd_sli_config_t, payload.embed));
3708
3709		if (sli_bmbx_command(sli4)) {
3710			ocs_log_crit(sli4->os, "bootstrap mailbox write fail (COMMON_GET_SLI4_PARAMETERS)\n");
3711			return -1;
3712		} else if (parms->hdr.status) {
3713			ocs_log_err(sli4->os, "COMMON_GET_SLI4_PARAMETERS bad status %#x att'l %#x\n",
3714					parms->hdr.status, parms->hdr.additional_status);
3715			return -1;
3716		}
3717
3718		sli4->config.auto_reg = parms->areg;
3719		sli4->config.auto_xfer_rdy = parms->agxf;
3720		sli4->config.hdr_template_req = parms->hdrr;
3721		sli4->config.t10_dif_inline_capable = parms->timm;
3722		sli4->config.t10_dif_separate_capable = parms->tsmm;
3723
3724		sli4->config.mq_create_version = parms->mqv;
3725		sli4->config.cq_create_version = parms->cqv;
3726		sli4->config.rq_min_buf_size = parms->min_rq_buffer_size;
3727		sli4->config.rq_max_buf_size = parms->max_rq_buffer_size;
3728
3729		sli4->config.qpage_count[SLI_QTYPE_EQ] = parms->eq_page_cnt;
3730		sli4->config.qpage_count[SLI_QTYPE_CQ] = parms->cq_page_cnt;
3731		sli4->config.qpage_count[SLI_QTYPE_MQ] = parms->mq_page_cnt;
3732		sli4->config.qpage_count[SLI_QTYPE_WQ] = parms->wq_page_cnt;
3733		sli4->config.qpage_count[SLI_QTYPE_RQ] = parms->rq_page_cnt;
3734
3735		/* save count methods and masks for each queue type */
3736		sli4->config.count_mask[SLI_QTYPE_EQ] = parms->eqe_count_mask;
3737		sli4->config.count_method[SLI_QTYPE_EQ] = parms->eqe_count_method;
3738		sli4->config.count_mask[SLI_QTYPE_CQ] = parms->cqe_count_mask;
3739		sli4->config.count_method[SLI_QTYPE_CQ] = parms->cqe_count_method;
3740		sli4->config.count_mask[SLI_QTYPE_MQ] = parms->mqe_count_mask;
3741		sli4->config.count_method[SLI_QTYPE_MQ] = parms->mqe_count_method;
3742		sli4->config.count_mask[SLI_QTYPE_WQ] = parms->wqe_count_mask;
3743		sli4->config.count_method[SLI_QTYPE_WQ] = parms->wqe_count_method;
3744		sli4->config.count_mask[SLI_QTYPE_RQ] = parms->rqe_count_mask;
3745		sli4->config.count_method[SLI_QTYPE_RQ] = parms->rqe_count_method;
3746
3747		/* now calculate max queue entries */
3748		sli_calc_max_qentries(sli4);
3749
3750		sli4->config.max_sgl_pages = parms->sgl_page_cnt;	/* max # of pages */
3751		sli4->config.sgl_page_sizes = parms->sgl_page_sizes;	/* bit map of available sizes */
3752		/* ignore HLM here. Use value from REQUEST_FEATURES */
3753
3754		sli4->config.sge_supported_length = parms->sge_supported_length;
3755		if (sli4->config.sge_supported_length > OCS_MAX_SGE_SIZE)
3756			sli4->config.sge_supported_length = OCS_MAX_SGE_SIZE;
3757
3758		sli4->config.sgl_pre_registration_required = parms->sglr;
3759		/* default to using pre-registered SGL's */
3760		sli4->config.sgl_pre_registered = TRUE;
3761
3762		sli4->config.perf_hint = parms->phon;
3763		sli4->config.perf_wq_id_association = parms->phwq;
3764
3765		sli4->config.rq_batch = parms->rq_db_window;
3766
3767		/* save the fields for skyhawk SGL chaining */
3768		sli4->config.sgl_chaining_params.chaining_capable =
3769			(parms->sglc == 1);
3770		sli4->config.sgl_chaining_params.frag_num_field_offset =
3771			parms->frag_num_field_offset;
3772		sli4->config.sgl_chaining_params.frag_num_field_mask =
3773			(1ull << parms->frag_num_field_size) - 1;
3774		sli4->config.sgl_chaining_params.sgl_index_field_offset =
3775			parms->sgl_index_field_offset;
3776		sli4->config.sgl_chaining_params.sgl_index_field_mask =
3777			(1ull << parms->sgl_index_field_size) - 1;
3778		sli4->config.sgl_chaining_params.chain_sge_initial_value_lo =
3779			parms->chain_sge_initial_value_lo;
3780		sli4->config.sgl_chaining_params.chain_sge_initial_value_hi =
3781			parms->chain_sge_initial_value_hi;
3782
3783		/* Use the highest available WQE size. */
3784		if (parms->wqe_sizes & SLI4_128BYTE_WQE_SUPPORT) {
3785			sli4->config.wqe_size = SLI4_WQE_EXT_BYTES;
3786		} else {
3787			sli4->config.wqe_size = SLI4_WQE_BYTES;
3788		}
3789	}
3790
3791	if (sli_query_fw_config(sli4)) {
3792		ocs_log_err(sli4->os, "Error sending QUERY_FW_CONFIG\n");
3793		return -1;
3794	}
3795
3796	sli4->config.port_number = 0;
3797
3798	/*
3799	 * Issue COMMON_GET_CNTL_ATTRIBUTES to get port_number. Temporarily
3800	 * uses VPD DMA buffer as the response won't fit in the embedded
3801	 * buffer.
3802	 */
3803	if (sli_cmd_common_get_cntl_attributes(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE, &sli4->vpd.data)) {
3804		sli4_res_common_get_cntl_attributes_t *attr = sli4->vpd.data.virt;
3805
3806		if (sli_bmbx_command(sli4)) {
3807			ocs_log_crit(sli4->os, "bootstrap mailbox write fail (COMMON_GET_CNTL_ATTRIBUTES)\n");
3808			return -1;
3809		} else if (attr->hdr.status) {
3810			ocs_log_err(sli4->os, "COMMON_GET_CNTL_ATTRIBUTES bad status %#x att'l %#x\n",
3811					attr->hdr.status, attr->hdr.additional_status);
3812			return -1;
3813		}
3814
3815		sli4->config.port_number = attr->port_number;
3816
3817		ocs_memcpy(sli4->config.bios_version_string, attr->bios_version_string,
3818				sizeof(sli4->config.bios_version_string));
3819	} else {
3820		ocs_log_err(sli4->os, "bad COMMON_GET_CNTL_ATTRIBUTES write\n");
3821		return -1;
3822	}
3823
3824	if (ocs_dma_alloc(sli4->os, &get_cntl_addl_data, sizeof(sli4_res_common_get_cntl_addl_attributes_t),
3825			  OCS_MIN_DMA_ALIGNMENT)) {
3826		ocs_log_err(sli4->os, "Failed to allocate memory for GET_CNTL_ADDL_ATTR data\n");
3827	} else {
3828		if (sli_cmd_common_get_cntl_addl_attributes(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE,
3829							    &get_cntl_addl_data)) {
3830			sli4_res_common_get_cntl_addl_attributes_t *attr = get_cntl_addl_data.virt;
3831
3832			if (sli_bmbx_command(sli4)) {
3833				ocs_log_crit(sli4->os,
3834					     "bootstrap mailbox write fail (COMMON_GET_CNTL_ADDL_ATTRIBUTES)\n");
3835				ocs_dma_free(sli4->os, &get_cntl_addl_data);
3836				return -1;
3837			}
3838			if (attr->hdr.status) {
3839				ocs_log_err(sli4->os, "COMMON_GET_CNTL_ADDL_ATTRIBUTES bad status %#x\n",
3840					    attr->hdr.status);
3841				ocs_dma_free(sli4->os, &get_cntl_addl_data);
3842				return -1;
3843			}
3844
3845			ocs_memcpy(sli4->config.ipl_name, attr->ipl_file_name, sizeof(sli4->config.ipl_name));
3846
3847			ocs_log_debug(sli4->os, "IPL:%s \n", (char*)sli4->config.ipl_name);
3848		} else {
3849			ocs_log_err(sli4->os, "bad COMMON_GET_CNTL_ADDL_ATTRIBUTES write\n");
3850			ocs_dma_free(sli4->os, &get_cntl_addl_data);
3851			return -1;
3852		}
3853
3854		ocs_dma_free(sli4->os, &get_cntl_addl_data);
3855	}
3856
3857	if (sli_cmd_common_get_port_name(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE)) {
3858		sli4_res_common_get_port_name_t	*port_name = (sli4_res_common_get_port_name_t *)(((uint8_t *)sli4->bmbx.virt) +
3859			offsetof(sli4_cmd_sli_config_t, payload.embed));
3860
3861		if (sli_bmbx_command(sli4)) {
3862			ocs_log_crit(sli4->os, "bootstrap mailbox write fail (COMMON_GET_PORT_NAME)\n");
3863			return -1;
3864		}
3865
3866		sli4->config.port_name[0] = port_name->port_name[sli4->config.port_number];
3867	}
3868	sli4->config.port_name[1] = '\0';
3869
3870	if (sli_cmd_read_rev(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE, &sli4->vpd.data)) {
3871		sli4_cmd_read_rev_t	*read_rev = sli4->bmbx.virt;
3872
3873		if (sli_bmbx_command(sli4)) {
3874			ocs_log_crit(sli4->os, "bootstrap mailbox write fail (READ_REV)\n");
3875			return -1;
3876		}
3877		if (read_rev->hdr.status) {
3878			ocs_log_err(sli4->os, "READ_REV bad status %#x\n",
3879					read_rev->hdr.status);
3880			return -1;
3881		}
3882
3883		sli4->config.fw_rev[0] = read_rev->first_fw_id;
3884		ocs_memcpy(sli4->config.fw_name[0],read_rev->first_fw_name, sizeof(sli4->config.fw_name[0]));
3885
3886		sli4->config.fw_rev[1] = read_rev->second_fw_id;
3887		ocs_memcpy(sli4->config.fw_name[1],read_rev->second_fw_name, sizeof(sli4->config.fw_name[1]));
3888
3889		sli4->config.hw_rev[0] = read_rev->first_hw_revision;
3890		sli4->config.hw_rev[1] = read_rev->second_hw_revision;
3891		sli4->config.hw_rev[2] = read_rev->third_hw_revision;
3892
3893		ocs_log_debug(sli4->os, "FW1:%s (%08x) / FW2:%s (%08x)\n",
3894				read_rev->first_fw_name, read_rev->first_fw_id,
3895				read_rev->second_fw_name, read_rev->second_fw_id);
3896
3897		ocs_log_debug(sli4->os, "HW1: %08x / HW2: %08x\n", read_rev->first_hw_revision,
3898				read_rev->second_hw_revision);
3899
3900		/* Check that all VPD data was returned */
3901		if (read_rev->returned_vpd_length != read_rev->actual_vpd_length) {
3902			ocs_log_test(sli4->os, "VPD length: available=%d returned=%d actual=%d\n",
3903					read_rev->available_length,
3904					read_rev->returned_vpd_length,
3905					read_rev->actual_vpd_length);
3906		}
3907		sli4->vpd.length = read_rev->returned_vpd_length;
3908	} else {
3909		ocs_log_err(sli4->os, "bad READ_REV write\n");
3910		return -1;
3911	}
3912
3913	if (sli_cmd_read_nvparms(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE)) {
3914		sli4_cmd_read_nvparms_t	*read_nvparms = sli4->bmbx.virt;
3915
3916		if (sli_bmbx_command(sli4)) {
3917			ocs_log_crit(sli4->os, "bootstrap mailbox write fail (READ_NVPARMS)\n");
3918			return -1;
3919		}
3920		if (read_nvparms->hdr.status) {
3921			ocs_log_err(sli4->os, "READ_NVPARMS bad status %#x\n",
3922					read_nvparms->hdr.status);
3923			return -1;
3924		}
3925
3926		ocs_memcpy(sli4->config.wwpn, read_nvparms->wwpn, sizeof(sli4->config.wwpn));
3927		ocs_memcpy(sli4->config.wwnn, read_nvparms->wwnn, sizeof(sli4->config.wwnn));
3928
3929		ocs_log_debug(sli4->os, "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
3930				sli4->config.wwpn[0],
3931				sli4->config.wwpn[1],
3932				sli4->config.wwpn[2],
3933				sli4->config.wwpn[3],
3934				sli4->config.wwpn[4],
3935				sli4->config.wwpn[5],
3936				sli4->config.wwpn[6],
3937				sli4->config.wwpn[7]);
3938		ocs_log_debug(sli4->os, "WWNN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
3939				sli4->config.wwnn[0],
3940				sli4->config.wwnn[1],
3941				sli4->config.wwnn[2],
3942				sli4->config.wwnn[3],
3943				sli4->config.wwnn[4],
3944				sli4->config.wwnn[5],
3945				sli4->config.wwnn[6],
3946				sli4->config.wwnn[7]);
3947	} else {
3948		ocs_log_err(sli4->os, "bad READ_NVPARMS write\n");
3949		return -1;
3950	}
3951
3952	return 0;
3953}
3954
3955/****************************************************************************
3956 * Public functions
3957 */
3958
3959/**
3960 * @ingroup sli
3961 * @brief Set up the SLI context.
3962 *
3963 * @param sli4 SLI context.
3964 * @param os Device abstraction.
3965 * @param port_type Protocol type of port (for example, FC and NIC).
3966 *
3967 * @return Returns 0 on success, or a non-zero value on failure.
3968 */
3969int32_t
3970sli_setup(sli4_t *sli4, ocs_os_handle_t os, sli4_port_type_e port_type)
3971{
3972	uint32_t sli_intf = UINT32_MAX;
3973	uint32_t pci_class_rev = 0;
3974	uint32_t rev_id = 0;
3975	uint32_t family = 0;
3976	uint32_t i;
3977	sli4_asic_entry_t *asic;
3978
3979	ocs_memset(sli4, 0, sizeof(sli4_t));
3980
3981	sli4->os = os;
3982	sli4->port_type = port_type;
3983
3984	/*
3985	 * Read the SLI_INTF register to discover the register layout
3986	 * and other capability information
3987	 */
3988	sli_intf = ocs_config_read32(os, SLI4_INTF_REG);
3989
3990	if (sli_intf_valid_check(sli_intf)) {
3991		ocs_log_err(os, "SLI_INTF is not valid\n");
3992		return -1;
3993	}
3994
3995	/* driver only support SLI-4 */
3996	sli4->sli_rev = sli_intf_sli_revision(sli_intf);
3997	if (4 != sli4->sli_rev) {
3998		ocs_log_err(os, "Unsupported SLI revision (intf=%#x)\n",
3999				sli_intf);
4000		return -1;
4001	}
4002
4003	sli4->sli_family = sli_intf_sli_family(sli_intf);
4004
4005	sli4->if_type = sli_intf_if_type(sli_intf);
4006
4007	if (SLI4_IF_TYPE_LANCER_FC_ETH == sli4->if_type) {
4008		ocs_log_debug(os, "status=%#x error1=%#x error2=%#x\n",
4009				sli_reg_read(sli4, SLI4_REG_SLIPORT_STATUS),
4010				sli_reg_read(sli4, SLI4_REG_SLIPORT_ERROR1),
4011				sli_reg_read(sli4, SLI4_REG_SLIPORT_ERROR2));
4012	}
4013
4014	/*
4015	 * set the ASIC type and revision
4016	 */
4017	pci_class_rev = ocs_config_read32(os, SLI4_PCI_CLASS_REVISION);
4018	rev_id = sli_pci_rev_id(pci_class_rev);
4019	family = sli4->sli_family;
4020	if (family == SLI4_FAMILY_CHECK_ASIC_TYPE) {
4021		uint32_t asic_id = ocs_config_read32(os, SLI4_ASIC_ID_REG);
4022		family = sli_asic_gen(asic_id);
4023	}
4024
4025	for (i = 0, asic = sli4_asic_table; i < ARRAY_SIZE(sli4_asic_table); i++, asic++) {
4026		if ((rev_id == asic->rev_id) && (family == asic->family)) {
4027			sli4->asic_type = asic->type;
4028			sli4->asic_rev = asic->rev;
4029			break;
4030		}
4031	}
4032	/* Fail if no matching asic type/rev was found */
4033	if( (sli4->asic_type == 0) || (sli4->asic_rev == 0)) {
4034		ocs_log_err(os, "no matching asic family/rev found: %02x/%02x\n", family, rev_id);
4035		return -1;
4036	}
4037
4038	/*
4039	 * The bootstrap mailbox is equivalent to a MQ with a single 256 byte
4040	 * entry, a CQ with a single 16 byte entry, and no event queue.
4041	 * Alignment must be 16 bytes as the low order address bits in the
4042	 * address register are also control / status.
4043	 */
4044	if (ocs_dma_alloc(sli4->os, &sli4->bmbx, SLI4_BMBX_SIZE +
4045				sizeof(sli4_mcqe_t), 16)) {
4046		ocs_log_err(os, "bootstrap mailbox allocation failed\n");
4047		return -1;
4048	}
4049
4050	if (sli4->bmbx.phys & SLI4_BMBX_MASK_LO) {
4051		ocs_log_err(os, "bad alignment for bootstrap mailbox\n");
4052		return -1;
4053	}
4054
4055	ocs_log_debug(os, "bmbx v=%p p=0x%x %08x s=%zd\n", sli4->bmbx.virt,
4056		ocs_addr32_hi(sli4->bmbx.phys),
4057		ocs_addr32_lo(sli4->bmbx.phys),
4058		sli4->bmbx.size);
4059
4060	/* TODO 4096 is arbitrary. What should this value actually be? */
4061	if (ocs_dma_alloc(sli4->os, &sli4->vpd.data, 4096/*TODO*/, 4096)) {
4062		/* Note that failure isn't fatal in this specific case */
4063		sli4->vpd.data.size = 0;
4064		ocs_log_test(os, "VPD buffer allocation failed\n");
4065	}
4066
4067	if (sli_fw_init(sli4)) {
4068		ocs_log_err(sli4->os, "FW initialization failed\n");
4069		return -1;
4070	}
4071
4072	/*
4073	 * Set one of fcpi(initiator), fcpt(target), fcpc(combined) to true
4074	 * in addition to any other desired features
4075	 */
4076	sli4->config.features.flag.iaab = TRUE;
4077	sli4->config.features.flag.npiv = TRUE;
4078	sli4->config.features.flag.dif = TRUE;
4079	sli4->config.features.flag.vf = TRUE;
4080	sli4->config.features.flag.fcpc = TRUE;
4081	sli4->config.features.flag.iaar = TRUE;
4082	sli4->config.features.flag.hlm = TRUE;
4083	sli4->config.features.flag.perfh = TRUE;
4084	sli4->config.features.flag.rxseq = TRUE;
4085	sli4->config.features.flag.rxri = TRUE;
4086	sli4->config.features.flag.mrqp = TRUE;
4087
4088	/* use performance hints if available */
4089	if (sli4->config.perf_hint) {
4090		sli4->config.features.flag.perfh = TRUE;
4091	}
4092
4093	if (sli_request_features(sli4, &sli4->config.features, TRUE)) {
4094		return -1;
4095	}
4096
4097	if (sli_get_config(sli4)) {
4098		return -1;
4099	}
4100
4101	return 0;
4102}
4103
4104int32_t
4105sli_init(sli4_t *sli4)
4106{
4107
4108	if (sli4->config.has_extents) {
4109		/* TODO COMMON_ALLOC_RESOURCE_EXTENTS */;
4110		ocs_log_test(sli4->os, "XXX need to implement extent allocation\n");
4111		return -1;
4112	}
4113
4114	sli4->config.features.flag.hlm = sli4->config.high_login_mode;
4115	sli4->config.features.flag.rxseq = FALSE;
4116	sli4->config.features.flag.rxri  = FALSE;
4117
4118	if (sli_request_features(sli4, &sli4->config.features, FALSE)) {
4119		return -1;
4120	}
4121
4122	return 0;
4123}
4124
4125int32_t
4126sli_reset(sli4_t *sli4)
4127{
4128	uint32_t	i;
4129
4130	if (sli_fw_init(sli4)) {
4131		ocs_log_crit(sli4->os, "FW initialization failed\n");
4132		return -1;
4133	}
4134
4135	if (sli4->config.extent[0].base) {
4136		ocs_free(sli4->os, sli4->config.extent[0].base, SLI_RSRC_MAX * sizeof(uint32_t));
4137		sli4->config.extent[0].base = NULL;
4138	}
4139
4140	for (i = 0; i < SLI_RSRC_MAX; i++) {
4141		if (sli4->config.extent[i].use_map) {
4142			ocs_bitmap_free(sli4->config.extent[i].use_map);
4143			sli4->config.extent[i].use_map = NULL;
4144		}
4145		sli4->config.extent[i].base = NULL;
4146	}
4147
4148	if (sli_get_config(sli4)) {
4149		return -1;
4150	}
4151
4152	return 0;
4153}
4154
4155/**
4156 * @ingroup sli
4157 * @brief Issue a Firmware Reset.
4158 *
4159 * @par Description
4160 * Issues a Firmware Reset to the chip.  This reset affects the entire chip,
4161 * so all PCI function on the same PCI bus and device are affected.
4162 * @n @n This type of reset can be used to activate newly downloaded firmware.
4163 * @n @n The driver should be considered to be in an unknown state after this
4164 * reset and should be reloaded.
4165 *
4166 * @param sli4 SLI context.
4167 *
4168 * @return Returns 0 on success, or -1 otherwise.
4169 */
4170
4171int32_t
4172sli_fw_reset(sli4_t *sli4)
4173{
4174	uint32_t val;
4175	uint32_t ready;
4176
4177	/*
4178	 * Firmware must be ready before issuing the reset.
4179	 */
4180	ready = sli_wait_for_fw_ready(sli4, SLI4_FW_READY_TIMEOUT_MSEC);
4181	if (!ready) {
4182		ocs_log_crit(sli4->os, "FW status is NOT ready\n");
4183		return -1;
4184	}
4185	switch(sli4->if_type) {
4186	case SLI4_IF_TYPE_BE3_SKH_PF:
4187		/* BE3 / Skyhawk use PCICFG_SOFT_RESET_CSR */
4188		val = ocs_config_read32(sli4->os, SLI4_PCI_SOFT_RESET_CSR);
4189		val |= SLI4_PCI_SOFT_RESET_MASK;
4190		ocs_config_write32(sli4->os, SLI4_PCI_SOFT_RESET_CSR, val);
4191		break;
4192	case SLI4_IF_TYPE_LANCER_FC_ETH:
4193		/* Lancer uses PHYDEV_CONTROL */
4194
4195		val = SLI4_PHYDEV_CONTROL_FRST;
4196		sli_reg_write(sli4, SLI4_REG_PHYSDEV_CONTROL, val);
4197		break;
4198	default:
4199		ocs_log_test(sli4->os, "Unexpected iftype %d\n", sli4->if_type);
4200		return -1;
4201		break;
4202	}
4203
4204	/* wait for the FW to become ready after the reset */
4205	ready = sli_wait_for_fw_ready(sli4, SLI4_FW_READY_TIMEOUT_MSEC);
4206	if (!ready) {
4207		ocs_log_crit(sli4->os, "Failed to become ready after firmware reset\n");
4208		return -1;
4209	}
4210	return 0;
4211}
4212
4213/**
4214 * @ingroup sli
4215 * @brief Tear down a SLI context.
4216 *
4217 * @param sli4 SLI context.
4218 *
4219 * @return Returns 0 on success, or non-zero otherwise.
4220 */
4221int32_t
4222sli_teardown(sli4_t *sli4)
4223{
4224	uint32_t i;
4225
4226	if (sli4->config.extent[0].base) {
4227		ocs_free(sli4->os, sli4->config.extent[0].base, SLI_RSRC_MAX * sizeof(uint32_t));
4228		sli4->config.extent[0].base = NULL;
4229	}
4230
4231	for (i = 0; i < SLI_RSRC_MAX; i++) {
4232		if (sli4->config.has_extents) {
4233			/* TODO COMMON_DEALLOC_RESOURCE_EXTENTS */;
4234		}
4235
4236		sli4->config.extent[i].base = NULL;
4237
4238		ocs_bitmap_free(sli4->config.extent[i].use_map);
4239		sli4->config.extent[i].use_map = NULL;
4240	}
4241
4242	if (sli_fw_term(sli4)) {
4243		ocs_log_err(sli4->os, "FW deinitialization failed\n");
4244	}
4245
4246	ocs_dma_free(sli4->os, &sli4->vpd.data);
4247	ocs_dma_free(sli4->os, &sli4->bmbx);
4248
4249	return 0;
4250}
4251
4252/**
4253 * @ingroup sli
4254 * @brief Register a callback for the given event.
4255 *
4256 * @param sli4 SLI context.
4257 * @param which Event of interest.
4258 * @param func Function to call when the event occurs.
4259 * @param arg Argument passed to the callback function.
4260 *
4261 * @return Returns 0 on success, or non-zero otherwise.
4262 */
4263int32_t
4264sli_callback(sli4_t *sli4, sli4_callback_e which, void *func, void *arg)
4265{
4266
4267	if (!sli4 || !func || (which >= SLI4_CB_MAX)) {
4268		ocs_log_err(NULL, "bad parameter sli4=%p which=%#x func=%p\n",
4269			    sli4, which, func);
4270		return -1;
4271	}
4272
4273	switch (which) {
4274	case SLI4_CB_LINK:
4275		sli4->link = func;
4276		sli4->link_arg = arg;
4277		break;
4278	case SLI4_CB_FIP:
4279		sli4->fip = func;
4280		sli4->fip_arg = arg;
4281		break;
4282	default:
4283		ocs_log_test(sli4->os, "unknown callback %#x\n", which);
4284		return -1;
4285	}
4286
4287	return 0;
4288}
4289
4290/**
4291 * @ingroup sli
4292 * @brief Initialize a queue object.
4293 *
4294 * @par Description
4295 * This initializes the sli4_queue_t object members, including the underlying
4296 * DMA memory.
4297 *
4298 * @param sli4 SLI context.
4299 * @param q Pointer to queue object.
4300 * @param qtype Type of queue to create.
4301 * @param size Size of each entry.
4302 * @param n_entries Number of entries to allocate.
4303 * @param align Starting memory address alignment.
4304 *
4305 * @note Checks if using the existing DMA memory (if any) is possible. If not,
4306 * it frees the existing memory and re-allocates.
4307 *
4308 * @return Returns 0 on success, or non-zero otherwise.
4309 */
4310int32_t
4311__sli_queue_init(sli4_t *sli4, sli4_queue_t *q, uint32_t qtype,
4312		size_t size, uint32_t n_entries, uint32_t align)
4313{
4314
4315	if ((q->dma.virt == NULL) || (size != q->size) || (n_entries != q->length)) {
4316		if (q->dma.size) {
4317			ocs_dma_free(sli4->os, &q->dma);
4318		}
4319
4320		ocs_memset(q, 0, sizeof(sli4_queue_t));
4321
4322		if (ocs_dma_alloc(sli4->os, &q->dma, size * n_entries, align)) {
4323			ocs_log_err(sli4->os, "%s allocation failed\n", SLI_QNAME[qtype]);
4324			return -1;
4325		}
4326
4327		ocs_memset(q->dma.virt, 0, size * n_entries);
4328
4329		ocs_lock_init(sli4->os, &q->lock, "%s lock[%d:%p]",
4330			SLI_QNAME[qtype], ocs_instance(sli4->os), &q->lock);
4331
4332		q->type = qtype;
4333		q->size = size;
4334		q->length = n_entries;
4335
4336		/* Limit to hwf the queue size per interrupt */
4337		q->proc_limit = n_entries / 2;
4338
4339		switch(q->type) {
4340		case SLI_QTYPE_EQ:
4341			q->posted_limit = q->length / 2;
4342			break;
4343		default:
4344			if ((sli4->if_type == SLI4_IF_TYPE_BE3_SKH_PF) ||
4345			    (sli4->if_type == SLI4_IF_TYPE_BE3_SKH_VF)) {
4346				/* For Skyhawk, ring the doorbell more often */
4347				q->posted_limit = 8;
4348			} else {
4349				q->posted_limit = 64;
4350			}
4351			break;
4352		}
4353	}
4354
4355	return 0;
4356}
4357
4358/**
4359 * @ingroup sli
4360 * @brief Issue the command to create a queue.
4361 *
4362 * @param sli4 SLI context.
4363 * @param q Pointer to queue object.
4364 *
4365 * @return Returns 0 on success, or non-zero otherwise.
4366 */
4367int32_t
4368__sli_create_queue(sli4_t *sli4, sli4_queue_t *q)
4369{
4370	sli4_res_common_create_queue_t *res_q = NULL;
4371
4372	if (sli_bmbx_command(sli4)){
4373		ocs_log_crit(sli4->os, "bootstrap mailbox write fail %s\n",
4374				SLI_QNAME[q->type]);
4375		ocs_dma_free(sli4->os, &q->dma);
4376		return -1;
4377	}
4378	if (sli_res_sli_config(sli4->bmbx.virt)) {
4379		ocs_log_err(sli4->os, "bad status create %s\n", SLI_QNAME[q->type]);
4380		ocs_dma_free(sli4->os, &q->dma);
4381		return -1;
4382	}
4383	res_q = (void *)((uint8_t *)sli4->bmbx.virt +
4384			offsetof(sli4_cmd_sli_config_t, payload));
4385
4386	if (res_q->hdr.status) {
4387		ocs_log_err(sli4->os, "bad create %s status=%#x addl=%#x\n",
4388				SLI_QNAME[q->type],
4389				res_q->hdr.status, res_q->hdr.additional_status);
4390		ocs_dma_free(sli4->os, &q->dma);
4391		return -1;
4392	} else {
4393		q->id = res_q->q_id;
4394		q->doorbell_offset = res_q->db_offset;
4395		q->doorbell_rset = res_q->db_rs;
4396
4397		switch (q->type) {
4398		case SLI_QTYPE_EQ:
4399			/* No doorbell information in response for EQs */
4400			q->doorbell_offset = regmap[SLI4_REG_EQCQ_DOORBELL][sli4->if_type].off;
4401			q->doorbell_rset = regmap[SLI4_REG_EQCQ_DOORBELL][sli4->if_type].rset;
4402			break;
4403		case SLI_QTYPE_CQ:
4404			/* No doorbell information in response for CQs */
4405			q->doorbell_offset = regmap[SLI4_REG_EQCQ_DOORBELL][sli4->if_type].off;
4406			q->doorbell_rset = regmap[SLI4_REG_EQCQ_DOORBELL][sli4->if_type].rset;
4407			break;
4408		case SLI_QTYPE_MQ:
4409			/* No doorbell information in response for MQs */
4410			q->doorbell_offset = regmap[SLI4_REG_MQ_DOORBELL][sli4->if_type].off;
4411			q->doorbell_rset = regmap[SLI4_REG_MQ_DOORBELL][sli4->if_type].rset;
4412			break;
4413		case SLI_QTYPE_RQ:
4414			/* set the doorbell for non-skyhawks */
4415			if (!sli4->config.dual_ulp_capable) {
4416				q->doorbell_offset = regmap[SLI4_REG_FCOE_RQ_DOORBELL][sli4->if_type].off;
4417				q->doorbell_rset = regmap[SLI4_REG_FCOE_RQ_DOORBELL][sli4->if_type].rset;
4418			}
4419			break;
4420		case SLI_QTYPE_WQ:
4421			/* set the doorbell for non-skyhawks */
4422			if (!sli4->config.dual_ulp_capable) {
4423				q->doorbell_offset = regmap[SLI4_REG_IO_WQ_DOORBELL][sli4->if_type].off;
4424				q->doorbell_rset = regmap[SLI4_REG_IO_WQ_DOORBELL][sli4->if_type].rset;
4425			}
4426			break;
4427		default:
4428			break;
4429		}
4430	}
4431
4432	return 0;
4433}
4434
4435/**
4436 * @ingroup sli
4437 * @brief Get queue entry size.
4438 *
4439 * Get queue entry size given queue type.
4440 *
4441 * @param sli4 SLI context
4442 * @param qtype Type for which the entry size is returned.
4443 *
4444 * @return Returns > 0 on success (queue entry size), or a negative value on failure.
4445 */
4446int32_t
4447sli_get_queue_entry_size(sli4_t *sli4, uint32_t qtype)
4448{
4449	uint32_t	size = 0;
4450
4451	if (!sli4) {
4452		ocs_log_err(NULL, "bad parameter sli4=%p\n", sli4);
4453		return -1;
4454	}
4455
4456	switch (qtype) {
4457	case SLI_QTYPE_EQ:
4458		size = sizeof(uint32_t);
4459		break;
4460	case SLI_QTYPE_CQ:
4461		size = 16;
4462		break;
4463	case SLI_QTYPE_MQ:
4464		size = 256;
4465		break;
4466	case SLI_QTYPE_WQ:
4467		if (SLI4_PORT_TYPE_FC == sli4->port_type) {
4468			size = sli4->config.wqe_size;
4469		} else {
4470			/* TODO */
4471			ocs_log_test(sli4->os, "unsupported queue entry size\n");
4472			return -1;
4473		}
4474		break;
4475	case SLI_QTYPE_RQ:
4476		size = SLI4_FCOE_RQE_SIZE;
4477		break;
4478	default:
4479		ocs_log_test(sli4->os, "unknown queue type %d\n", qtype);
4480		return -1;
4481	}
4482	return size;
4483}
4484
4485/**
4486 * @ingroup sli
4487 * @brief Modify the delay timer for all the EQs
4488 *
4489 * @param sli4 SLI context.
4490 * @param eq Array of EQs.
4491 * @param num_eq Count of EQs.
4492 * @param shift Phase shift for staggering interrupts.
4493 * @param delay_mult Delay multiplier for limiting interrupt frequency.
4494 *
4495 * @return Returns 0 on success, or -1 otherwise.
4496 */
4497int32_t
4498sli_eq_modify_delay(sli4_t *sli4, sli4_queue_t *eq, uint32_t num_eq, uint32_t shift, uint32_t delay_mult)
4499{
4500
4501	sli_cmd_common_modify_eq_delay(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE, eq, num_eq, shift, delay_mult);
4502
4503	if (sli_bmbx_command(sli4)) {
4504		ocs_log_crit(sli4->os, "bootstrap mailbox write fail (MODIFY EQ DELAY)\n");
4505		return -1;
4506	}
4507	if (sli_res_sli_config(sli4->bmbx.virt)) {
4508		ocs_log_err(sli4->os, "bad status MODIFY EQ DELAY\n");
4509		return -1;
4510	}
4511
4512	return 0;
4513}
4514
4515/**
4516 * @ingroup sli
4517 * @brief Allocate a queue.
4518 *
4519 * @par Description
4520 * Allocates DMA memory and configures the requested queue type.
4521 *
4522 * @param sli4 SLI context.
4523 * @param qtype Type of queue to create.
4524 * @param q Pointer to the queue object.
4525 * @param n_entries Number of entries to allocate.
4526 * @param assoc Associated queue (that is, the EQ for a CQ, the CQ for a MQ, and so on).
4527 * @param ulp The ULP to bind, which is only used for WQ and RQs
4528 *
4529 * @return Returns 0 on success, or -1 otherwise.
4530 */
4531int32_t
4532sli_queue_alloc(sli4_t *sli4, uint32_t qtype, sli4_queue_t *q, uint32_t n_entries,
4533		sli4_queue_t *assoc, uint16_t ulp)
4534{
4535	int32_t		size;
4536	uint32_t	align = 0;
4537	sli4_create_q_fn_t create = NULL;
4538
4539	if (!sli4 || !q) {
4540		ocs_log_err(NULL, "bad parameter sli4=%p q=%p\n", sli4, q);
4541		return -1;
4542	}
4543
4544	/* get queue size */
4545	size = sli_get_queue_entry_size(sli4, qtype);
4546	if (size < 0)
4547		return -1;
4548	align = SLI_PAGE_SIZE;
4549
4550	switch (qtype) {
4551	case SLI_QTYPE_EQ:
4552		create = sli_cmd_common_create_eq;
4553		break;
4554	case SLI_QTYPE_CQ:
4555		create = sli_cmd_common_create_cq;
4556		break;
4557	case SLI_QTYPE_MQ:
4558		/* Validate the number of entries */
4559		switch (n_entries) {
4560		case 16:
4561		case 32:
4562		case 64:
4563		case 128:
4564			break;
4565		default:
4566			ocs_log_test(sli4->os, "illegal n_entries value %d for MQ\n", n_entries);
4567			return -1;
4568		}
4569		assoc->u.flag.is_mq = TRUE;
4570		create = sli_cmd_common_create_mq_ext;
4571		break;
4572	case SLI_QTYPE_WQ:
4573		if (SLI4_PORT_TYPE_FC == sli4->port_type) {
4574			if (sli4->if_type == SLI4_IF_TYPE_BE3_SKH_PF) {
4575				create = sli_cmd_fcoe_wq_create;
4576			} else {
4577				create = sli_cmd_fcoe_wq_create_v1;
4578			}
4579		} else {
4580			/* TODO */
4581			ocs_log_test(sli4->os, "unsupported WQ create\n");
4582			return -1;
4583		}
4584		break;
4585	default:
4586		ocs_log_test(sli4->os, "unknown queue type %d\n", qtype);
4587		return -1;
4588	}
4589
4590
4591	if (__sli_queue_init(sli4, q, qtype, size, n_entries, align)) {
4592		ocs_log_err(sli4->os, "%s allocation failed\n", SLI_QNAME[qtype]);
4593		return -1;
4594	}
4595
4596	if (create(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE, &q->dma, assoc ? assoc->id : 0, ulp)) {
4597
4598		if (__sli_create_queue(sli4, q)) {
4599			ocs_log_err(sli4->os, "create %s failed\n", SLI_QNAME[qtype]);
4600			return -1;
4601		}
4602		q->ulp = ulp;
4603	} else {
4604		ocs_log_err(sli4->os, "cannot create %s\n", SLI_QNAME[qtype]);
4605		return -1;
4606	}
4607
4608	return 0;
4609}
4610
4611
4612/**
4613 * @ingroup sli
4614 * @brief Allocate a c queue set.
4615 *
4616 * @param sli4 SLI context.
4617 * @param num_cqs to create
4618 * @param qs Pointers to the queue objects.
4619 * @param n_entries Number of entries to allocate per CQ.
4620 * @param eqs Associated event queues
4621 *
4622 * @return Returns 0 on success, or -1 otherwise.
4623 */
4624int32_t
4625sli_cq_alloc_set(sli4_t *sli4, sli4_queue_t *qs[], uint32_t num_cqs,
4626		 uint32_t n_entries, sli4_queue_t *eqs[])
4627{
4628	uint32_t i, offset = 0,  page_bytes = 0, payload_size, cmd_size = 0;
4629	uint32_t p = 0, page_size = 0, n_cqe = 0, num_pages_cq;
4630	uintptr_t addr;
4631	ocs_dma_t dma;
4632	sli4_req_common_create_cq_set_v0_t  *req = NULL;
4633	sli4_res_common_create_queue_set_t *res = NULL;
4634
4635	if (!sli4) {
4636		ocs_log_err(NULL, "bad parameter sli4=%p\n", sli4);
4637		return -1;
4638	}
4639
4640	/* Align the queue DMA memory */
4641	for (i = 0; i < num_cqs; i++) {
4642		if (__sli_queue_init(sli4, qs[i], SLI_QTYPE_CQ, SLI4_CQE_BYTES,
4643			n_entries, SLI_PAGE_SIZE)) {
4644			ocs_log_err(sli4->os, "Queue init failed.\n");
4645			goto error;
4646		}
4647	}
4648
4649	n_cqe = qs[0]->dma.size / SLI4_CQE_BYTES;
4650	switch (n_cqe) {
4651	case 256:
4652	case 512:
4653	case 1024:
4654	case 2048:
4655		page_size = 1;
4656		break;
4657	case 4096:
4658		page_size = 2;
4659		break;
4660	default:
4661		return -1;
4662	}
4663
4664	page_bytes = page_size * SLI_PAGE_SIZE;
4665	num_pages_cq = sli_page_count(qs[0]->dma.size, page_bytes);
4666	cmd_size = sizeof(sli4_req_common_create_cq_set_v0_t) + (8 * num_pages_cq * num_cqs);
4667	payload_size = max((size_t)cmd_size, sizeof(sli4_res_common_create_queue_set_t));
4668
4669	if (ocs_dma_alloc(sli4->os, &dma, payload_size, SLI_PAGE_SIZE)) {
4670		ocs_log_err(sli4->os, "DMA allocation failed\n");
4671		goto error;
4672	}
4673	ocs_memset(dma.virt, 0, payload_size);
4674
4675	if (sli_cmd_sli_config(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE,
4676			payload_size, &dma) == -1) {
4677		goto error;
4678	}
4679
4680	/* Fill the request structure */
4681
4682	req = (sli4_req_common_create_cq_set_v0_t *)((uint8_t *)dma.virt);
4683	req->hdr.opcode = SLI4_OPC_COMMON_CREATE_CQ_SET;
4684	req->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
4685	req->hdr.version = 0;
4686	req->hdr.request_length = cmd_size - sizeof(sli4_req_hdr_t);
4687	req->page_size = page_size;
4688
4689	req->num_pages = num_pages_cq;
4690	switch (req->num_pages) {
4691	case 1:
4692		req->cqecnt = SLI4_CQ_CNT_256;
4693		break;
4694	case 2:
4695		req->cqecnt = SLI4_CQ_CNT_512;
4696		break;
4697	case 4:
4698		req->cqecnt = SLI4_CQ_CNT_1024;
4699		break;
4700	case 8:
4701		req->cqecnt = SLI4_CQ_CNT_LARGE;
4702		req->cqe_count = n_cqe;
4703		break;
4704	default:
4705		ocs_log_test(sli4->os, "num_pages %d not valid\n", req->num_pages);
4706		goto error;
4707	}
4708
4709	req->evt = TRUE;
4710	req->valid = TRUE;
4711	req->arm = FALSE;
4712	req->num_cq_req = num_cqs;
4713
4714	/* Fill page addresses of all the CQs. */
4715	for (i = 0; i < num_cqs; i++) {
4716		req->eq_id[i] = eqs[i]->id;
4717		for (p = 0, addr = qs[i]->dma.phys; p < req->num_pages; p++, addr += page_bytes) {
4718			req->page_physical_address[offset].low = ocs_addr32_lo(addr);
4719			req->page_physical_address[offset].high = ocs_addr32_hi(addr);
4720			offset++;
4721		}
4722	}
4723
4724	if (sli_bmbx_command(sli4)) {
4725		ocs_log_crit(sli4->os, "bootstrap mailbox write fail CQSet\n");
4726		goto error;
4727	}
4728
4729	res = (void *)((uint8_t *)dma.virt);
4730	if (res->hdr.status) {
4731		ocs_log_err(sli4->os, "bad create CQSet status=%#x addl=%#x\n",
4732			res->hdr.status, res->hdr.additional_status);
4733		goto error;
4734	} else {
4735		/* Check if we got all requested CQs. */
4736		if (res->num_q_allocated != num_cqs) {
4737			ocs_log_crit(sli4->os, "Requested count CQs doesnt match.\n");
4738			goto error;
4739		}
4740
4741		/* Fill the resp cq ids. */
4742		for (i = 0; i < num_cqs; i++) {
4743			qs[i]->id = res->q_id + i;
4744			qs[i]->doorbell_offset = regmap[SLI4_REG_EQCQ_DOORBELL][sli4->if_type].off;
4745			qs[i]->doorbell_rset   = regmap[SLI4_REG_EQCQ_DOORBELL][sli4->if_type].rset;
4746		}
4747	}
4748
4749	ocs_dma_free(sli4->os, &dma);
4750
4751	return 0;
4752
4753error:
4754	for (i = 0; i < num_cqs; i++) {
4755		if (qs[i]->dma.size) {
4756			ocs_dma_free(sli4->os, &qs[i]->dma);
4757		}
4758	}
4759
4760	if (dma.size) {
4761		ocs_dma_free(sli4->os, &dma);
4762	}
4763
4764	return -1;
4765}
4766
4767
4768
4769/**
4770 * @ingroup sli
4771 * @brief Free a queue.
4772 *
4773 * @par Description
4774 * Frees DMA memory and de-registers the requested queue.
4775 *
4776 * @param sli4 SLI context.
4777 * @param q Pointer to the queue object.
4778 * @param destroy_queues Non-zero if the mailbox commands should be sent to destroy the queues.
4779 * @param free_memory Non-zero if the DMA memory associated with the queue should be freed.
4780 *
4781 * @return Returns 0 on success, or -1 otherwise.
4782 */
4783int32_t
4784sli_queue_free(sli4_t *sli4, sli4_queue_t *q, uint32_t destroy_queues, uint32_t free_memory)
4785{
4786	sli4_destroy_q_fn_t destroy = NULL;
4787	int32_t		rc = -1;
4788
4789	if (!sli4 || !q) {
4790		ocs_log_err(NULL, "bad parameter sli4=%p q=%p\n", sli4, q);
4791		return -1;
4792	}
4793
4794	if (destroy_queues) {
4795		switch (q->type) {
4796		case SLI_QTYPE_EQ:
4797			destroy = sli_cmd_common_destroy_eq;
4798			break;
4799		case SLI_QTYPE_CQ:
4800			destroy = sli_cmd_common_destroy_cq;
4801			break;
4802		case SLI_QTYPE_MQ:
4803			destroy = sli_cmd_common_destroy_mq;
4804			break;
4805		case SLI_QTYPE_WQ:
4806			if (SLI4_PORT_TYPE_FC == sli4->port_type) {
4807				destroy = sli_cmd_fcoe_wq_destroy;
4808			} else {
4809				/* TODO */
4810				ocs_log_test(sli4->os, "unsupported WQ destroy\n");
4811				return -1;
4812			}
4813			break;
4814		case SLI_QTYPE_RQ:
4815			if (SLI4_PORT_TYPE_FC == sli4->port_type) {
4816				destroy = sli_cmd_fcoe_rq_destroy;
4817			} else {
4818				/* TODO */
4819				ocs_log_test(sli4->os, "unsupported RQ destroy\n");
4820				return -1;
4821			}
4822			break;
4823		default:
4824			ocs_log_test(sli4->os, "bad queue type %d\n",
4825					q->type);
4826			return -1;
4827		}
4828
4829		/*
4830		 * Destroying queues makes BE3 sad (version 0 interface type). Rely
4831		 * on COMMON_FUNCTION_RESET to free host allocated queue resources
4832		 * inside the SLI Port.
4833		 */
4834		if (SLI4_IF_TYPE_BE3_SKH_PF == sli4->if_type) {
4835			destroy = NULL;
4836		}
4837
4838		/* Destroy the queue if the operation is defined */
4839		if (destroy && destroy(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE, q->id)) {
4840			sli4_res_hdr_t	*res = NULL;
4841
4842			if (sli_bmbx_command(sli4)){
4843				ocs_log_crit(sli4->os, "bootstrap mailbox write fail destroy %s\n",
4844						SLI_QNAME[q->type]);
4845			} else if (sli_res_sli_config(sli4->bmbx.virt)) {
4846				ocs_log_err(sli4->os, "bad status destroy %s\n", SLI_QNAME[q->type]);
4847			} else {
4848				res = (void *)((uint8_t *)sli4->bmbx.virt +
4849						offsetof(sli4_cmd_sli_config_t, payload));
4850
4851				if (res->status) {
4852					ocs_log_err(sli4->os, "bad destroy %s status=%#x addl=%#x\n",
4853							SLI_QNAME[q->type],
4854							res->status, res->additional_status);
4855				} else {
4856					rc = 0;
4857				}
4858			}
4859		}
4860	}
4861
4862	if (free_memory) {
4863		ocs_lock_free(&q->lock);
4864
4865		if (ocs_dma_free(sli4->os, &q->dma)) {
4866			ocs_log_err(sli4->os, "%s queue ID %d free failed\n",
4867				    SLI_QNAME[q->type], q->id);
4868			rc = -1;
4869		}
4870	}
4871
4872	return rc;
4873}
4874
4875int32_t
4876sli_queue_reset(sli4_t *sli4, sli4_queue_t *q)
4877{
4878
4879	ocs_lock(&q->lock);
4880
4881	q->index = 0;
4882	q->n_posted = 0;
4883
4884	if (SLI_QTYPE_MQ == q->type) {
4885		q->u.r_idx = 0;
4886	}
4887
4888	if (q->dma.virt != NULL) {
4889		ocs_memset(q->dma.virt, 0, (q->size * q->length));
4890	}
4891
4892	ocs_unlock(&q->lock);
4893
4894	return 0;
4895}
4896
4897/**
4898 * @ingroup sli
4899 * @brief Check if the given queue is empty.
4900 *
4901 * @par Description
4902 * If the valid bit of the current entry is unset, the queue is empty.
4903 *
4904 * @param sli4 SLI context.
4905 * @param q Pointer to the queue object.
4906 *
4907 * @return Returns TRUE if empty, or FALSE otherwise.
4908 */
4909int32_t
4910sli_queue_is_empty(sli4_t *sli4, sli4_queue_t *q)
4911{
4912	int32_t		rc = TRUE;
4913	uint8_t		*qe = q->dma.virt;
4914
4915	ocs_lock(&q->lock);
4916
4917	ocs_dma_sync(&q->dma, OCS_DMASYNC_POSTREAD);
4918
4919	qe += q->index * q->size;
4920
4921	rc = !sli_queue_entry_is_valid(q, qe, FALSE);
4922
4923	ocs_unlock(&q->lock);
4924
4925	return rc;
4926}
4927
4928/**
4929 * @ingroup sli
4930 * @brief Arm an EQ.
4931 *
4932 * @param sli4 SLI context.
4933 * @param q Pointer to queue object.
4934 * @param arm If TRUE, arm the EQ.
4935 *
4936 * @return Returns 0 on success, or non-zero otherwise.
4937 */
4938int32_t
4939sli_queue_eq_arm(sli4_t *sli4, sli4_queue_t *q, uint8_t arm)
4940{
4941	uint32_t	val = 0;
4942
4943	ocs_lock(&q->lock);
4944		val = sli_eq_doorbell(q->n_posted, q->id, arm);
4945		ocs_reg_write32(sli4->os, q->doorbell_rset, q->doorbell_offset, val);
4946		q->n_posted = 0;
4947	ocs_unlock(&q->lock);
4948
4949	return 0;
4950}
4951
4952/**
4953 * @ingroup sli
4954 * @brief Arm a queue.
4955 *
4956 * @param sli4 SLI context.
4957 * @param q Pointer to queue object.
4958 * @param arm If TRUE, arm the queue.
4959 *
4960 * @return Returns 0 on success, or non-zero otherwise.
4961 */
4962int32_t
4963sli_queue_arm(sli4_t *sli4, sli4_queue_t *q, uint8_t arm)
4964{
4965	uint32_t	val = 0;
4966
4967	ocs_lock(&q->lock);
4968
4969	switch (q->type) {
4970	case SLI_QTYPE_EQ:
4971		val = sli_eq_doorbell(q->n_posted, q->id, arm);
4972		ocs_reg_write32(sli4->os, q->doorbell_rset, q->doorbell_offset, val);
4973		q->n_posted = 0;
4974		break;
4975	case SLI_QTYPE_CQ:
4976		val = sli_cq_doorbell(q->n_posted, q->id, arm);
4977		ocs_reg_write32(sli4->os, q->doorbell_rset, q->doorbell_offset, val);
4978		q->n_posted = 0;
4979		break;
4980	default:
4981		ocs_log_test(sli4->os, "should only be used for EQ/CQ, not %s\n",
4982			     SLI_QNAME[q->type]);
4983	}
4984
4985	ocs_unlock(&q->lock);
4986
4987	return 0;
4988}
4989
4990/**
4991 * @ingroup sli
4992 * @brief Write an entry to the queue object.
4993 *
4994 * Note: Assumes the q->lock will be locked and released by the caller.
4995 *
4996 * @param sli4 SLI context.
4997 * @param q Pointer to the queue object.
4998 * @param entry Pointer to the entry contents.
4999 *
5000 * @return Returns queue index on success, or negative error value otherwise.
5001 */
5002int32_t
5003_sli_queue_write(sli4_t *sli4, sli4_queue_t *q, uint8_t *entry)
5004{
5005	int32_t		rc = 0;
5006	uint8_t		*qe = q->dma.virt;
5007	uint32_t	qindex;
5008
5009	qindex = q->index;
5010	qe += q->index * q->size;
5011
5012	if (entry) {
5013		if ((SLI_QTYPE_WQ == q->type) && sli4->config.perf_wq_id_association) {
5014			sli_set_wq_id_association(entry, q->id);
5015		}
5016#if defined(OCS_INCLUDE_DEBUG)
5017		switch (q->type) {
5018		case SLI_QTYPE_WQ: {
5019			ocs_dump32(OCS_DEBUG_ENABLE_WQ_DUMP, sli4->os, "wqe", entry, q->size);
5020			break;
5021
5022		}
5023		case SLI_QTYPE_MQ:
5024			/* Note: we don't really need to dump the whole
5025			 * 256 bytes, just do 64 */
5026			ocs_dump32(OCS_DEBUG_ENABLE_MQ_DUMP, sli4->os, "mqe outbound", entry, 64);
5027			break;
5028
5029		default:
5030			break;
5031		}
5032#endif
5033		ocs_memcpy(qe, entry, q->size);
5034		q->n_posted = 1;
5035	}
5036
5037	ocs_dma_sync(&q->dma, OCS_DMASYNC_PREWRITE);
5038
5039	rc = sli_queue_doorbell(sli4, q);
5040
5041	q->index = (q->index + q->n_posted) & (q->length - 1);
5042	q->n_posted = 0;
5043
5044	if (rc < 0) {
5045		/* failure */
5046		return rc;
5047	} else if (rc > 0) {
5048		/* failure, but we need to return a negative value on failure */
5049		return -rc;
5050	} else {
5051		return qindex;
5052	}
5053}
5054
5055/**
5056 * @ingroup sli
5057 * @brief Write an entry to the queue object.
5058 *
5059 * Note: Assumes the q->lock will be locked and released by the caller.
5060 *
5061 * @param sli4 SLI context.
5062 * @param q Pointer to the queue object.
5063 * @param entry Pointer to the entry contents.
5064 *
5065 * @return Returns queue index on success, or negative error value otherwise.
5066 */
5067int32_t
5068sli_queue_write(sli4_t *sli4, sli4_queue_t *q, uint8_t *entry)
5069{
5070	int32_t rc;
5071
5072	ocs_lock(&q->lock);
5073		rc = _sli_queue_write(sli4, q, entry);
5074	ocs_unlock(&q->lock);
5075
5076	return rc;
5077}
5078
5079/**
5080 * @brief Check if the current queue entry is valid.
5081 *
5082 * @param q Pointer to the queue object.
5083 * @param qe Pointer to the queue entry.
5084 * @param clear Boolean to clear valid bit.
5085 *
5086 * @return Returns TRUE if the entry is valid, or FALSE otherwise.
5087 */
5088static uint8_t
5089sli_queue_entry_is_valid(sli4_queue_t *q, uint8_t *qe, uint8_t clear)
5090{
5091	uint8_t		valid = FALSE;
5092
5093	switch (q->type) {
5094	case SLI_QTYPE_EQ:
5095		valid = ((sli4_eqe_t *)qe)->vld;
5096		if (valid && clear) {
5097			((sli4_eqe_t *)qe)->vld = 0;
5098		}
5099		break;
5100	case SLI_QTYPE_CQ:
5101		/*
5102		 * For both MCQE and WCQE/RCQE, the valid bit
5103		 * is bit 31 of dword 3 (0 based)
5104		 */
5105		valid = (qe[15] & 0x80) != 0;
5106		if (valid & clear) {
5107			qe[15] &= ~0x80;
5108		}
5109		break;
5110	case SLI_QTYPE_MQ:
5111		valid = q->index != q->u.r_idx;
5112		break;
5113	case SLI_QTYPE_RQ:
5114		valid = TRUE;
5115		clear = FALSE;
5116		break;
5117	default:
5118		ocs_log_test(NULL, "doesn't handle type=%#x\n", q->type);
5119	}
5120
5121	if (clear) {
5122		ocs_dma_sync(&q->dma, OCS_DMASYNC_PREWRITE);
5123	}
5124
5125	return valid;
5126}
5127
5128/**
5129 * @ingroup sli
5130 * @brief Read an entry from the queue object.
5131 *
5132 * @param sli4 SLI context.
5133 * @param q Pointer to the queue object.
5134 * @param entry Destination pointer for the queue entry contents.
5135 *
5136 * @return Returns 0 on success, or non-zero otherwise.
5137 */
5138int32_t
5139sli_queue_read(sli4_t *sli4, sli4_queue_t *q, uint8_t *entry)
5140{
5141	int32_t		rc = 0;
5142	uint8_t		*qe = q->dma.virt;
5143	uint32_t	*qindex = NULL;
5144
5145	if (SLI_QTYPE_MQ == q->type) {
5146		qindex = &q->u.r_idx;
5147	} else {
5148		qindex = &q->index;
5149	}
5150
5151	ocs_lock(&q->lock);
5152
5153	ocs_dma_sync(&q->dma, OCS_DMASYNC_POSTREAD);
5154
5155	qe += *qindex * q->size;
5156
5157	if (!sli_queue_entry_is_valid(q, qe, TRUE)) {
5158		ocs_unlock(&q->lock);
5159		return -1;
5160	}
5161
5162	if (entry) {
5163		ocs_memcpy(entry, qe, q->size);
5164#if defined(OCS_INCLUDE_DEBUG)
5165		switch(q->type) {
5166		case SLI_QTYPE_CQ:
5167			ocs_dump32(OCS_DEBUG_ENABLE_CQ_DUMP, sli4->os, "cq", entry, q->size);
5168			break;
5169		case SLI_QTYPE_MQ:
5170			ocs_dump32(OCS_DEBUG_ENABLE_MQ_DUMP, sli4->os, "mq Compl", entry, 64);
5171			break;
5172		case SLI_QTYPE_EQ:
5173			ocs_dump32(OCS_DEBUG_ENABLE_EQ_DUMP, sli4->os, "eq Compl", entry, q->size);
5174			break;
5175		default:
5176			break;
5177		}
5178#endif
5179	}
5180
5181	switch (q->type) {
5182		case SLI_QTYPE_EQ:
5183		case SLI_QTYPE_CQ:
5184		case SLI_QTYPE_MQ:
5185			*qindex = (*qindex + 1) & (q->length - 1);
5186			if (SLI_QTYPE_MQ != q->type) {
5187				q->n_posted++;
5188			}
5189			break;
5190		default:
5191			/* reads don't update the index */
5192			break;
5193	}
5194
5195	ocs_unlock(&q->lock);
5196
5197	return rc;
5198}
5199
5200int32_t
5201sli_queue_index(sli4_t *sli4, sli4_queue_t *q)
5202{
5203
5204	if (q) {
5205		return q->index;
5206	} else {
5207		return -1;
5208	}
5209}
5210
5211int32_t
5212sli_queue_poke(sli4_t *sli4, sli4_queue_t *q, uint32_t index, uint8_t *entry)
5213{
5214	int32_t rc;
5215
5216	ocs_lock(&q->lock);
5217		rc = _sli_queue_poke(sli4, q, index, entry);
5218	ocs_unlock(&q->lock);
5219
5220	return rc;
5221}
5222
5223int32_t
5224_sli_queue_poke(sli4_t *sli4, sli4_queue_t *q, uint32_t index, uint8_t *entry)
5225{
5226	int32_t		rc = 0;
5227	uint8_t		*qe = q->dma.virt;
5228
5229	if (index >= q->length) {
5230		return -1;
5231	}
5232
5233	qe += index * q->size;
5234
5235	if (entry) {
5236		ocs_memcpy(qe, entry, q->size);
5237	}
5238
5239	ocs_dma_sync(&q->dma, OCS_DMASYNC_PREWRITE);
5240
5241	return rc;
5242}
5243
5244/**
5245 * @ingroup sli
5246 * @brief Allocate SLI Port resources.
5247 *
5248 * @par Description
5249 * Allocate port-related resources, such as VFI, RPI, XRI, and so on.
5250 * Resources are modeled using extents, regardless of whether the underlying
5251 * device implements resource extents. If the device does not implement
5252 * extents, the SLI layer models this as a single (albeit large) extent.
5253 *
5254 * @param sli4 SLI context.
5255 * @param rtype Resource type (for example, RPI or XRI)
5256 * @param rid Allocated resource ID.
5257 * @param index Index into the bitmap.
5258 *
5259 * @return Returns 0 on success, or a non-zero value on failure.
5260 */
5261int32_t
5262sli_resource_alloc(sli4_t *sli4, sli4_resource_e rtype, uint32_t *rid, uint32_t *index)
5263{
5264	int32_t		rc = 0;
5265	uint32_t	size;
5266	uint32_t	extent_idx;
5267	uint32_t	item_idx;
5268	int		status;
5269
5270	*rid = UINT32_MAX;
5271	*index = UINT32_MAX;
5272
5273	switch (rtype) {
5274	case SLI_RSRC_FCOE_VFI:
5275	case SLI_RSRC_FCOE_VPI:
5276	case SLI_RSRC_FCOE_RPI:
5277	case SLI_RSRC_FCOE_XRI:
5278		status = ocs_bitmap_find(sli4->config.extent[rtype].use_map,
5279				sli4->config.extent[rtype].map_size);
5280		if (status < 0) {
5281			ocs_log_err(sli4->os, "out of resource %d (alloc=%d)\n",
5282					rtype, sli4->config.extent[rtype].n_alloc);
5283			rc = -1;
5284			break;
5285		} else {
5286			*index = status;
5287		}
5288
5289		size = sli4->config.extent[rtype].size;
5290
5291		extent_idx = *index / size;
5292		item_idx   = *index % size;
5293
5294		*rid = sli4->config.extent[rtype].base[extent_idx] + item_idx;
5295
5296		sli4->config.extent[rtype].n_alloc++;
5297		break;
5298	default:
5299		rc = -1;
5300	}
5301
5302	return rc;
5303}
5304
5305/**
5306 * @ingroup sli
5307 * @brief Free the SLI Port resources.
5308 *
5309 * @par Description
5310 * Free port-related resources, such as VFI, RPI, XRI, and so. See discussion of
5311 * "extent" usage in sli_resource_alloc.
5312 *
5313 * @param sli4 SLI context.
5314 * @param rtype Resource type (for example, RPI or XRI).
5315 * @param rid Allocated resource ID.
5316 *
5317 * @return Returns 0 on success, or a non-zero value on failure.
5318 */
5319int32_t
5320sli_resource_free(sli4_t *sli4, sli4_resource_e rtype, uint32_t rid)
5321{
5322	int32_t		rc = -1;
5323	uint32_t	x;
5324	uint32_t	size, *base;
5325
5326	switch (rtype) {
5327	case SLI_RSRC_FCOE_VFI:
5328	case SLI_RSRC_FCOE_VPI:
5329	case SLI_RSRC_FCOE_RPI:
5330	case SLI_RSRC_FCOE_XRI:
5331		/*
5332		 * Figure out which extent contains the resource ID. I.e. find
5333		 * the extent such that
5334		 *   extent->base <= resource ID < extent->base + extent->size
5335		 */
5336		base = sli4->config.extent[rtype].base;
5337		size = sli4->config.extent[rtype].size;
5338
5339		/*
5340		 * In the case of FW reset, this may be cleared but the force_free path will
5341		 * still attempt to free the resource. Prevent a NULL pointer access.
5342		 */
5343		if (base != NULL) {
5344			for (x = 0; x < sli4->config.extent[rtype].number; x++) {
5345				if ((rid >= base[x]) && (rid < (base[x] + size))) {
5346					rid -= base[x];
5347					ocs_bitmap_clear(sli4->config.extent[rtype].use_map,
5348							 (x * size) + rid);
5349					rc = 0;
5350					break;
5351				}
5352			}
5353		}
5354		break;
5355	default:
5356		;
5357	}
5358
5359	return rc;
5360}
5361
5362int32_t
5363sli_resource_reset(sli4_t *sli4, sli4_resource_e rtype)
5364{
5365	int32_t		rc = -1;
5366	uint32_t	i;
5367
5368	switch (rtype) {
5369	case SLI_RSRC_FCOE_VFI:
5370	case SLI_RSRC_FCOE_VPI:
5371	case SLI_RSRC_FCOE_RPI:
5372	case SLI_RSRC_FCOE_XRI:
5373		for (i = 0; i < sli4->config.extent[rtype].map_size; i++) {
5374			ocs_bitmap_clear(sli4->config.extent[rtype].use_map, i);
5375		}
5376		rc = 0;
5377		break;
5378	default:
5379		;
5380	}
5381
5382	return rc;
5383}
5384
5385/**
5386 * @ingroup sli
5387 * @brief Parse an EQ entry to retrieve the CQ_ID for this event.
5388 *
5389 * @param sli4 SLI context.
5390 * @param buf Pointer to the EQ entry.
5391 * @param cq_id CQ_ID for this entry (only valid on success).
5392 *
5393 * @return
5394 * - 0 if success.
5395 * - < 0 if error.
5396 * - > 0 if firmware detects EQ overflow.
5397 */
5398int32_t
5399sli_eq_parse(sli4_t *sli4, uint8_t *buf, uint16_t *cq_id)
5400{
5401	sli4_eqe_t	*eqe = (void *)buf;
5402	int32_t		rc = 0;
5403
5404	if (!sli4 || !buf || !cq_id) {
5405		ocs_log_err(NULL, "bad parameters sli4=%p buf=%p cq_id=%p\n",
5406				sli4, buf, cq_id);
5407		return -1;
5408	}
5409
5410	switch (eqe->major_code) {
5411	case SLI4_MAJOR_CODE_STANDARD:
5412		*cq_id = eqe->resource_id;
5413		break;
5414	case SLI4_MAJOR_CODE_SENTINEL:
5415		ocs_log_debug(sli4->os, "sentinel EQE\n");
5416		rc = 1;
5417		break;
5418	default:
5419		ocs_log_test(sli4->os, "Unsupported EQE: major %x minor %x\n",
5420				eqe->major_code, eqe->minor_code);
5421		rc = -1;
5422	}
5423
5424	return rc;
5425}
5426
5427/**
5428 * @ingroup sli
5429 * @brief Parse a CQ entry to retrieve the event type and the associated queue.
5430 *
5431 * @param sli4 SLI context.
5432 * @param cq CQ to process.
5433 * @param cqe Pointer to the CQ entry.
5434 * @param etype CQ event type.
5435 * @param q_id Queue ID associated with this completion message
5436 * (that is, MQ_ID, RQ_ID, and so on).
5437 *
5438 * @return
5439 * - 0 if call completed correctly and CQE status is SUCCESS.
5440 * - -1 if call failed (no CQE status).
5441 * - Other value if call completed correctly and return value is a CQE status value.
5442 */
5443int32_t
5444sli_cq_parse(sli4_t *sli4, sli4_queue_t *cq, uint8_t *cqe, sli4_qentry_e *etype,
5445		uint16_t *q_id)
5446{
5447	int32_t	rc = 0;
5448
5449	if (!sli4 || !cq || !cqe || !etype) {
5450		ocs_log_err(NULL, "bad parameters sli4=%p cq=%p cqe=%p etype=%p q_id=%p\n",
5451			    sli4, cq, cqe, etype, q_id);
5452		return -1;
5453	}
5454
5455	if (cq->u.flag.is_mq) {
5456		sli4_mcqe_t	*mcqe = (void *)cqe;
5457
5458		if (mcqe->ae) {
5459			*etype = SLI_QENTRY_ASYNC;
5460		} else {
5461			*etype = SLI_QENTRY_MQ;
5462			rc = sli_cqe_mq(mcqe);
5463		}
5464		*q_id = -1;
5465	} else if (SLI4_PORT_TYPE_FC == sli4->port_type) {
5466		rc = sli_fc_cqe_parse(sli4, cq, cqe, etype, q_id);
5467	} else {
5468		ocs_log_test(sli4->os, "implement CQE parsing type = %#x\n",
5469			     sli4->port_type);
5470		rc = -1;
5471	}
5472
5473	return rc;
5474}
5475
5476/**
5477 * @ingroup sli
5478 * @brief Cause chip to enter an unrecoverable error state.
5479 *
5480 * @par Description
5481 * Cause chip to enter an unrecoverable error state. This is
5482 * used when detecting unexpected FW behavior so FW can be
5483 * hwted from the driver as soon as error is detected.
5484 *
5485 * @param sli4 SLI context.
5486 * @param dump Generate dump as part of reset.
5487 *
5488 * @return Returns 0 if call completed correctly, or -1 if call failed (unsupported chip).
5489 */
5490int32_t sli_raise_ue(sli4_t *sli4, uint8_t dump)
5491{
5492#define FDD 2
5493	if (SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(sli4)) {
5494		switch(sli_get_asic_type(sli4)) {
5495		case SLI4_ASIC_TYPE_BE3: {
5496			sli_reg_write(sli4, SLI4_REG_SW_UE_CSR1, 0xffffffff);
5497			sli_reg_write(sli4, SLI4_REG_SW_UE_CSR2, 0);
5498			break;
5499		}
5500		case SLI4_ASIC_TYPE_SKYHAWK: {
5501			uint32_t value;
5502			value = ocs_config_read32(sli4->os, SLI4_SW_UE_REG);
5503			ocs_config_write32(sli4->os, SLI4_SW_UE_REG, (value | (1U << 24)));
5504			break;
5505		}
5506		default:
5507			ocs_log_test(sli4->os, "invalid asic type %d\n", sli_get_asic_type(sli4));
5508			return -1;
5509		}
5510	} else if (SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(sli4)) {
5511		if (dump == FDD) {
5512			sli_reg_write(sli4, SLI4_REG_SLIPORT_CONTROL, SLI4_SLIPORT_CONTROL_FDD | SLI4_SLIPORT_CONTROL_IP);
5513		} else {
5514			uint32_t value = SLI4_PHYDEV_CONTROL_FRST;
5515			if (dump == 1) {
5516				value |= SLI4_PHYDEV_CONTROL_DD;
5517			}
5518			sli_reg_write(sli4, SLI4_REG_PHYSDEV_CONTROL, value);
5519		}
5520	} else {
5521		ocs_log_test(sli4->os, "invalid iftype=%d\n", sli_get_if_type(sli4));
5522		return -1;
5523	}
5524	return 0;
5525}
5526
5527/**
5528 * @ingroup sli
5529 * @brief Read the SLIPORT_STATUS register to to check if a dump is present.
5530 *
5531 * @param sli4 SLI context.
5532 *
5533 * @return  Returns 1 if the chip is ready, or 0 if the chip is not ready, 2 if fdp is present.
5534 */
5535int32_t sli_dump_is_ready(sli4_t *sli4)
5536{
5537	int32_t	rc = 0;
5538	uint32_t port_val;
5539	uint32_t bmbx_val;
5540	uint32_t uerr_lo;
5541	uint32_t uerr_hi;
5542	uint32_t uerr_mask_lo;
5543	uint32_t uerr_mask_hi;
5544
5545	if (SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(sli4)) {
5546		/* for iftype=0, dump ready when UE is encountered */
5547		uerr_lo = sli_reg_read(sli4, SLI4_REG_UERR_STATUS_LO);
5548		uerr_hi = sli_reg_read(sli4, SLI4_REG_UERR_STATUS_HI);
5549		uerr_mask_lo = sli_reg_read(sli4, SLI4_REG_UERR_MASK_LO);
5550		uerr_mask_hi = sli_reg_read(sli4, SLI4_REG_UERR_MASK_HI);
5551		if ((uerr_lo & ~uerr_mask_lo) || (uerr_hi & ~uerr_mask_hi)) {
5552			rc = 1;
5553		}
5554
5555	} else if (SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(sli4)) {
5556		/*
5557		 * Ensure that the port is ready AND the mailbox is
5558		 * ready before signaling that the dump is ready to go.
5559		 */
5560		port_val = sli_reg_read(sli4, SLI4_REG_SLIPORT_STATUS);
5561		bmbx_val = sli_reg_read(sli4, SLI4_REG_BMBX);
5562
5563		if ((bmbx_val & SLI4_BMBX_RDY) &&
5564		    SLI4_PORT_STATUS_READY(port_val)) {
5565		    	if(SLI4_PORT_STATUS_DUMP_PRESENT(port_val)) {
5566				rc = 1;
5567			}else if( SLI4_PORT_STATUS_FDP_PRESENT(port_val)) {
5568				rc = 2;
5569			}
5570		}
5571	} else {
5572		ocs_log_test(sli4->os, "invalid iftype=%d\n", sli_get_if_type(sli4));
5573		return -1;
5574	}
5575	return rc;
5576}
5577
5578/**
5579 * @ingroup sli
5580 * @brief Read the SLIPORT_STATUS register to check if a dump is present.
5581 *
5582 * @param sli4 SLI context.
5583 *
5584 * @return
5585 * - 0 if call completed correctly and no dump is present.
5586 * - 1 if call completed and dump is present.
5587 * - -1 if call failed (unsupported chip).
5588 */
5589int32_t sli_dump_is_present(sli4_t *sli4)
5590{
5591	uint32_t val;
5592	uint32_t ready;
5593
5594	if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(sli4)) {
5595		ocs_log_test(sli4->os, "Function only supported for I/F type 2");
5596		return -1;
5597	}
5598
5599	/* If the chip is not ready, then there cannot be a dump */
5600	ready = sli_wait_for_fw_ready(sli4, SLI4_INIT_PORT_DELAY_US);
5601	if (!ready) {
5602		return 0;
5603	}
5604
5605	val = sli_reg_read(sli4, SLI4_REG_SLIPORT_STATUS);
5606	if (UINT32_MAX == val) {
5607		ocs_log_err(sli4->os, "error reading SLIPORT_STATUS\n");
5608		return -1;
5609	} else {
5610		return ((val & SLI4_PORT_STATUS_DIP) ? 1 : 0);
5611	}
5612}
5613
5614/**
5615 * @ingroup sli
5616 * @brief Read the SLIPORT_STATUS register to check if the reset required is set.
5617 *
5618 * @param sli4 SLI context.
5619 *
5620 * @return
5621 * - 0 if call completed correctly and reset is not required.
5622 * - 1 if call completed and reset is required.
5623 * - -1 if call failed.
5624 */
5625int32_t sli_reset_required(sli4_t *sli4)
5626{
5627	uint32_t val;
5628
5629	if (SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(sli4)) {
5630		ocs_log_test(sli4->os, "reset required N/A for iftype 0\n");
5631		return 0;
5632	}
5633
5634	val = sli_reg_read(sli4, SLI4_REG_SLIPORT_STATUS);
5635	if (UINT32_MAX == val) {
5636		ocs_log_err(sli4->os, "error reading SLIPORT_STATUS\n");
5637		return -1;
5638	} else {
5639		return ((val & SLI4_PORT_STATUS_RN) ? 1 : 0);
5640	}
5641}
5642
5643/**
5644 * @ingroup sli
5645 * @brief Read the SLIPORT_SEMAPHORE and SLIPORT_STATUS registers to check if
5646 * the port status indicates that a FW error has occurred.
5647 *
5648 * @param sli4 SLI context.
5649 *
5650 * @return
5651 * - 0 if call completed correctly and no FW error occurred.
5652 * - > 0 which indicates that a FW error has occurred.
5653 * - -1 if call failed.
5654 */
5655int32_t sli_fw_error_status(sli4_t *sli4)
5656{
5657	uint32_t sliport_semaphore;
5658	int32_t rc = 0;
5659
5660	sliport_semaphore = sli_reg_read(sli4, SLI4_REG_SLIPORT_SEMAPHORE);
5661	if (UINT32_MAX == sliport_semaphore) {
5662		ocs_log_err(sli4->os, "error reading SLIPORT_SEMAPHORE register\n");
5663		return 1;
5664	}
5665	rc = (SLI4_PORT_SEMAPHORE_IN_ERR(sliport_semaphore) ? 1 : 0);
5666
5667	if (rc == 0) {
5668		if (SLI4_IF_TYPE_BE3_SKH_PF == sli4->if_type ||
5669		    (SLI4_IF_TYPE_BE3_SKH_VF == sli4->if_type)) {
5670			uint32_t uerr_mask_lo, uerr_mask_hi;
5671			uint32_t uerr_status_lo, uerr_status_hi;
5672
5673			uerr_mask_lo = sli_reg_read(sli4, SLI4_REG_UERR_MASK_LO);
5674			uerr_mask_hi = sli_reg_read(sli4, SLI4_REG_UERR_MASK_HI);
5675			uerr_status_lo = sli_reg_read(sli4, SLI4_REG_UERR_STATUS_LO);
5676			uerr_status_hi = sli_reg_read(sli4, SLI4_REG_UERR_STATUS_HI);
5677			if ((uerr_mask_lo & uerr_status_lo) != 0 ||
5678			    (uerr_mask_hi & uerr_status_hi) != 0) {
5679				rc = 1;
5680			}
5681		} else if ((SLI4_IF_TYPE_LANCER_FC_ETH == sli4->if_type)) {
5682			uint32_t sliport_status;
5683
5684			sliport_status = sli_reg_read(sli4, SLI4_REG_SLIPORT_STATUS);
5685			rc = (SLI4_PORT_STATUS_ERROR(sliport_status) ? 1 : 0);
5686		}
5687	}
5688	return rc;
5689}
5690
5691/**
5692 * @ingroup sli
5693 * @brief Determine if the chip FW is in a ready state
5694 *
5695 * @param sli4 SLI context.
5696 *
5697 * @return
5698 * - 0 if call completed correctly and FW is not ready.
5699 * - 1 if call completed correctly and FW is ready.
5700 * - -1 if call failed.
5701 */
5702int32_t
5703sli_fw_ready(sli4_t *sli4)
5704{
5705	uint32_t val;
5706	int32_t rc = -1;
5707
5708	/*
5709	 * Is firmware ready for operation? Check needed depends on IF_TYPE
5710	 */
5711	if (SLI4_IF_TYPE_BE3_SKH_PF == sli4->if_type ||
5712	    SLI4_IF_TYPE_BE3_SKH_VF == sli4->if_type) {
5713		val = sli_reg_read(sli4, SLI4_REG_SLIPORT_SEMAPHORE);
5714		rc = ((SLI4_PORT_SEMAPHORE_STATUS_POST_READY ==
5715		       SLI4_PORT_SEMAPHORE_PORT(val)) &&
5716		      (!SLI4_PORT_SEMAPHORE_IN_ERR(val)) ? 1 : 0);
5717	} else if (SLI4_IF_TYPE_LANCER_FC_ETH == sli4->if_type) {
5718		val = sli_reg_read(sli4, SLI4_REG_SLIPORT_STATUS);
5719		rc = (SLI4_PORT_STATUS_READY(val) ? 1 : 0);
5720	}
5721	return rc;
5722}
5723
5724/**
5725 * @ingroup sli
5726 * @brief Determine if the link can be configured
5727 *
5728 * @param sli4 SLI context.
5729 *
5730 * @return
5731 * - 0 if link is not configurable.
5732 * - 1 if link is configurable.
5733 */
5734int32_t sli_link_is_configurable(sli4_t *sli)
5735{
5736	int32_t rc = 0;
5737	/*
5738	 * Link config works on: Skyhawk and Lancer
5739	 * Link config does not work on: LancerG6
5740	 */
5741
5742	switch (sli_get_asic_type(sli)) {
5743	case SLI4_ASIC_TYPE_SKYHAWK:
5744	case SLI4_ASIC_TYPE_LANCER:
5745	case SLI4_ASIC_TYPE_CORSAIR:
5746		rc = 1;
5747		break;
5748	case SLI4_ASIC_TYPE_LANCERG6:
5749	case SLI4_ASIC_TYPE_BE3:
5750	default:
5751		rc = 0;
5752		break;
5753	}
5754
5755	return rc;
5756
5757}
5758
5759/* vim: set noexpandtab textwidth=120: */
5760
5761extern const char *SLI_QNAME[];
5762extern const sli4_reg_t regmap[SLI4_REG_MAX][SLI4_MAX_IF_TYPES];
5763
5764/**
5765 * @ingroup sli_fc
5766 * @brief Write an FCOE_WQ_CREATE command.
5767 *
5768 * @param sli4 SLI context.
5769 * @param buf Destination buffer for the command.
5770 * @param size Buffer size, in bytes.
5771 * @param qmem DMA memory for the queue.
5772 * @param cq_id Associated CQ_ID.
5773 * @param ulp The ULP to bind
5774 *
5775 * @note This creates a Version 0 message.
5776 *
5777 * @return Returns the number of bytes written.
5778 */
5779int32_t
5780sli_cmd_fcoe_wq_create(sli4_t *sli4, void *buf, size_t size,
5781		       ocs_dma_t *qmem, uint16_t cq_id, uint16_t ulp)
5782{
5783	sli4_req_fcoe_wq_create_t	*wq = NULL;
5784	uint32_t	sli_config_off = 0;
5785	uint32_t	p;
5786	uintptr_t	addr;
5787
5788	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
5789		uint32_t payload_size;
5790
5791		/* Payload length must accommodate both request and response */
5792		payload_size = max(sizeof(sli4_req_fcoe_wq_create_t),
5793				sizeof(sli4_res_common_create_queue_t));
5794
5795		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
5796				NULL);
5797	}
5798	wq = (sli4_req_fcoe_wq_create_t *)((uint8_t *)buf + sli_config_off);
5799
5800	wq->hdr.opcode = SLI4_OPC_FCOE_WQ_CREATE;
5801	wq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
5802	wq->hdr.request_length = sizeof(sli4_req_fcoe_wq_create_t) -
5803					sizeof(sli4_req_hdr_t);
5804	/* valid values for number of pages: 1-4 (sec 4.5.1) */
5805	wq->num_pages = sli_page_count(qmem->size, SLI_PAGE_SIZE);
5806	if (!wq->num_pages || (wq->num_pages > SLI4_FCOE_WQ_CREATE_V0_MAX_PAGES)) {
5807		return 0;
5808	}
5809
5810	wq->cq_id = cq_id;
5811
5812	if (sli4->config.dual_ulp_capable) {
5813		wq->dua = 1;
5814		wq->bqu = 1;
5815		wq->ulp = ulp;
5816	}
5817
5818	for (p = 0, addr = qmem->phys;
5819			p < wq->num_pages;
5820			p++, addr += SLI_PAGE_SIZE) {
5821		wq->page_physical_address[p].low  = ocs_addr32_lo(addr);
5822		wq->page_physical_address[p].high = ocs_addr32_hi(addr);
5823	}
5824
5825	return(sli_config_off + sizeof(sli4_req_fcoe_wq_create_t));
5826}
5827
5828/**
5829 * @ingroup sli_fc
5830 * @brief Write an FCOE_WQ_CREATE_V1 command.
5831 *
5832 * @param sli4 SLI context.
5833 * @param buf Destination buffer for the command.
5834 * @param size Buffer size, in bytes.
5835 * @param qmem DMA memory for the queue.
5836 * @param cq_id Associated CQ_ID.
5837 * @param ignored This parameter carries the ULP for WQ (ignored for V1)
5838
5839 *
5840 * @return Returns the number of bytes written.
5841 */
5842int32_t
5843sli_cmd_fcoe_wq_create_v1(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *qmem,
5844			  uint16_t cq_id, uint16_t ignored)
5845{
5846	sli4_req_fcoe_wq_create_v1_t	*wq = NULL;
5847	uint32_t	sli_config_off = 0;
5848	uint32_t	p;
5849	uintptr_t	addr;
5850	uint32_t	page_size = 0;
5851	uint32_t	page_bytes = 0;
5852	uint32_t	n_wqe = 0;
5853
5854	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
5855		uint32_t payload_size;
5856
5857		/* Payload length must accommodate both request and response */
5858		payload_size = max(sizeof(sli4_req_fcoe_wq_create_v1_t),
5859				sizeof(sli4_res_common_create_queue_t));
5860
5861		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
5862				NULL);
5863	}
5864	wq = (sli4_req_fcoe_wq_create_v1_t *)((uint8_t *)buf + sli_config_off);
5865
5866	wq->hdr.opcode = SLI4_OPC_FCOE_WQ_CREATE;
5867	wq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
5868	wq->hdr.request_length = sizeof(sli4_req_fcoe_wq_create_v1_t) -
5869					sizeof(sli4_req_hdr_t);
5870	wq->hdr.version = 1;
5871
5872	n_wqe = qmem->size / sli4->config.wqe_size;
5873
5874	/* This heuristic to determine the page size is simplistic
5875	 * but could be made more sophisticated
5876	 */
5877	switch (qmem->size) {
5878	case 4096:
5879	case 8192:
5880	case 16384:
5881	case 32768:
5882		page_size = 1;
5883		break;
5884	case 65536:
5885		page_size = 2;
5886		break;
5887	case 131072:
5888		page_size = 4;
5889		break;
5890	case 262144:
5891		page_size = 8;
5892		break;
5893	case 524288:
5894		page_size = 10;
5895		break;
5896	default:
5897		return 0;
5898	}
5899	page_bytes = page_size * SLI_PAGE_SIZE;
5900
5901	/* valid values for number of pages: 1-8 */
5902	wq->num_pages = sli_page_count(qmem->size, page_bytes);
5903	if (!wq->num_pages || (wq->num_pages > SLI4_FCOE_WQ_CREATE_V1_MAX_PAGES)) {
5904		return 0;
5905	}
5906
5907	wq->cq_id = cq_id;
5908
5909	wq->page_size = page_size;
5910
5911	if (sli4->config.wqe_size == SLI4_WQE_EXT_BYTES) {
5912		wq->wqe_size = SLI4_WQE_EXT_SIZE;
5913	} else {
5914		wq->wqe_size = SLI4_WQE_SIZE;
5915	}
5916
5917	wq->wqe_count = n_wqe;
5918
5919	for (p = 0, addr = qmem->phys;
5920			p < wq->num_pages;
5921			p++, addr += page_bytes) {
5922		wq->page_physical_address[p].low  = ocs_addr32_lo(addr);
5923		wq->page_physical_address[p].high = ocs_addr32_hi(addr);
5924	}
5925
5926	return(sli_config_off + sizeof(sli4_req_fcoe_wq_create_v1_t));
5927}
5928
5929/**
5930 * @ingroup sli_fc
5931 * @brief Write an FCOE_WQ_DESTROY command.
5932 *
5933 * @param sli4 SLI context.
5934 * @param buf Destination buffer for the command.
5935 * @param size Buffer size, in bytes.
5936 * @param wq_id WQ_ID.
5937 *
5938 * @return Returns the number of bytes written.
5939 */
5940int32_t
5941sli_cmd_fcoe_wq_destroy(sli4_t *sli4, void *buf, size_t size, uint16_t wq_id)
5942{
5943	sli4_req_fcoe_wq_destroy_t	*wq = NULL;
5944	uint32_t	sli_config_off = 0;
5945
5946	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
5947		uint32_t payload_size;
5948
5949		/* Payload length must accommodate both request and response */
5950		payload_size = max(sizeof(sli4_req_fcoe_wq_destroy_t),
5951				sizeof(sli4_res_hdr_t));
5952
5953		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
5954				NULL);
5955	}
5956	wq = (sli4_req_fcoe_wq_destroy_t *)((uint8_t *)buf + sli_config_off);
5957
5958	wq->hdr.opcode = SLI4_OPC_FCOE_WQ_DESTROY;
5959	wq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
5960	wq->hdr.request_length = sizeof(sli4_req_fcoe_wq_destroy_t) -
5961					sizeof(sli4_req_hdr_t);
5962
5963	wq->wq_id = wq_id;
5964
5965	return(sli_config_off + sizeof(sli4_req_fcoe_wq_destroy_t));
5966}
5967
5968/**
5969 * @ingroup sli_fc
5970 * @brief Write an FCOE_POST_SGL_PAGES command.
5971 *
5972 * @param sli4 SLI context.
5973 * @param buf Destination buffer for the command.
5974 * @param size Buffer size, in bytes.
5975 * @param xri starting XRI
5976 * @param xri_count XRI
5977 * @param page0 First SGL memory page.
5978 * @param page1 Second SGL memory page (optional).
5979 * @param dma DMA buffer for non-embedded mailbox command (options)
5980 *
5981 * if non-embedded mbx command is used, dma buffer must be at least (32 + xri_count*16) in length
5982 *
5983 * @return Returns the number of bytes written.
5984 */
5985int32_t
5986sli_cmd_fcoe_post_sgl_pages(sli4_t *sli4, void *buf, size_t size,
5987		uint16_t xri, uint32_t xri_count, ocs_dma_t *page0[], ocs_dma_t *page1[], ocs_dma_t *dma)
5988{
5989	sli4_req_fcoe_post_sgl_pages_t	*post = NULL;
5990	uint32_t	sli_config_off = 0;
5991	uint32_t	i;
5992
5993	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
5994		uint32_t payload_size;
5995
5996		/* Payload length must accommodate both request and response */
5997		payload_size = max(sizeof(sli4_req_fcoe_post_sgl_pages_t),
5998				sizeof(sli4_res_hdr_t));
5999
6000		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
6001				dma);
6002	}
6003	if (dma) {
6004		post = dma->virt;
6005		ocs_memset(post, 0, dma->size);
6006	} else {
6007		post = (sli4_req_fcoe_post_sgl_pages_t *)((uint8_t *)buf + sli_config_off);
6008	}
6009
6010	post->hdr.opcode = SLI4_OPC_FCOE_POST_SGL_PAGES;
6011	post->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6012	/* payload size calculation
6013	 *   4 = xri_start + xri_count
6014	 *   xri_count = # of XRI's registered
6015	 *   sizeof(uint64_t) = physical address size
6016	 *   2 = # of physical addresses per page set
6017	 */
6018	post->hdr.request_length = 4 + (xri_count * (sizeof(uint64_t) * 2));
6019
6020	post->xri_start = xri;
6021	post->xri_count = xri_count;
6022
6023	for (i = 0; i < xri_count; i++) {
6024		post->page_set[i].page0_low  = ocs_addr32_lo(page0[i]->phys);
6025		post->page_set[i].page0_high = ocs_addr32_hi(page0[i]->phys);
6026	}
6027
6028	if (page1) {
6029		for (i = 0; i < xri_count; i++) {
6030			post->page_set[i].page1_low  = ocs_addr32_lo(page1[i]->phys);
6031			post->page_set[i].page1_high = ocs_addr32_hi(page1[i]->phys);
6032		}
6033	}
6034
6035	return dma ? sli_config_off : (sli_config_off + sizeof(sli4_req_fcoe_post_sgl_pages_t));
6036}
6037
6038/**
6039 * @ingroup sli_fc
6040 * @brief Write an FCOE_RQ_CREATE command.
6041 *
6042 * @param sli4 SLI context.
6043 * @param buf Destination buffer for the command.
6044 * @param size Buffer size, in bytes.
6045 * @param qmem DMA memory for the queue.
6046 * @param cq_id Associated CQ_ID.
6047 * @param ulp This parameter carries the ULP for the RQ
6048 * @param buffer_size Buffer size pointed to by each RQE.
6049 *
6050 * @note This creates a Version 0 message.
6051 *
6052 * @return Returns the number of bytes written.
6053 */
6054int32_t
6055sli_cmd_fcoe_rq_create(sli4_t *sli4, void *buf, size_t size,
6056		ocs_dma_t *qmem, uint16_t cq_id, uint16_t ulp, uint16_t buffer_size)
6057{
6058	sli4_req_fcoe_rq_create_t	*rq = NULL;
6059	uint32_t	sli_config_off = 0;
6060	uint32_t	p;
6061	uintptr_t	addr;
6062
6063	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
6064		uint32_t payload_size;
6065
6066		/* Payload length must accommodate both request and response */
6067		payload_size = max(sizeof(sli4_req_fcoe_rq_create_t),
6068				sizeof(sli4_res_common_create_queue_t));
6069
6070		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
6071				NULL);
6072	}
6073	rq = (sli4_req_fcoe_rq_create_t *)((uint8_t *)buf + sli_config_off);
6074
6075	rq->hdr.opcode = SLI4_OPC_FCOE_RQ_CREATE;
6076	rq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6077	rq->hdr.request_length = sizeof(sli4_req_fcoe_rq_create_t) -
6078					sizeof(sli4_req_hdr_t);
6079	/* valid values for number of pages: 1-8 (sec 4.5.6) */
6080	rq->num_pages = sli_page_count(qmem->size, SLI_PAGE_SIZE);
6081	if (!rq->num_pages || (rq->num_pages > SLI4_FCOE_RQ_CREATE_V0_MAX_PAGES)) {
6082		ocs_log_test(sli4->os, "num_pages %d not valid\n", rq->num_pages);
6083		return 0;
6084	}
6085
6086	/*
6087	 * RQE count is the log base 2 of the total number of entries
6088	 */
6089	rq->rqe_count = ocs_lg2(qmem->size / SLI4_FCOE_RQE_SIZE);
6090
6091	if ((buffer_size < SLI4_FCOE_RQ_CREATE_V0_MIN_BUF_SIZE) ||
6092			(buffer_size > SLI4_FCOE_RQ_CREATE_V0_MAX_BUF_SIZE)) {
6093		ocs_log_err(sli4->os, "buffer_size %d out of range (%d-%d)\n",
6094				buffer_size,
6095				SLI4_FCOE_RQ_CREATE_V0_MIN_BUF_SIZE,
6096				SLI4_FCOE_RQ_CREATE_V0_MAX_BUF_SIZE);
6097		return -1;
6098	}
6099	rq->buffer_size = buffer_size;
6100
6101	rq->cq_id = cq_id;
6102
6103	if (sli4->config.dual_ulp_capable) {
6104		rq->dua = 1;
6105		rq->bqu = 1;
6106		rq->ulp = ulp;
6107	}
6108
6109	for (p = 0, addr = qmem->phys;
6110			p < rq->num_pages;
6111			p++, addr += SLI_PAGE_SIZE) {
6112		rq->page_physical_address[p].low  = ocs_addr32_lo(addr);
6113		rq->page_physical_address[p].high = ocs_addr32_hi(addr);
6114	}
6115
6116	return(sli_config_off + sizeof(sli4_req_fcoe_rq_create_t));
6117}
6118
6119/**
6120 * @ingroup sli_fc
6121 * @brief Write an FCOE_RQ_CREATE_V1 command.
6122 *
6123 * @param sli4 SLI context.
6124 * @param buf Destination buffer for the command.
6125 * @param size Buffer size, in bytes.
6126 * @param qmem DMA memory for the queue.
6127 * @param cq_id Associated CQ_ID.
6128 * @param ulp This parameter carries the ULP for RQ (ignored for V1)
6129 * @param buffer_size Buffer size pointed to by each RQE.
6130 *
6131 * @note This creates a Version 0 message
6132 *
6133 * @return Returns the number of bytes written.
6134 */
6135int32_t
6136sli_cmd_fcoe_rq_create_v1(sli4_t *sli4, void *buf, size_t size,
6137			  ocs_dma_t *qmem, uint16_t cq_id, uint16_t ulp,
6138			  uint16_t buffer_size)
6139{
6140	sli4_req_fcoe_rq_create_v1_t	*rq = NULL;
6141	uint32_t	sli_config_off = 0;
6142	uint32_t	p;
6143	uintptr_t	addr;
6144
6145	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
6146		uint32_t payload_size;
6147
6148		/* Payload length must accommodate both request and response */
6149		payload_size = max(sizeof(sli4_req_fcoe_rq_create_v1_t),
6150				sizeof(sli4_res_common_create_queue_t));
6151
6152		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
6153				NULL);
6154	}
6155	rq = (sli4_req_fcoe_rq_create_v1_t *)((uint8_t *)buf + sli_config_off);
6156
6157	rq->hdr.opcode = SLI4_OPC_FCOE_RQ_CREATE;
6158	rq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6159	rq->hdr.request_length = sizeof(sli4_req_fcoe_rq_create_v1_t) -
6160					sizeof(sli4_req_hdr_t);
6161	rq->hdr.version = 1;
6162
6163	/* Disable "no buffer warnings" to avoid Lancer bug */
6164	rq->dnb = TRUE;
6165
6166	/* valid values for number of pages: 1-8 (sec 4.5.6) */
6167	rq->num_pages = sli_page_count(qmem->size, SLI_PAGE_SIZE);
6168	if (!rq->num_pages || (rq->num_pages > SLI4_FCOE_RQ_CREATE_V1_MAX_PAGES)) {
6169		ocs_log_test(sli4->os, "num_pages %d not valid, max %d\n",
6170                rq->num_pages, SLI4_FCOE_RQ_CREATE_V1_MAX_PAGES);
6171		return 0;
6172	}
6173
6174	/*
6175	 * RQE count is the total number of entries (note not lg2(# entries))
6176	 */
6177	rq->rqe_count = qmem->size / SLI4_FCOE_RQE_SIZE;
6178
6179	rq->rqe_size = SLI4_FCOE_RQE_SIZE_8;
6180
6181	rq->page_size = SLI4_FCOE_RQ_PAGE_SIZE_4096;
6182
6183	if ((buffer_size < sli4->config.rq_min_buf_size) ||
6184	    (buffer_size > sli4->config.rq_max_buf_size)) {
6185		ocs_log_err(sli4->os, "buffer_size %d out of range (%d-%d)\n",
6186				buffer_size,
6187				sli4->config.rq_min_buf_size,
6188				sli4->config.rq_max_buf_size);
6189		return -1;
6190	}
6191	rq->buffer_size = buffer_size;
6192
6193	rq->cq_id = cq_id;
6194
6195	for (p = 0, addr = qmem->phys;
6196			p < rq->num_pages;
6197			p++, addr += SLI_PAGE_SIZE) {
6198		rq->page_physical_address[p].low  = ocs_addr32_lo(addr);
6199		rq->page_physical_address[p].high = ocs_addr32_hi(addr);
6200	}
6201
6202	return(sli_config_off + sizeof(sli4_req_fcoe_rq_create_v1_t));
6203}
6204
6205/**
6206 * @ingroup sli_fc
6207 * @brief Write an FCOE_RQ_DESTROY command.
6208 *
6209 * @param sli4 SLI context.
6210 * @param buf Destination buffer for the command.
6211 * @param size Buffer size, in bytes.
6212 * @param rq_id RQ_ID.
6213 *
6214 * @return Returns the number of bytes written.
6215 */
6216int32_t
6217sli_cmd_fcoe_rq_destroy(sli4_t *sli4, void *buf, size_t size, uint16_t rq_id)
6218{
6219	sli4_req_fcoe_rq_destroy_t	*rq = NULL;
6220	uint32_t	sli_config_off = 0;
6221
6222	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
6223		uint32_t payload_size;
6224
6225		/* Payload length must accommodate both request and response */
6226		payload_size = max(sizeof(sli4_req_fcoe_rq_destroy_t),
6227				sizeof(sli4_res_hdr_t));
6228
6229		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
6230				NULL);
6231	}
6232	rq = (sli4_req_fcoe_rq_destroy_t *)((uint8_t *)buf + sli_config_off);
6233
6234	rq->hdr.opcode = SLI4_OPC_FCOE_RQ_DESTROY;
6235	rq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6236	rq->hdr.request_length = sizeof(sli4_req_fcoe_rq_destroy_t) -
6237					sizeof(sli4_req_hdr_t);
6238
6239	rq->rq_id = rq_id;
6240
6241	return(sli_config_off + sizeof(sli4_req_fcoe_rq_destroy_t));
6242}
6243
6244/**
6245 * @ingroup sli_fc
6246 * @brief Write an FCOE_READ_FCF_TABLE command.
6247 *
6248 * @note
6249 * The response of this command exceeds the size of an embedded
6250 * command and requires an external buffer with DMA capability to hold the results.
6251 * The caller should allocate the ocs_dma_t structure / memory.
6252 *
6253 * @param sli4 SLI context.
6254 * @param buf Destination buffer for the command.
6255 * @param size Buffer size, in bytes.
6256 * @param dma Pointer to DMA memory structure. This is allocated by the caller.
6257 * @param index FCF table index to retrieve.
6258 *
6259 * @return Returns the number of bytes written.
6260 */
6261int32_t
6262sli_cmd_fcoe_read_fcf_table(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma, uint16_t index)
6263{
6264	sli4_req_fcoe_read_fcf_table_t *read_fcf = NULL;
6265
6266	if (SLI4_PORT_TYPE_FC != sli4->port_type) {
6267		ocs_log_test(sli4->os, "FCOE_READ_FCF_TABLE only supported on FC\n");
6268		return -1;
6269	}
6270
6271	read_fcf = dma->virt;
6272
6273	ocs_memset(read_fcf, 0, sizeof(sli4_req_fcoe_read_fcf_table_t));
6274
6275	read_fcf->hdr.opcode = SLI4_OPC_FCOE_READ_FCF_TABLE;
6276	read_fcf->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6277	read_fcf->hdr.request_length = dma->size -
6278		sizeof(sli4_req_fcoe_read_fcf_table_t);
6279	read_fcf->fcf_index = index;
6280
6281	return sli_cmd_sli_config(sli4, buf, size, 0, dma);
6282}
6283
6284/**
6285 * @ingroup sli_fc
6286 * @brief Write an FCOE_POST_HDR_TEMPLATES command.
6287 *
6288 * @param sli4 SLI context.
6289 * @param buf Destination buffer for the command.
6290 * @param size Buffer size, in bytes.
6291 * @param dma Pointer to DMA memory structure. This is allocated by the caller.
6292 * @param rpi Starting RPI index for the header templates.
6293 * @param payload_dma Pointer to DMA memory used to hold larger descriptor counts.
6294 *
6295 * @return Returns the number of bytes written.
6296 */
6297int32_t
6298sli_cmd_fcoe_post_hdr_templates(sli4_t *sli4, void *buf, size_t size,
6299		ocs_dma_t *dma, uint16_t rpi, ocs_dma_t *payload_dma)
6300{
6301	sli4_req_fcoe_post_hdr_templates_t *template = NULL;
6302	uint32_t	sli_config_off = 0;
6303	uintptr_t	phys = 0;
6304	uint32_t	i = 0;
6305	uint32_t	page_count;
6306	uint32_t	payload_size;
6307
6308	page_count = sli_page_count(dma->size, SLI_PAGE_SIZE);
6309
6310	payload_size = sizeof(sli4_req_fcoe_post_hdr_templates_t) +
6311				page_count * sizeof(sli4_physical_page_descriptor_t);
6312
6313	if (page_count > 16) {
6314		/* We can't fit more than 16 descriptors into an embedded mailbox
6315		   command, it has to be non-embedded */
6316		if (ocs_dma_alloc(sli4->os, payload_dma, payload_size, 4)) {
6317			ocs_log_err(sli4->os, "mailbox payload memory allocation fail\n");
6318			return 0;
6319		}
6320		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size, payload_dma);
6321		template = (sli4_req_fcoe_post_hdr_templates_t *)payload_dma->virt;
6322	} else {
6323		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size, NULL);
6324		template = (sli4_req_fcoe_post_hdr_templates_t *)((uint8_t *)buf + sli_config_off);
6325	}
6326
6327	if (UINT16_MAX == rpi) {
6328		rpi = sli4->config.extent[SLI_RSRC_FCOE_RPI].base[0];
6329	}
6330
6331	template->hdr.opcode = SLI4_OPC_FCOE_POST_HDR_TEMPLATES;
6332	template->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6333	template->hdr.request_length = sizeof(sli4_req_fcoe_post_hdr_templates_t) -
6334					sizeof(sli4_req_hdr_t);
6335
6336	template->rpi_offset = rpi;
6337	template->page_count = page_count;
6338	phys = dma->phys;
6339	for (i = 0; i < template->page_count; i++) {
6340		template->page_descriptor[i].low  = ocs_addr32_lo(phys);
6341		template->page_descriptor[i].high = ocs_addr32_hi(phys);
6342
6343		phys += SLI_PAGE_SIZE;
6344	}
6345
6346	return(sli_config_off + payload_size);
6347}
6348
6349int32_t
6350sli_cmd_fcoe_rediscover_fcf(sli4_t *sli4, void *buf, size_t size, uint16_t index)
6351{
6352	sli4_req_fcoe_rediscover_fcf_t *redisc = NULL;
6353	uint32_t	sli_config_off = 0;
6354
6355	sli_config_off = sli_cmd_sli_config(sli4, buf, size,
6356			sizeof(sli4_req_fcoe_rediscover_fcf_t),
6357			NULL);
6358
6359	redisc = (sli4_req_fcoe_rediscover_fcf_t *)((uint8_t *)buf + sli_config_off);
6360
6361	redisc->hdr.opcode = SLI4_OPC_FCOE_REDISCOVER_FCF;
6362	redisc->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6363	redisc->hdr.request_length = sizeof(sli4_req_fcoe_rediscover_fcf_t) -
6364					sizeof(sli4_req_hdr_t);
6365
6366	if (index == UINT16_MAX) {
6367		redisc->fcf_count = 0;
6368	} else {
6369		redisc->fcf_count = 1;
6370		redisc->fcf_index[0] = index;
6371	}
6372
6373	return(sli_config_off + sizeof(sli4_req_fcoe_rediscover_fcf_t));
6374}
6375
6376/**
6377 * @ingroup sli_fc
6378 * @brief Write an ABORT_WQE work queue entry.
6379 *
6380 * @param sli4 SLI context.
6381 * @param buf Destination buffer for the WQE.
6382 * @param size Buffer size, in bytes.
6383 * @param type Abort type, such as XRI, abort tag, and request tag.
6384 * @param send_abts Boolean to cause the hardware to automatically generate an ABTS.
6385 * @param ids ID of IOs to abort.
6386 * @param mask Mask applied to the ID values to abort.
6387 * @param tag Tag value associated with this abort.
6388 * @param cq_id The id of the completion queue where the WQE response is sent.
6389 * @param dnrx When set to 1, this field indicates that the SLI Port must not return the associated XRI to the SLI
6390 *             Port's optimized write XRI pool.
6391 *
6392 * @return Returns 0 on success, or a non-zero value on failure.
6393 */
6394int32_t
6395sli_abort_wqe(sli4_t *sli4, void *buf, size_t size, sli4_abort_type_e type, uint32_t send_abts,
6396	      uint32_t ids, uint32_t mask, uint16_t tag, uint16_t cq_id)
6397{
6398	sli4_abort_wqe_t	*abort = buf;
6399
6400	ocs_memset(buf, 0, size);
6401
6402	switch (type) {
6403	case SLI_ABORT_XRI:
6404		abort->criteria = SLI4_ABORT_CRITERIA_XRI_TAG;
6405		if (mask) {
6406			ocs_log_warn(sli4->os, "warning non-zero mask %#x when aborting XRI %#x\n", mask, ids);
6407			mask = 0;
6408		}
6409		break;
6410	case SLI_ABORT_ABORT_ID:
6411		abort->criteria = SLI4_ABORT_CRITERIA_ABORT_TAG;
6412		break;
6413	case SLI_ABORT_REQUEST_ID:
6414		abort->criteria = SLI4_ABORT_CRITERIA_REQUEST_TAG;
6415		break;
6416	default:
6417		ocs_log_test(sli4->os, "unsupported type %#x\n", type);
6418		return -1;
6419	}
6420
6421	abort->ia = send_abts ? 0 : 1;
6422
6423	/* Suppress ABTS retries */
6424	abort->ir = 1;
6425
6426	abort->t_mask = mask;
6427	abort->t_tag  = ids;
6428	abort->command = SLI4_WQE_ABORT;
6429	abort->request_tag = tag;
6430	abort->qosd = TRUE;
6431	abort->cq_id = cq_id;
6432	abort->cmd_type = SLI4_CMD_ABORT_WQE;
6433
6434	return 0;
6435}
6436
6437/**
6438 * @ingroup sli_fc
6439 * @brief Write an ELS_REQUEST64_WQE work queue entry.
6440 *
6441 * @param sli4 SLI context.
6442 * @param buf Destination buffer for the WQE.
6443 * @param size Buffer size, in bytes.
6444 * @param sgl DMA memory for the ELS request.
6445 * @param req_type ELS request type.
6446 * @param req_len Length of ELS request in bytes.
6447 * @param max_rsp_len Max length of ELS response in bytes.
6448 * @param timeout Time, in seconds, before an IO times out. Zero means 2 * R_A_TOV.
6449 * @param xri XRI for this exchange.
6450 * @param tag IO tag value.
6451 * @param cq_id The id of the completion queue where the WQE response is sent.
6452 * @param rnode Destination of ELS request (that is, the remote node).
6453 *
6454 * @return Returns 0 on success, or a non-zero value on failure.
6455 */
6456int32_t
6457sli_els_request64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint8_t req_type,
6458		      uint32_t req_len, uint32_t max_rsp_len, uint8_t timeout,
6459		      uint16_t xri, uint16_t tag, uint16_t cq_id, ocs_remote_node_t *rnode)
6460{
6461	sli4_els_request64_wqe_t	*els = buf;
6462	sli4_sge_t	*sge = sgl->virt;
6463	uint8_t		is_fabric = FALSE;
6464
6465	ocs_memset(buf, 0, size);
6466
6467	if (sli4->config.sgl_pre_registered) {
6468		els->xbl = FALSE;
6469
6470		els->dbde = TRUE;
6471		els->els_request_payload.bde_type = SLI4_BDE_TYPE_BDE_64;
6472
6473		els->els_request_payload.buffer_length = req_len;
6474		els->els_request_payload.u.data.buffer_address_low  = sge[0].buffer_address_low;
6475		els->els_request_payload.u.data.buffer_address_high = sge[0].buffer_address_high;
6476	} else {
6477		els->xbl = TRUE;
6478
6479		els->els_request_payload.bde_type = SLI4_BDE_TYPE_BLP;
6480
6481		els->els_request_payload.buffer_length = 2 * sizeof(sli4_sge_t);
6482		els->els_request_payload.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
6483		els->els_request_payload.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
6484	}
6485
6486	els->els_request_payload_length = req_len;
6487	els->max_response_payload_length = max_rsp_len;
6488
6489	els->xri_tag = xri;
6490	els->timer = timeout;
6491	els->class = SLI4_ELS_REQUEST64_CLASS_3;
6492
6493	els->command = SLI4_WQE_ELS_REQUEST64;
6494
6495	els->request_tag = tag;
6496
6497	if (rnode->node_group) {
6498		els->hlm = TRUE;
6499		els->remote_id = rnode->fc_id & 0x00ffffff;
6500	}
6501
6502	els->iod = SLI4_ELS_REQUEST64_DIR_READ;
6503
6504	els->qosd = TRUE;
6505
6506	/* figure out the ELS_ID value from the request buffer */
6507
6508	switch (req_type) {
6509	case FC_ELS_CMD_LOGO:
6510		els->els_id = SLI4_ELS_REQUEST64_LOGO;
6511		if (rnode->attached) {
6512			els->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6513			els->context_tag = rnode->indicator;
6514		} else {
6515			els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6516			els->context_tag = rnode->sport->indicator;
6517		}
6518		if (FC_ADDR_FABRIC == rnode->fc_id) {
6519			is_fabric = TRUE;
6520		}
6521		break;
6522	case FC_ELS_CMD_FDISC:
6523		if (FC_ADDR_FABRIC == rnode->fc_id) {
6524			is_fabric = TRUE;
6525		}
6526		if (0 == rnode->sport->fc_id) {
6527			els->els_id = SLI4_ELS_REQUEST64_FDISC;
6528			is_fabric = TRUE;
6529		} else {
6530			els->els_id = SLI4_ELS_REQUEST64_OTHER;
6531		}
6532		els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6533		els->context_tag = rnode->sport->indicator;
6534		els->sp = TRUE;
6535		break;
6536	case FC_ELS_CMD_FLOGI:
6537		els->els_id = SLI4_ELS_REQUEST64_FLOGIN;
6538		is_fabric = TRUE;
6539		if (SLI4_IF_TYPE_BE3_SKH_PF == sli4->if_type) {
6540			if (!rnode->sport->domain) {
6541				ocs_log_test(sli4->os, "invalid domain handle\n");
6542				return -1;
6543			}
6544			/*
6545			 * IF_TYPE 0 skips INIT_VFI/INIT_VPI and therefore must use the
6546			 * FCFI here
6547			 */
6548			els->ct = SLI4_ELS_REQUEST64_CONTEXT_FCFI;
6549			els->context_tag = rnode->sport->domain->fcf_indicator;
6550			els->sp = TRUE;
6551		} else {
6552			els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6553			els->context_tag = rnode->sport->indicator;
6554
6555			/*
6556			 * Set SP here ... we haven't done a REG_VPI yet
6557			 * TODO: need to maybe not set this when we have
6558			 *       completed VFI/VPI registrations ...
6559			 *
6560			 * Use the FC_ID of the SPORT if it has been allocated, otherwise
6561			 * use an S_ID of zero.
6562			 */
6563			els->sp = TRUE;
6564			if (rnode->sport->fc_id != UINT32_MAX) {
6565				els->sid = rnode->sport->fc_id;
6566			}
6567		}
6568		break;
6569	case FC_ELS_CMD_PLOGI:
6570		els->els_id = SLI4_ELS_REQUEST64_PLOGI;
6571		els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6572		els->context_tag = rnode->sport->indicator;
6573		break;
6574	case FC_ELS_CMD_SCR:
6575		els->els_id = SLI4_ELS_REQUEST64_OTHER;
6576		els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6577		els->context_tag = rnode->sport->indicator;
6578		break;
6579	default:
6580		els->els_id = SLI4_ELS_REQUEST64_OTHER;
6581		if (rnode->attached) {
6582			els->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6583			els->context_tag = rnode->indicator;
6584		} else {
6585			els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6586			els->context_tag = rnode->sport->indicator;
6587		}
6588		break;
6589	}
6590
6591	if (is_fabric) {
6592		els->cmd_type = SLI4_ELS_REQUEST64_CMD_FABRIC;
6593	} else {
6594		els->cmd_type = SLI4_ELS_REQUEST64_CMD_NON_FABRIC;
6595	}
6596
6597	els->cq_id = cq_id;
6598
6599	if (SLI4_ELS_REQUEST64_CONTEXT_RPI != els->ct) {
6600		els->remote_id = rnode->fc_id;
6601	}
6602	if (SLI4_ELS_REQUEST64_CONTEXT_VPI == els->ct) {
6603		els->temporary_rpi = rnode->indicator;
6604	}
6605
6606	return 0;
6607}
6608
6609
6610/**
6611 * @ingroup sli_fc
6612 * @brief Write an FCP_ICMND64_WQE work queue entry.
6613 *
6614 * @param sli4 SLI context.
6615 * @param buf Destination buffer for the WQE.
6616 * @param size Buffer size, in bytes.
6617 * @param sgl DMA memory for the scatter gather list.
6618 * @param xri XRI for this exchange.
6619 * @param tag IO tag value.
6620 * @param cq_id The id of the completion queue where the WQE response is sent.
6621 * @param rpi remote node indicator (RPI)
6622 * @param rnode Destination request (that is, the remote node).
6623 * @param timeout Time, in seconds, before an IO times out. Zero means no timeout.
6624 *
6625 * @return Returns 0 on success, or a non-zero value on failure.
6626 */
6627int32_t
6628sli_fcp_icmnd64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl,
6629		    uint16_t xri, uint16_t tag, uint16_t cq_id,
6630		    uint32_t rpi, ocs_remote_node_t *rnode, uint8_t timeout)
6631{
6632	sli4_fcp_icmnd64_wqe_t *icmnd = buf;
6633	sli4_sge_t	*sge = NULL;
6634
6635	ocs_memset(buf, 0, size);
6636
6637	if (!sgl || !sgl->virt) {
6638		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
6639			    sgl, sgl ? sgl->virt : NULL);
6640		return -1;
6641	}
6642	sge = sgl->virt;
6643
6644	if (sli4->config.sgl_pre_registered) {
6645		icmnd->xbl = FALSE;
6646
6647		icmnd->dbde = TRUE;
6648		icmnd->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6649
6650		icmnd->bde.buffer_length = sge[0].buffer_length;
6651		icmnd->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
6652		icmnd->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
6653	} else {
6654		icmnd->xbl = TRUE;
6655
6656		icmnd->bde.bde_type = SLI4_BDE_TYPE_BLP;
6657
6658		icmnd->bde.buffer_length = sgl->size;
6659		icmnd->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
6660		icmnd->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
6661	}
6662
6663	icmnd->payload_offset_length = sge[0].buffer_length + sge[1].buffer_length;
6664	icmnd->xri_tag = xri;
6665	icmnd->context_tag = rpi;
6666	icmnd->timer = timeout;
6667
6668	icmnd->pu = 2;	/* WQE word 4 contains read transfer length */
6669	icmnd->class = SLI4_ELS_REQUEST64_CLASS_3;
6670	icmnd->command = SLI4_WQE_FCP_ICMND64;
6671	icmnd->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6672
6673	icmnd->abort_tag = xri;
6674
6675	icmnd->request_tag = tag;
6676	icmnd->len_loc = 3;
6677	if (rnode->node_group) {
6678		icmnd->hlm = TRUE;
6679		icmnd->remote_n_port_id = rnode->fc_id & 0x00ffffff;
6680	}
6681	if (((ocs_node_t *)rnode->node)->fcp2device) {
6682		icmnd->erp = TRUE;
6683	}
6684	icmnd->cmd_type = SLI4_CMD_FCP_ICMND64_WQE;
6685	icmnd->cq_id = cq_id;
6686
6687	return  0;
6688}
6689
6690/**
6691 * @ingroup sli_fc
6692 * @brief Write an FCP_IREAD64_WQE work queue entry.
6693 *
6694 * @param sli4 SLI context.
6695 * @param buf Destination buffer for the WQE.
6696 * @param size Buffer size, in bytes.
6697 * @param sgl DMA memory for the scatter gather list.
6698 * @param first_data_sge Index of first data sge (used if perf hints are enabled)
6699 * @param xfer_len Data transfer length.
6700 * @param xri XRI for this exchange.
6701 * @param tag IO tag value.
6702 * @param cq_id The id of the completion queue where the WQE response is sent.
6703 * @param rpi remote node indicator (RPI)
6704 * @param rnode Destination request (i.e. remote node).
6705 * @param dif T10 DIF operation, or 0 to disable.
6706 * @param bs T10 DIF block size, or 0 if DIF is disabled.
6707 * @param timeout Time, in seconds, before an IO times out. Zero means no timeout.
6708 *
6709 * @return Returns 0 on success, or a non-zero value on failure.
6710 */
6711int32_t
6712sli_fcp_iread64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge,
6713		    uint32_t xfer_len, uint16_t xri, uint16_t tag, uint16_t cq_id,
6714		    uint32_t rpi, ocs_remote_node_t *rnode,
6715		    uint8_t dif, uint8_t bs, uint8_t timeout)
6716{
6717	sli4_fcp_iread64_wqe_t *iread = buf;
6718	sli4_sge_t	*sge = NULL;
6719
6720	ocs_memset(buf, 0, size);
6721
6722	if (!sgl || !sgl->virt) {
6723		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
6724			    sgl, sgl ? sgl->virt : NULL);
6725		return -1;
6726	}
6727	sge = sgl->virt;
6728
6729	if (sli4->config.sgl_pre_registered) {
6730		iread->xbl = FALSE;
6731
6732		iread->dbde = TRUE;
6733		iread->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6734
6735		iread->bde.buffer_length = sge[0].buffer_length;
6736		iread->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
6737		iread->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
6738	} else {
6739		iread->xbl = TRUE;
6740
6741		iread->bde.bde_type = SLI4_BDE_TYPE_BLP;
6742
6743		iread->bde.buffer_length = sgl->size;
6744		iread->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
6745		iread->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
6746
6747		/* fill out fcp_cmnd buffer len and change resp buffer to be of type
6748		 * "skip" (note: response will still be written to sge[1] if necessary) */
6749		iread->fcp_cmd_buffer_length = sge[0].buffer_length;
6750		sge[1].sge_type = SLI4_SGE_TYPE_SKIP;
6751	}
6752
6753	iread->payload_offset_length = sge[0].buffer_length + sge[1].buffer_length;
6754	iread->total_transfer_length = xfer_len;
6755
6756	iread->xri_tag = xri;
6757	iread->context_tag = rpi;
6758
6759	iread->timer = timeout;
6760
6761	iread->pu = 2;	/* WQE word 4 contains read transfer length */
6762	iread->class = SLI4_ELS_REQUEST64_CLASS_3;
6763	iread->command = SLI4_WQE_FCP_IREAD64;
6764	iread->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6765	iread->dif = dif;
6766	iread->bs  = bs;
6767
6768	iread->abort_tag = xri;
6769
6770	iread->request_tag = tag;
6771	iread->len_loc = 3;
6772	if (rnode->node_group) {
6773		iread->hlm = TRUE;
6774		iread->remote_n_port_id = rnode->fc_id & 0x00ffffff;
6775	}
6776	if (((ocs_node_t *)rnode->node)->fcp2device) {
6777		iread->erp = TRUE;
6778	}
6779	iread->iod = 1;
6780	iread->cmd_type = SLI4_CMD_FCP_IREAD64_WQE;
6781	iread->cq_id = cq_id;
6782
6783	if (sli4->config.perf_hint) {
6784		iread->first_data_bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6785		iread->first_data_bde.buffer_length = sge[first_data_sge].buffer_length;
6786		iread->first_data_bde.u.data.buffer_address_low  = sge[first_data_sge].buffer_address_low;
6787		iread->first_data_bde.u.data.buffer_address_high = sge[first_data_sge].buffer_address_high;
6788	}
6789
6790	return  0;
6791}
6792
6793
6794/**
6795 * @ingroup sli_fc
6796 * @brief Write an FCP_IWRITE64_WQE work queue entry.
6797 *
6798 * @param sli4 SLI context.
6799 * @param buf Destination buffer for the WQE.
6800 * @param size Buffer size, in bytes.
6801 * @param sgl DMA memory for the scatter gather list.
6802 * @param first_data_sge Index of first data sge (used if perf hints are enabled)
6803 * @param xfer_len Data transfer length.
6804 * @param first_burst The number of first burst bytes
6805 * @param xri XRI for this exchange.
6806 * @param tag IO tag value.
6807 * @param cq_id The id of the completion queue where the WQE response is sent.
6808 * @param rpi remote node indicator (RPI)
6809 * @param rnode Destination request (i.e. remote node)
6810 * @param dif T10 DIF operation, or 0 to disable
6811 * @param bs T10 DIF block size, or 0 if DIF is disabled
6812 * @param timeout Time, in seconds, before an IO times out. Zero means no timeout.
6813 *
6814 * @return Returns 0 on success, or a non-zero value on failure.
6815 */
6816int32_t
6817sli_fcp_iwrite64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge,
6818		     uint32_t xfer_len, uint32_t first_burst, uint16_t xri, uint16_t tag, uint16_t cq_id,
6819		     uint32_t rpi, ocs_remote_node_t *rnode,
6820		     uint8_t dif, uint8_t bs, uint8_t timeout)
6821{
6822	sli4_fcp_iwrite64_wqe_t *iwrite = buf;
6823	sli4_sge_t	*sge = NULL;
6824
6825	ocs_memset(buf, 0, size);
6826
6827	if (!sgl || !sgl->virt) {
6828		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
6829			    sgl, sgl ? sgl->virt : NULL);
6830		return -1;
6831	}
6832	sge = sgl->virt;
6833
6834	if (sli4->config.sgl_pre_registered) {
6835		iwrite->xbl = FALSE;
6836
6837		iwrite->dbde = TRUE;
6838		iwrite->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6839
6840		iwrite->bde.buffer_length = sge[0].buffer_length;
6841		iwrite->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
6842		iwrite->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
6843	} else {
6844		iwrite->xbl = TRUE;
6845
6846		iwrite->bde.bde_type = SLI4_BDE_TYPE_BLP;
6847
6848		iwrite->bde.buffer_length = sgl->size;
6849		iwrite->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
6850		iwrite->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
6851
6852		/* fill out fcp_cmnd buffer len and change resp buffer to be of type
6853		 * "skip" (note: response will still be written to sge[1] if necessary) */
6854		iwrite->fcp_cmd_buffer_length = sge[0].buffer_length;
6855		sge[1].sge_type = SLI4_SGE_TYPE_SKIP;
6856	}
6857
6858	iwrite->payload_offset_length = sge[0].buffer_length + sge[1].buffer_length;
6859	iwrite->total_transfer_length = xfer_len;
6860	iwrite->initial_transfer_length = MIN(xfer_len, first_burst);
6861
6862	iwrite->xri_tag = xri;
6863	iwrite->context_tag = rpi;
6864
6865	iwrite->timer = timeout;
6866
6867	iwrite->pu = 2;	/* WQE word 4 contains read transfer length */
6868	iwrite->class = SLI4_ELS_REQUEST64_CLASS_3;
6869	iwrite->command = SLI4_WQE_FCP_IWRITE64;
6870	iwrite->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6871	iwrite->dif = dif;
6872	iwrite->bs  = bs;
6873
6874	iwrite->abort_tag = xri;
6875
6876	iwrite->request_tag = tag;
6877	iwrite->len_loc = 3;
6878	if (rnode->node_group) {
6879		iwrite->hlm = TRUE;
6880		iwrite->remote_n_port_id = rnode->fc_id & 0x00ffffff;
6881	}
6882	if (((ocs_node_t *)rnode->node)->fcp2device) {
6883		iwrite->erp = TRUE;
6884	}
6885	iwrite->cmd_type = SLI4_CMD_FCP_IWRITE64_WQE;
6886	iwrite->cq_id = cq_id;
6887
6888	if (sli4->config.perf_hint) {
6889		iwrite->first_data_bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6890		iwrite->first_data_bde.buffer_length = sge[first_data_sge].buffer_length;
6891		iwrite->first_data_bde.u.data.buffer_address_low  = sge[first_data_sge].buffer_address_low;
6892		iwrite->first_data_bde.u.data.buffer_address_high = sge[first_data_sge].buffer_address_high;
6893	}
6894
6895	return  0;
6896}
6897
6898/**
6899 * @ingroup sli_fc
6900 * @brief Write an FCP_TRECEIVE64_WQE work queue entry.
6901 *
6902 * @param sli4 SLI context.
6903 * @param buf Destination buffer for the WQE.
6904 * @param size Buffer size, in bytes.
6905 * @param sgl DMA memory for the Scatter-Gather List.
6906 * @param first_data_sge Index of first data sge (used if perf hints are enabled)
6907 * @param relative_off Relative offset of the IO (if any).
6908 * @param xfer_len Data transfer length.
6909 * @param xri XRI for this exchange.
6910 * @param tag IO tag value.
6911 * @param xid OX_ID for the exchange.
6912 * @param cq_id The id of the completion queue where the WQE response is sent.
6913 * @param rpi remote node indicator (RPI)
6914 * @param rnode Destination request (i.e. remote node).
6915 * @param flags Optional attributes, including:
6916 *  - ACTIVE - IO is already active.
6917 *  - AUTO RSP - Automatically generate a good FCP_RSP.
6918 * @param dif T10 DIF operation, or 0 to disable.
6919 * @param bs T10 DIF block size, or 0 if DIF is disabled.
6920 * @param csctl value of csctl field.
6921 * @param app_id value for VM application header.
6922 *
6923 * @return Returns 0 on success, or a non-zero value on failure.
6924 */
6925int32_t
6926sli_fcp_treceive64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge,
6927		       uint32_t relative_off, uint32_t xfer_len, uint16_t xri, uint16_t tag, uint16_t cq_id,
6928		       uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode, uint32_t flags, uint8_t dif, uint8_t bs,
6929		       uint8_t csctl, uint32_t app_id)
6930{
6931	sli4_fcp_treceive64_wqe_t *trecv = buf;
6932	sli4_fcp_128byte_wqe_t *trecv_128 = buf;
6933	sli4_sge_t	*sge = NULL;
6934
6935	ocs_memset(buf, 0, size);
6936
6937	if (!sgl || !sgl->virt) {
6938		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
6939			    sgl, sgl ? sgl->virt : NULL);
6940		return -1;
6941	}
6942	sge = sgl->virt;
6943
6944	if (sli4->config.sgl_pre_registered) {
6945		trecv->xbl = FALSE;
6946
6947		trecv->dbde = TRUE;
6948		trecv->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6949
6950		trecv->bde.buffer_length = sge[0].buffer_length;
6951		trecv->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
6952		trecv->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
6953
6954		trecv->payload_offset_length = sge[0].buffer_length;
6955	} else {
6956		trecv->xbl = TRUE;
6957
6958		/* if data is a single physical address, use a BDE */
6959		if (!dif && (xfer_len <= sge[2].buffer_length)) {
6960			trecv->dbde = TRUE;
6961			trecv->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6962
6963			trecv->bde.buffer_length = sge[2].buffer_length;
6964			trecv->bde.u.data.buffer_address_low  = sge[2].buffer_address_low;
6965			trecv->bde.u.data.buffer_address_high = sge[2].buffer_address_high;
6966		} else {
6967			trecv->bde.bde_type = SLI4_BDE_TYPE_BLP;
6968			trecv->bde.buffer_length = sgl->size;
6969			trecv->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
6970			trecv->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
6971		}
6972	}
6973
6974	trecv->relative_offset = relative_off;
6975
6976	if (flags & SLI4_IO_CONTINUATION) {
6977		trecv->xc = TRUE;
6978	}
6979	trecv->xri_tag = xri;
6980
6981	trecv->context_tag = rpi;
6982
6983	trecv->pu = TRUE;	/* WQE uses relative offset */
6984
6985	if (flags & SLI4_IO_AUTO_GOOD_RESPONSE) {
6986		trecv->ar = TRUE;
6987	}
6988
6989	trecv->command = SLI4_WQE_FCP_TRECEIVE64;
6990	trecv->class = SLI4_ELS_REQUEST64_CLASS_3;
6991	trecv->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6992	trecv->dif = dif;
6993	trecv->bs  = bs;
6994
6995	trecv->remote_xid = xid;
6996
6997	trecv->request_tag = tag;
6998
6999	trecv->iod = 1;
7000
7001	trecv->len_loc = 0x2;
7002
7003	if (rnode->node_group) {
7004		trecv->hlm = TRUE;
7005		trecv->dword5.dword = rnode->fc_id & 0x00ffffff;
7006	}
7007
7008	trecv->cmd_type = SLI4_CMD_FCP_TRECEIVE64_WQE;
7009
7010	trecv->cq_id = cq_id;
7011
7012	trecv->fcp_data_receive_length = xfer_len;
7013
7014	if (sli4->config.perf_hint) {
7015		trecv->first_data_bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7016		trecv->first_data_bde.buffer_length = sge[first_data_sge].buffer_length;
7017		trecv->first_data_bde.u.data.buffer_address_low  = sge[first_data_sge].buffer_address_low;
7018		trecv->first_data_bde.u.data.buffer_address_high = sge[first_data_sge].buffer_address_high;
7019	}
7020
7021	/* The upper 7 bits of csctl is the priority */
7022	if (csctl & SLI4_MASK_CCP) {
7023		trecv->ccpe = 1;
7024		trecv->ccp = (csctl & SLI4_MASK_CCP);
7025	}
7026
7027	if (app_id && (sli4->config.wqe_size == SLI4_WQE_EXT_BYTES) && !trecv->eat) {
7028		trecv->app_id_valid = 1;
7029		trecv->wqes = 1;
7030		trecv_128->dw[31] = app_id;
7031	}
7032	return 0;
7033}
7034
7035/**
7036 * @ingroup sli_fc
7037 * @brief Write an FCP_CONT_TRECEIVE64_WQE work queue entry.
7038 *
7039 * @param sli4 SLI context.
7040 * @param buf Destination buffer for the WQE.
7041 * @param size Buffer size, in bytes.
7042 * @param sgl DMA memory for the Scatter-Gather List.
7043 * @param first_data_sge Index of first data sge (used if perf hints are enabled)
7044 * @param relative_off Relative offset of the IO (if any).
7045 * @param xfer_len Data transfer length.
7046 * @param xri XRI for this exchange.
7047 * @param sec_xri Secondary XRI for this exchange. (BZ 161832 workaround)
7048 * @param tag IO tag value.
7049 * @param xid OX_ID for the exchange.
7050 * @param cq_id The id of the completion queue where the WQE response is sent.
7051 * @param rpi remote node indicator (RPI)
7052 * @param rnode Destination request (i.e. remote node).
7053 * @param flags Optional attributes, including:
7054 *  - ACTIVE - IO is already active.
7055 *  - AUTO RSP - Automatically generate a good FCP_RSP.
7056 * @param dif T10 DIF operation, or 0 to disable.
7057 * @param bs T10 DIF block size, or 0 if DIF is disabled.
7058 * @param csctl value of csctl field.
7059 * @param app_id value for VM application header.
7060 *
7061 * @return Returns 0 on success, or a non-zero value on failure.
7062 */
7063int32_t
7064sli_fcp_cont_treceive64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge,
7065			uint32_t relative_off, uint32_t xfer_len, uint16_t xri, uint16_t sec_xri, uint16_t tag,
7066			uint16_t cq_id, uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode, uint32_t flags,
7067			uint8_t dif, uint8_t bs, uint8_t csctl, uint32_t app_id)
7068{
7069	int32_t rc;
7070
7071	rc = sli_fcp_treceive64_wqe(sli4, buf, size, sgl, first_data_sge, relative_off, xfer_len, xri, tag,
7072			cq_id, xid, rpi, rnode, flags, dif, bs, csctl, app_id);
7073	if (rc == 0) {
7074		sli4_fcp_treceive64_wqe_t *trecv = buf;
7075
7076		trecv->command = SLI4_WQE_FCP_CONT_TRECEIVE64;
7077		trecv->dword5.sec_xri_tag = sec_xri;
7078	}
7079	return rc;
7080}
7081
7082/**
7083 * @ingroup sli_fc
7084 * @brief Write an FCP_TRSP64_WQE work queue entry.
7085 *
7086 * @param sli4 SLI context.
7087 * @param buf Destination buffer for the WQE.
7088 * @param size Buffer size, in bytes.
7089 * @param sgl DMA memory for the Scatter-Gather List.
7090 * @param rsp_len Response data length.
7091 * @param xri XRI for this exchange.
7092 * @param tag IO tag value.
7093 * @param cq_id The id of the completion queue where the WQE response is sent.
7094 * @param xid OX_ID for the exchange.
7095 * @param rpi remote node indicator (RPI)
7096 * @param rnode Destination request (i.e. remote node).
7097 * @param flags Optional attributes, including:
7098 *  - ACTIVE - IO is already active
7099 *  - AUTO RSP - Automatically generate a good FCP_RSP.
7100 * @param csctl value of csctl field.
7101 * @param port_owned 0/1 to indicate if the XRI is port owned (used to set XBL=0)
7102 * @param app_id value for VM application header.
7103 *
7104 * @return Returns 0 on success, or a non-zero value on failure.
7105 */
7106int32_t
7107sli_fcp_trsp64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t rsp_len,
7108		   uint16_t xri, uint16_t tag, uint16_t cq_id, uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode,
7109		   uint32_t flags, uint8_t csctl, uint8_t port_owned, uint32_t app_id)
7110{
7111	sli4_fcp_trsp64_wqe_t *trsp = buf;
7112	sli4_fcp_128byte_wqe_t *trsp_128 = buf;
7113
7114	ocs_memset(buf, 0, size);
7115
7116	if (flags & SLI4_IO_AUTO_GOOD_RESPONSE) {
7117		trsp->ag = TRUE;
7118		/*
7119		 * The SLI-4 documentation states that the BDE is ignored when
7120		 * using auto-good response, but, at least for IF_TYPE 0 devices,
7121		 * this does not appear to be true.
7122		 */
7123		if (SLI4_IF_TYPE_BE3_SKH_PF == sli4->if_type) {
7124			trsp->bde.buffer_length = 12;	/* byte size of RSP */
7125		}
7126	} else {
7127		sli4_sge_t	*sge = sgl->virt;
7128
7129		if (sli4->config.sgl_pre_registered || port_owned) {
7130			trsp->dbde = TRUE;
7131		} else {
7132			trsp->xbl = TRUE;
7133		}
7134
7135		trsp->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7136		trsp->bde.buffer_length = sge[0].buffer_length;
7137		trsp->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
7138		trsp->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
7139
7140		trsp->fcp_response_length = rsp_len;
7141	}
7142
7143	if (flags & SLI4_IO_CONTINUATION) {
7144		trsp->xc = TRUE;
7145	}
7146
7147	if (rnode->node_group) {
7148		trsp->hlm = TRUE;
7149		trsp->dword5 = rnode->fc_id & 0x00ffffff;
7150	}
7151
7152	trsp->xri_tag = xri;
7153	trsp->rpi = rpi;
7154
7155	trsp->command = SLI4_WQE_FCP_TRSP64;
7156	trsp->class = SLI4_ELS_REQUEST64_CLASS_3;
7157
7158	trsp->remote_xid = xid;
7159	trsp->request_tag = tag;
7160	trsp->dnrx = ((flags & SLI4_IO_DNRX) == 0 ? 0 : 1);
7161	trsp->len_loc = 0x1;
7162	trsp->cq_id = cq_id;
7163	trsp->cmd_type = SLI4_CMD_FCP_TRSP64_WQE;
7164
7165	/* The upper 7 bits of csctl is the priority */
7166	if (csctl & SLI4_MASK_CCP) {
7167		trsp->ccpe = 1;
7168		trsp->ccp = (csctl & SLI4_MASK_CCP);
7169	}
7170
7171	if (app_id && (sli4->config.wqe_size == SLI4_WQE_EXT_BYTES) && !trsp->eat) {
7172		trsp->app_id_valid = 1;
7173		trsp->wqes = 1;
7174		trsp_128->dw[31] = app_id;
7175	}
7176	return 0;
7177}
7178
7179/**
7180 * @ingroup sli_fc
7181 * @brief Write an FCP_TSEND64_WQE work queue entry.
7182 *
7183 * @param sli4 SLI context.
7184 * @param buf Destination buffer for the WQE.
7185 * @param size Buffer size, in bytes.
7186 * @param sgl DMA memory for the scatter gather list.
7187 * @param first_data_sge Index of first data sge (used if perf hints are enabled)
7188 * @param relative_off Relative offset of the IO (if any).
7189 * @param xfer_len Data transfer length.
7190 * @param xri XRI for this exchange.
7191 * @param tag IO tag value.
7192 * @param cq_id The id of the completion queue where the WQE response is sent.
7193 * @param xid OX_ID for the exchange.
7194 * @param rpi remote node indicator (RPI)
7195 * @param rnode Destination request (i.e. remote node).
7196 * @param flags Optional attributes, including:
7197 *  - ACTIVE - IO is already active.
7198 *  - AUTO RSP - Automatically generate a good FCP_RSP.
7199 * @param dif T10 DIF operation, or 0 to disable.
7200 * @param bs T10 DIF block size, or 0 if DIF is disabled.
7201 * @param csctl value of csctl field.
7202 * @param app_id value for VM application header.
7203 *
7204 * @return Returns 0 on success, or a non-zero value on failure.
7205 */
7206int32_t
7207sli_fcp_tsend64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge,
7208		    uint32_t relative_off, uint32_t xfer_len,
7209		    uint16_t xri, uint16_t tag, uint16_t cq_id, uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode,
7210		    uint32_t flags, uint8_t dif, uint8_t bs, uint8_t csctl, uint32_t app_id)
7211{
7212	sli4_fcp_tsend64_wqe_t *tsend = buf;
7213	sli4_fcp_128byte_wqe_t *tsend_128 = buf;
7214	sli4_sge_t	*sge = NULL;
7215
7216	ocs_memset(buf, 0, size);
7217
7218	if (!sgl || !sgl->virt) {
7219		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
7220			    sgl, sgl ? sgl->virt : NULL);
7221		return -1;
7222	}
7223	sge = sgl->virt;
7224
7225	if (sli4->config.sgl_pre_registered) {
7226		tsend->xbl = FALSE;
7227
7228		tsend->dbde = TRUE;
7229		tsend->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7230
7231		/* TSEND64_WQE specifies first two SGE are skipped
7232		 * (i.e. 3rd is valid) */
7233		tsend->bde.buffer_length = sge[2].buffer_length;
7234		tsend->bde.u.data.buffer_address_low  = sge[2].buffer_address_low;
7235		tsend->bde.u.data.buffer_address_high = sge[2].buffer_address_high;
7236	} else {
7237		tsend->xbl = TRUE;
7238
7239		/* if data is a single physical address, use a BDE */
7240		if (!dif && (xfer_len <= sge[2].buffer_length)) {
7241			tsend->dbde = TRUE;
7242			tsend->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7243			/* TSEND64_WQE specifies first two SGE are skipped
7244			 * (i.e. 3rd is valid) */
7245			tsend->bde.buffer_length = sge[2].buffer_length;
7246			tsend->bde.u.data.buffer_address_low  = sge[2].buffer_address_low;
7247			tsend->bde.u.data.buffer_address_high = sge[2].buffer_address_high;
7248		} else {
7249			tsend->bde.bde_type = SLI4_BDE_TYPE_BLP;
7250			tsend->bde.buffer_length = sgl->size;
7251			tsend->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
7252			tsend->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
7253		}
7254	}
7255
7256	tsend->relative_offset = relative_off;
7257
7258	if (flags & SLI4_IO_CONTINUATION) {
7259		tsend->xc = TRUE;
7260	}
7261	tsend->xri_tag = xri;
7262
7263	tsend->rpi = rpi;
7264
7265	tsend->pu = TRUE;	/* WQE uses relative offset */
7266
7267	if (flags & SLI4_IO_AUTO_GOOD_RESPONSE) {
7268		tsend->ar = TRUE;
7269	}
7270
7271	tsend->command = SLI4_WQE_FCP_TSEND64;
7272	tsend->class = SLI4_ELS_REQUEST64_CLASS_3;
7273	tsend->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
7274	tsend->dif = dif;
7275	tsend->bs  = bs;
7276
7277	tsend->remote_xid = xid;
7278
7279	tsend->request_tag = tag;
7280
7281	tsend->len_loc = 0x2;
7282
7283	if (rnode->node_group) {
7284		tsend->hlm = TRUE;
7285		tsend->dword5 = rnode->fc_id & 0x00ffffff;
7286	}
7287
7288	tsend->cq_id = cq_id;
7289
7290	tsend->cmd_type = SLI4_CMD_FCP_TSEND64_WQE;
7291
7292	tsend->fcp_data_transmit_length = xfer_len;
7293
7294	if (sli4->config.perf_hint) {
7295		tsend->first_data_bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7296		tsend->first_data_bde.buffer_length = sge[first_data_sge].buffer_length;
7297		tsend->first_data_bde.u.data.buffer_address_low  = sge[first_data_sge].buffer_address_low;
7298		tsend->first_data_bde.u.data.buffer_address_high = sge[first_data_sge].buffer_address_high;
7299	}
7300
7301	/* The upper 7 bits of csctl is the priority */
7302	if (csctl & SLI4_MASK_CCP) {
7303		tsend->ccpe = 1;
7304		tsend->ccp = (csctl & SLI4_MASK_CCP);
7305	}
7306
7307	if (app_id && (sli4->config.wqe_size == SLI4_WQE_EXT_BYTES) && !tsend->eat) {
7308		tsend->app_id_valid = 1;
7309		tsend->wqes = 1;
7310		tsend_128->dw[31] = app_id;
7311	}
7312	return 0;
7313}
7314
7315/**
7316 * @ingroup sli_fc
7317 * @brief Write a GEN_REQUEST64 work queue entry.
7318 *
7319 * @note This WQE is only used to send FC-CT commands.
7320 *
7321 * @param sli4 SLI context.
7322 * @param buf Destination buffer for the WQE.
7323 * @param size Buffer size, in bytes.
7324 * @param sgl DMA memory for the request.
7325 * @param req_len Length of request.
7326 * @param max_rsp_len Max length of response.
7327 * @param timeout Time, in seconds, before an IO times out. Zero means infinite.
7328 * @param xri XRI for this exchange.
7329 * @param tag IO tag value.
7330 * @param cq_id The id of the completion queue where the WQE response is sent.
7331 * @param rnode Destination of request (that is, the remote node).
7332 * @param r_ctl R_CTL value for sequence.
7333 * @param type TYPE value for sequence.
7334 * @param df_ctl DF_CTL value for sequence.
7335 *
7336 * @return Returns 0 on success, or a non-zero value on failure.
7337 */
7338int32_t
7339sli_gen_request64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl,
7340		      uint32_t req_len, uint32_t max_rsp_len, uint8_t timeout,
7341		      uint16_t xri, uint16_t tag, uint16_t cq_id, ocs_remote_node_t *rnode,
7342		      uint8_t r_ctl, uint8_t type, uint8_t df_ctl)
7343{
7344	sli4_gen_request64_wqe_t	*gen = buf;
7345	sli4_sge_t	*sge = NULL;
7346
7347	ocs_memset(buf, 0, size);
7348
7349	if (!sgl || !sgl->virt) {
7350		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
7351			    sgl, sgl ? sgl->virt : NULL);
7352		return -1;
7353	}
7354	sge = sgl->virt;
7355
7356	if (sli4->config.sgl_pre_registered) {
7357		gen->xbl = FALSE;
7358
7359		gen->dbde = TRUE;
7360		gen->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7361
7362		gen->bde.buffer_length = req_len;
7363		gen->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
7364		gen->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
7365	} else {
7366		gen->xbl = TRUE;
7367
7368		gen->bde.bde_type = SLI4_BDE_TYPE_BLP;
7369
7370		gen->bde.buffer_length = 2 * sizeof(sli4_sge_t);
7371		gen->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
7372		gen->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
7373	}
7374
7375	gen->request_payload_length = req_len;
7376	gen->max_response_payload_length = max_rsp_len;
7377
7378	gen->df_ctl = df_ctl;
7379	gen->type = type;
7380	gen->r_ctl = r_ctl;
7381
7382	gen->xri_tag = xri;
7383
7384	gen->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
7385	gen->context_tag = rnode->indicator;
7386
7387	gen->class = SLI4_ELS_REQUEST64_CLASS_3;
7388
7389	gen->command = SLI4_WQE_GEN_REQUEST64;
7390
7391	gen->timer = timeout;
7392
7393	gen->request_tag = tag;
7394
7395	gen->iod = SLI4_ELS_REQUEST64_DIR_READ;
7396
7397	gen->qosd = TRUE;
7398
7399	if (rnode->node_group) {
7400		gen->hlm = TRUE;
7401		gen->remote_n_port_id = rnode->fc_id & 0x00ffffff;
7402	}
7403
7404	gen->cmd_type = SLI4_CMD_GEN_REQUEST64_WQE;
7405
7406	gen->cq_id = cq_id;
7407
7408	return 0;
7409}
7410
7411/**
7412 * @ingroup sli_fc
7413 * @brief Write a SEND_FRAME work queue entry
7414 *
7415 * @param sli4 SLI context.
7416 * @param buf Destination buffer for the WQE.
7417 * @param size Buffer size, in bytes.
7418 * @param sof Start of frame value
7419 * @param eof End of frame value
7420 * @param hdr Pointer to FC header data
7421 * @param payload DMA memory for the payload.
7422 * @param req_len Length of payload.
7423 * @param timeout Time, in seconds, before an IO times out. Zero means infinite.
7424 * @param xri XRI for this exchange.
7425 * @param req_tag IO tag value.
7426 *
7427 * @return Returns 0 on success, or a non-zero value on failure.
7428 */
7429int32_t
7430sli_send_frame_wqe(sli4_t *sli4, void *buf, size_t size, uint8_t sof, uint8_t eof, uint32_t *hdr,
7431		   ocs_dma_t *payload, uint32_t req_len, uint8_t timeout,
7432		   uint16_t xri, uint16_t req_tag)
7433{
7434	sli4_send_frame_wqe_t *sf = buf;
7435
7436	ocs_memset(buf, 0, size);
7437
7438	sf->dbde = TRUE;
7439	sf->bde.buffer_length = req_len;
7440	sf->bde.u.data.buffer_address_low = ocs_addr32_lo(payload->phys);
7441	sf->bde.u.data.buffer_address_high = ocs_addr32_hi(payload->phys);
7442
7443	/* Copy FC header */
7444	sf->fc_header_0_1[0] = hdr[0];
7445	sf->fc_header_0_1[1] = hdr[1];
7446	sf->fc_header_2_5[0] = hdr[2];
7447	sf->fc_header_2_5[1] = hdr[3];
7448	sf->fc_header_2_5[2] = hdr[4];
7449	sf->fc_header_2_5[3] = hdr[5];
7450
7451	sf->frame_length = req_len;
7452
7453	sf->xri_tag = xri;
7454	sf->pu = 0;
7455	sf->context_tag = 0;
7456
7457
7458	sf->ct = 0;
7459	sf->command = SLI4_WQE_SEND_FRAME;
7460	sf->class = SLI4_ELS_REQUEST64_CLASS_3;
7461	sf->timer = timeout;
7462
7463	sf->request_tag = req_tag;
7464	sf->eof = eof;
7465	sf->sof = sof;
7466
7467	sf->qosd = 0;
7468	sf->lenloc = 1;
7469	sf->xc = 0;
7470
7471	sf->xbl = 1;
7472
7473	sf->cmd_type = SLI4_CMD_SEND_FRAME_WQE;
7474	sf->cq_id = 0xffff;
7475
7476	return 0;
7477}
7478
7479/**
7480 * @ingroup sli_fc
7481 * @brief Write a XMIT_SEQUENCE64 work queue entry.
7482 *
7483 * This WQE is used to send FC-CT response frames.
7484 *
7485 * @note This API implements a restricted use for this WQE, a TODO: would
7486 * include passing in sequence initiative, and full SGL's
7487 *
7488 * @param sli4 SLI context.
7489 * @param buf Destination buffer for the WQE.
7490 * @param size Buffer size, in bytes.
7491 * @param payload DMA memory for the request.
7492 * @param payload_len Length of request.
7493 * @param timeout Time, in seconds, before an IO times out. Zero means infinite.
7494 * @param ox_id originator exchange ID
7495 * @param xri XRI for this exchange.
7496 * @param tag IO tag value.
7497 * @param rnode Destination of request (that is, the remote node).
7498 * @param r_ctl R_CTL value for sequence.
7499 * @param type TYPE value for sequence.
7500 * @param df_ctl DF_CTL value for sequence.
7501 *
7502 * @return Returns 0 on success, or a non-zero value on failure.
7503 */
7504int32_t
7505sli_xmit_sequence64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *payload,
7506		      uint32_t payload_len, uint8_t timeout, uint16_t ox_id,
7507		      uint16_t xri, uint16_t tag, ocs_remote_node_t *rnode,
7508		      uint8_t r_ctl, uint8_t type, uint8_t df_ctl)
7509{
7510	sli4_xmit_sequence64_wqe_t	*xmit = buf;
7511
7512	ocs_memset(buf, 0, size);
7513
7514	if ((payload == NULL) || (payload->virt == NULL)) {
7515		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
7516			    payload, payload ? payload->virt : NULL);
7517		return -1;
7518	}
7519
7520	if (sli4->config.sgl_pre_registered) {
7521		xmit->dbde = TRUE;
7522	} else {
7523		xmit->xbl = TRUE;
7524	}
7525
7526	xmit->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7527	xmit->bde.buffer_length = payload_len;
7528	xmit->bde.u.data.buffer_address_low  = ocs_addr32_lo(payload->phys);
7529	xmit->bde.u.data.buffer_address_high = ocs_addr32_hi(payload->phys);
7530	xmit->sequence_payload_len = payload_len;
7531
7532	xmit->remote_n_port_id = rnode->fc_id & 0x00ffffff;
7533
7534	xmit->relative_offset = 0;
7535
7536	xmit->si = 0;			/* sequence initiative - this matches what is seen from
7537					 * FC switches in response to FCGS commands */
7538	xmit->ft = 0;			/* force transmit */
7539	xmit->xo = 0;			/* exchange responder */
7540	xmit->ls = 1;			/* last in seqence */
7541	xmit->df_ctl = df_ctl;
7542	xmit->type = type;
7543	xmit->r_ctl = r_ctl;
7544
7545	xmit->xri_tag = xri;
7546	xmit->context_tag = rnode->indicator;
7547
7548	xmit->dif = 0;
7549	xmit->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
7550	xmit->bs = 0;
7551
7552	xmit->command = SLI4_WQE_XMIT_SEQUENCE64;
7553	xmit->class = SLI4_ELS_REQUEST64_CLASS_3;
7554	xmit->pu = 0;
7555	xmit->timer = timeout;
7556
7557	xmit->abort_tag = 0;
7558	xmit->request_tag = tag;
7559	xmit->remote_xid = ox_id;
7560
7561	xmit->iod = SLI4_ELS_REQUEST64_DIR_READ;
7562
7563	if (rnode->node_group) {
7564		xmit->hlm = TRUE;
7565		xmit->remote_n_port_id = rnode->fc_id & 0x00ffffff;
7566	}
7567
7568	xmit->cmd_type = SLI4_CMD_XMIT_SEQUENCE64_WQE;
7569
7570	xmit->len_loc = 2;
7571
7572	xmit->cq_id = 0xFFFF;
7573
7574	return 0;
7575}
7576
7577/**
7578 * @ingroup sli_fc
7579 * @brief Write a REQUEUE_XRI_WQE work queue entry.
7580 *
7581 * @param sli4 SLI context.
7582 * @param buf Destination buffer for the WQE.
7583 * @param size Buffer size, in bytes.
7584 * @param xri XRI for this exchange.
7585 * @param tag IO tag value.
7586 * @param cq_id The id of the completion queue where the WQE response is sent.
7587 *
7588 * @return Returns 0 on success, or a non-zero value on failure.
7589 */
7590int32_t
7591sli_requeue_xri_wqe(sli4_t *sli4, void *buf, size_t size, uint16_t xri, uint16_t tag, uint16_t cq_id)
7592{
7593	sli4_requeue_xri_wqe_t	*requeue = buf;
7594
7595	ocs_memset(buf, 0, size);
7596
7597	requeue->command = SLI4_WQE_REQUEUE_XRI;
7598	requeue->xri_tag = xri;
7599	requeue->request_tag = tag;
7600	requeue->xc = 1;
7601	requeue->qosd = 1;
7602	requeue->cq_id = cq_id;
7603	requeue->cmd_type = SLI4_CMD_REQUEUE_XRI_WQE;
7604	return 0;
7605}
7606
7607int32_t
7608sli_xmit_bcast64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *payload,
7609		uint32_t payload_len, uint8_t timeout, uint16_t xri, uint16_t tag,
7610		uint16_t cq_id, ocs_remote_node_t *rnode,
7611		uint8_t r_ctl, uint8_t type, uint8_t df_ctl)
7612{
7613	sli4_xmit_bcast64_wqe_t *bcast = buf;
7614
7615	/* Command requires a temporary RPI (i.e. unused remote node) */
7616	if (rnode->attached) {
7617		ocs_log_test(sli4->os, "remote node %d in use\n", rnode->indicator);
7618		return -1;
7619	}
7620
7621	ocs_memset(buf, 0, size);
7622
7623	bcast->dbde = TRUE;
7624	bcast->sequence_payload.bde_type = SLI4_BDE_TYPE_BDE_64;
7625	bcast->sequence_payload.buffer_length = payload_len;
7626	bcast->sequence_payload.u.data.buffer_address_low  = ocs_addr32_lo(payload->phys);
7627	bcast->sequence_payload.u.data.buffer_address_high = ocs_addr32_hi(payload->phys);
7628
7629	bcast->sequence_payload_length = payload_len;
7630
7631	bcast->df_ctl = df_ctl;
7632	bcast->type = type;
7633	bcast->r_ctl = r_ctl;
7634
7635	bcast->xri_tag = xri;
7636
7637	bcast->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
7638	bcast->context_tag = rnode->sport->indicator;
7639
7640	bcast->class = SLI4_ELS_REQUEST64_CLASS_3;
7641
7642	bcast->command = SLI4_WQE_XMIT_BCAST64;
7643
7644	bcast->timer = timeout;
7645
7646	bcast->request_tag = tag;
7647
7648	bcast->temporary_rpi = rnode->indicator;
7649
7650	bcast->len_loc = 0x1;
7651
7652	bcast->iod = SLI4_ELS_REQUEST64_DIR_WRITE;
7653
7654	bcast->cmd_type = SLI4_CMD_XMIT_BCAST64_WQE;
7655
7656	bcast->cq_id = cq_id;
7657
7658	return 0;
7659}
7660
7661/**
7662 * @ingroup sli_fc
7663 * @brief Write an XMIT_BLS_RSP64_WQE work queue entry.
7664 *
7665 * @param sli4 SLI context.
7666 * @param buf Destination buffer for the WQE.
7667 * @param size Buffer size, in bytes.
7668 * @param payload Contents of the BLS payload to be sent.
7669 * @param xri XRI for this exchange.
7670 * @param tag IO tag value.
7671 * @param cq_id The id of the completion queue where the WQE response is sent.
7672 * @param rnode Destination of request (that is, the remote node).
7673 * @param s_id Source ID to use in the response. If UINT32_MAX, use SLI Port's ID.
7674 *
7675 * @return Returns 0 on success, or a non-zero value on failure.
7676 */
7677int32_t
7678sli_xmit_bls_rsp64_wqe(sli4_t *sli4, void *buf, size_t size, sli_bls_payload_t *payload,
7679		       uint16_t xri, uint16_t tag, uint16_t cq_id, ocs_remote_node_t *rnode, uint32_t s_id)
7680{
7681	sli4_xmit_bls_rsp_wqe_t *bls = buf;
7682
7683	/*
7684	 * Callers can either specify RPI or S_ID, but not both
7685	 */
7686	if (rnode->attached && (s_id != UINT32_MAX)) {
7687		ocs_log_test(sli4->os, "S_ID specified for attached remote node %d\n",
7688			     rnode->indicator);
7689		return -1;
7690	}
7691
7692	ocs_memset(buf, 0, size);
7693
7694	if (SLI_BLS_ACC == payload->type) {
7695		bls->payload_word0 = (payload->u.acc.seq_id_last << 16) |
7696			(payload->u.acc.seq_id_validity << 24);
7697		bls->high_seq_cnt = payload->u.acc.high_seq_cnt;
7698		bls->low_seq_cnt = payload->u.acc.low_seq_cnt;
7699	} else if (SLI_BLS_RJT == payload->type) {
7700		bls->payload_word0 = *((uint32_t *)&payload->u.rjt);
7701		bls->ar = TRUE;
7702	} else {
7703		ocs_log_test(sli4->os, "bad BLS type %#x\n",
7704				payload->type);
7705		return -1;
7706	}
7707
7708	bls->ox_id = payload->ox_id;
7709	bls->rx_id = payload->rx_id;
7710
7711	if (rnode->attached) {
7712		bls->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
7713		bls->context_tag = rnode->indicator;
7714	} else {
7715		bls->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
7716		bls->context_tag = rnode->sport->indicator;
7717
7718		if (UINT32_MAX != s_id) {
7719			bls->local_n_port_id = s_id & 0x00ffffff;
7720		} else {
7721			bls->local_n_port_id = rnode->sport->fc_id & 0x00ffffff;
7722		}
7723		bls->remote_id = rnode->fc_id & 0x00ffffff;
7724
7725		bls->temporary_rpi = rnode->indicator;
7726	}
7727
7728	bls->xri_tag = xri;
7729
7730	bls->class = SLI4_ELS_REQUEST64_CLASS_3;
7731
7732	bls->command = SLI4_WQE_XMIT_BLS_RSP;
7733
7734	bls->request_tag = tag;
7735
7736	bls->qosd = TRUE;
7737
7738	if (rnode->node_group) {
7739		bls->hlm = TRUE;
7740		bls->remote_id = rnode->fc_id & 0x00ffffff;
7741	}
7742
7743	bls->cq_id = cq_id;
7744
7745	bls->cmd_type = SLI4_CMD_XMIT_BLS_RSP64_WQE;
7746
7747	return 0;
7748}
7749
7750/**
7751 * @ingroup sli_fc
7752 * @brief Write a XMIT_ELS_RSP64_WQE work queue entry.
7753 *
7754 * @param sli4 SLI context.
7755 * @param buf Destination buffer for the WQE.
7756 * @param size Buffer size, in bytes.
7757 * @param rsp DMA memory for the ELS response.
7758 * @param rsp_len Length of ELS response, in bytes.
7759 * @param xri XRI for this exchange.
7760 * @param tag IO tag value.
7761 * @param cq_id The id of the completion queue where the WQE response is sent.
7762 * @param ox_id OX_ID of the exchange containing the request.
7763 * @param rnode Destination of the ELS response (that is, the remote node).
7764 * @param flags Optional attributes, including:
7765 *  - SLI4_IO_CONTINUATION - IO is already active.
7766 * @param s_id S_ID used for special responses.
7767 *
7768 * @return Returns 0 on success, or a non-zero value on failure.
7769 */
7770int32_t
7771sli_xmit_els_rsp64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *rsp,
7772		       uint32_t rsp_len, uint16_t xri, uint16_t tag, uint16_t cq_id,
7773		       uint16_t ox_id, ocs_remote_node_t *rnode, uint32_t flags, uint32_t s_id)
7774{
7775	sli4_xmit_els_rsp64_wqe_t	*els = buf;
7776
7777	ocs_memset(buf, 0, size);
7778
7779	if (sli4->config.sgl_pre_registered) {
7780		els->dbde = TRUE;
7781	} else {
7782		els->xbl = TRUE;
7783	}
7784
7785	els->els_response_payload.bde_type = SLI4_BDE_TYPE_BDE_64;
7786	els->els_response_payload.buffer_length = rsp_len;
7787	els->els_response_payload.u.data.buffer_address_low  = ocs_addr32_lo(rsp->phys);
7788	els->els_response_payload.u.data.buffer_address_high = ocs_addr32_hi(rsp->phys);
7789
7790	els->els_response_payload_length = rsp_len;
7791
7792	els->xri_tag = xri;
7793
7794	els->class = SLI4_ELS_REQUEST64_CLASS_3;
7795
7796	els->command = SLI4_WQE_ELS_RSP64;
7797
7798	els->request_tag = tag;
7799
7800	els->ox_id = ox_id;
7801
7802	els->iod = SLI4_ELS_REQUEST64_DIR_WRITE;
7803
7804	els->qosd = TRUE;
7805
7806	if (flags & SLI4_IO_CONTINUATION) {
7807		els->xc = TRUE;
7808	}
7809
7810	if (rnode->attached) {
7811		els->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
7812		els->context_tag = rnode->indicator;
7813	} else {
7814		els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
7815		els->context_tag = rnode->sport->indicator;
7816		els->remote_id = rnode->fc_id & 0x00ffffff;
7817		els->temporary_rpi = rnode->indicator;
7818		if (UINT32_MAX != s_id) {
7819			els->sp = TRUE;
7820			els->s_id = s_id & 0x00ffffff;
7821		}
7822	}
7823
7824	if (rnode->node_group) {
7825		els->hlm = TRUE;
7826		els->remote_id = rnode->fc_id & 0x00ffffff;
7827	}
7828
7829	els->cmd_type = SLI4_ELS_REQUEST64_CMD_GEN;
7830
7831	els->cq_id = cq_id;
7832
7833	return 0;
7834}
7835
7836/**
7837 * @ingroup sli_fc
7838 * @brief Process an asynchronous Link State event entry.
7839 *
7840 * @par Description
7841 * Parses Asynchronous Completion Queue Entry (ACQE),
7842 * creates an abstracted event, and calls registered callback functions.
7843 *
7844 * @param sli4 SLI context.
7845 * @param acqe Pointer to the ACQE.
7846 *
7847 * @return Returns 0 on success, or a non-zero value on failure.
7848 */
7849int32_t
7850sli_fc_process_link_state(sli4_t *sli4, void *acqe)
7851{
7852	sli4_link_state_t	*link_state = acqe;
7853	sli4_link_event_t	event = { 0 };
7854	int32_t			rc = 0;
7855
7856	if (!sli4->link) {
7857		/* bail if there is no callback */
7858		return 0;
7859	}
7860
7861	if (SLI4_LINK_TYPE_ETHERNET == link_state->link_type) {
7862		event.topology = SLI_LINK_TOPO_NPORT;
7863		event.medium   = SLI_LINK_MEDIUM_ETHERNET;
7864	} else {
7865		/* TODO is this supported for anything other than FCoE? */
7866		ocs_log_test(sli4->os, "unsupported link type %#x\n",
7867				link_state->link_type);
7868		event.topology = SLI_LINK_TOPO_MAX;
7869		event.medium   = SLI_LINK_MEDIUM_MAX;
7870		rc = -1;
7871	}
7872
7873	switch (link_state->port_link_status) {
7874	case SLI4_PORT_LINK_STATUS_PHYSICAL_DOWN:
7875	case SLI4_PORT_LINK_STATUS_LOGICAL_DOWN:
7876		event.status = SLI_LINK_STATUS_DOWN;
7877		break;
7878	case SLI4_PORT_LINK_STATUS_PHYSICAL_UP:
7879	case SLI4_PORT_LINK_STATUS_LOGICAL_UP:
7880		event.status = SLI_LINK_STATUS_UP;
7881		break;
7882	default:
7883		ocs_log_test(sli4->os, "unsupported link status %#x\n",
7884				link_state->port_link_status);
7885		event.status = SLI_LINK_STATUS_MAX;
7886		rc = -1;
7887	}
7888
7889	switch (link_state->port_speed) {
7890	case 0:
7891		event.speed = 0;
7892		break;
7893	case 1:
7894		event.speed = 10;
7895		break;
7896	case 2:
7897		event.speed = 100;
7898		break;
7899	case 3:
7900		event.speed = 1000;
7901		break;
7902	case 4:
7903		event.speed = 10000;
7904		break;
7905	case 5:
7906		event.speed = 20000;
7907		break;
7908	case 6:
7909		event.speed = 25000;
7910		break;
7911	case 7:
7912		event.speed = 40000;
7913		break;
7914	case 8:
7915		event.speed = 100000;
7916		break;
7917	default:
7918		ocs_log_test(sli4->os, "unsupported port_speed %#x\n",
7919				link_state->port_speed);
7920		rc = -1;
7921	}
7922
7923	sli4->link(sli4->link_arg, (void *)&event);
7924
7925	return rc;
7926}
7927
7928/**
7929 * @ingroup sli_fc
7930 * @brief Process an asynchronous Link Attention event entry.
7931 *
7932 * @par Description
7933 * Parses Asynchronous Completion Queue Entry (ACQE),
7934 * creates an abstracted event, and calls the registered callback functions.
7935 *
7936 * @param sli4 SLI context.
7937 * @param acqe Pointer to the ACQE.
7938 *
7939 * @todo XXX all events return LINK_UP.
7940 *
7941 * @return Returns 0 on success, or a non-zero value on failure.
7942 */
7943int32_t
7944sli_fc_process_link_attention(sli4_t *sli4, void *acqe)
7945{
7946	sli4_link_attention_t	*link_attn = acqe;
7947	sli4_link_event_t	event = { 0 };
7948
7949	ocs_log_debug(sli4->os, "link_number=%d attn_type=%#x topology=%#x port_speed=%#x "
7950			"port_fault=%#x shared_link_status=%#x logical_link_speed=%#x "
7951			"event_tag=%#x\n", link_attn->link_number, link_attn->attn_type,
7952			link_attn->topology, link_attn->port_speed, link_attn->port_fault,
7953			link_attn->shared_link_status, link_attn->logical_link_speed,
7954			link_attn->event_tag);
7955
7956	if (!sli4->link) {
7957		return 0;
7958	}
7959
7960	event.medium   = SLI_LINK_MEDIUM_FC;
7961
7962	switch (link_attn->attn_type) {
7963	case SLI4_LINK_ATTN_TYPE_LINK_UP:
7964		event.status = SLI_LINK_STATUS_UP;
7965		break;
7966	case SLI4_LINK_ATTN_TYPE_LINK_DOWN:
7967		event.status = SLI_LINK_STATUS_DOWN;
7968		break;
7969	case SLI4_LINK_ATTN_TYPE_NO_HARD_ALPA:
7970		ocs_log_debug(sli4->os, "attn_type: no hard alpa\n");
7971		event.status = SLI_LINK_STATUS_NO_ALPA;
7972		break;
7973	default:
7974		ocs_log_test(sli4->os, "attn_type: unknown\n");
7975		break;
7976	}
7977
7978	switch (link_attn->event_type) {
7979	case SLI4_FC_EVENT_LINK_ATTENTION:
7980		break;
7981	case SLI4_FC_EVENT_SHARED_LINK_ATTENTION:
7982		ocs_log_debug(sli4->os, "event_type: FC shared link event \n");
7983		break;
7984	default:
7985		ocs_log_test(sli4->os, "event_type: unknown\n");
7986		break;
7987	}
7988
7989	switch (link_attn->topology) {
7990	case SLI4_LINK_ATTN_P2P:
7991		event.topology = SLI_LINK_TOPO_NPORT;
7992		break;
7993	case SLI4_LINK_ATTN_FC_AL:
7994		event.topology = SLI_LINK_TOPO_LOOP;
7995		break;
7996	case SLI4_LINK_ATTN_INTERNAL_LOOPBACK:
7997		ocs_log_debug(sli4->os, "topology Internal loopback\n");
7998		event.topology = SLI_LINK_TOPO_LOOPBACK_INTERNAL;
7999		break;
8000	case SLI4_LINK_ATTN_SERDES_LOOPBACK:
8001		ocs_log_debug(sli4->os, "topology serdes loopback\n");
8002		event.topology = SLI_LINK_TOPO_LOOPBACK_EXTERNAL;
8003		break;
8004	default:
8005		ocs_log_test(sli4->os, "topology: unknown\n");
8006		break;
8007	}
8008
8009	event.speed    = link_attn->port_speed * 1000;
8010
8011	sli4->link(sli4->link_arg, (void *)&event);
8012
8013	return 0;
8014}
8015
8016/**
8017 * @ingroup sli_fc
8018 * @brief Parse an FC/FCoE work queue CQ entry.
8019 *
8020 * @param sli4 SLI context.
8021 * @param cq CQ to process.
8022 * @param cqe Pointer to the CQ entry.
8023 * @param etype CQ event type.
8024 * @param r_id Resource ID associated with this completion message (such as the IO tag).
8025 *
8026 * @return Returns 0 on success, or a non-zero value on failure.
8027 */
8028int32_t
8029sli_fc_cqe_parse(sli4_t *sli4, sli4_queue_t *cq, uint8_t *cqe, sli4_qentry_e *etype,
8030		uint16_t *r_id)
8031{
8032	uint8_t		code = cqe[SLI4_CQE_CODE_OFFSET];
8033	int32_t		rc = -1;
8034
8035	switch (code) {
8036	case SLI4_CQE_CODE_WORK_REQUEST_COMPLETION:
8037	{
8038		sli4_fc_wcqe_t *wcqe = (void *)cqe;
8039
8040		*etype = SLI_QENTRY_WQ;
8041		*r_id = wcqe->request_tag;
8042		rc = wcqe->status;
8043
8044		/* Flag errors except for FCP_RSP_FAILURE */
8045		if (rc && (rc != SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE)) {
8046
8047			ocs_log_test(sli4->os, "WCQE: status=%#x hw_status=%#x tag=%#x w1=%#x w2=%#x xb=%d\n",
8048				wcqe->status, wcqe->hw_status,
8049				wcqe->request_tag, wcqe->wqe_specific_1,
8050				wcqe->wqe_specific_2, wcqe->xb);
8051			ocs_log_test(sli4->os, "      %08X %08X %08X %08X\n", ((uint32_t*) cqe)[0], ((uint32_t*) cqe)[1],
8052				((uint32_t*) cqe)[2], ((uint32_t*) cqe)[3]);
8053		}
8054
8055		/* TODO: need to pass additional status back out of here as well
8056		 * as status (could overload rc as status/addlstatus are only 8 bits each)
8057		 */
8058
8059		break;
8060	}
8061	case SLI4_CQE_CODE_RQ_ASYNC:
8062	{
8063		sli4_fc_async_rcqe_t *rcqe = (void *)cqe;
8064
8065		*etype = SLI_QENTRY_RQ;
8066		*r_id = rcqe->rq_id;
8067		rc = rcqe->status;
8068		break;
8069	}
8070	case SLI4_CQE_CODE_RQ_ASYNC_V1:
8071	{
8072		sli4_fc_async_rcqe_v1_t *rcqe = (void *)cqe;
8073
8074		*etype = SLI_QENTRY_RQ;
8075		*r_id = rcqe->rq_id;
8076		rc = rcqe->status;
8077		break;
8078	}
8079	case SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD:
8080	{
8081		sli4_fc_optimized_write_cmd_cqe_t *optcqe = (void *)cqe;
8082
8083		*etype = SLI_QENTRY_OPT_WRITE_CMD;
8084		*r_id = optcqe->rq_id;
8085		rc = optcqe->status;
8086		break;
8087	}
8088	case SLI4_CQE_CODE_OPTIMIZED_WRITE_DATA:
8089	{
8090		sli4_fc_optimized_write_data_cqe_t *dcqe = (void *)cqe;
8091
8092		*etype = SLI_QENTRY_OPT_WRITE_DATA;
8093		*r_id = dcqe->xri;
8094		rc = dcqe->status;
8095
8096		/* Flag errors */
8097		if (rc != SLI4_FC_WCQE_STATUS_SUCCESS) {
8098			ocs_log_test(sli4->os, "Optimized DATA CQE: status=%#x hw_status=%#x xri=%#x dpl=%#x w3=%#x xb=%d\n",
8099				dcqe->status, dcqe->hw_status,
8100				dcqe->xri, dcqe->total_data_placed,
8101				((uint32_t*) cqe)[3], dcqe->xb);
8102		}
8103		break;
8104	}
8105	case SLI4_CQE_CODE_RQ_COALESCING:
8106	{
8107		sli4_fc_coalescing_rcqe_t *rcqe = (void *)cqe;
8108
8109		*etype = SLI_QENTRY_RQ;
8110		*r_id = rcqe->rq_id;
8111		rc = rcqe->status;
8112		break;
8113	}
8114	case SLI4_CQE_CODE_XRI_ABORTED:
8115	{
8116		sli4_fc_xri_aborted_cqe_t *xa = (void *)cqe;
8117
8118		*etype = SLI_QENTRY_XABT;
8119		*r_id = xa->xri;
8120		rc = 0;
8121		break;
8122	}
8123	case SLI4_CQE_CODE_RELEASE_WQE: {
8124		sli4_fc_wqec_t *wqec = (void*) cqe;
8125
8126		*etype = SLI_QENTRY_WQ_RELEASE;
8127		*r_id = wqec->wq_id;
8128		rc = 0;
8129		break;
8130	}
8131	default:
8132		ocs_log_test(sli4->os, "CQE completion code %d not handled\n", code);
8133		*etype = SLI_QENTRY_MAX;
8134		*r_id = UINT16_MAX;
8135	}
8136
8137	return rc;
8138}
8139
8140/**
8141 * @ingroup sli_fc
8142 * @brief Return the ELS/CT response length.
8143 *
8144 * @param sli4 SLI context.
8145 * @param cqe Pointer to the CQ entry.
8146 *
8147 * @return Returns the length, in bytes.
8148 */
8149uint32_t
8150sli_fc_response_length(sli4_t *sli4, uint8_t *cqe)
8151{
8152	sli4_fc_wcqe_t *wcqe = (void *)cqe;
8153
8154	return wcqe->wqe_specific_1;
8155}
8156
8157/**
8158 * @ingroup sli_fc
8159 * @brief Return the FCP IO length.
8160 *
8161 * @param sli4 SLI context.
8162 * @param cqe Pointer to the CQ entry.
8163 *
8164 * @return Returns the length, in bytes.
8165 */
8166uint32_t
8167sli_fc_io_length(sli4_t *sli4, uint8_t *cqe)
8168{
8169	sli4_fc_wcqe_t *wcqe = (void *)cqe;
8170
8171	return wcqe->wqe_specific_1;
8172}
8173
8174/**
8175 * @ingroup sli_fc
8176 * @brief Retrieve the D_ID from the completion.
8177 *
8178 * @param sli4 SLI context.
8179 * @param cqe Pointer to the CQ entry.
8180 * @param d_id Pointer where the D_ID is written.
8181 *
8182 * @return Returns 0 on success, or a non-zero value on failure.
8183 */
8184int32_t
8185sli_fc_els_did(sli4_t *sli4, uint8_t *cqe, uint32_t *d_id)
8186{
8187	sli4_fc_wcqe_t *wcqe = (void *)cqe;
8188
8189	*d_id = 0;
8190
8191	if (wcqe->status) {
8192		return -1;
8193	} else {
8194		*d_id = wcqe->wqe_specific_2 & 0x00ffffff;
8195		return 0;
8196	}
8197}
8198
8199uint32_t
8200sli_fc_ext_status(sli4_t *sli4, uint8_t *cqe)
8201{
8202	sli4_fc_wcqe_t *wcqe = (void *)cqe;
8203	uint32_t	mask;
8204
8205	switch (wcqe->status) {
8206	case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
8207		mask = UINT32_MAX;
8208		break;
8209	case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
8210	case SLI4_FC_WCQE_STATUS_CMD_REJECT:
8211		mask = 0xff;
8212		break;
8213	case SLI4_FC_WCQE_STATUS_NPORT_RJT:
8214	case SLI4_FC_WCQE_STATUS_FABRIC_RJT:
8215	case SLI4_FC_WCQE_STATUS_NPORT_BSY:
8216	case SLI4_FC_WCQE_STATUS_FABRIC_BSY:
8217	case SLI4_FC_WCQE_STATUS_LS_RJT:
8218		mask = UINT32_MAX;
8219		break;
8220	case SLI4_FC_WCQE_STATUS_DI_ERROR:
8221		mask = UINT32_MAX;
8222		break;
8223	default:
8224		mask = 0;
8225	}
8226
8227	return wcqe->wqe_specific_2 & mask;
8228}
8229
8230/**
8231 * @ingroup sli_fc
8232 * @brief Retrieve the RQ index from the completion.
8233 *
8234 * @param sli4 SLI context.
8235 * @param cqe Pointer to the CQ entry.
8236 * @param rq_id Pointer where the rq_id is written.
8237 * @param index Pointer where the index is written.
8238 *
8239 * @return Returns 0 on success, or a non-zero value on failure.
8240 */
8241int32_t
8242sli_fc_rqe_rqid_and_index(sli4_t *sli4, uint8_t *cqe, uint16_t *rq_id, uint32_t *index)
8243{
8244	sli4_fc_async_rcqe_t	*rcqe = (void *)cqe;
8245	sli4_fc_async_rcqe_v1_t	*rcqe_v1 = (void *)cqe;
8246	int32_t	rc = -1;
8247	uint8_t	code = 0;
8248
8249	*rq_id = 0;
8250	*index = UINT32_MAX;
8251
8252	code = cqe[SLI4_CQE_CODE_OFFSET];
8253
8254	if (code == SLI4_CQE_CODE_RQ_ASYNC) {
8255		*rq_id = rcqe->rq_id;
8256		if (SLI4_FC_ASYNC_RQ_SUCCESS == rcqe->status) {
8257			*index = rcqe->rq_element_index;
8258			rc = 0;
8259		} else {
8260			*index = rcqe->rq_element_index;
8261			rc = rcqe->status;
8262			ocs_log_test(sli4->os, "status=%02x (%s) rq_id=%d, index=%x pdpl=%x sof=%02x eof=%02x hdpl=%x\n",
8263				rcqe->status, sli_fc_get_status_string(rcqe->status), rcqe->rq_id,
8264				rcqe->rq_element_index, rcqe->payload_data_placement_length, rcqe->sof_byte,
8265				rcqe->eof_byte, rcqe->header_data_placement_length);
8266		}
8267	} else if (code == SLI4_CQE_CODE_RQ_ASYNC_V1) {
8268		*rq_id = rcqe_v1->rq_id;
8269		if (SLI4_FC_ASYNC_RQ_SUCCESS == rcqe_v1->status) {
8270			*index = rcqe_v1->rq_element_index;
8271			rc = 0;
8272		} else {
8273			*index = rcqe_v1->rq_element_index;
8274			rc = rcqe_v1->status;
8275			ocs_log_test(sli4->os, "status=%02x (%s) rq_id=%d, index=%x pdpl=%x sof=%02x eof=%02x hdpl=%x\n",
8276				rcqe_v1->status, sli_fc_get_status_string(rcqe_v1->status),
8277				rcqe_v1->rq_id, rcqe_v1->rq_element_index,
8278				rcqe_v1->payload_data_placement_length, rcqe_v1->sof_byte,
8279				rcqe_v1->eof_byte, rcqe_v1->header_data_placement_length);
8280		}
8281	} else if (code == SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD) {
8282		sli4_fc_optimized_write_cmd_cqe_t *optcqe = (void *)cqe;
8283
8284		*rq_id = optcqe->rq_id;
8285		if (SLI4_FC_ASYNC_RQ_SUCCESS == optcqe->status) {
8286			*index = optcqe->rq_element_index;
8287			rc = 0;
8288		} else {
8289			*index = optcqe->rq_element_index;
8290			rc = optcqe->status;
8291			ocs_log_test(sli4->os, "status=%02x (%s) rq_id=%d, index=%x pdpl=%x hdpl=%x oox=%d agxr=%d xri=0x%x rpi=0x%x\n",
8292				optcqe->status, sli_fc_get_status_string(optcqe->status), optcqe->rq_id,
8293				optcqe->rq_element_index, optcqe->payload_data_placement_length,
8294				optcqe->header_data_placement_length, optcqe->oox, optcqe->agxr, optcqe->xri,
8295				optcqe->rpi);
8296		}
8297	} else if (code == SLI4_CQE_CODE_RQ_COALESCING) {
8298		sli4_fc_coalescing_rcqe_t	*rcqe = (void *)cqe;
8299
8300		*rq_id = rcqe->rq_id;
8301		if (SLI4_FC_COALESCE_RQ_SUCCESS == rcqe->status) {
8302			*index = rcqe->rq_element_index;
8303			rc = 0;
8304		} else {
8305			*index = UINT32_MAX;
8306			rc = rcqe->status;
8307
8308			ocs_log_test(sli4->os, "status=%02x (%s) rq_id=%d, index=%x rq_id=%#x sdpl=%x\n",
8309				rcqe->status, sli_fc_get_status_string(rcqe->status), rcqe->rq_id,
8310				rcqe->rq_element_index, rcqe->rq_id, rcqe->sequence_reporting_placement_length);
8311		}
8312	} else {
8313		*index = UINT32_MAX;
8314
8315		rc = rcqe->status;
8316
8317		ocs_log_debug(sli4->os, "status=%02x rq_id=%d, index=%x pdpl=%x sof=%02x eof=%02x hdpl=%x\n",
8318			rcqe->status, rcqe->rq_id, rcqe->rq_element_index, rcqe->payload_data_placement_length,
8319			rcqe->sof_byte, rcqe->eof_byte, rcqe->header_data_placement_length);
8320	}
8321
8322	return rc;
8323}
8324
8325/**
8326 * @ingroup sli_fc
8327 * @brief Process an asynchronous FCoE event entry.
8328 *
8329 * @par Description
8330 * Parses Asynchronous Completion Queue Entry (ACQE),
8331 * creates an abstracted event, and calls the registered callback functions.
8332 *
8333 * @param sli4 SLI context.
8334 * @param acqe Pointer to the ACQE.
8335 *
8336 * @return Returns 0 on success, or a non-zero value on failure.
8337 */
8338int32_t
8339sli_fc_process_fcoe(sli4_t *sli4, void *acqe)
8340{
8341	sli4_fcoe_fip_t	*fcoe = acqe;
8342	sli4_fip_event_t event = { 0 };
8343	uint32_t	mask = UINT32_MAX;
8344
8345	ocs_log_debug(sli4->os, "ACQE FCoE FIP type=%02x count=%d tag=%#x\n",
8346			fcoe->event_type,
8347			fcoe->fcf_count,
8348			fcoe->event_tag);
8349
8350	if (!sli4->fip) {
8351		return 0;
8352	}
8353
8354	event.type = fcoe->event_type;
8355	event.index = UINT32_MAX;
8356
8357	switch (fcoe->event_type) {
8358	case SLI4_FCOE_FIP_FCF_DISCOVERED:
8359		ocs_log_debug(sli4->os, "FCF Discovered index=%d\n", fcoe->event_information);
8360		break;
8361	case SLI4_FCOE_FIP_FCF_TABLE_FULL:
8362		ocs_log_debug(sli4->os, "FCF Table Full\n");
8363		mask = 0;
8364		break;
8365	case SLI4_FCOE_FIP_FCF_DEAD:
8366		ocs_log_debug(sli4->os, "FCF Dead/Gone index=%d\n", fcoe->event_information);
8367		break;
8368	case SLI4_FCOE_FIP_FCF_CLEAR_VLINK:
8369		mask = UINT16_MAX;
8370		ocs_log_debug(sli4->os, "Clear VLINK Received VPI=%#x\n", fcoe->event_information & mask);
8371		break;
8372	case SLI4_FCOE_FIP_FCF_MODIFIED:
8373		ocs_log_debug(sli4->os, "FCF Modified\n");
8374		break;
8375	default:
8376		ocs_log_test(sli4->os, "bad FCoE type %#x", fcoe->event_type);
8377		mask = 0;
8378	}
8379
8380	if (mask != 0) {
8381		event.index = fcoe->event_information & mask;
8382	}
8383
8384	sli4->fip(sli4->fip_arg, &event);
8385
8386	return 0;
8387}
8388
8389/**
8390 * @ingroup sli_fc
8391 * @brief Allocate a receive queue.
8392 *
8393 * @par Description
8394 * Allocates DMA memory and configures the requested queue type.
8395 *
8396 * @param sli4 SLI context.
8397 * @param q Pointer to the queue object for the header.
8398 * @param n_entries Number of entries to allocate.
8399 * @param buffer_size buffer size for the queue.
8400 * @param cq Associated CQ.
8401 * @param ulp The ULP to bind
8402 * @param is_hdr Used to validate the rq_id and set the type of queue
8403 *
8404 * @return Returns 0 on success, or -1 on failure.
8405 */
8406int32_t
8407sli_fc_rq_alloc(sli4_t *sli4, sli4_queue_t *q,
8408		uint32_t n_entries, uint32_t buffer_size,
8409		sli4_queue_t *cq, uint16_t ulp, uint8_t is_hdr)
8410{
8411	int32_t (*rq_create)(sli4_t *, void *, size_t, ocs_dma_t *, uint16_t, uint16_t, uint16_t);
8412
8413	if ((sli4 == NULL) || (q == NULL)) {
8414		void *os = sli4 != NULL ? sli4->os : NULL;
8415
8416		ocs_log_err(os, "bad parameter sli4=%p q=%p\n", sli4, q);
8417		return -1;
8418	}
8419
8420	if (__sli_queue_init(sli4, q, SLI_QTYPE_RQ, SLI4_FCOE_RQE_SIZE,
8421				n_entries, SLI_PAGE_SIZE)) {
8422		return -1;
8423	}
8424
8425	if (sli4->if_type == SLI4_IF_TYPE_BE3_SKH_PF) {
8426		rq_create = sli_cmd_fcoe_rq_create;
8427	} else {
8428		rq_create = sli_cmd_fcoe_rq_create_v1;
8429	}
8430
8431	if (rq_create(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE, &q->dma,
8432		      cq->id, ulp, buffer_size)) {
8433		if (__sli_create_queue(sli4, q)) {
8434			ocs_dma_free(sli4->os, &q->dma);
8435			return -1;
8436		}
8437		if (is_hdr && q->id & 1) {
8438			ocs_log_test(sli4->os, "bad header RQ_ID %d\n", q->id);
8439			ocs_dma_free(sli4->os, &q->dma);
8440			return -1;
8441		} else if (!is_hdr  && (q->id & 1) == 0) {
8442			ocs_log_test(sli4->os, "bad data RQ_ID %d\n", q->id);
8443			ocs_dma_free(sli4->os, &q->dma);
8444			return -1;
8445		}
8446	} else {
8447		return -1;
8448	}
8449	q->u.flag.is_hdr = is_hdr;
8450	if (SLI4_IF_TYPE_BE3_SKH_PF == sli4->if_type) {
8451		q->u.flag.rq_batch = TRUE;
8452	}
8453	return 0;
8454}
8455
8456
8457/**
8458 * @ingroup sli_fc
8459 * @brief Allocate a receive queue set.
8460 *
8461 * @param sli4 SLI context.
8462 * @param num_rq_pairs to create
8463 * @param qs Pointers to the queue objects for both header and data.
8464 *	Length of this arrays should be 2 * num_rq_pairs
8465 * @param base_cq_id. Assumes base_cq_id : (base_cq_id + num_rq_pairs) cqs as allotted.
8466 * @param n_entries number of entries in each RQ queue.
8467 * @param header_buffer_size
8468 * @param payload_buffer_size
8469 * @param ulp The ULP to bind
8470 *
8471 * @return Returns 0 on success, or -1 on failure.
8472 */
8473int32_t
8474sli_fc_rq_set_alloc(sli4_t *sli4, uint32_t num_rq_pairs,
8475		    sli4_queue_t *qs[], uint32_t base_cq_id,
8476		    uint32_t n_entries, uint32_t header_buffer_size,
8477		    uint32_t payload_buffer_size,  uint16_t ulp)
8478{
8479	uint32_t i, p, offset = 0;
8480	uint32_t payload_size, total_page_count = 0;
8481	uintptr_t addr;
8482	ocs_dma_t dma;
8483	sli4_res_common_create_queue_set_t *rsp = NULL;
8484	sli4_req_fcoe_rq_create_v2_t    *req = NULL;
8485
8486	for (i = 0; i < (num_rq_pairs * 2); i++) {
8487		if (__sli_queue_init(sli4, qs[i], SLI_QTYPE_RQ, SLI4_FCOE_RQE_SIZE,
8488					n_entries, SLI_PAGE_SIZE)) {
8489			goto error;
8490		}
8491	}
8492
8493	total_page_count = sli_page_count(qs[0]->dma.size, SLI_PAGE_SIZE) * num_rq_pairs * 2;
8494
8495	/* Payload length must accommodate both request and response */
8496	payload_size = max((sizeof(sli4_req_fcoe_rq_create_v1_t) + (8 * total_page_count)),
8497			 sizeof(sli4_res_common_create_queue_set_t));
8498
8499	if (ocs_dma_alloc(sli4->os, &dma, payload_size, SLI_PAGE_SIZE)) {
8500		ocs_log_err(sli4->os, "DMA allocation failed\n");
8501		goto error;
8502	}
8503	ocs_memset(dma.virt, 0, payload_size);
8504
8505	if (sli_cmd_sli_config(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE,
8506			payload_size, &dma) == -1) {
8507		goto error;
8508	}
8509	req = (sli4_req_fcoe_rq_create_v2_t *)((uint8_t *)dma.virt);
8510
8511	/* Fill Header fields */
8512	req->hdr.opcode    = SLI4_OPC_FCOE_RQ_CREATE;
8513	req->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
8514	req->hdr.version   = 2;
8515	req->hdr.request_length = sizeof(sli4_req_fcoe_rq_create_v2_t) - sizeof(sli4_req_hdr_t)
8516					+ (8 * total_page_count);
8517
8518	/* Fill Payload fields */
8519	req->dnb           = TRUE;
8520	req->num_pages     = sli_page_count(qs[0]->dma.size, SLI_PAGE_SIZE);
8521	req->rqe_count     = qs[0]->dma.size / SLI4_FCOE_RQE_SIZE;
8522	req->rqe_size      = SLI4_FCOE_RQE_SIZE_8;
8523	req->page_size     = SLI4_FCOE_RQ_PAGE_SIZE_4096;
8524	req->rq_count      = num_rq_pairs * 2;
8525	req->base_cq_id    = base_cq_id;
8526	req->hdr_buffer_size     = header_buffer_size;
8527	req->payload_buffer_size = payload_buffer_size;
8528
8529	for (i = 0; i < (num_rq_pairs * 2); i++) {
8530		for (p = 0, addr = qs[i]->dma.phys; p < req->num_pages; p++, addr += SLI_PAGE_SIZE) {
8531			req->page_physical_address[offset].low  = ocs_addr32_lo(addr);
8532			req->page_physical_address[offset].high = ocs_addr32_hi(addr);
8533			offset++;
8534		}
8535	}
8536
8537	if (sli_bmbx_command(sli4)){
8538		ocs_log_crit(sli4->os, "bootstrap mailbox write faild RQSet\n");
8539		goto error;
8540	}
8541
8542
8543	rsp = (void *)((uint8_t *)dma.virt);
8544	if (rsp->hdr.status) {
8545		ocs_log_err(sli4->os, "bad create RQSet status=%#x addl=%#x\n",
8546			rsp->hdr.status, rsp->hdr.additional_status);
8547		goto error;
8548	} else {
8549		for (i = 0; i < (num_rq_pairs * 2); i++) {
8550			qs[i]->id = i + rsp->q_id;
8551			if ((qs[i]->id & 1) == 0) {
8552				qs[i]->u.flag.is_hdr = TRUE;
8553			} else {
8554				qs[i]->u.flag.is_hdr = FALSE;
8555			}
8556			qs[i]->doorbell_offset = regmap[SLI4_REG_FCOE_RQ_DOORBELL][sli4->if_type].off;
8557			qs[i]->doorbell_rset = regmap[SLI4_REG_FCOE_RQ_DOORBELL][sli4->if_type].rset;
8558		}
8559	}
8560
8561	ocs_dma_free(sli4->os, &dma);
8562
8563	return 0;
8564
8565error:
8566	for (i = 0; i < (num_rq_pairs * 2); i++) {
8567		if (qs[i]->dma.size) {
8568			ocs_dma_free(sli4->os, &qs[i]->dma);
8569		}
8570	}
8571
8572	if (dma.size) {
8573		ocs_dma_free(sli4->os, &dma);
8574	}
8575
8576	return -1;
8577}
8578
8579/**
8580 * @ingroup sli_fc
8581 * @brief Get the RPI resource requirements.
8582 *
8583 * @param sli4 SLI context.
8584 * @param n_rpi Number of RPIs desired.
8585 *
8586 * @return Returns the number of bytes needed. This value may be zero.
8587 */
8588uint32_t
8589sli_fc_get_rpi_requirements(sli4_t *sli4, uint32_t n_rpi)
8590{
8591	uint32_t	bytes = 0;
8592
8593	/* Check if header templates needed */
8594	if (sli4->config.hdr_template_req) {
8595		/* round up to a page */
8596		bytes = SLI_ROUND_PAGE(n_rpi * SLI4_FCOE_HDR_TEMPLATE_SIZE);
8597	}
8598
8599	return bytes;
8600}
8601
8602/**
8603 * @ingroup sli_fc
8604 * @brief Return a text string corresponding to a CQE status value
8605 *
8606 * @param status Status value
8607 *
8608 * @return Returns corresponding string, otherwise "unknown"
8609 */
8610const char *
8611sli_fc_get_status_string(uint32_t status)
8612{
8613	static struct {
8614		uint32_t code;
8615		const char *label;
8616	} lookup[] = {
8617		{SLI4_FC_WCQE_STATUS_SUCCESS,			"SUCCESS"},
8618		{SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE,		"FCP_RSP_FAILURE"},
8619		{SLI4_FC_WCQE_STATUS_REMOTE_STOP,		"REMOTE_STOP"},
8620		{SLI4_FC_WCQE_STATUS_LOCAL_REJECT,		"LOCAL_REJECT"},
8621		{SLI4_FC_WCQE_STATUS_NPORT_RJT,			"NPORT_RJT"},
8622		{SLI4_FC_WCQE_STATUS_FABRIC_RJT,		"FABRIC_RJT"},
8623		{SLI4_FC_WCQE_STATUS_NPORT_BSY,			"NPORT_BSY"},
8624		{SLI4_FC_WCQE_STATUS_FABRIC_BSY,		"FABRIC_BSY"},
8625		{SLI4_FC_WCQE_STATUS_LS_RJT,			"LS_RJT"},
8626		{SLI4_FC_WCQE_STATUS_CMD_REJECT,		"CMD_REJECT"},
8627		{SLI4_FC_WCQE_STATUS_FCP_TGT_LENCHECK,		"FCP_TGT_LENCHECK"},
8628		{SLI4_FC_WCQE_STATUS_RQ_BUF_LEN_EXCEEDED,	"BUF_LEN_EXCEEDED"},
8629		{SLI4_FC_WCQE_STATUS_RQ_INSUFF_BUF_NEEDED,	"RQ_INSUFF_BUF_NEEDED"},
8630		{SLI4_FC_WCQE_STATUS_RQ_INSUFF_FRM_DISC,	"RQ_INSUFF_FRM_DESC"},
8631		{SLI4_FC_WCQE_STATUS_RQ_DMA_FAILURE,		"RQ_DMA_FAILURE"},
8632		{SLI4_FC_WCQE_STATUS_FCP_RSP_TRUNCATE,		"FCP_RSP_TRUNCATE"},
8633		{SLI4_FC_WCQE_STATUS_DI_ERROR,			"DI_ERROR"},
8634		{SLI4_FC_WCQE_STATUS_BA_RJT,			"BA_RJT"},
8635		{SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_NEEDED,	"RQ_INSUFF_XRI_NEEDED"},
8636		{SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_DISC,	"INSUFF_XRI_DISC"},
8637		{SLI4_FC_WCQE_STATUS_RX_ERROR_DETECT,		"RX_ERROR_DETECT"},
8638		{SLI4_FC_WCQE_STATUS_RX_ABORT_REQUEST,		"RX_ABORT_REQUEST"},
8639		};
8640	uint32_t i;
8641
8642	for (i = 0; i < ARRAY_SIZE(lookup); i++) {
8643		if (status == lookup[i].code) {
8644			return lookup[i].label;
8645		}
8646	}
8647	return "unknown";
8648}
8649