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