1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at
9 * http://www.opensource.org/licenses/cddl1.txt.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2004-2011 Emulex. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <emlxs.h>
28
29/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
30EMLXS_MSG_DEF(EMLXS_IP_C);
31
32
33extern int32_t
34emlxs_ip_handle_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
35{
36	emlxs_port_t *port = &PPORT;
37	IOCB *cmd;
38	emlxs_buf_t *sbp;
39	NODELIST *ndlp;
40
41	cmd = &iocbq->iocb;
42
43	HBASTATS.IpEvent++;
44
45	sbp = (emlxs_buf_t *)iocbq->sbp;
46
47	if (!sbp) {
48		HBASTATS.IpStray++;
49
50		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ip_completion_msg,
51		    "cmd=0x%x iotag=0x%x status=0x%x perr=0x%x",
52		    (uint32_t)cmd->ULPCOMMAND, (uint32_t)cmd->ULPIOTAG,
53		    cmd->ULPSTATUS, cmd->un.ulpWord[4]);
54
55		return (EIO);
56	}
57
58	if (cp->channelno != hba->channel_ip) {
59		HBASTATS.IpStray++;
60
61		return (0);
62	}
63
64	port = sbp->iocbq.port;
65
66	switch (cmd->ULPCOMMAND) {
67		/*
68		 * Error: Abnormal BCAST command completion  (Local error)
69		 */
70	case CMD_XMIT_BCAST_CN:
71	case CMD_XMIT_BCAST64_CN:
72
73		HBASTATS.IpBcastCompleted++;
74		HBASTATS.IpBcastError++;
75
76		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
77		    "XMIT BCAST completion error cmd=0x%x status=0x%x "
78		    "[%08x,%08x]", cmd->ULPCOMMAND, cmd->ULPSTATUS,
79		    cmd->un.ulpWord[4], cmd->un.ulpWord[5]);
80
81		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
82		    cmd->un.grsp.perr.statLocalError, 1);
83
84		break;
85
86		/*
87		 * Error: Abnormal XMIT SEQUENCE command completion
88		 * (Local error)
89		 */
90	case CMD_XMIT_SEQUENCE_CR:
91	case CMD_XMIT_SEQUENCE64_CR:
92
93		HBASTATS.IpSeqCompleted++;
94		HBASTATS.IpSeqError++;
95
96		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
97		    "XMIT SEQUENCE CR completion error: cmd=%x status=0x%x "
98		    "[%08x,%08x]", cmd->ULPCOMMAND, cmd->ULPSTATUS,
99		    cmd->un.ulpWord[4], cmd->un.ulpWord[5]);
100
101		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
102		    cmd->un.grsp.perr.statLocalError, 1);
103
104		break;
105
106		/*
107		 * Normal BCAST completion
108		 */
109	case CMD_XMIT_BCAST_CX:
110	case CMD_XMIT_BCAST64_CX:
111
112		HBASTATS.IpBcastCompleted++;
113		HBASTATS.IpBcastGood++;
114
115		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
116		    "XMIT BCAST CN completion: cmd=%x status=0x%x [%08x,%08x]",
117		    cmd->ULPCOMMAND, cmd->ULPSTATUS, cmd->un.ulpWord[4],
118		    cmd->un.ulpWord[5]);
119
120		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
121		    cmd->un.grsp.perr.statLocalError, 1);
122
123		break;
124
125		/*
126		 * Normal XMIT SEQUENCE completion
127		 */
128	case CMD_XMIT_SEQUENCE_CX:
129	case CMD_XMIT_SEQUENCE64_CX:
130
131		HBASTATS.IpSeqCompleted++;
132
133		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
134		    "XMIT SEQUENCE CR completion: cmd=%x status=0x%x"
135		    "[%08x,%08x]", cmd->ULPCOMMAND, cmd->ULPSTATUS,
136		    cmd->un.ulpWord[4], cmd->un.ulpWord[5]);
137
138		if (cmd->ULPSTATUS) {
139			HBASTATS.IpSeqError++;
140
141			if ((cmd->ULPSTATUS == IOSTAT_LOCAL_REJECT) &&
142			    ((cmd->un.ulpWord[4] & 0xff) == IOERR_NO_XRI)) {
143				ndlp = (NODELIST *)sbp->node;
144				if ((cmd->ULPCONTEXT == ndlp->nlp_Xri) &&
145				    !(ndlp->nlp_flag[hba->channel_ip] &
146				    NLP_RPI_XRI)) {
147					ndlp->nlp_Xri = 0;
148					(void) emlxs_create_xri(port, cp, ndlp);
149				}
150			}
151		} else {
152			HBASTATS.IpSeqGood++;
153		}
154
155		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
156		    cmd->un.grsp.perr.statLocalError, 1);
157
158		break;
159
160	default:
161
162		HBASTATS.IpStray++;
163
164		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_ip_msg,
165		    "Invalid iocb: cmd=0x%x", cmd->ULPCOMMAND);
166
167		break;
168
169	}	/* switch(cmd->ULPCOMMAND) */
170
171
172	return (0);
173
174} /* emlxs_ip_handle_event() */
175
176
177extern int32_t
178emlxs_ip_handle_unsol_req(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
179    MATCHMAP *mp, uint32_t size)
180{
181	emlxs_hba_t *hba = HBA;
182	fc_unsol_buf_t *ubp;
183	IOCB *cmd;
184	NETHDR *nd;
185	NODELIST *ndlp;
186	uint8_t *mac;
187	emlxs_ub_priv_t *ub_priv;
188	uint32_t sid;
189	uint32_t i;
190	uint32_t IpDropped = 1;
191	uint32_t IpBcastReceived = 0;
192	uint32_t IpSeqReceived = 0;
193
194	cmd = &iocbq->iocb;
195	ubp = NULL;
196
197	for (i = 0; i < MAX_VPORTS; i++) {
198		port = &VPORT(i);
199
200		if (!(port->flag & EMLXS_INI_BOUND) ||
201		    !(port->flag & EMLXS_PORT_IP_UP)) {
202			continue;
203		}
204
205		ubp =
206		    (fc_unsol_buf_t *)emlxs_ub_get(port, size,
207		    FC_TYPE_IS8802_SNAP, 0);
208
209		if (!ubp) {
210			/* Theoretically we should never get here. */
211			/* There should be one DMA buffer for every ub */
212			/* buffer. If we are out of ub buffers */
213			/* then some how this matching has been corrupted */
214
215			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ip_dropped_msg,
216			    "Buffer not found. paddr=%lx",
217			    PADDR(cmd->un.cont64[0].addrHigh,
218			    cmd->un.cont64[0].addrLow));
219
220			continue;
221		}
222
223		bcopy(mp->virt, ubp->ub_buffer, size);
224
225		ub_priv = ubp->ub_fca_private;
226		nd = (NETHDR *)ubp->ub_buffer;
227		mac = nd->fc_srcname.IEEE;
228		ndlp = emlxs_node_find_mac(port, mac);
229
230		if (ndlp) {
231			sid = ndlp->nlp_DID;
232
233			if ((ndlp->nlp_Xri == 0) &&
234			    !(ndlp->nlp_flag[hba->channel_ip] & NLP_RPI_XRI)) {
235				(void) emlxs_create_xri(port, cp, ndlp);
236			}
237		}
238
239		/*
240		 * If no node is found, then check if this is a
241		 * broadcast frame
242		 */
243		else if (cmd->un.xrseq.w5.hcsw.Fctl & BC) {
244			sid = cmd->un.ulpWord[4] & 0x00ffffff;
245		}
246
247		else {
248			/* We have to drop this frame because we do not have */
249			/* the S_ID of the request */
250			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ip_dropped_msg,
251			    "Node not found. mac=%02x%02x%02x%02x%02x%02x",
252			    mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
253
254			(void) emlxs_fca_ub_release((opaque_t)port, 1,
255			    &ubp->ub_token);
256
257			continue;
258		}
259
260		if (cmd->un.xrseq.w5.hcsw.Fctl & BC) {
261			IpBcastReceived++;
262		} else {
263			IpSeqReceived++;
264		}
265
266		/*
267		 * Setup frame header
268		 */
269		ubp->ub_frame.r_ctl = cmd->un.xrseq.w5.hcsw.Rctl;
270		ubp->ub_frame.type = cmd->un.xrseq.w5.hcsw.Type;
271		ubp->ub_frame.s_id = sid;
272		ubp->ub_frame.ox_id = ub_priv->token;
273		ubp->ub_frame.rx_id = cmd->ULPCONTEXT;
274		ubp->ub_class = FC_TRAN_CLASS3;
275
276		emlxs_ub_callback(port, ubp);
277		IpDropped = 0;
278	}
279	port = &PPORT;
280
281out:
282
283	if (IpDropped) {
284		HBASTATS.IpDropped++;
285	}
286
287	if (IpBcastReceived) {
288		HBASTATS.IpBcastReceived++;
289	}
290
291	if (IpSeqReceived) {
292		HBASTATS.IpSeqReceived++;
293	}
294
295	return (0);
296
297} /* emlxs_ip_handle_unsol_req() */
298
299
300extern int32_t
301emlxs_ip_handle_rcv_seq_list(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
302{
303	emlxs_port_t *port = &PPORT;
304	IOCB *cmd;
305	uint64_t bdeAddr;
306	MATCHMAP *mp = NULL;
307	HBQE_t *hbqE;
308	uint32_t hbq_id;
309	uint32_t hbqe_tag;
310	RING *rp;
311
312	/*
313	 * No action required for now.
314	 */
315	cmd = &iocbq->iocb;
316	rp = &hba->sli.sli3.ring[cp->channelno];
317
318	HBASTATS.IpRcvEvent++;
319
320	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
321	    "Receive sequence list: cmd=0x%x iotag=0x%x status=0x%x "
322	    "w4=0x%x channelno=0x%x", cmd->ULPCOMMAND, cmd->ULPIOTAG,
323	    cmd->ULPSTATUS, cmd->un.ulpWord[4], cp->channelno);
324
325	if (cmd->ULPSTATUS) {
326		goto out;
327	}
328
329	hbqE = (HBQE_t *)&iocbq->iocb;
330	hbq_id = hbqE->unt.ext.HBQ_tag;
331	hbqe_tag = hbqE->unt.ext.HBQE_tag;
332
333	if (hba->flag & FC_HBQ_ENABLED) {
334		HBQ_INIT_t *hbq;
335
336		hbq = &hba->sli.sli3.hbq_table[hbq_id];
337
338		HBASTATS.IpUbPosted--;
339
340		if (hbqe_tag >= hbq->HBQ_numEntries) {
341			mp = NULL;
342		} else {
343			mp = hba->sli.sli3.hbq_table
344			    [hbq_id].HBQ_PostBufs[hbqe_tag];
345		}
346	} else {
347		/* Check for valid buffer */
348		if (!(cmd->un.cont64[0].tus.f.bdeFlags & BUFF_TYPE_INVALID)) {
349			bdeAddr =
350			    PADDR(cmd->un.cont64[0].addrHigh,
351			    cmd->un.cont64[0].addrLow);
352			mp = emlxs_mem_get_vaddr(hba, rp, bdeAddr);
353		}
354	}
355
356out:
357
358	if (hba->flag & FC_HBQ_ENABLED) {
359		emlxs_update_HBQ_index(hba, hbq_id);
360	} else {
361		if (mp) {
362			emlxs_mem_put(hba, MEM_IPBUF, (void *)mp);
363		}
364		(void) emlxs_post_buffer(hba, rp, 1);
365	}
366
367	HBASTATS.IpDropped++;
368
369	return (0);
370
371} /* emlxs_ip_handle_rcv_seq_list() */
372
373
374
375/*
376 * Process a create_xri command completion.
377 */
378extern int32_t
379emlxs_handle_create_xri(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
380{
381	emlxs_port_t *port = &PPORT;
382	IOCB *cmd;
383	NODELIST *ndlp;
384	fc_packet_t *pkt;
385	emlxs_buf_t *sbp;
386	int32_t rval = 0;
387
388	cmd = &iocbq->iocb;
389
390	sbp = (emlxs_buf_t *)iocbq->sbp;
391
392	if (!sbp) {
393		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ip_completion_msg,
394		    "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x. "
395		    "NULL sbp found.",
396		    cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
397		    cmd->un.ulpWord[4]);
398
399		return (EIO);
400	}
401
402	/* check for first xmit completion in sequence */
403	ndlp = (NODELIST *)sbp->node;
404
405	if (!ndlp) {
406		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_bad_ip_completion_msg,
407		    "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x. "
408		    "NULL node found.",
409		    cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
410		    cmd->un.ulpWord[4]);
411
412		rval = EIO;
413		goto done;
414	}
415
416	if (cmd->ULPSTATUS) {
417		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_bad_ip_completion_msg,
418		    "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x. "
419		    "Completion error.",
420		    cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
421		    cmd->un.ulpWord[4]);
422
423		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
424		ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
425		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
426
427		rval = EIO;
428		goto done;
429	}
430
431	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
432	ndlp->nlp_Xri = cmd->ULPCONTEXT;
433	ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
434	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
435
436	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
437	    "create_xri completed: DID=0x%x Xri=0x%x iotag=0x%x",
438	    ndlp->nlp_DID, ndlp->nlp_Xri, cmd->ULPIOTAG);
439
440done:
441	pkt = sbp->pkt;
442	if (pkt) {
443		emlxs_pkt_free(pkt);
444	}
445
446	return (rval);
447
448} /* emlxs_handle_create_xri()  */
449
450
451/*
452 * Issue an iocb command to create an exchange with the remote Nport
453 * specified by the NODELIST entry.
454 */
455extern int32_t
456emlxs_create_xri(emlxs_port_t *port, CHANNEL *cp, NODELIST *ndlp)
457{
458	emlxs_hba_t *hba = HBA;
459	IOCB *icmd;
460	IOCBQ *iocbq;
461	fc_packet_t *pkt;
462	emlxs_buf_t *sbp;
463	uint16_t iotag;
464
465	/* Check if an XRI has already been requested */
466	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
467	if (ndlp->nlp_Xri != 0 ||
468	    (ndlp->nlp_flag[cp->channelno] & NLP_RPI_XRI)) {
469		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
470		return (0);
471	}
472	ndlp->nlp_flag[cp->channelno] |= NLP_RPI_XRI;
473	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
474
475	if (!(pkt = emlxs_pkt_alloc(port, 0, 0, 0, KM_NOSLEEP))) {
476		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
477		    "create_xri failed: Unable to allocate pkt. did=0x%x",
478		    ndlp->nlp_DID);
479
480		goto fail;
481	}
482
483	sbp = (emlxs_buf_t *)pkt->pkt_fca_private;
484	iocbq = &sbp->iocbq;
485
486	/* Clear the PACKET_ULP_OWNED flag */
487	sbp->pkt_flags &= ~PACKET_ULP_OWNED;
488
489	/* Get the iotag by registering the packet */
490	iotag = emlxs_register_pkt(cp, sbp);
491
492	if (!iotag) {
493		/*
494		 * No more command slots available, retry later
495		 */
496		emlxs_pkt_free(pkt);
497
498		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
499		    "create_xri failed: Unable to allocate IOTAG. did=0x%x",
500		    ndlp->nlp_DID);
501
502		goto fail;
503	}
504
505	icmd = &iocbq->iocb;
506	icmd->ULPIOTAG = iotag;
507	icmd->ULPCONTEXT = ndlp->nlp_Rpi;
508	icmd->ULPLE = 1;
509	icmd->ULPCOMMAND = CMD_CREATE_XRI_CR;
510	icmd->ULPOWNER = OWN_CHIP;
511
512	/* Initalize iocbq */
513	iocbq->port = (void *)port;
514	iocbq->node = (void *)ndlp;
515	iocbq->channel = (void *)cp;
516
517	mutex_enter(&sbp->mtx);
518	sbp->node = (void *)ndlp;
519	sbp->channel = cp;
520	mutex_exit(&sbp->mtx);
521
522	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
523	    "create_xri sent: DID=0x%x Xri=0x%x iotag=0x%x", ndlp->nlp_DID,
524	    ndlp->nlp_Xri, iotag);
525
526	EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
527
528	return (0);
529
530fail:
531
532	/* Clear the XRI flag */
533	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
534	ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
535	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
536
537	return (1);
538
539} /* emlxs_create_xri() */
540