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: stable/11/sys/dev/ocs_fc/sli4.c 332040 2018-04-04 18:06:52Z 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
5761/**
5762 * @ingroup sli_fc
5763 * @brief Write an FCOE_WQ_CREATE command.
5764 *
5765 * @param sli4 SLI context.
5766 * @param buf Destination buffer for the command.
5767 * @param size Buffer size, in bytes.
5768 * @param qmem DMA memory for the queue.
5769 * @param cq_id Associated CQ_ID.
5770 * @param ulp The ULP to bind
5771 *
5772 * @note This creates a Version 0 message.
5773 *
5774 * @return Returns the number of bytes written.
5775 */
5776int32_t
5777sli_cmd_fcoe_wq_create(sli4_t *sli4, void *buf, size_t size,
5778		       ocs_dma_t *qmem, uint16_t cq_id, uint16_t ulp)
5779{
5780	sli4_req_fcoe_wq_create_t	*wq = NULL;
5781	uint32_t	sli_config_off = 0;
5782	uint32_t	p;
5783	uintptr_t	addr;
5784
5785	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
5786		uint32_t payload_size;
5787
5788		/* Payload length must accommodate both request and response */
5789		payload_size = max(sizeof(sli4_req_fcoe_wq_create_t),
5790				sizeof(sli4_res_common_create_queue_t));
5791
5792		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
5793				NULL);
5794	}
5795	wq = (sli4_req_fcoe_wq_create_t *)((uint8_t *)buf + sli_config_off);
5796
5797	wq->hdr.opcode = SLI4_OPC_FCOE_WQ_CREATE;
5798	wq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
5799	wq->hdr.request_length = sizeof(sli4_req_fcoe_wq_create_t) -
5800					sizeof(sli4_req_hdr_t);
5801	/* valid values for number of pages: 1-4 (sec 4.5.1) */
5802	wq->num_pages = sli_page_count(qmem->size, SLI_PAGE_SIZE);
5803	if (!wq->num_pages || (wq->num_pages > SLI4_FCOE_WQ_CREATE_V0_MAX_PAGES)) {
5804		return 0;
5805	}
5806
5807	wq->cq_id = cq_id;
5808
5809	if (sli4->config.dual_ulp_capable) {
5810		wq->dua = 1;
5811		wq->bqu = 1;
5812		wq->ulp = ulp;
5813	}
5814
5815	for (p = 0, addr = qmem->phys;
5816			p < wq->num_pages;
5817			p++, addr += SLI_PAGE_SIZE) {
5818		wq->page_physical_address[p].low  = ocs_addr32_lo(addr);
5819		wq->page_physical_address[p].high = ocs_addr32_hi(addr);
5820	}
5821
5822	return(sli_config_off + sizeof(sli4_req_fcoe_wq_create_t));
5823}
5824
5825/**
5826 * @ingroup sli_fc
5827 * @brief Write an FCOE_WQ_CREATE_V1 command.
5828 *
5829 * @param sli4 SLI context.
5830 * @param buf Destination buffer for the command.
5831 * @param size Buffer size, in bytes.
5832 * @param qmem DMA memory for the queue.
5833 * @param cq_id Associated CQ_ID.
5834 * @param ignored This parameter carries the ULP for WQ (ignored for V1)
5835
5836 *
5837 * @return Returns the number of bytes written.
5838 */
5839int32_t
5840sli_cmd_fcoe_wq_create_v1(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *qmem,
5841			  uint16_t cq_id, uint16_t ignored)
5842{
5843	sli4_req_fcoe_wq_create_v1_t	*wq = NULL;
5844	uint32_t	sli_config_off = 0;
5845	uint32_t	p;
5846	uintptr_t	addr;
5847	uint32_t	page_size = 0;
5848	uint32_t	page_bytes = 0;
5849	uint32_t	n_wqe = 0;
5850
5851	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
5852		uint32_t payload_size;
5853
5854		/* Payload length must accommodate both request and response */
5855		payload_size = max(sizeof(sli4_req_fcoe_wq_create_v1_t),
5856				sizeof(sli4_res_common_create_queue_t));
5857
5858		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
5859				NULL);
5860	}
5861	wq = (sli4_req_fcoe_wq_create_v1_t *)((uint8_t *)buf + sli_config_off);
5862
5863	wq->hdr.opcode = SLI4_OPC_FCOE_WQ_CREATE;
5864	wq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
5865	wq->hdr.request_length = sizeof(sli4_req_fcoe_wq_create_v1_t) -
5866					sizeof(sli4_req_hdr_t);
5867	wq->hdr.version = 1;
5868
5869	n_wqe = qmem->size / sli4->config.wqe_size;
5870
5871	/* This heuristic to determine the page size is simplistic
5872	 * but could be made more sophisticated
5873	 */
5874	switch (qmem->size) {
5875	case 4096:
5876	case 8192:
5877	case 16384:
5878	case 32768:
5879		page_size = 1;
5880		break;
5881	case 65536:
5882		page_size = 2;
5883		break;
5884	case 131072:
5885		page_size = 4;
5886		break;
5887	case 262144:
5888		page_size = 8;
5889		break;
5890	case 524288:
5891		page_size = 10;
5892		break;
5893	default:
5894		return 0;
5895	}
5896	page_bytes = page_size * SLI_PAGE_SIZE;
5897
5898	/* valid values for number of pages: 1-8 */
5899	wq->num_pages = sli_page_count(qmem->size, page_bytes);
5900	if (!wq->num_pages || (wq->num_pages > SLI4_FCOE_WQ_CREATE_V1_MAX_PAGES)) {
5901		return 0;
5902	}
5903
5904	wq->cq_id = cq_id;
5905
5906	wq->page_size = page_size;
5907
5908	if (sli4->config.wqe_size == SLI4_WQE_EXT_BYTES) {
5909		wq->wqe_size = SLI4_WQE_EXT_SIZE;
5910	} else {
5911		wq->wqe_size = SLI4_WQE_SIZE;
5912	}
5913
5914	wq->wqe_count = n_wqe;
5915
5916	for (p = 0, addr = qmem->phys;
5917			p < wq->num_pages;
5918			p++, addr += page_bytes) {
5919		wq->page_physical_address[p].low  = ocs_addr32_lo(addr);
5920		wq->page_physical_address[p].high = ocs_addr32_hi(addr);
5921	}
5922
5923	return(sli_config_off + sizeof(sli4_req_fcoe_wq_create_v1_t));
5924}
5925
5926/**
5927 * @ingroup sli_fc
5928 * @brief Write an FCOE_WQ_DESTROY command.
5929 *
5930 * @param sli4 SLI context.
5931 * @param buf Destination buffer for the command.
5932 * @param size Buffer size, in bytes.
5933 * @param wq_id WQ_ID.
5934 *
5935 * @return Returns the number of bytes written.
5936 */
5937int32_t
5938sli_cmd_fcoe_wq_destroy(sli4_t *sli4, void *buf, size_t size, uint16_t wq_id)
5939{
5940	sli4_req_fcoe_wq_destroy_t	*wq = NULL;
5941	uint32_t	sli_config_off = 0;
5942
5943	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
5944		uint32_t payload_size;
5945
5946		/* Payload length must accommodate both request and response */
5947		payload_size = max(sizeof(sli4_req_fcoe_wq_destroy_t),
5948				sizeof(sli4_res_hdr_t));
5949
5950		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
5951				NULL);
5952	}
5953	wq = (sli4_req_fcoe_wq_destroy_t *)((uint8_t *)buf + sli_config_off);
5954
5955	wq->hdr.opcode = SLI4_OPC_FCOE_WQ_DESTROY;
5956	wq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
5957	wq->hdr.request_length = sizeof(sli4_req_fcoe_wq_destroy_t) -
5958					sizeof(sli4_req_hdr_t);
5959
5960	wq->wq_id = wq_id;
5961
5962	return(sli_config_off + sizeof(sli4_req_fcoe_wq_destroy_t));
5963}
5964
5965/**
5966 * @ingroup sli_fc
5967 * @brief Write an FCOE_POST_SGL_PAGES command.
5968 *
5969 * @param sli4 SLI context.
5970 * @param buf Destination buffer for the command.
5971 * @param size Buffer size, in bytes.
5972 * @param xri starting XRI
5973 * @param xri_count XRI
5974 * @param page0 First SGL memory page.
5975 * @param page1 Second SGL memory page (optional).
5976 * @param dma DMA buffer for non-embedded mailbox command (options)
5977 *
5978 * if non-embedded mbx command is used, dma buffer must be at least (32 + xri_count*16) in length
5979 *
5980 * @return Returns the number of bytes written.
5981 */
5982int32_t
5983sli_cmd_fcoe_post_sgl_pages(sli4_t *sli4, void *buf, size_t size,
5984		uint16_t xri, uint32_t xri_count, ocs_dma_t *page0[], ocs_dma_t *page1[], ocs_dma_t *dma)
5985{
5986	sli4_req_fcoe_post_sgl_pages_t	*post = NULL;
5987	uint32_t	sli_config_off = 0;
5988	uint32_t	i;
5989
5990	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
5991		uint32_t payload_size;
5992
5993		/* Payload length must accommodate both request and response */
5994		payload_size = max(sizeof(sli4_req_fcoe_post_sgl_pages_t),
5995				sizeof(sli4_res_hdr_t));
5996
5997		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
5998				dma);
5999	}
6000	if (dma) {
6001		post = dma->virt;
6002		ocs_memset(post, 0, dma->size);
6003	} else {
6004		post = (sli4_req_fcoe_post_sgl_pages_t *)((uint8_t *)buf + sli_config_off);
6005	}
6006
6007	post->hdr.opcode = SLI4_OPC_FCOE_POST_SGL_PAGES;
6008	post->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6009	/* payload size calculation
6010	 *   4 = xri_start + xri_count
6011	 *   xri_count = # of XRI's registered
6012	 *   sizeof(uint64_t) = physical address size
6013	 *   2 = # of physical addresses per page set
6014	 */
6015	post->hdr.request_length = 4 + (xri_count * (sizeof(uint64_t) * 2));
6016
6017	post->xri_start = xri;
6018	post->xri_count = xri_count;
6019
6020	for (i = 0; i < xri_count; i++) {
6021		post->page_set[i].page0_low  = ocs_addr32_lo(page0[i]->phys);
6022		post->page_set[i].page0_high = ocs_addr32_hi(page0[i]->phys);
6023	}
6024
6025	if (page1) {
6026		for (i = 0; i < xri_count; i++) {
6027			post->page_set[i].page1_low  = ocs_addr32_lo(page1[i]->phys);
6028			post->page_set[i].page1_high = ocs_addr32_hi(page1[i]->phys);
6029		}
6030	}
6031
6032	return dma ? sli_config_off : (sli_config_off + sizeof(sli4_req_fcoe_post_sgl_pages_t));
6033}
6034
6035/**
6036 * @ingroup sli_fc
6037 * @brief Write an FCOE_RQ_CREATE command.
6038 *
6039 * @param sli4 SLI context.
6040 * @param buf Destination buffer for the command.
6041 * @param size Buffer size, in bytes.
6042 * @param qmem DMA memory for the queue.
6043 * @param cq_id Associated CQ_ID.
6044 * @param ulp This parameter carries the ULP for the RQ
6045 * @param buffer_size Buffer size pointed to by each RQE.
6046 *
6047 * @note This creates a Version 0 message.
6048 *
6049 * @return Returns the number of bytes written.
6050 */
6051int32_t
6052sli_cmd_fcoe_rq_create(sli4_t *sli4, void *buf, size_t size,
6053		ocs_dma_t *qmem, uint16_t cq_id, uint16_t ulp, uint16_t buffer_size)
6054{
6055	sli4_req_fcoe_rq_create_t	*rq = NULL;
6056	uint32_t	sli_config_off = 0;
6057	uint32_t	p;
6058	uintptr_t	addr;
6059
6060	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
6061		uint32_t payload_size;
6062
6063		/* Payload length must accommodate both request and response */
6064		payload_size = max(sizeof(sli4_req_fcoe_rq_create_t),
6065				sizeof(sli4_res_common_create_queue_t));
6066
6067		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
6068				NULL);
6069	}
6070	rq = (sli4_req_fcoe_rq_create_t *)((uint8_t *)buf + sli_config_off);
6071
6072	rq->hdr.opcode = SLI4_OPC_FCOE_RQ_CREATE;
6073	rq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6074	rq->hdr.request_length = sizeof(sli4_req_fcoe_rq_create_t) -
6075					sizeof(sli4_req_hdr_t);
6076	/* valid values for number of pages: 1-8 (sec 4.5.6) */
6077	rq->num_pages = sli_page_count(qmem->size, SLI_PAGE_SIZE);
6078	if (!rq->num_pages || (rq->num_pages > SLI4_FCOE_RQ_CREATE_V0_MAX_PAGES)) {
6079		ocs_log_test(sli4->os, "num_pages %d not valid\n", rq->num_pages);
6080		return 0;
6081	}
6082
6083	/*
6084	 * RQE count is the log base 2 of the total number of entries
6085	 */
6086	rq->rqe_count = ocs_lg2(qmem->size / SLI4_FCOE_RQE_SIZE);
6087
6088	if ((buffer_size < SLI4_FCOE_RQ_CREATE_V0_MIN_BUF_SIZE) ||
6089			(buffer_size > SLI4_FCOE_RQ_CREATE_V0_MAX_BUF_SIZE)) {
6090		ocs_log_err(sli4->os, "buffer_size %d out of range (%d-%d)\n",
6091				buffer_size,
6092				SLI4_FCOE_RQ_CREATE_V0_MIN_BUF_SIZE,
6093				SLI4_FCOE_RQ_CREATE_V0_MAX_BUF_SIZE);
6094		return -1;
6095	}
6096	rq->buffer_size = buffer_size;
6097
6098	rq->cq_id = cq_id;
6099
6100	if (sli4->config.dual_ulp_capable) {
6101		rq->dua = 1;
6102		rq->bqu = 1;
6103		rq->ulp = ulp;
6104	}
6105
6106	for (p = 0, addr = qmem->phys;
6107			p < rq->num_pages;
6108			p++, addr += SLI_PAGE_SIZE) {
6109		rq->page_physical_address[p].low  = ocs_addr32_lo(addr);
6110		rq->page_physical_address[p].high = ocs_addr32_hi(addr);
6111	}
6112
6113	return(sli_config_off + sizeof(sli4_req_fcoe_rq_create_t));
6114}
6115
6116/**
6117 * @ingroup sli_fc
6118 * @brief Write an FCOE_RQ_CREATE_V1 command.
6119 *
6120 * @param sli4 SLI context.
6121 * @param buf Destination buffer for the command.
6122 * @param size Buffer size, in bytes.
6123 * @param qmem DMA memory for the queue.
6124 * @param cq_id Associated CQ_ID.
6125 * @param ulp This parameter carries the ULP for RQ (ignored for V1)
6126 * @param buffer_size Buffer size pointed to by each RQE.
6127 *
6128 * @note This creates a Version 0 message
6129 *
6130 * @return Returns the number of bytes written.
6131 */
6132int32_t
6133sli_cmd_fcoe_rq_create_v1(sli4_t *sli4, void *buf, size_t size,
6134			  ocs_dma_t *qmem, uint16_t cq_id, uint16_t ulp,
6135			  uint16_t buffer_size)
6136{
6137	sli4_req_fcoe_rq_create_v1_t	*rq = NULL;
6138	uint32_t	sli_config_off = 0;
6139	uint32_t	p;
6140	uintptr_t	addr;
6141
6142	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
6143		uint32_t payload_size;
6144
6145		/* Payload length must accommodate both request and response */
6146		payload_size = max(sizeof(sli4_req_fcoe_rq_create_v1_t),
6147				sizeof(sli4_res_common_create_queue_t));
6148
6149		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
6150				NULL);
6151	}
6152	rq = (sli4_req_fcoe_rq_create_v1_t *)((uint8_t *)buf + sli_config_off);
6153
6154	rq->hdr.opcode = SLI4_OPC_FCOE_RQ_CREATE;
6155	rq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6156	rq->hdr.request_length = sizeof(sli4_req_fcoe_rq_create_v1_t) -
6157					sizeof(sli4_req_hdr_t);
6158	rq->hdr.version = 1;
6159
6160	/* Disable "no buffer warnings" to avoid Lancer bug */
6161	rq->dnb = TRUE;
6162
6163	/* valid values for number of pages: 1-8 (sec 4.5.6) */
6164	rq->num_pages = sli_page_count(qmem->size, SLI_PAGE_SIZE);
6165	if (!rq->num_pages || (rq->num_pages > SLI4_FCOE_RQ_CREATE_V1_MAX_PAGES)) {
6166		ocs_log_test(sli4->os, "num_pages %d not valid, max %d\n",
6167                rq->num_pages, SLI4_FCOE_RQ_CREATE_V1_MAX_PAGES);
6168		return 0;
6169	}
6170
6171	/*
6172	 * RQE count is the total number of entries (note not lg2(# entries))
6173	 */
6174	rq->rqe_count = qmem->size / SLI4_FCOE_RQE_SIZE;
6175
6176	rq->rqe_size = SLI4_FCOE_RQE_SIZE_8;
6177
6178	rq->page_size = SLI4_FCOE_RQ_PAGE_SIZE_4096;
6179
6180	if ((buffer_size < sli4->config.rq_min_buf_size) ||
6181	    (buffer_size > sli4->config.rq_max_buf_size)) {
6182		ocs_log_err(sli4->os, "buffer_size %d out of range (%d-%d)\n",
6183				buffer_size,
6184				sli4->config.rq_min_buf_size,
6185				sli4->config.rq_max_buf_size);
6186		return -1;
6187	}
6188	rq->buffer_size = buffer_size;
6189
6190	rq->cq_id = cq_id;
6191
6192	for (p = 0, addr = qmem->phys;
6193			p < rq->num_pages;
6194			p++, addr += SLI_PAGE_SIZE) {
6195		rq->page_physical_address[p].low  = ocs_addr32_lo(addr);
6196		rq->page_physical_address[p].high = ocs_addr32_hi(addr);
6197	}
6198
6199	return(sli_config_off + sizeof(sli4_req_fcoe_rq_create_v1_t));
6200}
6201
6202/**
6203 * @ingroup sli_fc
6204 * @brief Write an FCOE_RQ_DESTROY command.
6205 *
6206 * @param sli4 SLI context.
6207 * @param buf Destination buffer for the command.
6208 * @param size Buffer size, in bytes.
6209 * @param rq_id RQ_ID.
6210 *
6211 * @return Returns the number of bytes written.
6212 */
6213int32_t
6214sli_cmd_fcoe_rq_destroy(sli4_t *sli4, void *buf, size_t size, uint16_t rq_id)
6215{
6216	sli4_req_fcoe_rq_destroy_t	*rq = NULL;
6217	uint32_t	sli_config_off = 0;
6218
6219	if (SLI4_PORT_TYPE_FC == sli4->port_type) {
6220		uint32_t payload_size;
6221
6222		/* Payload length must accommodate both request and response */
6223		payload_size = max(sizeof(sli4_req_fcoe_rq_destroy_t),
6224				sizeof(sli4_res_hdr_t));
6225
6226		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size,
6227				NULL);
6228	}
6229	rq = (sli4_req_fcoe_rq_destroy_t *)((uint8_t *)buf + sli_config_off);
6230
6231	rq->hdr.opcode = SLI4_OPC_FCOE_RQ_DESTROY;
6232	rq->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6233	rq->hdr.request_length = sizeof(sli4_req_fcoe_rq_destroy_t) -
6234					sizeof(sli4_req_hdr_t);
6235
6236	rq->rq_id = rq_id;
6237
6238	return(sli_config_off + sizeof(sli4_req_fcoe_rq_destroy_t));
6239}
6240
6241/**
6242 * @ingroup sli_fc
6243 * @brief Write an FCOE_READ_FCF_TABLE command.
6244 *
6245 * @note
6246 * The response of this command exceeds the size of an embedded
6247 * command and requires an external buffer with DMA capability to hold the results.
6248 * The caller should allocate the ocs_dma_t structure / memory.
6249 *
6250 * @param sli4 SLI context.
6251 * @param buf Destination buffer for the command.
6252 * @param size Buffer size, in bytes.
6253 * @param dma Pointer to DMA memory structure. This is allocated by the caller.
6254 * @param index FCF table index to retrieve.
6255 *
6256 * @return Returns the number of bytes written.
6257 */
6258int32_t
6259sli_cmd_fcoe_read_fcf_table(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma, uint16_t index)
6260{
6261	sli4_req_fcoe_read_fcf_table_t *read_fcf = NULL;
6262
6263	if (SLI4_PORT_TYPE_FC != sli4->port_type) {
6264		ocs_log_test(sli4->os, "FCOE_READ_FCF_TABLE only supported on FC\n");
6265		return -1;
6266	}
6267
6268	read_fcf = dma->virt;
6269
6270	ocs_memset(read_fcf, 0, sizeof(sli4_req_fcoe_read_fcf_table_t));
6271
6272	read_fcf->hdr.opcode = SLI4_OPC_FCOE_READ_FCF_TABLE;
6273	read_fcf->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6274	read_fcf->hdr.request_length = dma->size -
6275		sizeof(sli4_req_fcoe_read_fcf_table_t);
6276	read_fcf->fcf_index = index;
6277
6278	return sli_cmd_sli_config(sli4, buf, size, 0, dma);
6279}
6280
6281/**
6282 * @ingroup sli_fc
6283 * @brief Write an FCOE_POST_HDR_TEMPLATES command.
6284 *
6285 * @param sli4 SLI context.
6286 * @param buf Destination buffer for the command.
6287 * @param size Buffer size, in bytes.
6288 * @param dma Pointer to DMA memory structure. This is allocated by the caller.
6289 * @param rpi Starting RPI index for the header templates.
6290 * @param payload_dma Pointer to DMA memory used to hold larger descriptor counts.
6291 *
6292 * @return Returns the number of bytes written.
6293 */
6294int32_t
6295sli_cmd_fcoe_post_hdr_templates(sli4_t *sli4, void *buf, size_t size,
6296		ocs_dma_t *dma, uint16_t rpi, ocs_dma_t *payload_dma)
6297{
6298	sli4_req_fcoe_post_hdr_templates_t *template = NULL;
6299	uint32_t	sli_config_off = 0;
6300	uintptr_t	phys = 0;
6301	uint32_t	i = 0;
6302	uint32_t	page_count;
6303	uint32_t	payload_size;
6304
6305	page_count = sli_page_count(dma->size, SLI_PAGE_SIZE);
6306
6307	payload_size = sizeof(sli4_req_fcoe_post_hdr_templates_t) +
6308				page_count * sizeof(sli4_physical_page_descriptor_t);
6309
6310	if (page_count > 16) {
6311		/* We can't fit more than 16 descriptors into an embedded mailbox
6312		   command, it has to be non-embedded */
6313		if (ocs_dma_alloc(sli4->os, payload_dma, payload_size, 4)) {
6314			ocs_log_err(sli4->os, "mailbox payload memory allocation fail\n");
6315			return 0;
6316		}
6317		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size, payload_dma);
6318		template = (sli4_req_fcoe_post_hdr_templates_t *)payload_dma->virt;
6319	} else {
6320		sli_config_off = sli_cmd_sli_config(sli4, buf, size, payload_size, NULL);
6321		template = (sli4_req_fcoe_post_hdr_templates_t *)((uint8_t *)buf + sli_config_off);
6322	}
6323
6324	if (UINT16_MAX == rpi) {
6325		rpi = sli4->config.extent[SLI_RSRC_FCOE_RPI].base[0];
6326	}
6327
6328	template->hdr.opcode = SLI4_OPC_FCOE_POST_HDR_TEMPLATES;
6329	template->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6330	template->hdr.request_length = sizeof(sli4_req_fcoe_post_hdr_templates_t) -
6331					sizeof(sli4_req_hdr_t);
6332
6333	template->rpi_offset = rpi;
6334	template->page_count = page_count;
6335	phys = dma->phys;
6336	for (i = 0; i < template->page_count; i++) {
6337		template->page_descriptor[i].low  = ocs_addr32_lo(phys);
6338		template->page_descriptor[i].high = ocs_addr32_hi(phys);
6339
6340		phys += SLI_PAGE_SIZE;
6341	}
6342
6343	return(sli_config_off + payload_size);
6344}
6345
6346int32_t
6347sli_cmd_fcoe_rediscover_fcf(sli4_t *sli4, void *buf, size_t size, uint16_t index)
6348{
6349	sli4_req_fcoe_rediscover_fcf_t *redisc = NULL;
6350	uint32_t	sli_config_off = 0;
6351
6352	sli_config_off = sli_cmd_sli_config(sli4, buf, size,
6353			sizeof(sli4_req_fcoe_rediscover_fcf_t),
6354			NULL);
6355
6356	redisc = (sli4_req_fcoe_rediscover_fcf_t *)((uint8_t *)buf + sli_config_off);
6357
6358	redisc->hdr.opcode = SLI4_OPC_FCOE_REDISCOVER_FCF;
6359	redisc->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
6360	redisc->hdr.request_length = sizeof(sli4_req_fcoe_rediscover_fcf_t) -
6361					sizeof(sli4_req_hdr_t);
6362
6363	if (index == UINT16_MAX) {
6364		redisc->fcf_count = 0;
6365	} else {
6366		redisc->fcf_count = 1;
6367		redisc->fcf_index[0] = index;
6368	}
6369
6370	return(sli_config_off + sizeof(sli4_req_fcoe_rediscover_fcf_t));
6371}
6372
6373/**
6374 * @ingroup sli_fc
6375 * @brief Write an ABORT_WQE work queue entry.
6376 *
6377 * @param sli4 SLI context.
6378 * @param buf Destination buffer for the WQE.
6379 * @param size Buffer size, in bytes.
6380 * @param type Abort type, such as XRI, abort tag, and request tag.
6381 * @param send_abts Boolean to cause the hardware to automatically generate an ABTS.
6382 * @param ids ID of IOs to abort.
6383 * @param mask Mask applied to the ID values to abort.
6384 * @param tag Tag value associated with this abort.
6385 * @param cq_id The id of the completion queue where the WQE response is sent.
6386 * @param dnrx When set to 1, this field indicates that the SLI Port must not return the associated XRI to the SLI
6387 *             Port's optimized write XRI pool.
6388 *
6389 * @return Returns 0 on success, or a non-zero value on failure.
6390 */
6391int32_t
6392sli_abort_wqe(sli4_t *sli4, void *buf, size_t size, sli4_abort_type_e type, uint32_t send_abts,
6393	      uint32_t ids, uint32_t mask, uint16_t tag, uint16_t cq_id)
6394{
6395	sli4_abort_wqe_t	*abort = buf;
6396
6397	ocs_memset(buf, 0, size);
6398
6399	switch (type) {
6400	case SLI_ABORT_XRI:
6401		abort->criteria = SLI4_ABORT_CRITERIA_XRI_TAG;
6402		if (mask) {
6403			ocs_log_warn(sli4->os, "warning non-zero mask %#x when aborting XRI %#x\n", mask, ids);
6404			mask = 0;
6405		}
6406		break;
6407	case SLI_ABORT_ABORT_ID:
6408		abort->criteria = SLI4_ABORT_CRITERIA_ABORT_TAG;
6409		break;
6410	case SLI_ABORT_REQUEST_ID:
6411		abort->criteria = SLI4_ABORT_CRITERIA_REQUEST_TAG;
6412		break;
6413	default:
6414		ocs_log_test(sli4->os, "unsupported type %#x\n", type);
6415		return -1;
6416	}
6417
6418	abort->ia = send_abts ? 0 : 1;
6419
6420	/* Suppress ABTS retries */
6421	abort->ir = 1;
6422
6423	abort->t_mask = mask;
6424	abort->t_tag  = ids;
6425	abort->command = SLI4_WQE_ABORT;
6426	abort->request_tag = tag;
6427	abort->qosd = TRUE;
6428	abort->cq_id = cq_id;
6429	abort->cmd_type = SLI4_CMD_ABORT_WQE;
6430
6431	return 0;
6432}
6433
6434/**
6435 * @ingroup sli_fc
6436 * @brief Write an ELS_REQUEST64_WQE work queue entry.
6437 *
6438 * @param sli4 SLI context.
6439 * @param buf Destination buffer for the WQE.
6440 * @param size Buffer size, in bytes.
6441 * @param sgl DMA memory for the ELS request.
6442 * @param req_type ELS request type.
6443 * @param req_len Length of ELS request in bytes.
6444 * @param max_rsp_len Max length of ELS response in bytes.
6445 * @param timeout Time, in seconds, before an IO times out. Zero means 2 * R_A_TOV.
6446 * @param xri XRI for this exchange.
6447 * @param tag IO tag value.
6448 * @param cq_id The id of the completion queue where the WQE response is sent.
6449 * @param rnode Destination of ELS request (that is, the remote node).
6450 *
6451 * @return Returns 0 on success, or a non-zero value on failure.
6452 */
6453int32_t
6454sli_els_request64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint8_t req_type,
6455		      uint32_t req_len, uint32_t max_rsp_len, uint8_t timeout,
6456		      uint16_t xri, uint16_t tag, uint16_t cq_id, ocs_remote_node_t *rnode)
6457{
6458	sli4_els_request64_wqe_t	*els = buf;
6459	sli4_sge_t	*sge = sgl->virt;
6460	uint8_t		is_fabric = FALSE;
6461
6462	ocs_memset(buf, 0, size);
6463
6464	if (sli4->config.sgl_pre_registered) {
6465		els->xbl = FALSE;
6466
6467		els->dbde = TRUE;
6468		els->els_request_payload.bde_type = SLI4_BDE_TYPE_BDE_64;
6469
6470		els->els_request_payload.buffer_length = req_len;
6471		els->els_request_payload.u.data.buffer_address_low  = sge[0].buffer_address_low;
6472		els->els_request_payload.u.data.buffer_address_high = sge[0].buffer_address_high;
6473	} else {
6474		els->xbl = TRUE;
6475
6476		els->els_request_payload.bde_type = SLI4_BDE_TYPE_BLP;
6477
6478		els->els_request_payload.buffer_length = 2 * sizeof(sli4_sge_t);
6479		els->els_request_payload.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
6480		els->els_request_payload.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
6481	}
6482
6483	els->els_request_payload_length = req_len;
6484	els->max_response_payload_length = max_rsp_len;
6485
6486	els->xri_tag = xri;
6487	els->timer = timeout;
6488	els->class = SLI4_ELS_REQUEST64_CLASS_3;
6489
6490	els->command = SLI4_WQE_ELS_REQUEST64;
6491
6492	els->request_tag = tag;
6493
6494	if (rnode->node_group) {
6495		els->hlm = TRUE;
6496		els->remote_id = rnode->fc_id & 0x00ffffff;
6497	}
6498
6499	els->iod = SLI4_ELS_REQUEST64_DIR_READ;
6500
6501	els->qosd = TRUE;
6502
6503	/* figure out the ELS_ID value from the request buffer */
6504
6505	switch (req_type) {
6506	case FC_ELS_CMD_LOGO:
6507		els->els_id = SLI4_ELS_REQUEST64_LOGO;
6508		if (rnode->attached) {
6509			els->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6510			els->context_tag = rnode->indicator;
6511		} else {
6512			els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6513			els->context_tag = rnode->sport->indicator;
6514		}
6515		if (FC_ADDR_FABRIC == rnode->fc_id) {
6516			is_fabric = TRUE;
6517		}
6518		break;
6519	case FC_ELS_CMD_FDISC:
6520		if (FC_ADDR_FABRIC == rnode->fc_id) {
6521			is_fabric = TRUE;
6522		}
6523		if (0 == rnode->sport->fc_id) {
6524			els->els_id = SLI4_ELS_REQUEST64_FDISC;
6525			is_fabric = TRUE;
6526		} else {
6527			els->els_id = SLI4_ELS_REQUEST64_OTHER;
6528		}
6529		els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6530		els->context_tag = rnode->sport->indicator;
6531		els->sp = TRUE;
6532		break;
6533	case FC_ELS_CMD_FLOGI:
6534		els->els_id = SLI4_ELS_REQUEST64_FLOGIN;
6535		is_fabric = TRUE;
6536		if (SLI4_IF_TYPE_BE3_SKH_PF == sli4->if_type) {
6537			if (!rnode->sport->domain) {
6538				ocs_log_test(sli4->os, "invalid domain handle\n");
6539				return -1;
6540			}
6541			/*
6542			 * IF_TYPE 0 skips INIT_VFI/INIT_VPI and therefore must use the
6543			 * FCFI here
6544			 */
6545			els->ct = SLI4_ELS_REQUEST64_CONTEXT_FCFI;
6546			els->context_tag = rnode->sport->domain->fcf_indicator;
6547			els->sp = TRUE;
6548		} else {
6549			els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6550			els->context_tag = rnode->sport->indicator;
6551
6552			/*
6553			 * Set SP here ... we haven't done a REG_VPI yet
6554			 * TODO: need to maybe not set this when we have
6555			 *       completed VFI/VPI registrations ...
6556			 *
6557			 * Use the FC_ID of the SPORT if it has been allocated, otherwise
6558			 * use an S_ID of zero.
6559			 */
6560			els->sp = TRUE;
6561			if (rnode->sport->fc_id != UINT32_MAX) {
6562				els->sid = rnode->sport->fc_id;
6563			}
6564		}
6565		break;
6566	case FC_ELS_CMD_PLOGI:
6567		els->els_id = SLI4_ELS_REQUEST64_PLOGI;
6568		els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6569		els->context_tag = rnode->sport->indicator;
6570		break;
6571	case FC_ELS_CMD_SCR:
6572		els->els_id = SLI4_ELS_REQUEST64_OTHER;
6573		els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6574		els->context_tag = rnode->sport->indicator;
6575		break;
6576	default:
6577		els->els_id = SLI4_ELS_REQUEST64_OTHER;
6578		if (rnode->attached) {
6579			els->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6580			els->context_tag = rnode->indicator;
6581		} else {
6582			els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
6583			els->context_tag = rnode->sport->indicator;
6584		}
6585		break;
6586	}
6587
6588	if (is_fabric) {
6589		els->cmd_type = SLI4_ELS_REQUEST64_CMD_FABRIC;
6590	} else {
6591		els->cmd_type = SLI4_ELS_REQUEST64_CMD_NON_FABRIC;
6592	}
6593
6594	els->cq_id = cq_id;
6595
6596	if (SLI4_ELS_REQUEST64_CONTEXT_RPI != els->ct) {
6597		els->remote_id = rnode->fc_id;
6598	}
6599	if (SLI4_ELS_REQUEST64_CONTEXT_VPI == els->ct) {
6600		els->temporary_rpi = rnode->indicator;
6601	}
6602
6603	return 0;
6604}
6605
6606
6607/**
6608 * @ingroup sli_fc
6609 * @brief Write an FCP_ICMND64_WQE work queue entry.
6610 *
6611 * @param sli4 SLI context.
6612 * @param buf Destination buffer for the WQE.
6613 * @param size Buffer size, in bytes.
6614 * @param sgl DMA memory for the scatter gather list.
6615 * @param xri XRI for this exchange.
6616 * @param tag IO tag value.
6617 * @param cq_id The id of the completion queue where the WQE response is sent.
6618 * @param rpi remote node indicator (RPI)
6619 * @param rnode Destination request (that is, the remote node).
6620 * @param timeout Time, in seconds, before an IO times out. Zero means no timeout.
6621 *
6622 * @return Returns 0 on success, or a non-zero value on failure.
6623 */
6624int32_t
6625sli_fcp_icmnd64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl,
6626		    uint16_t xri, uint16_t tag, uint16_t cq_id,
6627		    uint32_t rpi, ocs_remote_node_t *rnode, uint8_t timeout)
6628{
6629	sli4_fcp_icmnd64_wqe_t *icmnd = buf;
6630	sli4_sge_t	*sge = NULL;
6631
6632	ocs_memset(buf, 0, size);
6633
6634	if (!sgl || !sgl->virt) {
6635		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
6636			    sgl, sgl ? sgl->virt : NULL);
6637		return -1;
6638	}
6639	sge = sgl->virt;
6640
6641	if (sli4->config.sgl_pre_registered) {
6642		icmnd->xbl = FALSE;
6643
6644		icmnd->dbde = TRUE;
6645		icmnd->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6646
6647		icmnd->bde.buffer_length = sge[0].buffer_length;
6648		icmnd->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
6649		icmnd->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
6650	} else {
6651		icmnd->xbl = TRUE;
6652
6653		icmnd->bde.bde_type = SLI4_BDE_TYPE_BLP;
6654
6655		icmnd->bde.buffer_length = sgl->size;
6656		icmnd->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
6657		icmnd->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
6658	}
6659
6660	icmnd->payload_offset_length = sge[0].buffer_length + sge[1].buffer_length;
6661	icmnd->xri_tag = xri;
6662	icmnd->context_tag = rpi;
6663	icmnd->timer = timeout;
6664
6665	icmnd->pu = 2;	/* WQE word 4 contains read transfer length */
6666	icmnd->class = SLI4_ELS_REQUEST64_CLASS_3;
6667	icmnd->command = SLI4_WQE_FCP_ICMND64;
6668	icmnd->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6669
6670	icmnd->abort_tag = xri;
6671
6672	icmnd->request_tag = tag;
6673	icmnd->len_loc = 3;
6674	if (rnode->node_group) {
6675		icmnd->hlm = TRUE;
6676		icmnd->remote_n_port_id = rnode->fc_id & 0x00ffffff;
6677	}
6678	if (((ocs_node_t *)rnode->node)->fcp2device) {
6679		icmnd->erp = TRUE;
6680	}
6681	icmnd->cmd_type = SLI4_CMD_FCP_ICMND64_WQE;
6682	icmnd->cq_id = cq_id;
6683
6684	return  0;
6685}
6686
6687/**
6688 * @ingroup sli_fc
6689 * @brief Write an FCP_IREAD64_WQE work queue entry.
6690 *
6691 * @param sli4 SLI context.
6692 * @param buf Destination buffer for the WQE.
6693 * @param size Buffer size, in bytes.
6694 * @param sgl DMA memory for the scatter gather list.
6695 * @param first_data_sge Index of first data sge (used if perf hints are enabled)
6696 * @param xfer_len Data transfer length.
6697 * @param xri XRI for this exchange.
6698 * @param tag IO tag value.
6699 * @param cq_id The id of the completion queue where the WQE response is sent.
6700 * @param rpi remote node indicator (RPI)
6701 * @param rnode Destination request (i.e. remote node).
6702 * @param dif T10 DIF operation, or 0 to disable.
6703 * @param bs T10 DIF block size, or 0 if DIF is disabled.
6704 * @param timeout Time, in seconds, before an IO times out. Zero means no timeout.
6705 *
6706 * @return Returns 0 on success, or a non-zero value on failure.
6707 */
6708int32_t
6709sli_fcp_iread64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge,
6710		    uint32_t xfer_len, uint16_t xri, uint16_t tag, uint16_t cq_id,
6711		    uint32_t rpi, ocs_remote_node_t *rnode,
6712		    uint8_t dif, uint8_t bs, uint8_t timeout)
6713{
6714	sli4_fcp_iread64_wqe_t *iread = buf;
6715	sli4_sge_t	*sge = NULL;
6716
6717	ocs_memset(buf, 0, size);
6718
6719	if (!sgl || !sgl->virt) {
6720		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
6721			    sgl, sgl ? sgl->virt : NULL);
6722		return -1;
6723	}
6724	sge = sgl->virt;
6725
6726	if (sli4->config.sgl_pre_registered) {
6727		iread->xbl = FALSE;
6728
6729		iread->dbde = TRUE;
6730		iread->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6731
6732		iread->bde.buffer_length = sge[0].buffer_length;
6733		iread->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
6734		iread->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
6735	} else {
6736		iread->xbl = TRUE;
6737
6738		iread->bde.bde_type = SLI4_BDE_TYPE_BLP;
6739
6740		iread->bde.buffer_length = sgl->size;
6741		iread->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
6742		iread->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
6743
6744		/* fill out fcp_cmnd buffer len and change resp buffer to be of type
6745		 * "skip" (note: response will still be written to sge[1] if necessary) */
6746		iread->fcp_cmd_buffer_length = sge[0].buffer_length;
6747		sge[1].sge_type = SLI4_SGE_TYPE_SKIP;
6748	}
6749
6750	iread->payload_offset_length = sge[0].buffer_length + sge[1].buffer_length;
6751	iread->total_transfer_length = xfer_len;
6752
6753	iread->xri_tag = xri;
6754	iread->context_tag = rpi;
6755
6756	iread->timer = timeout;
6757
6758	iread->pu = 2;	/* WQE word 4 contains read transfer length */
6759	iread->class = SLI4_ELS_REQUEST64_CLASS_3;
6760	iread->command = SLI4_WQE_FCP_IREAD64;
6761	iread->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6762	iread->dif = dif;
6763	iread->bs  = bs;
6764
6765	iread->abort_tag = xri;
6766
6767	iread->request_tag = tag;
6768	iread->len_loc = 3;
6769	if (rnode->node_group) {
6770		iread->hlm = TRUE;
6771		iread->remote_n_port_id = rnode->fc_id & 0x00ffffff;
6772	}
6773	if (((ocs_node_t *)rnode->node)->fcp2device) {
6774		iread->erp = TRUE;
6775	}
6776	iread->iod = 1;
6777	iread->cmd_type = SLI4_CMD_FCP_IREAD64_WQE;
6778	iread->cq_id = cq_id;
6779
6780	if (sli4->config.perf_hint) {
6781		iread->first_data_bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6782		iread->first_data_bde.buffer_length = sge[first_data_sge].buffer_length;
6783		iread->first_data_bde.u.data.buffer_address_low  = sge[first_data_sge].buffer_address_low;
6784		iread->first_data_bde.u.data.buffer_address_high = sge[first_data_sge].buffer_address_high;
6785	}
6786
6787	return  0;
6788}
6789
6790
6791/**
6792 * @ingroup sli_fc
6793 * @brief Write an FCP_IWRITE64_WQE work queue entry.
6794 *
6795 * @param sli4 SLI context.
6796 * @param buf Destination buffer for the WQE.
6797 * @param size Buffer size, in bytes.
6798 * @param sgl DMA memory for the scatter gather list.
6799 * @param first_data_sge Index of first data sge (used if perf hints are enabled)
6800 * @param xfer_len Data transfer length.
6801 * @param first_burst The number of first burst bytes
6802 * @param xri XRI for this exchange.
6803 * @param tag IO tag value.
6804 * @param cq_id The id of the completion queue where the WQE response is sent.
6805 * @param rpi remote node indicator (RPI)
6806 * @param rnode Destination request (i.e. remote node)
6807 * @param dif T10 DIF operation, or 0 to disable
6808 * @param bs T10 DIF block size, or 0 if DIF is disabled
6809 * @param timeout Time, in seconds, before an IO times out. Zero means no timeout.
6810 *
6811 * @return Returns 0 on success, or a non-zero value on failure.
6812 */
6813int32_t
6814sli_fcp_iwrite64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge,
6815		     uint32_t xfer_len, uint32_t first_burst, uint16_t xri, uint16_t tag, uint16_t cq_id,
6816		     uint32_t rpi, ocs_remote_node_t *rnode,
6817		     uint8_t dif, uint8_t bs, uint8_t timeout)
6818{
6819	sli4_fcp_iwrite64_wqe_t *iwrite = buf;
6820	sli4_sge_t	*sge = NULL;
6821
6822	ocs_memset(buf, 0, size);
6823
6824	if (!sgl || !sgl->virt) {
6825		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
6826			    sgl, sgl ? sgl->virt : NULL);
6827		return -1;
6828	}
6829	sge = sgl->virt;
6830
6831	if (sli4->config.sgl_pre_registered) {
6832		iwrite->xbl = FALSE;
6833
6834		iwrite->dbde = TRUE;
6835		iwrite->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6836
6837		iwrite->bde.buffer_length = sge[0].buffer_length;
6838		iwrite->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
6839		iwrite->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
6840	} else {
6841		iwrite->xbl = TRUE;
6842
6843		iwrite->bde.bde_type = SLI4_BDE_TYPE_BLP;
6844
6845		iwrite->bde.buffer_length = sgl->size;
6846		iwrite->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
6847		iwrite->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
6848
6849		/* fill out fcp_cmnd buffer len and change resp buffer to be of type
6850		 * "skip" (note: response will still be written to sge[1] if necessary) */
6851		iwrite->fcp_cmd_buffer_length = sge[0].buffer_length;
6852		sge[1].sge_type = SLI4_SGE_TYPE_SKIP;
6853	}
6854
6855	iwrite->payload_offset_length = sge[0].buffer_length + sge[1].buffer_length;
6856	iwrite->total_transfer_length = xfer_len;
6857	iwrite->initial_transfer_length = MIN(xfer_len, first_burst);
6858
6859	iwrite->xri_tag = xri;
6860	iwrite->context_tag = rpi;
6861
6862	iwrite->timer = timeout;
6863
6864	iwrite->pu = 2;	/* WQE word 4 contains read transfer length */
6865	iwrite->class = SLI4_ELS_REQUEST64_CLASS_3;
6866	iwrite->command = SLI4_WQE_FCP_IWRITE64;
6867	iwrite->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6868	iwrite->dif = dif;
6869	iwrite->bs  = bs;
6870
6871	iwrite->abort_tag = xri;
6872
6873	iwrite->request_tag = tag;
6874	iwrite->len_loc = 3;
6875	if (rnode->node_group) {
6876		iwrite->hlm = TRUE;
6877		iwrite->remote_n_port_id = rnode->fc_id & 0x00ffffff;
6878	}
6879	if (((ocs_node_t *)rnode->node)->fcp2device) {
6880		iwrite->erp = TRUE;
6881	}
6882	iwrite->cmd_type = SLI4_CMD_FCP_IWRITE64_WQE;
6883	iwrite->cq_id = cq_id;
6884
6885	if (sli4->config.perf_hint) {
6886		iwrite->first_data_bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6887		iwrite->first_data_bde.buffer_length = sge[first_data_sge].buffer_length;
6888		iwrite->first_data_bde.u.data.buffer_address_low  = sge[first_data_sge].buffer_address_low;
6889		iwrite->first_data_bde.u.data.buffer_address_high = sge[first_data_sge].buffer_address_high;
6890	}
6891
6892	return  0;
6893}
6894
6895/**
6896 * @ingroup sli_fc
6897 * @brief Write an FCP_TRECEIVE64_WQE work queue entry.
6898 *
6899 * @param sli4 SLI context.
6900 * @param buf Destination buffer for the WQE.
6901 * @param size Buffer size, in bytes.
6902 * @param sgl DMA memory for the Scatter-Gather List.
6903 * @param first_data_sge Index of first data sge (used if perf hints are enabled)
6904 * @param relative_off Relative offset of the IO (if any).
6905 * @param xfer_len Data transfer length.
6906 * @param xri XRI for this exchange.
6907 * @param tag IO tag value.
6908 * @param xid OX_ID for the exchange.
6909 * @param cq_id The id of the completion queue where the WQE response is sent.
6910 * @param rpi remote node indicator (RPI)
6911 * @param rnode Destination request (i.e. remote node).
6912 * @param flags Optional attributes, including:
6913 *  - ACTIVE - IO is already active.
6914 *  - AUTO RSP - Automatically generate a good FCP_RSP.
6915 * @param dif T10 DIF operation, or 0 to disable.
6916 * @param bs T10 DIF block size, or 0 if DIF is disabled.
6917 * @param csctl value of csctl field.
6918 * @param app_id value for VM application header.
6919 *
6920 * @return Returns 0 on success, or a non-zero value on failure.
6921 */
6922int32_t
6923sli_fcp_treceive64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge,
6924		       uint32_t relative_off, uint32_t xfer_len, uint16_t xri, uint16_t tag, uint16_t cq_id,
6925		       uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode, uint32_t flags, uint8_t dif, uint8_t bs,
6926		       uint8_t csctl, uint32_t app_id)
6927{
6928	sli4_fcp_treceive64_wqe_t *trecv = buf;
6929	sli4_fcp_128byte_wqe_t *trecv_128 = buf;
6930	sli4_sge_t	*sge = NULL;
6931
6932	ocs_memset(buf, 0, size);
6933
6934	if (!sgl || !sgl->virt) {
6935		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
6936			    sgl, sgl ? sgl->virt : NULL);
6937		return -1;
6938	}
6939	sge = sgl->virt;
6940
6941	if (sli4->config.sgl_pre_registered) {
6942		trecv->xbl = FALSE;
6943
6944		trecv->dbde = TRUE;
6945		trecv->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6946
6947		trecv->bde.buffer_length = sge[0].buffer_length;
6948		trecv->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
6949		trecv->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
6950
6951		trecv->payload_offset_length = sge[0].buffer_length;
6952	} else {
6953		trecv->xbl = TRUE;
6954
6955		/* if data is a single physical address, use a BDE */
6956		if (!dif && (xfer_len <= sge[2].buffer_length)) {
6957			trecv->dbde = TRUE;
6958			trecv->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
6959
6960			trecv->bde.buffer_length = sge[2].buffer_length;
6961			trecv->bde.u.data.buffer_address_low  = sge[2].buffer_address_low;
6962			trecv->bde.u.data.buffer_address_high = sge[2].buffer_address_high;
6963		} else {
6964			trecv->bde.bde_type = SLI4_BDE_TYPE_BLP;
6965			trecv->bde.buffer_length = sgl->size;
6966			trecv->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
6967			trecv->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
6968		}
6969	}
6970
6971	trecv->relative_offset = relative_off;
6972
6973	if (flags & SLI4_IO_CONTINUATION) {
6974		trecv->xc = TRUE;
6975	}
6976	trecv->xri_tag = xri;
6977
6978	trecv->context_tag = rpi;
6979
6980	trecv->pu = TRUE;	/* WQE uses relative offset */
6981
6982	if (flags & SLI4_IO_AUTO_GOOD_RESPONSE) {
6983		trecv->ar = TRUE;
6984	}
6985
6986	trecv->command = SLI4_WQE_FCP_TRECEIVE64;
6987	trecv->class = SLI4_ELS_REQUEST64_CLASS_3;
6988	trecv->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
6989	trecv->dif = dif;
6990	trecv->bs  = bs;
6991
6992	trecv->remote_xid = xid;
6993
6994	trecv->request_tag = tag;
6995
6996	trecv->iod = 1;
6997
6998	trecv->len_loc = 0x2;
6999
7000	if (rnode->node_group) {
7001		trecv->hlm = TRUE;
7002		trecv->dword5.dword = rnode->fc_id & 0x00ffffff;
7003	}
7004
7005	trecv->cmd_type = SLI4_CMD_FCP_TRECEIVE64_WQE;
7006
7007	trecv->cq_id = cq_id;
7008
7009	trecv->fcp_data_receive_length = xfer_len;
7010
7011	if (sli4->config.perf_hint) {
7012		trecv->first_data_bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7013		trecv->first_data_bde.buffer_length = sge[first_data_sge].buffer_length;
7014		trecv->first_data_bde.u.data.buffer_address_low  = sge[first_data_sge].buffer_address_low;
7015		trecv->first_data_bde.u.data.buffer_address_high = sge[first_data_sge].buffer_address_high;
7016	}
7017
7018	/* The upper 7 bits of csctl is the priority */
7019	if (csctl & SLI4_MASK_CCP) {
7020		trecv->ccpe = 1;
7021		trecv->ccp = (csctl & SLI4_MASK_CCP);
7022	}
7023
7024	if (app_id && (sli4->config.wqe_size == SLI4_WQE_EXT_BYTES) && !trecv->eat) {
7025		trecv->app_id_valid = 1;
7026		trecv->wqes = 1;
7027		trecv_128->dw[31] = app_id;
7028	}
7029	return 0;
7030}
7031
7032/**
7033 * @ingroup sli_fc
7034 * @brief Write an FCP_CONT_TRECEIVE64_WQE work queue entry.
7035 *
7036 * @param sli4 SLI context.
7037 * @param buf Destination buffer for the WQE.
7038 * @param size Buffer size, in bytes.
7039 * @param sgl DMA memory for the Scatter-Gather List.
7040 * @param first_data_sge Index of first data sge (used if perf hints are enabled)
7041 * @param relative_off Relative offset of the IO (if any).
7042 * @param xfer_len Data transfer length.
7043 * @param xri XRI for this exchange.
7044 * @param sec_xri Secondary XRI for this exchange. (BZ 161832 workaround)
7045 * @param tag IO tag value.
7046 * @param xid OX_ID for the exchange.
7047 * @param cq_id The id of the completion queue where the WQE response is sent.
7048 * @param rpi remote node indicator (RPI)
7049 * @param rnode Destination request (i.e. remote node).
7050 * @param flags Optional attributes, including:
7051 *  - ACTIVE - IO is already active.
7052 *  - AUTO RSP - Automatically generate a good FCP_RSP.
7053 * @param dif T10 DIF operation, or 0 to disable.
7054 * @param bs T10 DIF block size, or 0 if DIF is disabled.
7055 * @param csctl value of csctl field.
7056 * @param app_id value for VM application header.
7057 *
7058 * @return Returns 0 on success, or a non-zero value on failure.
7059 */
7060int32_t
7061sli_fcp_cont_treceive64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge,
7062			uint32_t relative_off, uint32_t xfer_len, uint16_t xri, uint16_t sec_xri, uint16_t tag,
7063			uint16_t cq_id, uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode, uint32_t flags,
7064			uint8_t dif, uint8_t bs, uint8_t csctl, uint32_t app_id)
7065{
7066	int32_t rc;
7067
7068	rc = sli_fcp_treceive64_wqe(sli4, buf, size, sgl, first_data_sge, relative_off, xfer_len, xri, tag,
7069			cq_id, xid, rpi, rnode, flags, dif, bs, csctl, app_id);
7070	if (rc == 0) {
7071		sli4_fcp_treceive64_wqe_t *trecv = buf;
7072
7073		trecv->command = SLI4_WQE_FCP_CONT_TRECEIVE64;
7074		trecv->dword5.sec_xri_tag = sec_xri;
7075	}
7076	return rc;
7077}
7078
7079/**
7080 * @ingroup sli_fc
7081 * @brief Write an FCP_TRSP64_WQE work queue entry.
7082 *
7083 * @param sli4 SLI context.
7084 * @param buf Destination buffer for the WQE.
7085 * @param size Buffer size, in bytes.
7086 * @param sgl DMA memory for the Scatter-Gather List.
7087 * @param rsp_len Response data length.
7088 * @param xri XRI for this exchange.
7089 * @param tag IO tag value.
7090 * @param cq_id The id of the completion queue where the WQE response is sent.
7091 * @param xid OX_ID for the exchange.
7092 * @param rpi remote node indicator (RPI)
7093 * @param rnode Destination request (i.e. remote node).
7094 * @param flags Optional attributes, including:
7095 *  - ACTIVE - IO is already active
7096 *  - AUTO RSP - Automatically generate a good FCP_RSP.
7097 * @param csctl value of csctl field.
7098 * @param port_owned 0/1 to indicate if the XRI is port owned (used to set XBL=0)
7099 * @param app_id value for VM application header.
7100 *
7101 * @return Returns 0 on success, or a non-zero value on failure.
7102 */
7103int32_t
7104sli_fcp_trsp64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t rsp_len,
7105		   uint16_t xri, uint16_t tag, uint16_t cq_id, uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode,
7106		   uint32_t flags, uint8_t csctl, uint8_t port_owned, uint32_t app_id)
7107{
7108	sli4_fcp_trsp64_wqe_t *trsp = buf;
7109	sli4_fcp_128byte_wqe_t *trsp_128 = buf;
7110
7111	ocs_memset(buf, 0, size);
7112
7113	if (flags & SLI4_IO_AUTO_GOOD_RESPONSE) {
7114		trsp->ag = TRUE;
7115		/*
7116		 * The SLI-4 documentation states that the BDE is ignored when
7117		 * using auto-good response, but, at least for IF_TYPE 0 devices,
7118		 * this does not appear to be true.
7119		 */
7120		if (SLI4_IF_TYPE_BE3_SKH_PF == sli4->if_type) {
7121			trsp->bde.buffer_length = 12;	/* byte size of RSP */
7122		}
7123	} else {
7124		sli4_sge_t	*sge = sgl->virt;
7125
7126		if (sli4->config.sgl_pre_registered || port_owned) {
7127			trsp->dbde = TRUE;
7128		} else {
7129			trsp->xbl = TRUE;
7130		}
7131
7132		trsp->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7133		trsp->bde.buffer_length = sge[0].buffer_length;
7134		trsp->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
7135		trsp->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
7136
7137		trsp->fcp_response_length = rsp_len;
7138	}
7139
7140	if (flags & SLI4_IO_CONTINUATION) {
7141		trsp->xc = TRUE;
7142	}
7143
7144	if (rnode->node_group) {
7145		trsp->hlm = TRUE;
7146		trsp->dword5 = rnode->fc_id & 0x00ffffff;
7147	}
7148
7149	trsp->xri_tag = xri;
7150	trsp->rpi = rpi;
7151
7152	trsp->command = SLI4_WQE_FCP_TRSP64;
7153	trsp->class = SLI4_ELS_REQUEST64_CLASS_3;
7154
7155	trsp->remote_xid = xid;
7156	trsp->request_tag = tag;
7157	trsp->dnrx = ((flags & SLI4_IO_DNRX) == 0 ? 0 : 1);
7158	trsp->len_loc = 0x1;
7159	trsp->cq_id = cq_id;
7160	trsp->cmd_type = SLI4_CMD_FCP_TRSP64_WQE;
7161
7162	/* The upper 7 bits of csctl is the priority */
7163	if (csctl & SLI4_MASK_CCP) {
7164		trsp->ccpe = 1;
7165		trsp->ccp = (csctl & SLI4_MASK_CCP);
7166	}
7167
7168	if (app_id && (sli4->config.wqe_size == SLI4_WQE_EXT_BYTES) && !trsp->eat) {
7169		trsp->app_id_valid = 1;
7170		trsp->wqes = 1;
7171		trsp_128->dw[31] = app_id;
7172	}
7173	return 0;
7174}
7175
7176/**
7177 * @ingroup sli_fc
7178 * @brief Write an FCP_TSEND64_WQE work queue entry.
7179 *
7180 * @param sli4 SLI context.
7181 * @param buf Destination buffer for the WQE.
7182 * @param size Buffer size, in bytes.
7183 * @param sgl DMA memory for the scatter gather list.
7184 * @param first_data_sge Index of first data sge (used if perf hints are enabled)
7185 * @param relative_off Relative offset of the IO (if any).
7186 * @param xfer_len Data transfer length.
7187 * @param xri XRI for this exchange.
7188 * @param tag IO tag value.
7189 * @param cq_id The id of the completion queue where the WQE response is sent.
7190 * @param xid OX_ID for the exchange.
7191 * @param rpi remote node indicator (RPI)
7192 * @param rnode Destination request (i.e. remote node).
7193 * @param flags Optional attributes, including:
7194 *  - ACTIVE - IO is already active.
7195 *  - AUTO RSP - Automatically generate a good FCP_RSP.
7196 * @param dif T10 DIF operation, or 0 to disable.
7197 * @param bs T10 DIF block size, or 0 if DIF is disabled.
7198 * @param csctl value of csctl field.
7199 * @param app_id value for VM application header.
7200 *
7201 * @return Returns 0 on success, or a non-zero value on failure.
7202 */
7203int32_t
7204sli_fcp_tsend64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge,
7205		    uint32_t relative_off, uint32_t xfer_len,
7206		    uint16_t xri, uint16_t tag, uint16_t cq_id, uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode,
7207		    uint32_t flags, uint8_t dif, uint8_t bs, uint8_t csctl, uint32_t app_id)
7208{
7209	sli4_fcp_tsend64_wqe_t *tsend = buf;
7210	sli4_fcp_128byte_wqe_t *tsend_128 = buf;
7211	sli4_sge_t	*sge = NULL;
7212
7213	ocs_memset(buf, 0, size);
7214
7215	if (!sgl || !sgl->virt) {
7216		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
7217			    sgl, sgl ? sgl->virt : NULL);
7218		return -1;
7219	}
7220	sge = sgl->virt;
7221
7222	if (sli4->config.sgl_pre_registered) {
7223		tsend->xbl = FALSE;
7224
7225		tsend->dbde = TRUE;
7226		tsend->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7227
7228		/* TSEND64_WQE specifies first two SGE are skipped
7229		 * (i.e. 3rd is valid) */
7230		tsend->bde.buffer_length = sge[2].buffer_length;
7231		tsend->bde.u.data.buffer_address_low  = sge[2].buffer_address_low;
7232		tsend->bde.u.data.buffer_address_high = sge[2].buffer_address_high;
7233	} else {
7234		tsend->xbl = TRUE;
7235
7236		/* if data is a single physical address, use a BDE */
7237		if (!dif && (xfer_len <= sge[2].buffer_length)) {
7238			tsend->dbde = TRUE;
7239			tsend->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7240			/* TSEND64_WQE specifies first two SGE are skipped
7241			 * (i.e. 3rd is valid) */
7242			tsend->bde.buffer_length = sge[2].buffer_length;
7243			tsend->bde.u.data.buffer_address_low  = sge[2].buffer_address_low;
7244			tsend->bde.u.data.buffer_address_high = sge[2].buffer_address_high;
7245		} else {
7246			tsend->bde.bde_type = SLI4_BDE_TYPE_BLP;
7247			tsend->bde.buffer_length = sgl->size;
7248			tsend->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
7249			tsend->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
7250		}
7251	}
7252
7253	tsend->relative_offset = relative_off;
7254
7255	if (flags & SLI4_IO_CONTINUATION) {
7256		tsend->xc = TRUE;
7257	}
7258	tsend->xri_tag = xri;
7259
7260	tsend->rpi = rpi;
7261
7262	tsend->pu = TRUE;	/* WQE uses relative offset */
7263
7264	if (flags & SLI4_IO_AUTO_GOOD_RESPONSE) {
7265		tsend->ar = TRUE;
7266	}
7267
7268	tsend->command = SLI4_WQE_FCP_TSEND64;
7269	tsend->class = SLI4_ELS_REQUEST64_CLASS_3;
7270	tsend->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
7271	tsend->dif = dif;
7272	tsend->bs  = bs;
7273
7274	tsend->remote_xid = xid;
7275
7276	tsend->request_tag = tag;
7277
7278	tsend->len_loc = 0x2;
7279
7280	if (rnode->node_group) {
7281		tsend->hlm = TRUE;
7282		tsend->dword5 = rnode->fc_id & 0x00ffffff;
7283	}
7284
7285	tsend->cq_id = cq_id;
7286
7287	tsend->cmd_type = SLI4_CMD_FCP_TSEND64_WQE;
7288
7289	tsend->fcp_data_transmit_length = xfer_len;
7290
7291	if (sli4->config.perf_hint) {
7292		tsend->first_data_bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7293		tsend->first_data_bde.buffer_length = sge[first_data_sge].buffer_length;
7294		tsend->first_data_bde.u.data.buffer_address_low  = sge[first_data_sge].buffer_address_low;
7295		tsend->first_data_bde.u.data.buffer_address_high = sge[first_data_sge].buffer_address_high;
7296	}
7297
7298	/* The upper 7 bits of csctl is the priority */
7299	if (csctl & SLI4_MASK_CCP) {
7300		tsend->ccpe = 1;
7301		tsend->ccp = (csctl & SLI4_MASK_CCP);
7302	}
7303
7304	if (app_id && (sli4->config.wqe_size == SLI4_WQE_EXT_BYTES) && !tsend->eat) {
7305		tsend->app_id_valid = 1;
7306		tsend->wqes = 1;
7307		tsend_128->dw[31] = app_id;
7308	}
7309	return 0;
7310}
7311
7312/**
7313 * @ingroup sli_fc
7314 * @brief Write a GEN_REQUEST64 work queue entry.
7315 *
7316 * @note This WQE is only used to send FC-CT commands.
7317 *
7318 * @param sli4 SLI context.
7319 * @param buf Destination buffer for the WQE.
7320 * @param size Buffer size, in bytes.
7321 * @param sgl DMA memory for the request.
7322 * @param req_len Length of request.
7323 * @param max_rsp_len Max length of response.
7324 * @param timeout Time, in seconds, before an IO times out. Zero means infinite.
7325 * @param xri XRI for this exchange.
7326 * @param tag IO tag value.
7327 * @param cq_id The id of the completion queue where the WQE response is sent.
7328 * @param rnode Destination of request (that is, the remote node).
7329 * @param r_ctl R_CTL value for sequence.
7330 * @param type TYPE value for sequence.
7331 * @param df_ctl DF_CTL value for sequence.
7332 *
7333 * @return Returns 0 on success, or a non-zero value on failure.
7334 */
7335int32_t
7336sli_gen_request64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl,
7337		      uint32_t req_len, uint32_t max_rsp_len, uint8_t timeout,
7338		      uint16_t xri, uint16_t tag, uint16_t cq_id, ocs_remote_node_t *rnode,
7339		      uint8_t r_ctl, uint8_t type, uint8_t df_ctl)
7340{
7341	sli4_gen_request64_wqe_t	*gen = buf;
7342	sli4_sge_t	*sge = NULL;
7343
7344	ocs_memset(buf, 0, size);
7345
7346	if (!sgl || !sgl->virt) {
7347		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
7348			    sgl, sgl ? sgl->virt : NULL);
7349		return -1;
7350	}
7351	sge = sgl->virt;
7352
7353	if (sli4->config.sgl_pre_registered) {
7354		gen->xbl = FALSE;
7355
7356		gen->dbde = TRUE;
7357		gen->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7358
7359		gen->bde.buffer_length = req_len;
7360		gen->bde.u.data.buffer_address_low  = sge[0].buffer_address_low;
7361		gen->bde.u.data.buffer_address_high = sge[0].buffer_address_high;
7362	} else {
7363		gen->xbl = TRUE;
7364
7365		gen->bde.bde_type = SLI4_BDE_TYPE_BLP;
7366
7367		gen->bde.buffer_length = 2 * sizeof(sli4_sge_t);
7368		gen->bde.u.blp.sgl_segment_address_low  = ocs_addr32_lo(sgl->phys);
7369		gen->bde.u.blp.sgl_segment_address_high = ocs_addr32_hi(sgl->phys);
7370	}
7371
7372	gen->request_payload_length = req_len;
7373	gen->max_response_payload_length = max_rsp_len;
7374
7375	gen->df_ctl = df_ctl;
7376	gen->type = type;
7377	gen->r_ctl = r_ctl;
7378
7379	gen->xri_tag = xri;
7380
7381	gen->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
7382	gen->context_tag = rnode->indicator;
7383
7384	gen->class = SLI4_ELS_REQUEST64_CLASS_3;
7385
7386	gen->command = SLI4_WQE_GEN_REQUEST64;
7387
7388	gen->timer = timeout;
7389
7390	gen->request_tag = tag;
7391
7392	gen->iod = SLI4_ELS_REQUEST64_DIR_READ;
7393
7394	gen->qosd = TRUE;
7395
7396	if (rnode->node_group) {
7397		gen->hlm = TRUE;
7398		gen->remote_n_port_id = rnode->fc_id & 0x00ffffff;
7399	}
7400
7401	gen->cmd_type = SLI4_CMD_GEN_REQUEST64_WQE;
7402
7403	gen->cq_id = cq_id;
7404
7405	return 0;
7406}
7407
7408/**
7409 * @ingroup sli_fc
7410 * @brief Write a SEND_FRAME work queue entry
7411 *
7412 * @param sli4 SLI context.
7413 * @param buf Destination buffer for the WQE.
7414 * @param size Buffer size, in bytes.
7415 * @param sof Start of frame value
7416 * @param eof End of frame value
7417 * @param hdr Pointer to FC header data
7418 * @param payload DMA memory for the payload.
7419 * @param req_len Length of payload.
7420 * @param timeout Time, in seconds, before an IO times out. Zero means infinite.
7421 * @param xri XRI for this exchange.
7422 * @param req_tag IO tag value.
7423 *
7424 * @return Returns 0 on success, or a non-zero value on failure.
7425 */
7426int32_t
7427sli_send_frame_wqe(sli4_t *sli4, void *buf, size_t size, uint8_t sof, uint8_t eof, uint32_t *hdr,
7428		   ocs_dma_t *payload, uint32_t req_len, uint8_t timeout,
7429		   uint16_t xri, uint16_t req_tag)
7430{
7431	sli4_send_frame_wqe_t *sf = buf;
7432
7433	ocs_memset(buf, 0, size);
7434
7435	sf->dbde = TRUE;
7436	sf->bde.buffer_length = req_len;
7437	sf->bde.u.data.buffer_address_low = ocs_addr32_lo(payload->phys);
7438	sf->bde.u.data.buffer_address_high = ocs_addr32_hi(payload->phys);
7439
7440	/* Copy FC header */
7441	sf->fc_header_0_1[0] = hdr[0];
7442	sf->fc_header_0_1[1] = hdr[1];
7443	sf->fc_header_2_5[0] = hdr[2];
7444	sf->fc_header_2_5[1] = hdr[3];
7445	sf->fc_header_2_5[2] = hdr[4];
7446	sf->fc_header_2_5[3] = hdr[5];
7447
7448	sf->frame_length = req_len;
7449
7450	sf->xri_tag = xri;
7451	sf->pu = 0;
7452	sf->context_tag = 0;
7453
7454
7455	sf->ct = 0;
7456	sf->command = SLI4_WQE_SEND_FRAME;
7457	sf->class = SLI4_ELS_REQUEST64_CLASS_3;
7458	sf->timer = timeout;
7459
7460	sf->request_tag = req_tag;
7461	sf->eof = eof;
7462	sf->sof = sof;
7463
7464	sf->qosd = 0;
7465	sf->lenloc = 1;
7466	sf->xc = 0;
7467
7468	sf->xbl = 1;
7469
7470	sf->cmd_type = SLI4_CMD_SEND_FRAME_WQE;
7471	sf->cq_id = 0xffff;
7472
7473	return 0;
7474}
7475
7476/**
7477 * @ingroup sli_fc
7478 * @brief Write a XMIT_SEQUENCE64 work queue entry.
7479 *
7480 * This WQE is used to send FC-CT response frames.
7481 *
7482 * @note This API implements a restricted use for this WQE, a TODO: would
7483 * include passing in sequence initiative, and full SGL's
7484 *
7485 * @param sli4 SLI context.
7486 * @param buf Destination buffer for the WQE.
7487 * @param size Buffer size, in bytes.
7488 * @param payload DMA memory for the request.
7489 * @param payload_len Length of request.
7490 * @param timeout Time, in seconds, before an IO times out. Zero means infinite.
7491 * @param ox_id originator exchange ID
7492 * @param xri XRI for this exchange.
7493 * @param tag IO tag value.
7494 * @param rnode Destination of request (that is, the remote node).
7495 * @param r_ctl R_CTL value for sequence.
7496 * @param type TYPE value for sequence.
7497 * @param df_ctl DF_CTL value for sequence.
7498 *
7499 * @return Returns 0 on success, or a non-zero value on failure.
7500 */
7501int32_t
7502sli_xmit_sequence64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *payload,
7503		      uint32_t payload_len, uint8_t timeout, uint16_t ox_id,
7504		      uint16_t xri, uint16_t tag, ocs_remote_node_t *rnode,
7505		      uint8_t r_ctl, uint8_t type, uint8_t df_ctl)
7506{
7507	sli4_xmit_sequence64_wqe_t	*xmit = buf;
7508
7509	ocs_memset(buf, 0, size);
7510
7511	if ((payload == NULL) || (payload->virt == NULL)) {
7512		ocs_log_err(sli4->os, "bad parameter sgl=%p virt=%p\n",
7513			    payload, payload ? payload->virt : NULL);
7514		return -1;
7515	}
7516
7517	if (sli4->config.sgl_pre_registered) {
7518		xmit->dbde = TRUE;
7519	} else {
7520		xmit->xbl = TRUE;
7521	}
7522
7523	xmit->bde.bde_type = SLI4_BDE_TYPE_BDE_64;
7524	xmit->bde.buffer_length = payload_len;
7525	xmit->bde.u.data.buffer_address_low  = ocs_addr32_lo(payload->phys);
7526	xmit->bde.u.data.buffer_address_high = ocs_addr32_hi(payload->phys);
7527	xmit->sequence_payload_len = payload_len;
7528
7529	xmit->remote_n_port_id = rnode->fc_id & 0x00ffffff;
7530
7531	xmit->relative_offset = 0;
7532
7533	xmit->si = 0;			/* sequence initiative - this matches what is seen from
7534					 * FC switches in response to FCGS commands */
7535	xmit->ft = 0;			/* force transmit */
7536	xmit->xo = 0;			/* exchange responder */
7537	xmit->ls = 1;			/* last in seqence */
7538	xmit->df_ctl = df_ctl;
7539	xmit->type = type;
7540	xmit->r_ctl = r_ctl;
7541
7542	xmit->xri_tag = xri;
7543	xmit->context_tag = rnode->indicator;
7544
7545	xmit->dif = 0;
7546	xmit->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
7547	xmit->bs = 0;
7548
7549	xmit->command = SLI4_WQE_XMIT_SEQUENCE64;
7550	xmit->class = SLI4_ELS_REQUEST64_CLASS_3;
7551	xmit->pu = 0;
7552	xmit->timer = timeout;
7553
7554	xmit->abort_tag = 0;
7555	xmit->request_tag = tag;
7556	xmit->remote_xid = ox_id;
7557
7558	xmit->iod = SLI4_ELS_REQUEST64_DIR_READ;
7559
7560	if (rnode->node_group) {
7561		xmit->hlm = TRUE;
7562		xmit->remote_n_port_id = rnode->fc_id & 0x00ffffff;
7563	}
7564
7565	xmit->cmd_type = SLI4_CMD_XMIT_SEQUENCE64_WQE;
7566
7567	xmit->len_loc = 2;
7568
7569	xmit->cq_id = 0xFFFF;
7570
7571	return 0;
7572}
7573
7574/**
7575 * @ingroup sli_fc
7576 * @brief Write a REQUEUE_XRI_WQE work queue entry.
7577 *
7578 * @param sli4 SLI context.
7579 * @param buf Destination buffer for the WQE.
7580 * @param size Buffer size, in bytes.
7581 * @param xri XRI for this exchange.
7582 * @param tag IO tag value.
7583 * @param cq_id The id of the completion queue where the WQE response is sent.
7584 *
7585 * @return Returns 0 on success, or a non-zero value on failure.
7586 */
7587int32_t
7588sli_requeue_xri_wqe(sli4_t *sli4, void *buf, size_t size, uint16_t xri, uint16_t tag, uint16_t cq_id)
7589{
7590	sli4_requeue_xri_wqe_t	*requeue = buf;
7591
7592	ocs_memset(buf, 0, size);
7593
7594	requeue->command = SLI4_WQE_REQUEUE_XRI;
7595	requeue->xri_tag = xri;
7596	requeue->request_tag = tag;
7597	requeue->xc = 1;
7598	requeue->qosd = 1;
7599	requeue->cq_id = cq_id;
7600	requeue->cmd_type = SLI4_CMD_REQUEUE_XRI_WQE;
7601	return 0;
7602}
7603
7604int32_t
7605sli_xmit_bcast64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *payload,
7606		uint32_t payload_len, uint8_t timeout, uint16_t xri, uint16_t tag,
7607		uint16_t cq_id, ocs_remote_node_t *rnode,
7608		uint8_t r_ctl, uint8_t type, uint8_t df_ctl)
7609{
7610	sli4_xmit_bcast64_wqe_t *bcast = buf;
7611
7612	/* Command requires a temporary RPI (i.e. unused remote node) */
7613	if (rnode->attached) {
7614		ocs_log_test(sli4->os, "remote node %d in use\n", rnode->indicator);
7615		return -1;
7616	}
7617
7618	ocs_memset(buf, 0, size);
7619
7620	bcast->dbde = TRUE;
7621	bcast->sequence_payload.bde_type = SLI4_BDE_TYPE_BDE_64;
7622	bcast->sequence_payload.buffer_length = payload_len;
7623	bcast->sequence_payload.u.data.buffer_address_low  = ocs_addr32_lo(payload->phys);
7624	bcast->sequence_payload.u.data.buffer_address_high = ocs_addr32_hi(payload->phys);
7625
7626	bcast->sequence_payload_length = payload_len;
7627
7628	bcast->df_ctl = df_ctl;
7629	bcast->type = type;
7630	bcast->r_ctl = r_ctl;
7631
7632	bcast->xri_tag = xri;
7633
7634	bcast->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
7635	bcast->context_tag = rnode->sport->indicator;
7636
7637	bcast->class = SLI4_ELS_REQUEST64_CLASS_3;
7638
7639	bcast->command = SLI4_WQE_XMIT_BCAST64;
7640
7641	bcast->timer = timeout;
7642
7643	bcast->request_tag = tag;
7644
7645	bcast->temporary_rpi = rnode->indicator;
7646
7647	bcast->len_loc = 0x1;
7648
7649	bcast->iod = SLI4_ELS_REQUEST64_DIR_WRITE;
7650
7651	bcast->cmd_type = SLI4_CMD_XMIT_BCAST64_WQE;
7652
7653	bcast->cq_id = cq_id;
7654
7655	return 0;
7656}
7657
7658/**
7659 * @ingroup sli_fc
7660 * @brief Write an XMIT_BLS_RSP64_WQE work queue entry.
7661 *
7662 * @param sli4 SLI context.
7663 * @param buf Destination buffer for the WQE.
7664 * @param size Buffer size, in bytes.
7665 * @param payload Contents of the BLS payload to be sent.
7666 * @param xri XRI for this exchange.
7667 * @param tag IO tag value.
7668 * @param cq_id The id of the completion queue where the WQE response is sent.
7669 * @param rnode Destination of request (that is, the remote node).
7670 * @param s_id Source ID to use in the response. If UINT32_MAX, use SLI Port's ID.
7671 *
7672 * @return Returns 0 on success, or a non-zero value on failure.
7673 */
7674int32_t
7675sli_xmit_bls_rsp64_wqe(sli4_t *sli4, void *buf, size_t size, sli_bls_payload_t *payload,
7676		       uint16_t xri, uint16_t tag, uint16_t cq_id, ocs_remote_node_t *rnode, uint32_t s_id)
7677{
7678	sli4_xmit_bls_rsp_wqe_t *bls = buf;
7679
7680	/*
7681	 * Callers can either specify RPI or S_ID, but not both
7682	 */
7683	if (rnode->attached && (s_id != UINT32_MAX)) {
7684		ocs_log_test(sli4->os, "S_ID specified for attached remote node %d\n",
7685			     rnode->indicator);
7686		return -1;
7687	}
7688
7689	ocs_memset(buf, 0, size);
7690
7691	if (SLI_BLS_ACC == payload->type) {
7692		bls->payload_word0 = (payload->u.acc.seq_id_last << 16) |
7693			(payload->u.acc.seq_id_validity << 24);
7694		bls->high_seq_cnt = payload->u.acc.high_seq_cnt;
7695		bls->low_seq_cnt = payload->u.acc.low_seq_cnt;
7696	} else if (SLI_BLS_RJT == payload->type) {
7697		bls->payload_word0 = *((uint32_t *)&payload->u.rjt);
7698		bls->ar = TRUE;
7699	} else {
7700		ocs_log_test(sli4->os, "bad BLS type %#x\n",
7701				payload->type);
7702		return -1;
7703	}
7704
7705	bls->ox_id = payload->ox_id;
7706	bls->rx_id = payload->rx_id;
7707
7708	if (rnode->attached) {
7709		bls->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
7710		bls->context_tag = rnode->indicator;
7711	} else {
7712		bls->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
7713		bls->context_tag = rnode->sport->indicator;
7714
7715		if (UINT32_MAX != s_id) {
7716			bls->local_n_port_id = s_id & 0x00ffffff;
7717		} else {
7718			bls->local_n_port_id = rnode->sport->fc_id & 0x00ffffff;
7719		}
7720		bls->remote_id = rnode->fc_id & 0x00ffffff;
7721
7722		bls->temporary_rpi = rnode->indicator;
7723	}
7724
7725	bls->xri_tag = xri;
7726
7727	bls->class = SLI4_ELS_REQUEST64_CLASS_3;
7728
7729	bls->command = SLI4_WQE_XMIT_BLS_RSP;
7730
7731	bls->request_tag = tag;
7732
7733	bls->qosd = TRUE;
7734
7735	if (rnode->node_group) {
7736		bls->hlm = TRUE;
7737		bls->remote_id = rnode->fc_id & 0x00ffffff;
7738	}
7739
7740	bls->cq_id = cq_id;
7741
7742	bls->cmd_type = SLI4_CMD_XMIT_BLS_RSP64_WQE;
7743
7744	return 0;
7745}
7746
7747/**
7748 * @ingroup sli_fc
7749 * @brief Write a XMIT_ELS_RSP64_WQE work queue entry.
7750 *
7751 * @param sli4 SLI context.
7752 * @param buf Destination buffer for the WQE.
7753 * @param size Buffer size, in bytes.
7754 * @param rsp DMA memory for the ELS response.
7755 * @param rsp_len Length of ELS response, in bytes.
7756 * @param xri XRI for this exchange.
7757 * @param tag IO tag value.
7758 * @param cq_id The id of the completion queue where the WQE response is sent.
7759 * @param ox_id OX_ID of the exchange containing the request.
7760 * @param rnode Destination of the ELS response (that is, the remote node).
7761 * @param flags Optional attributes, including:
7762 *  - SLI4_IO_CONTINUATION - IO is already active.
7763 * @param s_id S_ID used for special responses.
7764 *
7765 * @return Returns 0 on success, or a non-zero value on failure.
7766 */
7767int32_t
7768sli_xmit_els_rsp64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *rsp,
7769		       uint32_t rsp_len, uint16_t xri, uint16_t tag, uint16_t cq_id,
7770		       uint16_t ox_id, ocs_remote_node_t *rnode, uint32_t flags, uint32_t s_id)
7771{
7772	sli4_xmit_els_rsp64_wqe_t	*els = buf;
7773
7774	ocs_memset(buf, 0, size);
7775
7776	if (sli4->config.sgl_pre_registered) {
7777		els->dbde = TRUE;
7778	} else {
7779		els->xbl = TRUE;
7780	}
7781
7782	els->els_response_payload.bde_type = SLI4_BDE_TYPE_BDE_64;
7783	els->els_response_payload.buffer_length = rsp_len;
7784	els->els_response_payload.u.data.buffer_address_low  = ocs_addr32_lo(rsp->phys);
7785	els->els_response_payload.u.data.buffer_address_high = ocs_addr32_hi(rsp->phys);
7786
7787	els->els_response_payload_length = rsp_len;
7788
7789	els->xri_tag = xri;
7790
7791	els->class = SLI4_ELS_REQUEST64_CLASS_3;
7792
7793	els->command = SLI4_WQE_ELS_RSP64;
7794
7795	els->request_tag = tag;
7796
7797	els->ox_id = ox_id;
7798
7799	els->iod = SLI4_ELS_REQUEST64_DIR_WRITE;
7800
7801	els->qosd = TRUE;
7802
7803	if (flags & SLI4_IO_CONTINUATION) {
7804		els->xc = TRUE;
7805	}
7806
7807	if (rnode->attached) {
7808		els->ct = SLI4_ELS_REQUEST64_CONTEXT_RPI;
7809		els->context_tag = rnode->indicator;
7810	} else {
7811		els->ct = SLI4_ELS_REQUEST64_CONTEXT_VPI;
7812		els->context_tag = rnode->sport->indicator;
7813		els->remote_id = rnode->fc_id & 0x00ffffff;
7814		els->temporary_rpi = rnode->indicator;
7815		if (UINT32_MAX != s_id) {
7816			els->sp = TRUE;
7817			els->s_id = s_id & 0x00ffffff;
7818		}
7819	}
7820
7821	if (rnode->node_group) {
7822		els->hlm = TRUE;
7823		els->remote_id = rnode->fc_id & 0x00ffffff;
7824	}
7825
7826	els->cmd_type = SLI4_ELS_REQUEST64_CMD_GEN;
7827
7828	els->cq_id = cq_id;
7829
7830	return 0;
7831}
7832
7833/**
7834 * @ingroup sli_fc
7835 * @brief Process an asynchronous Link State event entry.
7836 *
7837 * @par Description
7838 * Parses Asynchronous Completion Queue Entry (ACQE),
7839 * creates an abstracted event, and calls registered callback functions.
7840 *
7841 * @param sli4 SLI context.
7842 * @param acqe Pointer to the ACQE.
7843 *
7844 * @return Returns 0 on success, or a non-zero value on failure.
7845 */
7846int32_t
7847sli_fc_process_link_state(sli4_t *sli4, void *acqe)
7848{
7849	sli4_link_state_t	*link_state = acqe;
7850	sli4_link_event_t	event = { 0 };
7851	int32_t			rc = 0;
7852
7853	if (!sli4->link) {
7854		/* bail if there is no callback */
7855		return 0;
7856	}
7857
7858	if (SLI4_LINK_TYPE_ETHERNET == link_state->link_type) {
7859		event.topology = SLI_LINK_TOPO_NPORT;
7860		event.medium   = SLI_LINK_MEDIUM_ETHERNET;
7861	} else {
7862		/* TODO is this supported for anything other than FCoE? */
7863		ocs_log_test(sli4->os, "unsupported link type %#x\n",
7864				link_state->link_type);
7865		event.topology = SLI_LINK_TOPO_MAX;
7866		event.medium   = SLI_LINK_MEDIUM_MAX;
7867		rc = -1;
7868	}
7869
7870	switch (link_state->port_link_status) {
7871	case SLI4_PORT_LINK_STATUS_PHYSICAL_DOWN:
7872	case SLI4_PORT_LINK_STATUS_LOGICAL_DOWN:
7873		event.status = SLI_LINK_STATUS_DOWN;
7874		break;
7875	case SLI4_PORT_LINK_STATUS_PHYSICAL_UP:
7876	case SLI4_PORT_LINK_STATUS_LOGICAL_UP:
7877		event.status = SLI_LINK_STATUS_UP;
7878		break;
7879	default:
7880		ocs_log_test(sli4->os, "unsupported link status %#x\n",
7881				link_state->port_link_status);
7882		event.status = SLI_LINK_STATUS_MAX;
7883		rc = -1;
7884	}
7885
7886	switch (link_state->port_speed) {
7887	case 0:
7888		event.speed = 0;
7889		break;
7890	case 1:
7891		event.speed = 10;
7892		break;
7893	case 2:
7894		event.speed = 100;
7895		break;
7896	case 3:
7897		event.speed = 1000;
7898		break;
7899	case 4:
7900		event.speed = 10000;
7901		break;
7902	case 5:
7903		event.speed = 20000;
7904		break;
7905	case 6:
7906		event.speed = 25000;
7907		break;
7908	case 7:
7909		event.speed = 40000;
7910		break;
7911	case 8:
7912		event.speed = 100000;
7913		break;
7914	default:
7915		ocs_log_test(sli4->os, "unsupported port_speed %#x\n",
7916				link_state->port_speed);
7917		rc = -1;
7918	}
7919
7920	sli4->link(sli4->link_arg, (void *)&event);
7921
7922	return rc;
7923}
7924
7925/**
7926 * @ingroup sli_fc
7927 * @brief Process an asynchronous Link Attention event entry.
7928 *
7929 * @par Description
7930 * Parses Asynchronous Completion Queue Entry (ACQE),
7931 * creates an abstracted event, and calls the registered callback functions.
7932 *
7933 * @param sli4 SLI context.
7934 * @param acqe Pointer to the ACQE.
7935 *
7936 * @todo XXX all events return LINK_UP.
7937 *
7938 * @return Returns 0 on success, or a non-zero value on failure.
7939 */
7940int32_t
7941sli_fc_process_link_attention(sli4_t *sli4, void *acqe)
7942{
7943	sli4_link_attention_t	*link_attn = acqe;
7944	sli4_link_event_t	event = { 0 };
7945
7946	ocs_log_debug(sli4->os, "link_number=%d attn_type=%#x topology=%#x port_speed=%#x "
7947			"port_fault=%#x shared_link_status=%#x logical_link_speed=%#x "
7948			"event_tag=%#x\n", link_attn->link_number, link_attn->attn_type,
7949			link_attn->topology, link_attn->port_speed, link_attn->port_fault,
7950			link_attn->shared_link_status, link_attn->logical_link_speed,
7951			link_attn->event_tag);
7952
7953	if (!sli4->link) {
7954		return 0;
7955	}
7956
7957	event.medium   = SLI_LINK_MEDIUM_FC;
7958
7959	switch (link_attn->attn_type) {
7960	case SLI4_LINK_ATTN_TYPE_LINK_UP:
7961		event.status = SLI_LINK_STATUS_UP;
7962		break;
7963	case SLI4_LINK_ATTN_TYPE_LINK_DOWN:
7964		event.status = SLI_LINK_STATUS_DOWN;
7965		break;
7966	case SLI4_LINK_ATTN_TYPE_NO_HARD_ALPA:
7967		ocs_log_debug(sli4->os, "attn_type: no hard alpa\n");
7968		event.status = SLI_LINK_STATUS_NO_ALPA;
7969		break;
7970	default:
7971		ocs_log_test(sli4->os, "attn_type: unknown\n");
7972		break;
7973	}
7974
7975	switch (link_attn->event_type) {
7976	case SLI4_FC_EVENT_LINK_ATTENTION:
7977		break;
7978	case SLI4_FC_EVENT_SHARED_LINK_ATTENTION:
7979		ocs_log_debug(sli4->os, "event_type: FC shared link event \n");
7980		break;
7981	default:
7982		ocs_log_test(sli4->os, "event_type: unknown\n");
7983		break;
7984	}
7985
7986	switch (link_attn->topology) {
7987	case SLI4_LINK_ATTN_P2P:
7988		event.topology = SLI_LINK_TOPO_NPORT;
7989		break;
7990	case SLI4_LINK_ATTN_FC_AL:
7991		event.topology = SLI_LINK_TOPO_LOOP;
7992		break;
7993	case SLI4_LINK_ATTN_INTERNAL_LOOPBACK:
7994		ocs_log_debug(sli4->os, "topology Internal loopback\n");
7995		event.topology = SLI_LINK_TOPO_LOOPBACK_INTERNAL;
7996		break;
7997	case SLI4_LINK_ATTN_SERDES_LOOPBACK:
7998		ocs_log_debug(sli4->os, "topology serdes loopback\n");
7999		event.topology = SLI_LINK_TOPO_LOOPBACK_EXTERNAL;
8000		break;
8001	default:
8002		ocs_log_test(sli4->os, "topology: unknown\n");
8003		break;
8004	}
8005
8006	event.speed    = link_attn->port_speed * 1000;
8007
8008	sli4->link(sli4->link_arg, (void *)&event);
8009
8010	return 0;
8011}
8012
8013/**
8014 * @ingroup sli_fc
8015 * @brief Parse an FC/FCoE work queue CQ entry.
8016 *
8017 * @param sli4 SLI context.
8018 * @param cq CQ to process.
8019 * @param cqe Pointer to the CQ entry.
8020 * @param etype CQ event type.
8021 * @param r_id Resource ID associated with this completion message (such as the IO tag).
8022 *
8023 * @return Returns 0 on success, or a non-zero value on failure.
8024 */
8025int32_t
8026sli_fc_cqe_parse(sli4_t *sli4, sli4_queue_t *cq, uint8_t *cqe, sli4_qentry_e *etype,
8027		uint16_t *r_id)
8028{
8029	uint8_t		code = cqe[SLI4_CQE_CODE_OFFSET];
8030	int32_t		rc = -1;
8031
8032	switch (code) {
8033	case SLI4_CQE_CODE_WORK_REQUEST_COMPLETION:
8034	{
8035		sli4_fc_wcqe_t *wcqe = (void *)cqe;
8036
8037		*etype = SLI_QENTRY_WQ;
8038		*r_id = wcqe->request_tag;
8039		rc = wcqe->status;
8040
8041		/* Flag errors except for FCP_RSP_FAILURE */
8042		if (rc && (rc != SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE)) {
8043
8044			ocs_log_test(sli4->os, "WCQE: status=%#x hw_status=%#x tag=%#x w1=%#x w2=%#x xb=%d\n",
8045				wcqe->status, wcqe->hw_status,
8046				wcqe->request_tag, wcqe->wqe_specific_1,
8047				wcqe->wqe_specific_2, wcqe->xb);
8048			ocs_log_test(sli4->os, "      %08X %08X %08X %08X\n", ((uint32_t*) cqe)[0], ((uint32_t*) cqe)[1],
8049				((uint32_t*) cqe)[2], ((uint32_t*) cqe)[3]);
8050		}
8051
8052		/* TODO: need to pass additional status back out of here as well
8053		 * as status (could overload rc as status/addlstatus are only 8 bits each)
8054		 */
8055
8056		break;
8057	}
8058	case SLI4_CQE_CODE_RQ_ASYNC:
8059	{
8060		sli4_fc_async_rcqe_t *rcqe = (void *)cqe;
8061
8062		*etype = SLI_QENTRY_RQ;
8063		*r_id = rcqe->rq_id;
8064		rc = rcqe->status;
8065		break;
8066	}
8067	case SLI4_CQE_CODE_RQ_ASYNC_V1:
8068	{
8069		sli4_fc_async_rcqe_v1_t *rcqe = (void *)cqe;
8070
8071		*etype = SLI_QENTRY_RQ;
8072		*r_id = rcqe->rq_id;
8073		rc = rcqe->status;
8074		break;
8075	}
8076	case SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD:
8077	{
8078		sli4_fc_optimized_write_cmd_cqe_t *optcqe = (void *)cqe;
8079
8080		*etype = SLI_QENTRY_OPT_WRITE_CMD;
8081		*r_id = optcqe->rq_id;
8082		rc = optcqe->status;
8083		break;
8084	}
8085	case SLI4_CQE_CODE_OPTIMIZED_WRITE_DATA:
8086	{
8087		sli4_fc_optimized_write_data_cqe_t *dcqe = (void *)cqe;
8088
8089		*etype = SLI_QENTRY_OPT_WRITE_DATA;
8090		*r_id = dcqe->xri;
8091		rc = dcqe->status;
8092
8093		/* Flag errors */
8094		if (rc != SLI4_FC_WCQE_STATUS_SUCCESS) {
8095			ocs_log_test(sli4->os, "Optimized DATA CQE: status=%#x hw_status=%#x xri=%#x dpl=%#x w3=%#x xb=%d\n",
8096				dcqe->status, dcqe->hw_status,
8097				dcqe->xri, dcqe->total_data_placed,
8098				((uint32_t*) cqe)[3], dcqe->xb);
8099		}
8100		break;
8101	}
8102	case SLI4_CQE_CODE_RQ_COALESCING:
8103	{
8104		sli4_fc_coalescing_rcqe_t *rcqe = (void *)cqe;
8105
8106		*etype = SLI_QENTRY_RQ;
8107		*r_id = rcqe->rq_id;
8108		rc = rcqe->status;
8109		break;
8110	}
8111	case SLI4_CQE_CODE_XRI_ABORTED:
8112	{
8113		sli4_fc_xri_aborted_cqe_t *xa = (void *)cqe;
8114
8115		*etype = SLI_QENTRY_XABT;
8116		*r_id = xa->xri;
8117		rc = 0;
8118		break;
8119	}
8120	case SLI4_CQE_CODE_RELEASE_WQE: {
8121		sli4_fc_wqec_t *wqec = (void*) cqe;
8122
8123		*etype = SLI_QENTRY_WQ_RELEASE;
8124		*r_id = wqec->wq_id;
8125		rc = 0;
8126		break;
8127	}
8128	default:
8129		ocs_log_test(sli4->os, "CQE completion code %d not handled\n", code);
8130		*etype = SLI_QENTRY_MAX;
8131		*r_id = UINT16_MAX;
8132	}
8133
8134	return rc;
8135}
8136
8137/**
8138 * @ingroup sli_fc
8139 * @brief Return the ELS/CT response length.
8140 *
8141 * @param sli4 SLI context.
8142 * @param cqe Pointer to the CQ entry.
8143 *
8144 * @return Returns the length, in bytes.
8145 */
8146uint32_t
8147sli_fc_response_length(sli4_t *sli4, uint8_t *cqe)
8148{
8149	sli4_fc_wcqe_t *wcqe = (void *)cqe;
8150
8151	return wcqe->wqe_specific_1;
8152}
8153
8154/**
8155 * @ingroup sli_fc
8156 * @brief Return the FCP IO length.
8157 *
8158 * @param sli4 SLI context.
8159 * @param cqe Pointer to the CQ entry.
8160 *
8161 * @return Returns the length, in bytes.
8162 */
8163uint32_t
8164sli_fc_io_length(sli4_t *sli4, uint8_t *cqe)
8165{
8166	sli4_fc_wcqe_t *wcqe = (void *)cqe;
8167
8168	return wcqe->wqe_specific_1;
8169}
8170
8171/**
8172 * @ingroup sli_fc
8173 * @brief Retrieve the D_ID from the completion.
8174 *
8175 * @param sli4 SLI context.
8176 * @param cqe Pointer to the CQ entry.
8177 * @param d_id Pointer where the D_ID is written.
8178 *
8179 * @return Returns 0 on success, or a non-zero value on failure.
8180 */
8181int32_t
8182sli_fc_els_did(sli4_t *sli4, uint8_t *cqe, uint32_t *d_id)
8183{
8184	sli4_fc_wcqe_t *wcqe = (void *)cqe;
8185
8186	*d_id = 0;
8187
8188	if (wcqe->status) {
8189		return -1;
8190	} else {
8191		*d_id = wcqe->wqe_specific_2 & 0x00ffffff;
8192		return 0;
8193	}
8194}
8195
8196uint32_t
8197sli_fc_ext_status(sli4_t *sli4, uint8_t *cqe)
8198{
8199	sli4_fc_wcqe_t *wcqe = (void *)cqe;
8200	uint32_t	mask;
8201
8202	switch (wcqe->status) {
8203	case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
8204		mask = UINT32_MAX;
8205		break;
8206	case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
8207	case SLI4_FC_WCQE_STATUS_CMD_REJECT:
8208		mask = 0xff;
8209		break;
8210	case SLI4_FC_WCQE_STATUS_NPORT_RJT:
8211	case SLI4_FC_WCQE_STATUS_FABRIC_RJT:
8212	case SLI4_FC_WCQE_STATUS_NPORT_BSY:
8213	case SLI4_FC_WCQE_STATUS_FABRIC_BSY:
8214	case SLI4_FC_WCQE_STATUS_LS_RJT:
8215		mask = UINT32_MAX;
8216		break;
8217	case SLI4_FC_WCQE_STATUS_DI_ERROR:
8218		mask = UINT32_MAX;
8219		break;
8220	default:
8221		mask = 0;
8222	}
8223
8224	return wcqe->wqe_specific_2 & mask;
8225}
8226
8227/**
8228 * @ingroup sli_fc
8229 * @brief Retrieve the RQ index from the completion.
8230 *
8231 * @param sli4 SLI context.
8232 * @param cqe Pointer to the CQ entry.
8233 * @param rq_id Pointer where the rq_id is written.
8234 * @param index Pointer where the index is written.
8235 *
8236 * @return Returns 0 on success, or a non-zero value on failure.
8237 */
8238int32_t
8239sli_fc_rqe_rqid_and_index(sli4_t *sli4, uint8_t *cqe, uint16_t *rq_id, uint32_t *index)
8240{
8241	sli4_fc_async_rcqe_t	*rcqe = (void *)cqe;
8242	sli4_fc_async_rcqe_v1_t	*rcqe_v1 = (void *)cqe;
8243	int32_t	rc = -1;
8244	uint8_t	code = 0;
8245
8246	*rq_id = 0;
8247	*index = UINT32_MAX;
8248
8249	code = cqe[SLI4_CQE_CODE_OFFSET];
8250
8251	if (code == SLI4_CQE_CODE_RQ_ASYNC) {
8252		*rq_id = rcqe->rq_id;
8253		if (SLI4_FC_ASYNC_RQ_SUCCESS == rcqe->status) {
8254			*index = rcqe->rq_element_index;
8255			rc = 0;
8256		} else {
8257			*index = rcqe->rq_element_index;
8258			rc = rcqe->status;
8259			ocs_log_test(sli4->os, "status=%02x (%s) rq_id=%d, index=%x pdpl=%x sof=%02x eof=%02x hdpl=%x\n",
8260				rcqe->status, sli_fc_get_status_string(rcqe->status), rcqe->rq_id,
8261				rcqe->rq_element_index, rcqe->payload_data_placement_length, rcqe->sof_byte,
8262				rcqe->eof_byte, rcqe->header_data_placement_length);
8263		}
8264	} else if (code == SLI4_CQE_CODE_RQ_ASYNC_V1) {
8265		*rq_id = rcqe_v1->rq_id;
8266		if (SLI4_FC_ASYNC_RQ_SUCCESS == rcqe_v1->status) {
8267			*index = rcqe_v1->rq_element_index;
8268			rc = 0;
8269		} else {
8270			*index = rcqe_v1->rq_element_index;
8271			rc = rcqe_v1->status;
8272			ocs_log_test(sli4->os, "status=%02x (%s) rq_id=%d, index=%x pdpl=%x sof=%02x eof=%02x hdpl=%x\n",
8273				rcqe_v1->status, sli_fc_get_status_string(rcqe_v1->status),
8274				rcqe_v1->rq_id, rcqe_v1->rq_element_index,
8275				rcqe_v1->payload_data_placement_length, rcqe_v1->sof_byte,
8276				rcqe_v1->eof_byte, rcqe_v1->header_data_placement_length);
8277		}
8278	} else if (code == SLI4_CQE_CODE_OPTIMIZED_WRITE_CMD) {
8279		sli4_fc_optimized_write_cmd_cqe_t *optcqe = (void *)cqe;
8280
8281		*rq_id = optcqe->rq_id;
8282		if (SLI4_FC_ASYNC_RQ_SUCCESS == optcqe->status) {
8283			*index = optcqe->rq_element_index;
8284			rc = 0;
8285		} else {
8286			*index = optcqe->rq_element_index;
8287			rc = optcqe->status;
8288			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",
8289				optcqe->status, sli_fc_get_status_string(optcqe->status), optcqe->rq_id,
8290				optcqe->rq_element_index, optcqe->payload_data_placement_length,
8291				optcqe->header_data_placement_length, optcqe->oox, optcqe->agxr, optcqe->xri,
8292				optcqe->rpi);
8293		}
8294	} else if (code == SLI4_CQE_CODE_RQ_COALESCING) {
8295		sli4_fc_coalescing_rcqe_t	*rcqe = (void *)cqe;
8296
8297		*rq_id = rcqe->rq_id;
8298		if (SLI4_FC_COALESCE_RQ_SUCCESS == rcqe->status) {
8299			*index = rcqe->rq_element_index;
8300			rc = 0;
8301		} else {
8302			*index = UINT32_MAX;
8303			rc = rcqe->status;
8304
8305			ocs_log_test(sli4->os, "status=%02x (%s) rq_id=%d, index=%x rq_id=%#x sdpl=%x\n",
8306				rcqe->status, sli_fc_get_status_string(rcqe->status), rcqe->rq_id,
8307				rcqe->rq_element_index, rcqe->rq_id, rcqe->sequence_reporting_placement_length);
8308		}
8309	} else {
8310		*index = UINT32_MAX;
8311
8312		rc = rcqe->status;
8313
8314		ocs_log_debug(sli4->os, "status=%02x rq_id=%d, index=%x pdpl=%x sof=%02x eof=%02x hdpl=%x\n",
8315			rcqe->status, rcqe->rq_id, rcqe->rq_element_index, rcqe->payload_data_placement_length,
8316			rcqe->sof_byte, rcqe->eof_byte, rcqe->header_data_placement_length);
8317	}
8318
8319	return rc;
8320}
8321
8322/**
8323 * @ingroup sli_fc
8324 * @brief Process an asynchronous FCoE event entry.
8325 *
8326 * @par Description
8327 * Parses Asynchronous Completion Queue Entry (ACQE),
8328 * creates an abstracted event, and calls the registered callback functions.
8329 *
8330 * @param sli4 SLI context.
8331 * @param acqe Pointer to the ACQE.
8332 *
8333 * @return Returns 0 on success, or a non-zero value on failure.
8334 */
8335int32_t
8336sli_fc_process_fcoe(sli4_t *sli4, void *acqe)
8337{
8338	sli4_fcoe_fip_t	*fcoe = acqe;
8339	sli4_fip_event_t event = { 0 };
8340	uint32_t	mask = UINT32_MAX;
8341
8342	ocs_log_debug(sli4->os, "ACQE FCoE FIP type=%02x count=%d tag=%#x\n",
8343			fcoe->event_type,
8344			fcoe->fcf_count,
8345			fcoe->event_tag);
8346
8347	if (!sli4->fip) {
8348		return 0;
8349	}
8350
8351	event.type = fcoe->event_type;
8352	event.index = UINT32_MAX;
8353
8354	switch (fcoe->event_type) {
8355	case SLI4_FCOE_FIP_FCF_DISCOVERED:
8356		ocs_log_debug(sli4->os, "FCF Discovered index=%d\n", fcoe->event_information);
8357		break;
8358	case SLI4_FCOE_FIP_FCF_TABLE_FULL:
8359		ocs_log_debug(sli4->os, "FCF Table Full\n");
8360		mask = 0;
8361		break;
8362	case SLI4_FCOE_FIP_FCF_DEAD:
8363		ocs_log_debug(sli4->os, "FCF Dead/Gone index=%d\n", fcoe->event_information);
8364		break;
8365	case SLI4_FCOE_FIP_FCF_CLEAR_VLINK:
8366		mask = UINT16_MAX;
8367		ocs_log_debug(sli4->os, "Clear VLINK Received VPI=%#x\n", fcoe->event_information & mask);
8368		break;
8369	case SLI4_FCOE_FIP_FCF_MODIFIED:
8370		ocs_log_debug(sli4->os, "FCF Modified\n");
8371		break;
8372	default:
8373		ocs_log_test(sli4->os, "bad FCoE type %#x", fcoe->event_type);
8374		mask = 0;
8375	}
8376
8377	if (mask != 0) {
8378		event.index = fcoe->event_information & mask;
8379	}
8380
8381	sli4->fip(sli4->fip_arg, &event);
8382
8383	return 0;
8384}
8385
8386/**
8387 * @ingroup sli_fc
8388 * @brief Allocate a receive queue.
8389 *
8390 * @par Description
8391 * Allocates DMA memory and configures the requested queue type.
8392 *
8393 * @param sli4 SLI context.
8394 * @param q Pointer to the queue object for the header.
8395 * @param n_entries Number of entries to allocate.
8396 * @param buffer_size buffer size for the queue.
8397 * @param cq Associated CQ.
8398 * @param ulp The ULP to bind
8399 * @param is_hdr Used to validate the rq_id and set the type of queue
8400 *
8401 * @return Returns 0 on success, or -1 on failure.
8402 */
8403int32_t
8404sli_fc_rq_alloc(sli4_t *sli4, sli4_queue_t *q,
8405		uint32_t n_entries, uint32_t buffer_size,
8406		sli4_queue_t *cq, uint16_t ulp, uint8_t is_hdr)
8407{
8408	int32_t (*rq_create)(sli4_t *, void *, size_t, ocs_dma_t *, uint16_t, uint16_t, uint16_t);
8409
8410	if ((sli4 == NULL) || (q == NULL)) {
8411		void *os = sli4 != NULL ? sli4->os : NULL;
8412
8413		ocs_log_err(os, "bad parameter sli4=%p q=%p\n", sli4, q);
8414		return -1;
8415	}
8416
8417	if (__sli_queue_init(sli4, q, SLI_QTYPE_RQ, SLI4_FCOE_RQE_SIZE,
8418				n_entries, SLI_PAGE_SIZE)) {
8419		return -1;
8420	}
8421
8422	if (sli4->if_type == SLI4_IF_TYPE_BE3_SKH_PF) {
8423		rq_create = sli_cmd_fcoe_rq_create;
8424	} else {
8425		rq_create = sli_cmd_fcoe_rq_create_v1;
8426	}
8427
8428	if (rq_create(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE, &q->dma,
8429		      cq->id, ulp, buffer_size)) {
8430		if (__sli_create_queue(sli4, q)) {
8431			ocs_dma_free(sli4->os, &q->dma);
8432			return -1;
8433		}
8434		if (is_hdr && q->id & 1) {
8435			ocs_log_test(sli4->os, "bad header RQ_ID %d\n", q->id);
8436			ocs_dma_free(sli4->os, &q->dma);
8437			return -1;
8438		} else if (!is_hdr  && (q->id & 1) == 0) {
8439			ocs_log_test(sli4->os, "bad data RQ_ID %d\n", q->id);
8440			ocs_dma_free(sli4->os, &q->dma);
8441			return -1;
8442		}
8443	} else {
8444		return -1;
8445	}
8446	q->u.flag.is_hdr = is_hdr;
8447	if (SLI4_IF_TYPE_BE3_SKH_PF == sli4->if_type) {
8448		q->u.flag.rq_batch = TRUE;
8449	}
8450	return 0;
8451}
8452
8453
8454/**
8455 * @ingroup sli_fc
8456 * @brief Allocate a receive queue set.
8457 *
8458 * @param sli4 SLI context.
8459 * @param num_rq_pairs to create
8460 * @param qs Pointers to the queue objects for both header and data.
8461 *	Length of this arrays should be 2 * num_rq_pairs
8462 * @param base_cq_id. Assumes base_cq_id : (base_cq_id + num_rq_pairs) cqs as allotted.
8463 * @param n_entries number of entries in each RQ queue.
8464 * @param header_buffer_size
8465 * @param payload_buffer_size
8466 * @param ulp The ULP to bind
8467 *
8468 * @return Returns 0 on success, or -1 on failure.
8469 */
8470int32_t
8471sli_fc_rq_set_alloc(sli4_t *sli4, uint32_t num_rq_pairs,
8472		    sli4_queue_t *qs[], uint32_t base_cq_id,
8473		    uint32_t n_entries, uint32_t header_buffer_size,
8474		    uint32_t payload_buffer_size,  uint16_t ulp)
8475{
8476	uint32_t i, p, offset = 0;
8477	uint32_t payload_size, total_page_count = 0;
8478	uintptr_t addr;
8479	ocs_dma_t dma;
8480	sli4_res_common_create_queue_set_t *rsp = NULL;
8481	sli4_req_fcoe_rq_create_v2_t    *req = NULL;
8482
8483	for (i = 0; i < (num_rq_pairs * 2); i++) {
8484		if (__sli_queue_init(sli4, qs[i], SLI_QTYPE_RQ, SLI4_FCOE_RQE_SIZE,
8485					n_entries, SLI_PAGE_SIZE)) {
8486			goto error;
8487		}
8488	}
8489
8490	total_page_count = sli_page_count(qs[0]->dma.size, SLI_PAGE_SIZE) * num_rq_pairs * 2;
8491
8492	/* Payload length must accommodate both request and response */
8493	payload_size = max((sizeof(sli4_req_fcoe_rq_create_v1_t) + (8 * total_page_count)),
8494			 sizeof(sli4_res_common_create_queue_set_t));
8495
8496	if (ocs_dma_alloc(sli4->os, &dma, payload_size, SLI_PAGE_SIZE)) {
8497		ocs_log_err(sli4->os, "DMA allocation failed\n");
8498		goto error;
8499	}
8500	ocs_memset(dma.virt, 0, payload_size);
8501
8502	if (sli_cmd_sli_config(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE,
8503			payload_size, &dma) == -1) {
8504		goto error;
8505	}
8506	req = (sli4_req_fcoe_rq_create_v2_t *)((uint8_t *)dma.virt);
8507
8508	/* Fill Header fields */
8509	req->hdr.opcode    = SLI4_OPC_FCOE_RQ_CREATE;
8510	req->hdr.subsystem = SLI4_SUBSYSTEM_FCFCOE;
8511	req->hdr.version   = 2;
8512	req->hdr.request_length = sizeof(sli4_req_fcoe_rq_create_v2_t) - sizeof(sli4_req_hdr_t)
8513					+ (8 * total_page_count);
8514
8515	/* Fill Payload fields */
8516	req->dnb           = TRUE;
8517	req->num_pages     = sli_page_count(qs[0]->dma.size, SLI_PAGE_SIZE);
8518	req->rqe_count     = qs[0]->dma.size / SLI4_FCOE_RQE_SIZE;
8519	req->rqe_size      = SLI4_FCOE_RQE_SIZE_8;
8520	req->page_size     = SLI4_FCOE_RQ_PAGE_SIZE_4096;
8521	req->rq_count      = num_rq_pairs * 2;
8522	req->base_cq_id    = base_cq_id;
8523	req->hdr_buffer_size     = header_buffer_size;
8524	req->payload_buffer_size = payload_buffer_size;
8525
8526	for (i = 0; i < (num_rq_pairs * 2); i++) {
8527		for (p = 0, addr = qs[i]->dma.phys; p < req->num_pages; p++, addr += SLI_PAGE_SIZE) {
8528			req->page_physical_address[offset].low  = ocs_addr32_lo(addr);
8529			req->page_physical_address[offset].high = ocs_addr32_hi(addr);
8530			offset++;
8531		}
8532	}
8533
8534	if (sli_bmbx_command(sli4)){
8535		ocs_log_crit(sli4->os, "bootstrap mailbox write faild RQSet\n");
8536		goto error;
8537	}
8538
8539
8540	rsp = (void *)((uint8_t *)dma.virt);
8541	if (rsp->hdr.status) {
8542		ocs_log_err(sli4->os, "bad create RQSet status=%#x addl=%#x\n",
8543			rsp->hdr.status, rsp->hdr.additional_status);
8544		goto error;
8545	} else {
8546		for (i = 0; i < (num_rq_pairs * 2); i++) {
8547			qs[i]->id = i + rsp->q_id;
8548			if ((qs[i]->id & 1) == 0) {
8549				qs[i]->u.flag.is_hdr = TRUE;
8550			} else {
8551				qs[i]->u.flag.is_hdr = FALSE;
8552			}
8553			qs[i]->doorbell_offset = regmap[SLI4_REG_FCOE_RQ_DOORBELL][sli4->if_type].off;
8554			qs[i]->doorbell_rset = regmap[SLI4_REG_FCOE_RQ_DOORBELL][sli4->if_type].rset;
8555		}
8556	}
8557
8558	ocs_dma_free(sli4->os, &dma);
8559
8560	return 0;
8561
8562error:
8563	for (i = 0; i < (num_rq_pairs * 2); i++) {
8564		if (qs[i]->dma.size) {
8565			ocs_dma_free(sli4->os, &qs[i]->dma);
8566		}
8567	}
8568
8569	if (dma.size) {
8570		ocs_dma_free(sli4->os, &dma);
8571	}
8572
8573	return -1;
8574}
8575
8576/**
8577 * @ingroup sli_fc
8578 * @brief Get the RPI resource requirements.
8579 *
8580 * @param sli4 SLI context.
8581 * @param n_rpi Number of RPIs desired.
8582 *
8583 * @return Returns the number of bytes needed. This value may be zero.
8584 */
8585uint32_t
8586sli_fc_get_rpi_requirements(sli4_t *sli4, uint32_t n_rpi)
8587{
8588	uint32_t	bytes = 0;
8589
8590	/* Check if header templates needed */
8591	if (sli4->config.hdr_template_req) {
8592		/* round up to a page */
8593		bytes = SLI_ROUND_PAGE(n_rpi * SLI4_FCOE_HDR_TEMPLATE_SIZE);
8594	}
8595
8596	return bytes;
8597}
8598
8599/**
8600 * @ingroup sli_fc
8601 * @brief Return a text string corresponding to a CQE status value
8602 *
8603 * @param status Status value
8604 *
8605 * @return Returns corresponding string, otherwise "unknown"
8606 */
8607const char *
8608sli_fc_get_status_string(uint32_t status)
8609{
8610	static struct {
8611		uint32_t code;
8612		const char *label;
8613	} lookup[] = {
8614		{SLI4_FC_WCQE_STATUS_SUCCESS,			"SUCCESS"},
8615		{SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE,		"FCP_RSP_FAILURE"},
8616		{SLI4_FC_WCQE_STATUS_REMOTE_STOP,		"REMOTE_STOP"},
8617		{SLI4_FC_WCQE_STATUS_LOCAL_REJECT,		"LOCAL_REJECT"},
8618		{SLI4_FC_WCQE_STATUS_NPORT_RJT,			"NPORT_RJT"},
8619		{SLI4_FC_WCQE_STATUS_FABRIC_RJT,		"FABRIC_RJT"},
8620		{SLI4_FC_WCQE_STATUS_NPORT_BSY,			"NPORT_BSY"},
8621		{SLI4_FC_WCQE_STATUS_FABRIC_BSY,		"FABRIC_BSY"},
8622		{SLI4_FC_WCQE_STATUS_LS_RJT,			"LS_RJT"},
8623		{SLI4_FC_WCQE_STATUS_CMD_REJECT,		"CMD_REJECT"},
8624		{SLI4_FC_WCQE_STATUS_FCP_TGT_LENCHECK,		"FCP_TGT_LENCHECK"},
8625		{SLI4_FC_WCQE_STATUS_RQ_BUF_LEN_EXCEEDED,	"BUF_LEN_EXCEEDED"},
8626		{SLI4_FC_WCQE_STATUS_RQ_INSUFF_BUF_NEEDED,	"RQ_INSUFF_BUF_NEEDED"},
8627		{SLI4_FC_WCQE_STATUS_RQ_INSUFF_FRM_DISC,	"RQ_INSUFF_FRM_DESC"},
8628		{SLI4_FC_WCQE_STATUS_RQ_DMA_FAILURE,		"RQ_DMA_FAILURE"},
8629		{SLI4_FC_WCQE_STATUS_FCP_RSP_TRUNCATE,		"FCP_RSP_TRUNCATE"},
8630		{SLI4_FC_WCQE_STATUS_DI_ERROR,			"DI_ERROR"},
8631		{SLI4_FC_WCQE_STATUS_BA_RJT,			"BA_RJT"},
8632		{SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_NEEDED,	"RQ_INSUFF_XRI_NEEDED"},
8633		{SLI4_FC_WCQE_STATUS_RQ_INSUFF_XRI_DISC,	"INSUFF_XRI_DISC"},
8634		{SLI4_FC_WCQE_STATUS_RX_ERROR_DETECT,		"RX_ERROR_DETECT"},
8635		{SLI4_FC_WCQE_STATUS_RX_ABORT_REQUEST,		"RX_ABORT_REQUEST"},
8636		};
8637	uint32_t i;
8638
8639	for (i = 0; i < ARRAY_SIZE(lookup); i++) {
8640		if (status == lookup[i].code) {
8641			return lookup[i].label;
8642		}
8643	}
8644	return "unknown";
8645}
8646