xref: /openbmc/linux/net/ncsi/ncsi-rsp.c (revision 360823a09426347ea8f232b0b0b5156d0aed0302)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2138635ccSGavin Shan /*
3138635ccSGavin Shan  * Copyright Gavin Shan, IBM Corporation 2016.
4138635ccSGavin Shan  */
5138635ccSGavin Shan 
6138635ccSGavin Shan #include <linux/module.h>
7138635ccSGavin Shan #include <linux/kernel.h>
8138635ccSGavin Shan #include <linux/init.h>
9138635ccSGavin Shan #include <linux/netdevice.h>
101c5c12eeSTao Ren #include <linux/etherdevice.h>
11138635ccSGavin Shan #include <linux/skbuff.h>
12138635ccSGavin Shan 
13138635ccSGavin Shan #include <net/ncsi.h>
14138635ccSGavin Shan #include <net/net_namespace.h>
15138635ccSGavin Shan #include <net/sock.h>
169771b8ccSJustin.Lee1@Dell.com #include <net/genetlink.h>
17138635ccSGavin Shan 
18138635ccSGavin Shan #include "internal.h"
19138635ccSGavin Shan #include "ncsi-pkt.h"
209771b8ccSJustin.Lee1@Dell.com #include "ncsi-netlink.h"
21138635ccSGavin Shan 
221c83c708SPeter Delevoryas /* Nibbles within [0xA, 0xF] add zero "0" to the returned value.
231c83c708SPeter Delevoryas  * Optional fields (encoded as 0xFF) will default to zero.
241c83c708SPeter Delevoryas  */
decode_bcd_u8(u8 x)251c83c708SPeter Delevoryas static u8 decode_bcd_u8(u8 x)
261c83c708SPeter Delevoryas {
271c83c708SPeter Delevoryas 	int lo = x & 0xF;
281c83c708SPeter Delevoryas 	int hi = x >> 4;
291c83c708SPeter Delevoryas 
301c83c708SPeter Delevoryas 	lo = lo < 0xA ? lo : 0;
311c83c708SPeter Delevoryas 	hi = hi < 0xA ? hi : 0;
321c83c708SPeter Delevoryas 	return lo + hi * 10;
331c83c708SPeter Delevoryas }
341c83c708SPeter Delevoryas 
ncsi_validate_rsp_pkt(struct ncsi_request * nr,unsigned short payload)35138635ccSGavin Shan static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
36138635ccSGavin Shan 				 unsigned short payload)
37138635ccSGavin Shan {
38138635ccSGavin Shan 	struct ncsi_rsp_pkt_hdr *h;
39138635ccSGavin Shan 	u32 checksum;
40138635ccSGavin Shan 	__be32 *pchecksum;
41138635ccSGavin Shan 
42138635ccSGavin Shan 	/* Check NCSI packet header. We don't need validate
43138635ccSGavin Shan 	 * the packet type, which should have been checked
44138635ccSGavin Shan 	 * before calling this function.
45138635ccSGavin Shan 	 */
46138635ccSGavin Shan 	h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp);
479771b8ccSJustin.Lee1@Dell.com 
489771b8ccSJustin.Lee1@Dell.com 	if (h->common.revision != NCSI_PKT_REVISION) {
499771b8ccSJustin.Lee1@Dell.com 		netdev_dbg(nr->ndp->ndev.dev,
509771b8ccSJustin.Lee1@Dell.com 			   "NCSI: unsupported header revision\n");
51138635ccSGavin Shan 		return -EINVAL;
529771b8ccSJustin.Lee1@Dell.com 	}
539771b8ccSJustin.Lee1@Dell.com 	if (ntohs(h->common.length) != payload) {
549771b8ccSJustin.Lee1@Dell.com 		netdev_dbg(nr->ndp->ndev.dev,
559771b8ccSJustin.Lee1@Dell.com 			   "NCSI: payload length mismatched\n");
56138635ccSGavin Shan 		return -EINVAL;
579771b8ccSJustin.Lee1@Dell.com 	}
58138635ccSGavin Shan 
59138635ccSGavin Shan 	/* Check on code and reason */
60138635ccSGavin Shan 	if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED ||
619771b8ccSJustin.Lee1@Dell.com 	    ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) {
629771b8ccSJustin.Lee1@Dell.com 		netdev_dbg(nr->ndp->ndev.dev,
6396a1b033STerry S. Duncan 			   "NCSI: non zero response/reason code %04xh, %04xh\n",
6496a1b033STerry S. Duncan 			    ntohs(h->code), ntohs(h->reason));
659771b8ccSJustin.Lee1@Dell.com 		return -EPERM;
669771b8ccSJustin.Lee1@Dell.com 	}
67138635ccSGavin Shan 
68138635ccSGavin Shan 	/* Validate checksum, which might be zeroes if the
69138635ccSGavin Shan 	 * sender doesn't support checksum according to NCSI
70138635ccSGavin Shan 	 * specification.
71138635ccSGavin Shan 	 */
7296a1b033STerry S. Duncan 	pchecksum = (__be32 *)((void *)(h + 1) + ALIGN(payload, 4) - 4);
73138635ccSGavin Shan 	if (ntohl(*pchecksum) == 0)
74138635ccSGavin Shan 		return 0;
75138635ccSGavin Shan 
76138635ccSGavin Shan 	checksum = ncsi_calculate_checksum((unsigned char *)h,
77138635ccSGavin Shan 					   sizeof(*h) + payload - 4);
789771b8ccSJustin.Lee1@Dell.com 
799771b8ccSJustin.Lee1@Dell.com 	if (*pchecksum != htonl(checksum)) {
8096a1b033STerry S. Duncan 		netdev_dbg(nr->ndp->ndev.dev,
8196a1b033STerry S. Duncan 			   "NCSI: checksum mismatched; recd: %08x calc: %08x\n",
8296a1b033STerry S. Duncan 			   *pchecksum, htonl(checksum));
83138635ccSGavin Shan 		return -EINVAL;
849771b8ccSJustin.Lee1@Dell.com 	}
85138635ccSGavin Shan 
86138635ccSGavin Shan 	return 0;
87138635ccSGavin Shan }
88138635ccSGavin Shan 
ncsi_rsp_handler_cis(struct ncsi_request * nr)89138635ccSGavin Shan static int ncsi_rsp_handler_cis(struct ncsi_request *nr)
90138635ccSGavin Shan {
91138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
92138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
93138635ccSGavin Shan 	struct ncsi_package *np;
94138635ccSGavin Shan 	struct ncsi_channel *nc;
95138635ccSGavin Shan 	unsigned char id;
96138635ccSGavin Shan 
97138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
98138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, &nc);
99138635ccSGavin Shan 	if (!nc) {
100e6f44ed6SGavin Shan 		if (ndp->flags & NCSI_DEV_PROBED)
101e6f44ed6SGavin Shan 			return -ENXIO;
102e6f44ed6SGavin Shan 
103138635ccSGavin Shan 		id = NCSI_CHANNEL_INDEX(rsp->rsp.common.channel);
104138635ccSGavin Shan 		nc = ncsi_add_channel(np, id);
105138635ccSGavin Shan 	}
106138635ccSGavin Shan 
107138635ccSGavin Shan 	return nc ? 0 : -ENODEV;
108138635ccSGavin Shan }
109138635ccSGavin Shan 
ncsi_rsp_handler_sp(struct ncsi_request * nr)110138635ccSGavin Shan static int ncsi_rsp_handler_sp(struct ncsi_request *nr)
111138635ccSGavin Shan {
112138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
113138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
114138635ccSGavin Shan 	struct ncsi_package *np;
115138635ccSGavin Shan 	unsigned char id;
116138635ccSGavin Shan 
117138635ccSGavin Shan 	/* Add the package if it's not existing. Otherwise,
118138635ccSGavin Shan 	 * to change the state of its child channels.
119138635ccSGavin Shan 	 */
120138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
121138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
122138635ccSGavin Shan 				      &np, NULL);
123138635ccSGavin Shan 	if (!np) {
124e6f44ed6SGavin Shan 		if (ndp->flags & NCSI_DEV_PROBED)
125e6f44ed6SGavin Shan 			return -ENXIO;
126e6f44ed6SGavin Shan 
127138635ccSGavin Shan 		id = NCSI_PACKAGE_INDEX(rsp->rsp.common.channel);
128138635ccSGavin Shan 		np = ncsi_add_package(ndp, id);
129138635ccSGavin Shan 		if (!np)
130138635ccSGavin Shan 			return -ENODEV;
131138635ccSGavin Shan 	}
132138635ccSGavin Shan 
133138635ccSGavin Shan 	return 0;
134138635ccSGavin Shan }
135138635ccSGavin Shan 
ncsi_rsp_handler_dp(struct ncsi_request * nr)136138635ccSGavin Shan static int ncsi_rsp_handler_dp(struct ncsi_request *nr)
137138635ccSGavin Shan {
138138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
139138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
140138635ccSGavin Shan 	struct ncsi_package *np;
141138635ccSGavin Shan 	struct ncsi_channel *nc;
142138635ccSGavin Shan 	unsigned long flags;
143138635ccSGavin Shan 
144138635ccSGavin Shan 	/* Find the package */
145138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
146138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
147138635ccSGavin Shan 				      &np, NULL);
148138635ccSGavin Shan 	if (!np)
149138635ccSGavin Shan 		return -ENODEV;
150138635ccSGavin Shan 
151138635ccSGavin Shan 	/* Change state of all channels attached to the package */
152138635ccSGavin Shan 	NCSI_FOR_EACH_CHANNEL(np, nc) {
153138635ccSGavin Shan 		spin_lock_irqsave(&nc->lock, flags);
154138635ccSGavin Shan 		nc->state = NCSI_CHANNEL_INACTIVE;
155138635ccSGavin Shan 		spin_unlock_irqrestore(&nc->lock, flags);
156138635ccSGavin Shan 	}
157138635ccSGavin Shan 
158138635ccSGavin Shan 	return 0;
159138635ccSGavin Shan }
160138635ccSGavin Shan 
ncsi_rsp_handler_ec(struct ncsi_request * nr)161138635ccSGavin Shan static int ncsi_rsp_handler_ec(struct ncsi_request *nr)
162138635ccSGavin Shan {
163138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
164138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
165138635ccSGavin Shan 	struct ncsi_channel *nc;
166138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
167138635ccSGavin Shan 
168138635ccSGavin Shan 	/* Find the package and channel */
169138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
170138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
171138635ccSGavin Shan 				      NULL, &nc);
172138635ccSGavin Shan 	if (!nc)
173138635ccSGavin Shan 		return -ENODEV;
174138635ccSGavin Shan 
175138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_ENABLE];
176138635ccSGavin Shan 	if (ncm->enable)
17704bad8bdSSamuel Mendoza-Jonas 		return 0;
178138635ccSGavin Shan 
179138635ccSGavin Shan 	ncm->enable = 1;
180138635ccSGavin Shan 	return 0;
181138635ccSGavin Shan }
182138635ccSGavin Shan 
ncsi_rsp_handler_dc(struct ncsi_request * nr)183138635ccSGavin Shan static int ncsi_rsp_handler_dc(struct ncsi_request *nr)
184138635ccSGavin Shan {
185138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
186138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
187138635ccSGavin Shan 	struct ncsi_channel *nc;
188138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
189138635ccSGavin Shan 	int ret;
190138635ccSGavin Shan 
191138635ccSGavin Shan 	ret = ncsi_validate_rsp_pkt(nr, 4);
192138635ccSGavin Shan 	if (ret)
193138635ccSGavin Shan 		return ret;
194138635ccSGavin Shan 
195138635ccSGavin Shan 	/* Find the package and channel */
196138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
197138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
198138635ccSGavin Shan 				      NULL, &nc);
199138635ccSGavin Shan 	if (!nc)
200138635ccSGavin Shan 		return -ENODEV;
201138635ccSGavin Shan 
202138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_ENABLE];
203138635ccSGavin Shan 	if (!ncm->enable)
20404bad8bdSSamuel Mendoza-Jonas 		return 0;
205138635ccSGavin Shan 
206138635ccSGavin Shan 	ncm->enable = 0;
207138635ccSGavin Shan 	return 0;
208138635ccSGavin Shan }
209138635ccSGavin Shan 
ncsi_rsp_handler_rc(struct ncsi_request * nr)210138635ccSGavin Shan static int ncsi_rsp_handler_rc(struct ncsi_request *nr)
211138635ccSGavin Shan {
212138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
213138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
214138635ccSGavin Shan 	struct ncsi_channel *nc;
215138635ccSGavin Shan 	unsigned long flags;
216138635ccSGavin Shan 
217138635ccSGavin Shan 	/* Find the package and channel */
218138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
219138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
220138635ccSGavin Shan 				      NULL, &nc);
221138635ccSGavin Shan 	if (!nc)
222138635ccSGavin Shan 		return -ENODEV;
223138635ccSGavin Shan 
224138635ccSGavin Shan 	/* Update state for the specified channel */
225138635ccSGavin Shan 	spin_lock_irqsave(&nc->lock, flags);
226138635ccSGavin Shan 	nc->state = NCSI_CHANNEL_INACTIVE;
227138635ccSGavin Shan 	spin_unlock_irqrestore(&nc->lock, flags);
228138635ccSGavin Shan 
229138635ccSGavin Shan 	return 0;
230138635ccSGavin Shan }
231138635ccSGavin Shan 
ncsi_rsp_handler_ecnt(struct ncsi_request * nr)232138635ccSGavin Shan static int ncsi_rsp_handler_ecnt(struct ncsi_request *nr)
233138635ccSGavin Shan {
234138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
235138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
236138635ccSGavin Shan 	struct ncsi_channel *nc;
237138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
238138635ccSGavin Shan 
239138635ccSGavin Shan 	/* Find the package and channel */
240138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
241138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
242138635ccSGavin Shan 				      NULL, &nc);
243138635ccSGavin Shan 	if (!nc)
244138635ccSGavin Shan 		return -ENODEV;
245138635ccSGavin Shan 
246138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
247138635ccSGavin Shan 	if (ncm->enable)
24804bad8bdSSamuel Mendoza-Jonas 		return 0;
249138635ccSGavin Shan 
250138635ccSGavin Shan 	ncm->enable = 1;
251138635ccSGavin Shan 	return 0;
252138635ccSGavin Shan }
253138635ccSGavin Shan 
ncsi_rsp_handler_dcnt(struct ncsi_request * nr)254138635ccSGavin Shan static int ncsi_rsp_handler_dcnt(struct ncsi_request *nr)
255138635ccSGavin Shan {
256138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
257138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
258138635ccSGavin Shan 	struct ncsi_channel *nc;
259138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
260138635ccSGavin Shan 
261138635ccSGavin Shan 	/* Find the package and channel */
262138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
263138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
264138635ccSGavin Shan 				      NULL, &nc);
265138635ccSGavin Shan 	if (!nc)
266138635ccSGavin Shan 		return -ENODEV;
267138635ccSGavin Shan 
268138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
269138635ccSGavin Shan 	if (!ncm->enable)
27004bad8bdSSamuel Mendoza-Jonas 		return 0;
271138635ccSGavin Shan 
2728d951a75SSamuel Mendoza-Jonas 	ncm->enable = 0;
273138635ccSGavin Shan 	return 0;
274138635ccSGavin Shan }
275138635ccSGavin Shan 
ncsi_rsp_handler_ae(struct ncsi_request * nr)276138635ccSGavin Shan static int ncsi_rsp_handler_ae(struct ncsi_request *nr)
277138635ccSGavin Shan {
278138635ccSGavin Shan 	struct ncsi_cmd_ae_pkt *cmd;
279138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
280138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
281138635ccSGavin Shan 	struct ncsi_channel *nc;
282138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
283138635ccSGavin Shan 
284138635ccSGavin Shan 	/* Find the package and channel */
285138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
286138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
287138635ccSGavin Shan 				      NULL, &nc);
288138635ccSGavin Shan 	if (!nc)
289138635ccSGavin Shan 		return -ENODEV;
290138635ccSGavin Shan 
291138635ccSGavin Shan 	/* Check if the AEN has been enabled */
292138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_AEN];
293138635ccSGavin Shan 	if (ncm->enable)
29404bad8bdSSamuel Mendoza-Jonas 		return 0;
295138635ccSGavin Shan 
296138635ccSGavin Shan 	/* Update to AEN configuration */
297138635ccSGavin Shan 	cmd = (struct ncsi_cmd_ae_pkt *)skb_network_header(nr->cmd);
298138635ccSGavin Shan 	ncm->enable = 1;
299138635ccSGavin Shan 	ncm->data[0] = cmd->mc_id;
300138635ccSGavin Shan 	ncm->data[1] = ntohl(cmd->mode);
301138635ccSGavin Shan 
302138635ccSGavin Shan 	return 0;
303138635ccSGavin Shan }
304138635ccSGavin Shan 
ncsi_rsp_handler_sl(struct ncsi_request * nr)305138635ccSGavin Shan static int ncsi_rsp_handler_sl(struct ncsi_request *nr)
306138635ccSGavin Shan {
307138635ccSGavin Shan 	struct ncsi_cmd_sl_pkt *cmd;
308138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
309138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
310138635ccSGavin Shan 	struct ncsi_channel *nc;
311138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
312138635ccSGavin Shan 
313138635ccSGavin Shan 	/* Find the package and channel */
314138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
315138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
316138635ccSGavin Shan 				      NULL, &nc);
317138635ccSGavin Shan 	if (!nc)
318138635ccSGavin Shan 		return -ENODEV;
319138635ccSGavin Shan 
320138635ccSGavin Shan 	cmd = (struct ncsi_cmd_sl_pkt *)skb_network_header(nr->cmd);
321138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_LINK];
322138635ccSGavin Shan 	ncm->data[0] = ntohl(cmd->mode);
323138635ccSGavin Shan 	ncm->data[1] = ntohl(cmd->oem_mode);
324138635ccSGavin Shan 
325138635ccSGavin Shan 	return 0;
326138635ccSGavin Shan }
327138635ccSGavin Shan 
ncsi_rsp_handler_gls(struct ncsi_request * nr)328138635ccSGavin Shan static int ncsi_rsp_handler_gls(struct ncsi_request *nr)
329138635ccSGavin Shan {
330138635ccSGavin Shan 	struct ncsi_rsp_gls_pkt *rsp;
331138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
332138635ccSGavin Shan 	struct ncsi_channel *nc;
333138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
334e6f44ed6SGavin Shan 	unsigned long flags;
335138635ccSGavin Shan 
336138635ccSGavin Shan 	/* Find the package and channel */
337138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gls_pkt *)skb_network_header(nr->rsp);
338138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
339138635ccSGavin Shan 				      NULL, &nc);
340138635ccSGavin Shan 	if (!nc)
341138635ccSGavin Shan 		return -ENODEV;
342138635ccSGavin Shan 
343138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_LINK];
344138635ccSGavin Shan 	ncm->data[2] = ntohl(rsp->status);
345138635ccSGavin Shan 	ncm->data[3] = ntohl(rsp->other);
346138635ccSGavin Shan 	ncm->data[4] = ntohl(rsp->oem_status);
347138635ccSGavin Shan 
348a0509cbeSGavin Shan 	if (nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN)
349e6f44ed6SGavin Shan 		return 0;
350e6f44ed6SGavin Shan 
351e6f44ed6SGavin Shan 	/* Reset the channel monitor if it has been enabled */
352e6f44ed6SGavin Shan 	spin_lock_irqsave(&nc->lock, flags);
35383afdc6aSGavin Shan 	nc->monitor.state = NCSI_CHANNEL_MONITOR_START;
354e6f44ed6SGavin Shan 	spin_unlock_irqrestore(&nc->lock, flags);
355e6f44ed6SGavin Shan 
356138635ccSGavin Shan 	return 0;
357138635ccSGavin Shan }
358138635ccSGavin Shan 
ncsi_rsp_handler_svf(struct ncsi_request * nr)359138635ccSGavin Shan static int ncsi_rsp_handler_svf(struct ncsi_request *nr)
360138635ccSGavin Shan {
361138635ccSGavin Shan 	struct ncsi_cmd_svf_pkt *cmd;
362138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
363138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
364138635ccSGavin Shan 	struct ncsi_channel *nc;
365062b3e1bSSamuel Mendoza-Jonas 	struct ncsi_channel_vlan_filter *ncf;
366062b3e1bSSamuel Mendoza-Jonas 	unsigned long flags;
367062b3e1bSSamuel Mendoza-Jonas 	void *bitmap;
368138635ccSGavin Shan 
369138635ccSGavin Shan 	/* Find the package and channel */
370138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
371138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
372138635ccSGavin Shan 				      NULL, &nc);
373138635ccSGavin Shan 	if (!nc)
374138635ccSGavin Shan 		return -ENODEV;
375138635ccSGavin Shan 
376138635ccSGavin Shan 	cmd = (struct ncsi_cmd_svf_pkt *)skb_network_header(nr->cmd);
377062b3e1bSSamuel Mendoza-Jonas 	ncf = &nc->vlan_filter;
378990a9d49SDan Carpenter 	if (cmd->index == 0 || cmd->index > ncf->n_vids)
379138635ccSGavin Shan 		return -ERANGE;
380138635ccSGavin Shan 
381062b3e1bSSamuel Mendoza-Jonas 	/* Add or remove the VLAN filter. Remember HW indexes from 1 */
382062b3e1bSSamuel Mendoza-Jonas 	spin_lock_irqsave(&nc->lock, flags);
383062b3e1bSSamuel Mendoza-Jonas 	bitmap = &ncf->bitmap;
384138635ccSGavin Shan 	if (!(cmd->enable & 0x1)) {
385062b3e1bSSamuel Mendoza-Jonas 		if (test_and_clear_bit(cmd->index - 1, bitmap))
386062b3e1bSSamuel Mendoza-Jonas 			ncf->vids[cmd->index - 1] = 0;
387138635ccSGavin Shan 	} else {
388062b3e1bSSamuel Mendoza-Jonas 		set_bit(cmd->index - 1, bitmap);
389062b3e1bSSamuel Mendoza-Jonas 		ncf->vids[cmd->index - 1] = ntohs(cmd->vlan);
390138635ccSGavin Shan 	}
391062b3e1bSSamuel Mendoza-Jonas 	spin_unlock_irqrestore(&nc->lock, flags);
392138635ccSGavin Shan 
393062b3e1bSSamuel Mendoza-Jonas 	return 0;
394138635ccSGavin Shan }
395138635ccSGavin Shan 
ncsi_rsp_handler_ev(struct ncsi_request * nr)396138635ccSGavin Shan static int ncsi_rsp_handler_ev(struct ncsi_request *nr)
397138635ccSGavin Shan {
398138635ccSGavin Shan 	struct ncsi_cmd_ev_pkt *cmd;
399138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
400138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
401138635ccSGavin Shan 	struct ncsi_channel *nc;
402138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
403138635ccSGavin Shan 
404138635ccSGavin Shan 	/* Find the package and channel */
405138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
406138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
407138635ccSGavin Shan 				      NULL, &nc);
408138635ccSGavin Shan 	if (!nc)
409138635ccSGavin Shan 		return -ENODEV;
410138635ccSGavin Shan 
411138635ccSGavin Shan 	/* Check if VLAN mode has been enabled */
412138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_VLAN];
413138635ccSGavin Shan 	if (ncm->enable)
41404bad8bdSSamuel Mendoza-Jonas 		return 0;
415138635ccSGavin Shan 
416138635ccSGavin Shan 	/* Update to VLAN mode */
417138635ccSGavin Shan 	cmd = (struct ncsi_cmd_ev_pkt *)skb_network_header(nr->cmd);
418138635ccSGavin Shan 	ncm->enable = 1;
41927fa107dSIvan Mikhaylov 	ncm->data[0] = ntohl((__force __be32)cmd->mode);
420138635ccSGavin Shan 
421138635ccSGavin Shan 	return 0;
422138635ccSGavin Shan }
423138635ccSGavin Shan 
ncsi_rsp_handler_dv(struct ncsi_request * nr)424138635ccSGavin Shan static int ncsi_rsp_handler_dv(struct ncsi_request *nr)
425138635ccSGavin Shan {
426138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
427138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
428138635ccSGavin Shan 	struct ncsi_channel *nc;
429138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
430138635ccSGavin Shan 
431138635ccSGavin Shan 	/* Find the package and channel */
432138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
433138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
434138635ccSGavin Shan 				      NULL, &nc);
435138635ccSGavin Shan 	if (!nc)
436138635ccSGavin Shan 		return -ENODEV;
437138635ccSGavin Shan 
438138635ccSGavin Shan 	/* Check if VLAN mode has been enabled */
439138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_VLAN];
440138635ccSGavin Shan 	if (!ncm->enable)
44104bad8bdSSamuel Mendoza-Jonas 		return 0;
442138635ccSGavin Shan 
443138635ccSGavin Shan 	/* Update to VLAN mode */
444138635ccSGavin Shan 	ncm->enable = 0;
445138635ccSGavin Shan 	return 0;
446138635ccSGavin Shan }
447138635ccSGavin Shan 
ncsi_rsp_handler_sma(struct ncsi_request * nr)448138635ccSGavin Shan static int ncsi_rsp_handler_sma(struct ncsi_request *nr)
449138635ccSGavin Shan {
450138635ccSGavin Shan 	struct ncsi_cmd_sma_pkt *cmd;
451138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
452138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
453138635ccSGavin Shan 	struct ncsi_channel *nc;
454062b3e1bSSamuel Mendoza-Jonas 	struct ncsi_channel_mac_filter *ncf;
455062b3e1bSSamuel Mendoza-Jonas 	unsigned long flags;
456138635ccSGavin Shan 	void *bitmap;
457062b3e1bSSamuel Mendoza-Jonas 	bool enabled;
458062b3e1bSSamuel Mendoza-Jonas 	int index;
459062b3e1bSSamuel Mendoza-Jonas 
460138635ccSGavin Shan 
461138635ccSGavin Shan 	/* Find the package and channel */
462138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
463138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
464138635ccSGavin Shan 				      NULL, &nc);
465138635ccSGavin Shan 	if (!nc)
466138635ccSGavin Shan 		return -ENODEV;
467138635ccSGavin Shan 
468138635ccSGavin Shan 	/* According to NCSI spec 1.01, the mixed filter table
469138635ccSGavin Shan 	 * isn't supported yet.
470138635ccSGavin Shan 	 */
471138635ccSGavin Shan 	cmd = (struct ncsi_cmd_sma_pkt *)skb_network_header(nr->cmd);
472062b3e1bSSamuel Mendoza-Jonas 	enabled = cmd->at_e & 0x1;
473062b3e1bSSamuel Mendoza-Jonas 	ncf = &nc->mac_filter;
474062b3e1bSSamuel Mendoza-Jonas 	bitmap = &ncf->bitmap;
475138635ccSGavin Shan 
476990a9d49SDan Carpenter 	if (cmd->index == 0 ||
477990a9d49SDan Carpenter 	    cmd->index > ncf->n_uc + ncf->n_mc + ncf->n_mixed)
478138635ccSGavin Shan 		return -ERANGE;
479138635ccSGavin Shan 
480062b3e1bSSamuel Mendoza-Jonas 	index = (cmd->index - 1) * ETH_ALEN;
481062b3e1bSSamuel Mendoza-Jonas 	spin_lock_irqsave(&nc->lock, flags);
482062b3e1bSSamuel Mendoza-Jonas 	if (enabled) {
483062b3e1bSSamuel Mendoza-Jonas 		set_bit(cmd->index - 1, bitmap);
484062b3e1bSSamuel Mendoza-Jonas 		memcpy(&ncf->addrs[index], cmd->mac, ETH_ALEN);
485138635ccSGavin Shan 	} else {
486062b3e1bSSamuel Mendoza-Jonas 		clear_bit(cmd->index - 1, bitmap);
48749b0aa1bSMiaohe Lin 		eth_zero_addr(&ncf->addrs[index]);
488138635ccSGavin Shan 	}
489062b3e1bSSamuel Mendoza-Jonas 	spin_unlock_irqrestore(&nc->lock, flags);
490138635ccSGavin Shan 
491138635ccSGavin Shan 	return 0;
492138635ccSGavin Shan }
493138635ccSGavin Shan 
ncsi_rsp_handler_ebf(struct ncsi_request * nr)494138635ccSGavin Shan static int ncsi_rsp_handler_ebf(struct ncsi_request *nr)
495138635ccSGavin Shan {
496138635ccSGavin Shan 	struct ncsi_cmd_ebf_pkt *cmd;
497138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
498138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
499138635ccSGavin Shan 	struct ncsi_channel *nc;
500138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
501138635ccSGavin Shan 
502138635ccSGavin Shan 	/* Find the package and channel */
503138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
504138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc);
505138635ccSGavin Shan 	if (!nc)
506138635ccSGavin Shan 		return -ENODEV;
507138635ccSGavin Shan 
508138635ccSGavin Shan 	/* Check if broadcast filter has been enabled */
509138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_BC];
510138635ccSGavin Shan 	if (ncm->enable)
51104bad8bdSSamuel Mendoza-Jonas 		return 0;
512138635ccSGavin Shan 
513138635ccSGavin Shan 	/* Update to broadcast filter mode */
514138635ccSGavin Shan 	cmd = (struct ncsi_cmd_ebf_pkt *)skb_network_header(nr->cmd);
515138635ccSGavin Shan 	ncm->enable = 1;
516138635ccSGavin Shan 	ncm->data[0] = ntohl(cmd->mode);
517138635ccSGavin Shan 
518138635ccSGavin Shan 	return 0;
519138635ccSGavin Shan }
520138635ccSGavin Shan 
ncsi_rsp_handler_dbf(struct ncsi_request * nr)521138635ccSGavin Shan static int ncsi_rsp_handler_dbf(struct ncsi_request *nr)
522138635ccSGavin Shan {
523138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
524138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
525138635ccSGavin Shan 	struct ncsi_channel *nc;
526138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
527138635ccSGavin Shan 
528138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
529138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
530138635ccSGavin Shan 				      NULL, &nc);
531138635ccSGavin Shan 	if (!nc)
532138635ccSGavin Shan 		return -ENODEV;
533138635ccSGavin Shan 
534138635ccSGavin Shan 	/* Check if broadcast filter isn't enabled */
535138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_BC];
536138635ccSGavin Shan 	if (!ncm->enable)
53704bad8bdSSamuel Mendoza-Jonas 		return 0;
538138635ccSGavin Shan 
539138635ccSGavin Shan 	/* Update to broadcast filter mode */
540138635ccSGavin Shan 	ncm->enable = 0;
541138635ccSGavin Shan 	ncm->data[0] = 0;
542138635ccSGavin Shan 
543138635ccSGavin Shan 	return 0;
544138635ccSGavin Shan }
545138635ccSGavin Shan 
ncsi_rsp_handler_egmf(struct ncsi_request * nr)546138635ccSGavin Shan static int ncsi_rsp_handler_egmf(struct ncsi_request *nr)
547138635ccSGavin Shan {
548138635ccSGavin Shan 	struct ncsi_cmd_egmf_pkt *cmd;
549138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
550138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
551138635ccSGavin Shan 	struct ncsi_channel *nc;
552138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
553138635ccSGavin Shan 
554138635ccSGavin Shan 	/* Find the channel */
555138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
556138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
557138635ccSGavin Shan 				      NULL, &nc);
558138635ccSGavin Shan 	if (!nc)
559138635ccSGavin Shan 		return -ENODEV;
560138635ccSGavin Shan 
561138635ccSGavin Shan 	/* Check if multicast filter has been enabled */
562138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_MC];
563138635ccSGavin Shan 	if (ncm->enable)
56404bad8bdSSamuel Mendoza-Jonas 		return 0;
565138635ccSGavin Shan 
566138635ccSGavin Shan 	/* Update to multicast filter mode */
567138635ccSGavin Shan 	cmd = (struct ncsi_cmd_egmf_pkt *)skb_network_header(nr->cmd);
568138635ccSGavin Shan 	ncm->enable = 1;
569138635ccSGavin Shan 	ncm->data[0] = ntohl(cmd->mode);
570138635ccSGavin Shan 
571138635ccSGavin Shan 	return 0;
572138635ccSGavin Shan }
573138635ccSGavin Shan 
ncsi_rsp_handler_dgmf(struct ncsi_request * nr)574138635ccSGavin Shan static int ncsi_rsp_handler_dgmf(struct ncsi_request *nr)
575138635ccSGavin Shan {
576138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
577138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
578138635ccSGavin Shan 	struct ncsi_channel *nc;
579138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
580138635ccSGavin Shan 
581138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
582138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
583138635ccSGavin Shan 				      NULL, &nc);
584138635ccSGavin Shan 	if (!nc)
585138635ccSGavin Shan 		return -ENODEV;
586138635ccSGavin Shan 
587138635ccSGavin Shan 	/* Check if multicast filter has been enabled */
588138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_MC];
589138635ccSGavin Shan 	if (!ncm->enable)
59004bad8bdSSamuel Mendoza-Jonas 		return 0;
591138635ccSGavin Shan 
592138635ccSGavin Shan 	/* Update to multicast filter mode */
593138635ccSGavin Shan 	ncm->enable = 0;
594138635ccSGavin Shan 	ncm->data[0] = 0;
595138635ccSGavin Shan 
596138635ccSGavin Shan 	return 0;
597138635ccSGavin Shan }
598138635ccSGavin Shan 
ncsi_rsp_handler_snfc(struct ncsi_request * nr)599138635ccSGavin Shan static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
600138635ccSGavin Shan {
601138635ccSGavin Shan 	struct ncsi_cmd_snfc_pkt *cmd;
602138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
603138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
604138635ccSGavin Shan 	struct ncsi_channel *nc;
605138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
606138635ccSGavin Shan 
607138635ccSGavin Shan 	/* Find the channel */
608138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
609138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
610138635ccSGavin Shan 				      NULL, &nc);
611138635ccSGavin Shan 	if (!nc)
612138635ccSGavin Shan 		return -ENODEV;
613138635ccSGavin Shan 
614138635ccSGavin Shan 	/* Check if flow control has been enabled */
615138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_FC];
616138635ccSGavin Shan 	if (ncm->enable)
61704bad8bdSSamuel Mendoza-Jonas 		return 0;
618138635ccSGavin Shan 
619138635ccSGavin Shan 	/* Update to flow control mode */
620138635ccSGavin Shan 	cmd = (struct ncsi_cmd_snfc_pkt *)skb_network_header(nr->cmd);
621138635ccSGavin Shan 	ncm->enable = 1;
622138635ccSGavin Shan 	ncm->data[0] = cmd->mode;
623138635ccSGavin Shan 
624138635ccSGavin Shan 	return 0;
625138635ccSGavin Shan }
626138635ccSGavin Shan 
62774b449b9SIvan Mikhaylov /* Response handler for Get Mac Address command */
ncsi_rsp_handler_oem_gma(struct ncsi_request * nr,int mfr_id)62874b449b9SIvan Mikhaylov static int ncsi_rsp_handler_oem_gma(struct ncsi_request *nr, int mfr_id)
62916e8c4caSVijay Khemka {
63016e8c4caSVijay Khemka 	struct ncsi_dev_priv *ndp = nr->ndp;
631ba32f06eSPaul Fertser 	struct sockaddr *saddr = &ndp->pending_mac;
63216e8c4caSVijay Khemka 	struct net_device *ndev = ndp->ndev.dev;
63316e8c4caSVijay Khemka 	struct ncsi_rsp_oem_pkt *rsp;
63474b449b9SIvan Mikhaylov 	u32 mac_addr_off = 0;
63516e8c4caSVijay Khemka 
63616e8c4caSVijay Khemka 	/* Get the response header */
63716e8c4caSVijay Khemka 	rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
63816e8c4caSVijay Khemka 
63916e8c4caSVijay Khemka 	ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
64074b449b9SIvan Mikhaylov 	if (mfr_id == NCSI_OEM_MFR_BCM_ID)
64174b449b9SIvan Mikhaylov 		mac_addr_off = BCM_MAC_ADDR_OFFSET;
64274b449b9SIvan Mikhaylov 	else if (mfr_id == NCSI_OEM_MFR_MLX_ID)
64374b449b9SIvan Mikhaylov 		mac_addr_off = MLX_MAC_ADDR_OFFSET;
64474b449b9SIvan Mikhaylov 	else if (mfr_id == NCSI_OEM_MFR_INTEL_ID)
64574b449b9SIvan Mikhaylov 		mac_addr_off = INTEL_MAC_ADDR_OFFSET;
64674b449b9SIvan Mikhaylov 
647ba32f06eSPaul Fertser 	saddr->sa_family = ndev->type;
648ba32f06eSPaul Fertser 	memcpy(saddr->sa_data, &rsp->data[mac_addr_off], ETH_ALEN);
64974b449b9SIvan Mikhaylov 	if (mfr_id == NCSI_OEM_MFR_BCM_ID || mfr_id == NCSI_OEM_MFR_INTEL_ID)
650ba32f06eSPaul Fertser 		eth_addr_inc((u8 *)saddr->sa_data);
651ba32f06eSPaul Fertser 	if (!is_valid_ether_addr((const u8 *)saddr->sa_data))
65274b449b9SIvan Mikhaylov 		return -ENXIO;
65374b449b9SIvan Mikhaylov 
6549e860947SVijay Khemka 	/* Set the flag for GMA command which should only be called once */
6559e860947SVijay Khemka 	ndp->gma_flag = 1;
6569e860947SVijay Khemka 
657ba32f06eSPaul Fertser 	return 0;
65816e8c4caSVijay Khemka }
65916e8c4caSVijay Khemka 
66016e8c4caSVijay Khemka /* Response handler for Mellanox card */
ncsi_rsp_handler_oem_mlx(struct ncsi_request * nr)66116e8c4caSVijay Khemka static int ncsi_rsp_handler_oem_mlx(struct ncsi_request *nr)
66216e8c4caSVijay Khemka {
66316e8c4caSVijay Khemka 	struct ncsi_rsp_oem_mlx_pkt *mlx;
66416e8c4caSVijay Khemka 	struct ncsi_rsp_oem_pkt *rsp;
66516e8c4caSVijay Khemka 
66616e8c4caSVijay Khemka 	/* Get the response header */
66716e8c4caSVijay Khemka 	rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
66816e8c4caSVijay Khemka 	mlx = (struct ncsi_rsp_oem_mlx_pkt *)(rsp->data);
66916e8c4caSVijay Khemka 
67016e8c4caSVijay Khemka 	if (mlx->cmd == NCSI_OEM_MLX_CMD_GMA &&
67116e8c4caSVijay Khemka 	    mlx->param == NCSI_OEM_MLX_CMD_GMA_PARAM)
67274b449b9SIvan Mikhaylov 		return ncsi_rsp_handler_oem_gma(nr, NCSI_OEM_MFR_MLX_ID);
67316e8c4caSVijay Khemka 	return 0;
67416e8c4caSVijay Khemka }
67516e8c4caSVijay Khemka 
676cb10c7c0SVijay Khemka /* Response handler for Broadcom card */
ncsi_rsp_handler_oem_bcm(struct ncsi_request * nr)677cb10c7c0SVijay Khemka static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr)
678cb10c7c0SVijay Khemka {
679cb10c7c0SVijay Khemka 	struct ncsi_rsp_oem_bcm_pkt *bcm;
680cb10c7c0SVijay Khemka 	struct ncsi_rsp_oem_pkt *rsp;
681cb10c7c0SVijay Khemka 
682cb10c7c0SVijay Khemka 	/* Get the response header */
683cb10c7c0SVijay Khemka 	rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
684cb10c7c0SVijay Khemka 	bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data);
685cb10c7c0SVijay Khemka 
686cb10c7c0SVijay Khemka 	if (bcm->type == NCSI_OEM_BCM_CMD_GMA)
68774b449b9SIvan Mikhaylov 		return ncsi_rsp_handler_oem_gma(nr, NCSI_OEM_MFR_BCM_ID);
688cb10c7c0SVijay Khemka 	return 0;
689cb10c7c0SVijay Khemka }
690cb10c7c0SVijay Khemka 
691163f5de5SIvan Mikhaylov /* Response handler for Intel card */
ncsi_rsp_handler_oem_intel(struct ncsi_request * nr)692163f5de5SIvan Mikhaylov static int ncsi_rsp_handler_oem_intel(struct ncsi_request *nr)
693163f5de5SIvan Mikhaylov {
694205b95feSIvan Mikhaylov 	struct ncsi_rsp_oem_intel_pkt *intel;
695205b95feSIvan Mikhaylov 	struct ncsi_rsp_oem_pkt *rsp;
696205b95feSIvan Mikhaylov 
697205b95feSIvan Mikhaylov 	/* Get the response header */
698205b95feSIvan Mikhaylov 	rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
699205b95feSIvan Mikhaylov 	intel = (struct ncsi_rsp_oem_intel_pkt *)(rsp->data);
700205b95feSIvan Mikhaylov 
701205b95feSIvan Mikhaylov 	if (intel->cmd == NCSI_OEM_INTEL_CMD_GMA)
70274b449b9SIvan Mikhaylov 		return ncsi_rsp_handler_oem_gma(nr, NCSI_OEM_MFR_INTEL_ID);
703205b95feSIvan Mikhaylov 
704163f5de5SIvan Mikhaylov 	return 0;
705163f5de5SIvan Mikhaylov }
706163f5de5SIvan Mikhaylov 
707fb4ee675SVijay Khemka static struct ncsi_rsp_oem_handler {
708fb4ee675SVijay Khemka 	unsigned int	mfr_id;
709fb4ee675SVijay Khemka 	int		(*handler)(struct ncsi_request *nr);
710fb4ee675SVijay Khemka } ncsi_rsp_oem_handlers[] = {
71116e8c4caSVijay Khemka 	{ NCSI_OEM_MFR_MLX_ID, ncsi_rsp_handler_oem_mlx },
712163f5de5SIvan Mikhaylov 	{ NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm },
713163f5de5SIvan Mikhaylov 	{ NCSI_OEM_MFR_INTEL_ID, ncsi_rsp_handler_oem_intel }
714fb4ee675SVijay Khemka };
715fb4ee675SVijay Khemka 
716fb4ee675SVijay Khemka /* Response handler for OEM command */
ncsi_rsp_handler_oem(struct ncsi_request * nr)717fb4ee675SVijay Khemka static int ncsi_rsp_handler_oem(struct ncsi_request *nr)
718fb4ee675SVijay Khemka {
719fb4ee675SVijay Khemka 	struct ncsi_rsp_oem_handler *nrh = NULL;
720cb10c7c0SVijay Khemka 	struct ncsi_rsp_oem_pkt *rsp;
721fb4ee675SVijay Khemka 	unsigned int mfr_id, i;
722fb4ee675SVijay Khemka 
723fb4ee675SVijay Khemka 	/* Get the response header */
724fb4ee675SVijay Khemka 	rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
725fb4ee675SVijay Khemka 	mfr_id = ntohl(rsp->mfr_id);
726fb4ee675SVijay Khemka 
727fb4ee675SVijay Khemka 	/* Check for manufacturer id and Find the handler */
728fb4ee675SVijay Khemka 	for (i = 0; i < ARRAY_SIZE(ncsi_rsp_oem_handlers); i++) {
729fb4ee675SVijay Khemka 		if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) {
730fb4ee675SVijay Khemka 			if (ncsi_rsp_oem_handlers[i].handler)
731fb4ee675SVijay Khemka 				nrh = &ncsi_rsp_oem_handlers[i];
732fb4ee675SVijay Khemka 			else
733fb4ee675SVijay Khemka 				nrh = NULL;
734fb4ee675SVijay Khemka 
735fb4ee675SVijay Khemka 			break;
736fb4ee675SVijay Khemka 		}
737fb4ee675SVijay Khemka 	}
738fb4ee675SVijay Khemka 
739fb4ee675SVijay Khemka 	if (!nrh) {
740fb4ee675SVijay Khemka 		netdev_err(nr->ndp->ndev.dev, "Received unrecognized OEM packet with MFR-ID (0x%x)\n",
741fb4ee675SVijay Khemka 			   mfr_id);
742fb4ee675SVijay Khemka 		return -ENOENT;
743fb4ee675SVijay Khemka 	}
744fb4ee675SVijay Khemka 
745fb4ee675SVijay Khemka 	/* Process the packet */
746fb4ee675SVijay Khemka 	return nrh->handler(nr);
747fb4ee675SVijay Khemka }
748fb4ee675SVijay Khemka 
ncsi_rsp_handler_gvi(struct ncsi_request * nr)749138635ccSGavin Shan static int ncsi_rsp_handler_gvi(struct ncsi_request *nr)
750138635ccSGavin Shan {
751138635ccSGavin Shan 	struct ncsi_rsp_gvi_pkt *rsp;
752138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
753138635ccSGavin Shan 	struct ncsi_channel *nc;
754138635ccSGavin Shan 	struct ncsi_channel_version *ncv;
755138635ccSGavin Shan 	int i;
756138635ccSGavin Shan 
757138635ccSGavin Shan 	/* Find the channel */
758138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gvi_pkt *)skb_network_header(nr->rsp);
759138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
760138635ccSGavin Shan 				      NULL, &nc);
761138635ccSGavin Shan 	if (!nc)
762138635ccSGavin Shan 		return -ENODEV;
763138635ccSGavin Shan 
7641c83c708SPeter Delevoryas 	/* Update channel's version info
7651c83c708SPeter Delevoryas 	 *
7661c83c708SPeter Delevoryas 	 * Major, minor, and update fields are supposed to be
7671c83c708SPeter Delevoryas 	 * unsigned integers encoded as packed BCD.
7681c83c708SPeter Delevoryas 	 *
7691c83c708SPeter Delevoryas 	 * Alpha1 and alpha2 are ISO/IEC 8859-1 characters.
7701c83c708SPeter Delevoryas 	 */
771138635ccSGavin Shan 	ncv = &nc->version;
7721c83c708SPeter Delevoryas 	ncv->major = decode_bcd_u8(rsp->major);
7731c83c708SPeter Delevoryas 	ncv->minor = decode_bcd_u8(rsp->minor);
7741c83c708SPeter Delevoryas 	ncv->update = decode_bcd_u8(rsp->update);
7751c83c708SPeter Delevoryas 	ncv->alpha1 = rsp->alpha1;
776138635ccSGavin Shan 	ncv->alpha2 = rsp->alpha2;
777138635ccSGavin Shan 	memcpy(ncv->fw_name, rsp->fw_name, 12);
778138635ccSGavin Shan 	ncv->fw_version = ntohl(rsp->fw_version);
779138635ccSGavin Shan 	for (i = 0; i < ARRAY_SIZE(ncv->pci_ids); i++)
780138635ccSGavin Shan 		ncv->pci_ids[i] = ntohs(rsp->pci_ids[i]);
781138635ccSGavin Shan 	ncv->mf_id = ntohl(rsp->mf_id);
782138635ccSGavin Shan 
783138635ccSGavin Shan 	return 0;
784138635ccSGavin Shan }
785138635ccSGavin Shan 
ncsi_rsp_handler_gc(struct ncsi_request * nr)786138635ccSGavin Shan static int ncsi_rsp_handler_gc(struct ncsi_request *nr)
787138635ccSGavin Shan {
788138635ccSGavin Shan 	struct ncsi_rsp_gc_pkt *rsp;
789138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
790138635ccSGavin Shan 	struct ncsi_channel *nc;
791645e643eSDelphineCCChiu 	struct ncsi_package *np;
792062b3e1bSSamuel Mendoza-Jonas 	size_t size;
793138635ccSGavin Shan 
794138635ccSGavin Shan 	/* Find the channel */
795138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gc_pkt *)skb_network_header(nr->rsp);
796138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
797645e643eSDelphineCCChiu 				      &np, &nc);
798138635ccSGavin Shan 	if (!nc)
799138635ccSGavin Shan 		return -ENODEV;
800138635ccSGavin Shan 
801138635ccSGavin Shan 	/* Update channel's capabilities */
802138635ccSGavin Shan 	nc->caps[NCSI_CAP_GENERIC].cap = ntohl(rsp->cap) &
803138635ccSGavin Shan 					 NCSI_CAP_GENERIC_MASK;
804138635ccSGavin Shan 	nc->caps[NCSI_CAP_BC].cap = ntohl(rsp->bc_cap) &
805138635ccSGavin Shan 				    NCSI_CAP_BC_MASK;
806138635ccSGavin Shan 	nc->caps[NCSI_CAP_MC].cap = ntohl(rsp->mc_cap) &
807138635ccSGavin Shan 				    NCSI_CAP_MC_MASK;
808138635ccSGavin Shan 	nc->caps[NCSI_CAP_BUFFER].cap = ntohl(rsp->buf_cap);
809138635ccSGavin Shan 	nc->caps[NCSI_CAP_AEN].cap = ntohl(rsp->aen_cap) &
810138635ccSGavin Shan 				     NCSI_CAP_AEN_MASK;
811138635ccSGavin Shan 	nc->caps[NCSI_CAP_VLAN].cap = rsp->vlan_mode &
812138635ccSGavin Shan 				      NCSI_CAP_VLAN_MASK;
813138635ccSGavin Shan 
814062b3e1bSSamuel Mendoza-Jonas 	size = (rsp->uc_cnt + rsp->mc_cnt + rsp->mixed_cnt) * ETH_ALEN;
815b0949618SSamuel Mendoza-Jonas 	nc->mac_filter.addrs = kzalloc(size, GFP_ATOMIC);
816062b3e1bSSamuel Mendoza-Jonas 	if (!nc->mac_filter.addrs)
817138635ccSGavin Shan 		return -ENOMEM;
818062b3e1bSSamuel Mendoza-Jonas 	nc->mac_filter.n_uc = rsp->uc_cnt;
819062b3e1bSSamuel Mendoza-Jonas 	nc->mac_filter.n_mc = rsp->mc_cnt;
820062b3e1bSSamuel Mendoza-Jonas 	nc->mac_filter.n_mixed = rsp->mixed_cnt;
821138635ccSGavin Shan 
822062b3e1bSSamuel Mendoza-Jonas 	nc->vlan_filter.vids = kcalloc(rsp->vlan_cnt,
823062b3e1bSSamuel Mendoza-Jonas 				       sizeof(*nc->vlan_filter.vids),
824b0949618SSamuel Mendoza-Jonas 				       GFP_ATOMIC);
825062b3e1bSSamuel Mendoza-Jonas 	if (!nc->vlan_filter.vids)
826062b3e1bSSamuel Mendoza-Jonas 		return -ENOMEM;
827062b3e1bSSamuel Mendoza-Jonas 	/* Set VLAN filters active so they are cleared in the first
828062b3e1bSSamuel Mendoza-Jonas 	 * configuration state
82921acf630SSamuel Mendoza-Jonas 	 */
830062b3e1bSSamuel Mendoza-Jonas 	nc->vlan_filter.bitmap = U64_MAX;
831062b3e1bSSamuel Mendoza-Jonas 	nc->vlan_filter.n_vids = rsp->vlan_cnt;
832645e643eSDelphineCCChiu 	np->ndp->channel_count = rsp->channel_cnt;
833138635ccSGavin Shan 
834138635ccSGavin Shan 	return 0;
835138635ccSGavin Shan }
836138635ccSGavin Shan 
ncsi_rsp_handler_gp(struct ncsi_request * nr)837138635ccSGavin Shan static int ncsi_rsp_handler_gp(struct ncsi_request *nr)
838138635ccSGavin Shan {
839062b3e1bSSamuel Mendoza-Jonas 	struct ncsi_channel_vlan_filter *ncvf;
840062b3e1bSSamuel Mendoza-Jonas 	struct ncsi_channel_mac_filter *ncmf;
841138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
842062b3e1bSSamuel Mendoza-Jonas 	struct ncsi_rsp_gp_pkt *rsp;
843138635ccSGavin Shan 	struct ncsi_channel *nc;
844062b3e1bSSamuel Mendoza-Jonas 	unsigned short enable;
845138635ccSGavin Shan 	unsigned char *pdata;
846062b3e1bSSamuel Mendoza-Jonas 	unsigned long flags;
847062b3e1bSSamuel Mendoza-Jonas 	void *bitmap;
848062b3e1bSSamuel Mendoza-Jonas 	int i;
849138635ccSGavin Shan 
850138635ccSGavin Shan 	/* Find the channel */
851138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gp_pkt *)skb_network_header(nr->rsp);
852138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
853138635ccSGavin Shan 				      NULL, &nc);
854138635ccSGavin Shan 	if (!nc)
855138635ccSGavin Shan 		return -ENODEV;
856138635ccSGavin Shan 
857138635ccSGavin Shan 	/* Modes with explicit enabled indications */
858138635ccSGavin Shan 	if (ntohl(rsp->valid_modes) & 0x1) {	/* BC filter mode */
859138635ccSGavin Shan 		nc->modes[NCSI_MODE_BC].enable = 1;
860138635ccSGavin Shan 		nc->modes[NCSI_MODE_BC].data[0] = ntohl(rsp->bc_mode);
861138635ccSGavin Shan 	}
862138635ccSGavin Shan 	if (ntohl(rsp->valid_modes) & 0x2)	/* Channel enabled */
863138635ccSGavin Shan 		nc->modes[NCSI_MODE_ENABLE].enable = 1;
864138635ccSGavin Shan 	if (ntohl(rsp->valid_modes) & 0x4)	/* Channel Tx enabled */
865138635ccSGavin Shan 		nc->modes[NCSI_MODE_TX_ENABLE].enable = 1;
866138635ccSGavin Shan 	if (ntohl(rsp->valid_modes) & 0x8)	/* MC filter mode */
867138635ccSGavin Shan 		nc->modes[NCSI_MODE_MC].enable = 1;
868138635ccSGavin Shan 
869138635ccSGavin Shan 	/* Modes without explicit enabled indications */
870138635ccSGavin Shan 	nc->modes[NCSI_MODE_LINK].enable = 1;
871138635ccSGavin Shan 	nc->modes[NCSI_MODE_LINK].data[0] = ntohl(rsp->link_mode);
872138635ccSGavin Shan 	nc->modes[NCSI_MODE_VLAN].enable = 1;
873138635ccSGavin Shan 	nc->modes[NCSI_MODE_VLAN].data[0] = rsp->vlan_mode;
874138635ccSGavin Shan 	nc->modes[NCSI_MODE_FC].enable = 1;
875138635ccSGavin Shan 	nc->modes[NCSI_MODE_FC].data[0] = rsp->fc_mode;
876138635ccSGavin Shan 	nc->modes[NCSI_MODE_AEN].enable = 1;
877138635ccSGavin Shan 	nc->modes[NCSI_MODE_AEN].data[0] = ntohl(rsp->aen_mode);
878138635ccSGavin Shan 
879138635ccSGavin Shan 	/* MAC addresses filter table */
880138635ccSGavin Shan 	pdata = (unsigned char *)rsp + 48;
881138635ccSGavin Shan 	enable = rsp->mac_enable;
882062b3e1bSSamuel Mendoza-Jonas 	ncmf = &nc->mac_filter;
883062b3e1bSSamuel Mendoza-Jonas 	spin_lock_irqsave(&nc->lock, flags);
884062b3e1bSSamuel Mendoza-Jonas 	bitmap = &ncmf->bitmap;
885138635ccSGavin Shan 	for (i = 0; i < rsp->mac_cnt; i++, pdata += 6) {
886138635ccSGavin Shan 		if (!(enable & (0x1 << i)))
887062b3e1bSSamuel Mendoza-Jonas 			clear_bit(i, bitmap);
888062b3e1bSSamuel Mendoza-Jonas 		else
889062b3e1bSSamuel Mendoza-Jonas 			set_bit(i, bitmap);
890138635ccSGavin Shan 
891062b3e1bSSamuel Mendoza-Jonas 		memcpy(&ncmf->addrs[i * ETH_ALEN], pdata, ETH_ALEN);
892138635ccSGavin Shan 	}
893062b3e1bSSamuel Mendoza-Jonas 	spin_unlock_irqrestore(&nc->lock, flags);
894138635ccSGavin Shan 
895138635ccSGavin Shan 	/* VLAN filter table */
896138635ccSGavin Shan 	enable = ntohs(rsp->vlan_enable);
897062b3e1bSSamuel Mendoza-Jonas 	ncvf = &nc->vlan_filter;
898062b3e1bSSamuel Mendoza-Jonas 	bitmap = &ncvf->bitmap;
899062b3e1bSSamuel Mendoza-Jonas 	spin_lock_irqsave(&nc->lock, flags);
900138635ccSGavin Shan 	for (i = 0; i < rsp->vlan_cnt; i++, pdata += 2) {
901138635ccSGavin Shan 		if (!(enable & (0x1 << i)))
902062b3e1bSSamuel Mendoza-Jonas 			clear_bit(i, bitmap);
903062b3e1bSSamuel Mendoza-Jonas 		else
904062b3e1bSSamuel Mendoza-Jonas 			set_bit(i, bitmap);
905138635ccSGavin Shan 
906062b3e1bSSamuel Mendoza-Jonas 		ncvf->vids[i] = ntohs(*(__be16 *)pdata);
907138635ccSGavin Shan 	}
908062b3e1bSSamuel Mendoza-Jonas 	spin_unlock_irqrestore(&nc->lock, flags);
909138635ccSGavin Shan 
910138635ccSGavin Shan 	return 0;
911138635ccSGavin Shan }
912138635ccSGavin Shan 
ncsi_rsp_handler_gcps(struct ncsi_request * nr)913138635ccSGavin Shan static int ncsi_rsp_handler_gcps(struct ncsi_request *nr)
914138635ccSGavin Shan {
915138635ccSGavin Shan 	struct ncsi_rsp_gcps_pkt *rsp;
916138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
917138635ccSGavin Shan 	struct ncsi_channel *nc;
918138635ccSGavin Shan 	struct ncsi_channel_stats *ncs;
919138635ccSGavin Shan 
920138635ccSGavin Shan 	/* Find the channel */
921138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gcps_pkt *)skb_network_header(nr->rsp);
922138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
923138635ccSGavin Shan 				      NULL, &nc);
924138635ccSGavin Shan 	if (!nc)
925138635ccSGavin Shan 		return -ENODEV;
926138635ccSGavin Shan 
927138635ccSGavin Shan 	/* Update HNC's statistics */
928138635ccSGavin Shan 	ncs = &nc->stats;
929138635ccSGavin Shan 	ncs->hnc_cnt_hi         = ntohl(rsp->cnt_hi);
930138635ccSGavin Shan 	ncs->hnc_cnt_lo         = ntohl(rsp->cnt_lo);
931138635ccSGavin Shan 	ncs->hnc_rx_bytes       = ntohl(rsp->rx_bytes);
932138635ccSGavin Shan 	ncs->hnc_tx_bytes       = ntohl(rsp->tx_bytes);
933138635ccSGavin Shan 	ncs->hnc_rx_uc_pkts     = ntohl(rsp->rx_uc_pkts);
934138635ccSGavin Shan 	ncs->hnc_rx_mc_pkts     = ntohl(rsp->rx_mc_pkts);
935138635ccSGavin Shan 	ncs->hnc_rx_bc_pkts     = ntohl(rsp->rx_bc_pkts);
936138635ccSGavin Shan 	ncs->hnc_tx_uc_pkts     = ntohl(rsp->tx_uc_pkts);
937138635ccSGavin Shan 	ncs->hnc_tx_mc_pkts     = ntohl(rsp->tx_mc_pkts);
938138635ccSGavin Shan 	ncs->hnc_tx_bc_pkts     = ntohl(rsp->tx_bc_pkts);
939138635ccSGavin Shan 	ncs->hnc_fcs_err        = ntohl(rsp->fcs_err);
940138635ccSGavin Shan 	ncs->hnc_align_err      = ntohl(rsp->align_err);
941138635ccSGavin Shan 	ncs->hnc_false_carrier  = ntohl(rsp->false_carrier);
942138635ccSGavin Shan 	ncs->hnc_runt_pkts      = ntohl(rsp->runt_pkts);
943138635ccSGavin Shan 	ncs->hnc_jabber_pkts    = ntohl(rsp->jabber_pkts);
944138635ccSGavin Shan 	ncs->hnc_rx_pause_xon   = ntohl(rsp->rx_pause_xon);
945138635ccSGavin Shan 	ncs->hnc_rx_pause_xoff  = ntohl(rsp->rx_pause_xoff);
946138635ccSGavin Shan 	ncs->hnc_tx_pause_xon   = ntohl(rsp->tx_pause_xon);
947138635ccSGavin Shan 	ncs->hnc_tx_pause_xoff  = ntohl(rsp->tx_pause_xoff);
948138635ccSGavin Shan 	ncs->hnc_tx_s_collision = ntohl(rsp->tx_s_collision);
949138635ccSGavin Shan 	ncs->hnc_tx_m_collision = ntohl(rsp->tx_m_collision);
950138635ccSGavin Shan 	ncs->hnc_l_collision    = ntohl(rsp->l_collision);
951138635ccSGavin Shan 	ncs->hnc_e_collision    = ntohl(rsp->e_collision);
952138635ccSGavin Shan 	ncs->hnc_rx_ctl_frames  = ntohl(rsp->rx_ctl_frames);
953138635ccSGavin Shan 	ncs->hnc_rx_64_frames   = ntohl(rsp->rx_64_frames);
954138635ccSGavin Shan 	ncs->hnc_rx_127_frames  = ntohl(rsp->rx_127_frames);
955138635ccSGavin Shan 	ncs->hnc_rx_255_frames  = ntohl(rsp->rx_255_frames);
956138635ccSGavin Shan 	ncs->hnc_rx_511_frames  = ntohl(rsp->rx_511_frames);
957138635ccSGavin Shan 	ncs->hnc_rx_1023_frames = ntohl(rsp->rx_1023_frames);
958138635ccSGavin Shan 	ncs->hnc_rx_1522_frames = ntohl(rsp->rx_1522_frames);
959138635ccSGavin Shan 	ncs->hnc_rx_9022_frames = ntohl(rsp->rx_9022_frames);
960138635ccSGavin Shan 	ncs->hnc_tx_64_frames   = ntohl(rsp->tx_64_frames);
961138635ccSGavin Shan 	ncs->hnc_tx_127_frames  = ntohl(rsp->tx_127_frames);
962138635ccSGavin Shan 	ncs->hnc_tx_255_frames  = ntohl(rsp->tx_255_frames);
963138635ccSGavin Shan 	ncs->hnc_tx_511_frames  = ntohl(rsp->tx_511_frames);
964138635ccSGavin Shan 	ncs->hnc_tx_1023_frames = ntohl(rsp->tx_1023_frames);
965138635ccSGavin Shan 	ncs->hnc_tx_1522_frames = ntohl(rsp->tx_1522_frames);
966138635ccSGavin Shan 	ncs->hnc_tx_9022_frames = ntohl(rsp->tx_9022_frames);
967138635ccSGavin Shan 	ncs->hnc_rx_valid_bytes = ntohl(rsp->rx_valid_bytes);
968138635ccSGavin Shan 	ncs->hnc_rx_runt_pkts   = ntohl(rsp->rx_runt_pkts);
969138635ccSGavin Shan 	ncs->hnc_rx_jabber_pkts = ntohl(rsp->rx_jabber_pkts);
970138635ccSGavin Shan 
971138635ccSGavin Shan 	return 0;
972138635ccSGavin Shan }
973138635ccSGavin Shan 
ncsi_rsp_handler_gns(struct ncsi_request * nr)974138635ccSGavin Shan static int ncsi_rsp_handler_gns(struct ncsi_request *nr)
975138635ccSGavin Shan {
976138635ccSGavin Shan 	struct ncsi_rsp_gns_pkt *rsp;
977138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
978138635ccSGavin Shan 	struct ncsi_channel *nc;
979138635ccSGavin Shan 	struct ncsi_channel_stats *ncs;
980138635ccSGavin Shan 
981138635ccSGavin Shan 	/* Find the channel */
982138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gns_pkt *)skb_network_header(nr->rsp);
983138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
984138635ccSGavin Shan 				      NULL, &nc);
985138635ccSGavin Shan 	if (!nc)
986138635ccSGavin Shan 		return -ENODEV;
987138635ccSGavin Shan 
988138635ccSGavin Shan 	/* Update HNC's statistics */
989138635ccSGavin Shan 	ncs = &nc->stats;
990138635ccSGavin Shan 	ncs->ncsi_rx_cmds       = ntohl(rsp->rx_cmds);
991138635ccSGavin Shan 	ncs->ncsi_dropped_cmds  = ntohl(rsp->dropped_cmds);
992138635ccSGavin Shan 	ncs->ncsi_cmd_type_errs = ntohl(rsp->cmd_type_errs);
993138635ccSGavin Shan 	ncs->ncsi_cmd_csum_errs = ntohl(rsp->cmd_csum_errs);
994138635ccSGavin Shan 	ncs->ncsi_rx_pkts       = ntohl(rsp->rx_pkts);
995138635ccSGavin Shan 	ncs->ncsi_tx_pkts       = ntohl(rsp->tx_pkts);
996138635ccSGavin Shan 	ncs->ncsi_tx_aen_pkts   = ntohl(rsp->tx_aen_pkts);
997138635ccSGavin Shan 
998138635ccSGavin Shan 	return 0;
999138635ccSGavin Shan }
1000138635ccSGavin Shan 
ncsi_rsp_handler_gnpts(struct ncsi_request * nr)1001138635ccSGavin Shan static int ncsi_rsp_handler_gnpts(struct ncsi_request *nr)
1002138635ccSGavin Shan {
1003138635ccSGavin Shan 	struct ncsi_rsp_gnpts_pkt *rsp;
1004138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
1005138635ccSGavin Shan 	struct ncsi_channel *nc;
1006138635ccSGavin Shan 	struct ncsi_channel_stats *ncs;
1007138635ccSGavin Shan 
1008138635ccSGavin Shan 	/* Find the channel */
1009138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gnpts_pkt *)skb_network_header(nr->rsp);
1010138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
1011138635ccSGavin Shan 				      NULL, &nc);
1012138635ccSGavin Shan 	if (!nc)
1013138635ccSGavin Shan 		return -ENODEV;
1014138635ccSGavin Shan 
1015138635ccSGavin Shan 	/* Update HNC's statistics */
1016138635ccSGavin Shan 	ncs = &nc->stats;
1017138635ccSGavin Shan 	ncs->pt_tx_pkts        = ntohl(rsp->tx_pkts);
1018138635ccSGavin Shan 	ncs->pt_tx_dropped     = ntohl(rsp->tx_dropped);
1019138635ccSGavin Shan 	ncs->pt_tx_channel_err = ntohl(rsp->tx_channel_err);
1020138635ccSGavin Shan 	ncs->pt_tx_us_err      = ntohl(rsp->tx_us_err);
1021138635ccSGavin Shan 	ncs->pt_rx_pkts        = ntohl(rsp->rx_pkts);
1022138635ccSGavin Shan 	ncs->pt_rx_dropped     = ntohl(rsp->rx_dropped);
1023138635ccSGavin Shan 	ncs->pt_rx_channel_err = ntohl(rsp->rx_channel_err);
1024138635ccSGavin Shan 	ncs->pt_rx_us_err      = ntohl(rsp->rx_us_err);
1025138635ccSGavin Shan 	ncs->pt_rx_os_err      = ntohl(rsp->rx_os_err);
1026138635ccSGavin Shan 
1027138635ccSGavin Shan 	return 0;
1028138635ccSGavin Shan }
1029138635ccSGavin Shan 
ncsi_rsp_handler_gps(struct ncsi_request * nr)1030138635ccSGavin Shan static int ncsi_rsp_handler_gps(struct ncsi_request *nr)
1031138635ccSGavin Shan {
1032138635ccSGavin Shan 	struct ncsi_rsp_gps_pkt *rsp;
1033138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
1034138635ccSGavin Shan 	struct ncsi_package *np;
1035138635ccSGavin Shan 
1036138635ccSGavin Shan 	/* Find the package */
1037138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gps_pkt *)skb_network_header(nr->rsp);
1038138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
1039138635ccSGavin Shan 				      &np, NULL);
1040138635ccSGavin Shan 	if (!np)
1041138635ccSGavin Shan 		return -ENODEV;
1042138635ccSGavin Shan 
1043138635ccSGavin Shan 	return 0;
1044138635ccSGavin Shan }
1045138635ccSGavin Shan 
ncsi_rsp_handler_gpuuid(struct ncsi_request * nr)1046138635ccSGavin Shan static int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr)
1047138635ccSGavin Shan {
1048138635ccSGavin Shan 	struct ncsi_rsp_gpuuid_pkt *rsp;
1049138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
1050138635ccSGavin Shan 	struct ncsi_package *np;
1051138635ccSGavin Shan 
1052138635ccSGavin Shan 	/* Find the package */
1053138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gpuuid_pkt *)skb_network_header(nr->rsp);
1054138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
1055138635ccSGavin Shan 				      &np, NULL);
1056138635ccSGavin Shan 	if (!np)
1057138635ccSGavin Shan 		return -ENODEV;
1058138635ccSGavin Shan 
1059138635ccSGavin Shan 	memcpy(np->uuid, rsp->uuid, sizeof(rsp->uuid));
1060138635ccSGavin Shan 
1061138635ccSGavin Shan 	return 0;
1062138635ccSGavin Shan }
1063138635ccSGavin Shan 
ncsi_rsp_handler_pldm(struct ncsi_request * nr)10646f671045SBen Wei static int ncsi_rsp_handler_pldm(struct ncsi_request *nr)
10656f671045SBen Wei {
10666f671045SBen Wei 	return 0;
10676f671045SBen Wei }
10686f671045SBen Wei 
ncsi_rsp_handler_netlink(struct ncsi_request * nr)10699771b8ccSJustin.Lee1@Dell.com static int ncsi_rsp_handler_netlink(struct ncsi_request *nr)
10709771b8ccSJustin.Lee1@Dell.com {
10719771b8ccSJustin.Lee1@Dell.com 	struct ncsi_dev_priv *ndp = nr->ndp;
10729771b8ccSJustin.Lee1@Dell.com 	struct ncsi_rsp_pkt *rsp;
10739771b8ccSJustin.Lee1@Dell.com 	struct ncsi_package *np;
10749771b8ccSJustin.Lee1@Dell.com 	struct ncsi_channel *nc;
10759771b8ccSJustin.Lee1@Dell.com 	int ret;
10769771b8ccSJustin.Lee1@Dell.com 
10779771b8ccSJustin.Lee1@Dell.com 	/* Find the package */
10789771b8ccSJustin.Lee1@Dell.com 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
10799771b8ccSJustin.Lee1@Dell.com 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
10809771b8ccSJustin.Lee1@Dell.com 				      &np, &nc);
10819771b8ccSJustin.Lee1@Dell.com 	if (!np)
10829771b8ccSJustin.Lee1@Dell.com 		return -ENODEV;
10839771b8ccSJustin.Lee1@Dell.com 
10849771b8ccSJustin.Lee1@Dell.com 	ret = ncsi_send_netlink_rsp(nr, np, nc);
10859771b8ccSJustin.Lee1@Dell.com 
10869771b8ccSJustin.Lee1@Dell.com 	return ret;
10879771b8ccSJustin.Lee1@Dell.com }
10889771b8ccSJustin.Lee1@Dell.com 
ncsi_rsp_handler_gmcma(struct ncsi_request * nr)108967515088SPeter Delevoryas static int ncsi_rsp_handler_gmcma(struct ncsi_request *nr)
109067515088SPeter Delevoryas {
109167515088SPeter Delevoryas 	struct ncsi_dev_priv *ndp = nr->ndp;
1092*2cc0f0e1SPaul Fertser 	struct sockaddr *saddr = &ndp->pending_mac;
109367515088SPeter Delevoryas 	struct net_device *ndev = ndp->ndev.dev;
109467515088SPeter Delevoryas 	struct ncsi_rsp_gmcma_pkt *rsp;
109567515088SPeter Delevoryas 	int i;
109667515088SPeter Delevoryas 
109767515088SPeter Delevoryas 	rsp = (struct ncsi_rsp_gmcma_pkt *)skb_network_header(nr->rsp);
109867515088SPeter Delevoryas 	ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
109967515088SPeter Delevoryas 
110067515088SPeter Delevoryas 	netdev_info(ndev, "NCSI: Received %d provisioned MAC addresses\n",
110167515088SPeter Delevoryas 		    rsp->address_count);
110267515088SPeter Delevoryas 	for (i = 0; i < rsp->address_count; i++) {
110367515088SPeter Delevoryas 		netdev_info(ndev, "NCSI: MAC address %d: %02x:%02x:%02x:%02x:%02x:%02x\n",
110467515088SPeter Delevoryas 			    i, rsp->addresses[i][0], rsp->addresses[i][1],
110567515088SPeter Delevoryas 			    rsp->addresses[i][2], rsp->addresses[i][3],
110667515088SPeter Delevoryas 			    rsp->addresses[i][4], rsp->addresses[i][5]);
110767515088SPeter Delevoryas 	}
110867515088SPeter Delevoryas 
1109*2cc0f0e1SPaul Fertser 	saddr->sa_family = ndev->type;
111067515088SPeter Delevoryas 	for (i = 0; i < rsp->address_count; i++) {
1111*2cc0f0e1SPaul Fertser 		if (!is_valid_ether_addr(rsp->addresses[i])) {
111267515088SPeter Delevoryas 			netdev_warn(ndev, "NCSI: Unable to assign %pM to device\n",
1113*2cc0f0e1SPaul Fertser 				    rsp->addresses[i]);
111467515088SPeter Delevoryas 			continue;
111567515088SPeter Delevoryas 		}
1116*2cc0f0e1SPaul Fertser 		memcpy(saddr->sa_data, rsp->addresses[i], ETH_ALEN);
1117*2cc0f0e1SPaul Fertser 		netdev_warn(ndev, "NCSI: Will set MAC address to %pM\n", saddr->sa_data);
111867515088SPeter Delevoryas 		break;
111967515088SPeter Delevoryas 	}
112067515088SPeter Delevoryas 
1121*2cc0f0e1SPaul Fertser 	ndp->gma_flag = 1;
1122*2cc0f0e1SPaul Fertser 	return 0;
112367515088SPeter Delevoryas }
112467515088SPeter Delevoryas 
1125138635ccSGavin Shan static struct ncsi_rsp_handler {
1126138635ccSGavin Shan 	unsigned char	type;
1127138635ccSGavin Shan 	int             payload;
1128138635ccSGavin Shan 	int		(*handler)(struct ncsi_request *nr);
1129138635ccSGavin Shan } ncsi_rsp_handlers[] = {
1130138635ccSGavin Shan 	{ NCSI_PKT_RSP_CIS,     4, ncsi_rsp_handler_cis     },
1131138635ccSGavin Shan 	{ NCSI_PKT_RSP_SP,      4, ncsi_rsp_handler_sp      },
1132138635ccSGavin Shan 	{ NCSI_PKT_RSP_DP,      4, ncsi_rsp_handler_dp      },
1133138635ccSGavin Shan 	{ NCSI_PKT_RSP_EC,      4, ncsi_rsp_handler_ec      },
1134138635ccSGavin Shan 	{ NCSI_PKT_RSP_DC,      4, ncsi_rsp_handler_dc      },
1135138635ccSGavin Shan 	{ NCSI_PKT_RSP_RC,      4, ncsi_rsp_handler_rc      },
1136138635ccSGavin Shan 	{ NCSI_PKT_RSP_ECNT,    4, ncsi_rsp_handler_ecnt    },
1137138635ccSGavin Shan 	{ NCSI_PKT_RSP_DCNT,    4, ncsi_rsp_handler_dcnt    },
1138138635ccSGavin Shan 	{ NCSI_PKT_RSP_AE,      4, ncsi_rsp_handler_ae      },
1139138635ccSGavin Shan 	{ NCSI_PKT_RSP_SL,      4, ncsi_rsp_handler_sl      },
1140138635ccSGavin Shan 	{ NCSI_PKT_RSP_GLS,    16, ncsi_rsp_handler_gls     },
1141138635ccSGavin Shan 	{ NCSI_PKT_RSP_SVF,     4, ncsi_rsp_handler_svf     },
1142138635ccSGavin Shan 	{ NCSI_PKT_RSP_EV,      4, ncsi_rsp_handler_ev      },
1143138635ccSGavin Shan 	{ NCSI_PKT_RSP_DV,      4, ncsi_rsp_handler_dv      },
1144138635ccSGavin Shan 	{ NCSI_PKT_RSP_SMA,     4, ncsi_rsp_handler_sma     },
1145138635ccSGavin Shan 	{ NCSI_PKT_RSP_EBF,     4, ncsi_rsp_handler_ebf     },
1146138635ccSGavin Shan 	{ NCSI_PKT_RSP_DBF,     4, ncsi_rsp_handler_dbf     },
1147138635ccSGavin Shan 	{ NCSI_PKT_RSP_EGMF,    4, ncsi_rsp_handler_egmf    },
1148138635ccSGavin Shan 	{ NCSI_PKT_RSP_DGMF,    4, ncsi_rsp_handler_dgmf    },
1149138635ccSGavin Shan 	{ NCSI_PKT_RSP_SNFC,    4, ncsi_rsp_handler_snfc    },
11500a90e251SGavin Shan 	{ NCSI_PKT_RSP_GVI,    40, ncsi_rsp_handler_gvi     },
1151138635ccSGavin Shan 	{ NCSI_PKT_RSP_GC,     32, ncsi_rsp_handler_gc      },
1152138635ccSGavin Shan 	{ NCSI_PKT_RSP_GP,     -1, ncsi_rsp_handler_gp      },
11536d24e141SBen Wei 	{ NCSI_PKT_RSP_GCPS,  204, ncsi_rsp_handler_gcps    },
11546d24e141SBen Wei 	{ NCSI_PKT_RSP_GNS,    32, ncsi_rsp_handler_gns     },
11556d24e141SBen Wei 	{ NCSI_PKT_RSP_GNPTS,  48, ncsi_rsp_handler_gnpts   },
1156138635ccSGavin Shan 	{ NCSI_PKT_RSP_GPS,     8, ncsi_rsp_handler_gps     },
1157fb4ee675SVijay Khemka 	{ NCSI_PKT_RSP_OEM,    -1, ncsi_rsp_handler_oem     },
11586f671045SBen Wei 	{ NCSI_PKT_RSP_PLDM,   -1, ncsi_rsp_handler_pldm    },
11596f671045SBen Wei 	{ NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid  },
11606f671045SBen Wei 	{ NCSI_PKT_RSP_QPNPR,  -1, ncsi_rsp_handler_pldm    },
116167515088SPeter Delevoryas 	{ NCSI_PKT_RSP_SNPR,   -1, ncsi_rsp_handler_pldm    },
116267515088SPeter Delevoryas 	{ NCSI_PKT_RSP_GMCMA,  -1, ncsi_rsp_handler_gmcma   },
1163138635ccSGavin Shan };
1164138635ccSGavin Shan 
ncsi_rcv_rsp(struct sk_buff * skb,struct net_device * dev,struct packet_type * pt,struct net_device * orig_dev)1165138635ccSGavin Shan int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
1166138635ccSGavin Shan 		 struct packet_type *pt, struct net_device *orig_dev)
1167138635ccSGavin Shan {
1168138635ccSGavin Shan 	struct ncsi_rsp_handler *nrh = NULL;
1169138635ccSGavin Shan 	struct ncsi_dev *nd;
1170138635ccSGavin Shan 	struct ncsi_dev_priv *ndp;
1171138635ccSGavin Shan 	struct ncsi_request *nr;
1172138635ccSGavin Shan 	struct ncsi_pkt_hdr *hdr;
1173138635ccSGavin Shan 	unsigned long flags;
1174138635ccSGavin Shan 	int payload, i, ret;
1175138635ccSGavin Shan 
1176138635ccSGavin Shan 	/* Find the NCSI device */
1177427c9405SJohn Wang 	nd = ncsi_find_dev(orig_dev);
1178138635ccSGavin Shan 	ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL;
1179138635ccSGavin Shan 	if (!ndp)
1180138635ccSGavin Shan 		return -ENODEV;
1181138635ccSGavin Shan 
11827a82ecf4SGavin Shan 	/* Check if it is AEN packet */
1183138635ccSGavin Shan 	hdr = (struct ncsi_pkt_hdr *)skb_network_header(skb);
11847a82ecf4SGavin Shan 	if (hdr->type == NCSI_PKT_AEN)
11857a82ecf4SGavin Shan 		return ncsi_aen_handler(ndp, skb);
11867a82ecf4SGavin Shan 
11877a82ecf4SGavin Shan 	/* Find the handler */
1188138635ccSGavin Shan 	for (i = 0; i < ARRAY_SIZE(ncsi_rsp_handlers); i++) {
1189138635ccSGavin Shan 		if (ncsi_rsp_handlers[i].type == hdr->type) {
1190138635ccSGavin Shan 			if (ncsi_rsp_handlers[i].handler)
1191138635ccSGavin Shan 				nrh = &ncsi_rsp_handlers[i];
1192138635ccSGavin Shan 			else
1193138635ccSGavin Shan 				nrh = NULL;
1194138635ccSGavin Shan 
1195138635ccSGavin Shan 			break;
1196138635ccSGavin Shan 		}
1197138635ccSGavin Shan 	}
1198138635ccSGavin Shan 
1199138635ccSGavin Shan 	if (!nrh) {
1200138635ccSGavin Shan 		netdev_err(nd->dev, "Received unrecognized packet (0x%x)\n",
1201138635ccSGavin Shan 			   hdr->type);
1202138635ccSGavin Shan 		return -ENOENT;
1203138635ccSGavin Shan 	}
1204138635ccSGavin Shan 
1205138635ccSGavin Shan 	/* Associate with the request */
1206138635ccSGavin Shan 	spin_lock_irqsave(&ndp->lock, flags);
1207138635ccSGavin Shan 	nr = &ndp->requests[hdr->id];
1208138635ccSGavin Shan 	if (!nr->used) {
1209138635ccSGavin Shan 		spin_unlock_irqrestore(&ndp->lock, flags);
1210138635ccSGavin Shan 		return -ENODEV;
1211138635ccSGavin Shan 	}
1212138635ccSGavin Shan 
1213138635ccSGavin Shan 	nr->rsp = skb;
1214138635ccSGavin Shan 	if (!nr->enabled) {
1215138635ccSGavin Shan 		spin_unlock_irqrestore(&ndp->lock, flags);
1216138635ccSGavin Shan 		ret = -ENOENT;
1217138635ccSGavin Shan 		goto out;
1218138635ccSGavin Shan 	}
1219138635ccSGavin Shan 
1220138635ccSGavin Shan 	/* Validate the packet */
1221138635ccSGavin Shan 	spin_unlock_irqrestore(&ndp->lock, flags);
1222138635ccSGavin Shan 	payload = nrh->payload;
1223138635ccSGavin Shan 	if (payload < 0)
1224138635ccSGavin Shan 		payload = ntohs(hdr->length);
1225138635ccSGavin Shan 	ret = ncsi_validate_rsp_pkt(nr, payload);
12269ef8690bSSamuel Mendoza-Jonas 	if (ret) {
12279ef8690bSSamuel Mendoza-Jonas 		netdev_warn(ndp->ndev.dev,
12289ef8690bSSamuel Mendoza-Jonas 			    "NCSI: 'bad' packet ignored for type 0x%x\n",
12299ef8690bSSamuel Mendoza-Jonas 			    hdr->type);
12309771b8ccSJustin.Lee1@Dell.com 
12319771b8ccSJustin.Lee1@Dell.com 		if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
12329771b8ccSJustin.Lee1@Dell.com 			if (ret == -EPERM)
12339771b8ccSJustin.Lee1@Dell.com 				goto out_netlink;
12349771b8ccSJustin.Lee1@Dell.com 			else
12359771b8ccSJustin.Lee1@Dell.com 				ncsi_send_netlink_err(ndp->ndev.dev,
12369771b8ccSJustin.Lee1@Dell.com 						      nr->snd_seq,
12379771b8ccSJustin.Lee1@Dell.com 						      nr->snd_portid,
12389771b8ccSJustin.Lee1@Dell.com 						      &nr->nlhdr,
12399771b8ccSJustin.Lee1@Dell.com 						      ret);
12409771b8ccSJustin.Lee1@Dell.com 		}
1241138635ccSGavin Shan 		goto out;
12429ef8690bSSamuel Mendoza-Jonas 	}
1243138635ccSGavin Shan 
1244138635ccSGavin Shan 	/* Process the packet */
1245138635ccSGavin Shan 	ret = nrh->handler(nr);
12469ef8690bSSamuel Mendoza-Jonas 	if (ret)
12479ef8690bSSamuel Mendoza-Jonas 		netdev_err(ndp->ndev.dev,
12489ef8690bSSamuel Mendoza-Jonas 			   "NCSI: Handler for packet type 0x%x returned %d\n",
12499ef8690bSSamuel Mendoza-Jonas 			   hdr->type, ret);
12509771b8ccSJustin.Lee1@Dell.com 
12519771b8ccSJustin.Lee1@Dell.com out_netlink:
12529771b8ccSJustin.Lee1@Dell.com 	if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
12539771b8ccSJustin.Lee1@Dell.com 		ret = ncsi_rsp_handler_netlink(nr);
12549771b8ccSJustin.Lee1@Dell.com 		if (ret) {
12559771b8ccSJustin.Lee1@Dell.com 			netdev_err(ndp->ndev.dev,
12569771b8ccSJustin.Lee1@Dell.com 				   "NCSI: Netlink handler for packet type 0x%x returned %d\n",
12579771b8ccSJustin.Lee1@Dell.com 				   hdr->type, ret);
12589771b8ccSJustin.Lee1@Dell.com 		}
12599771b8ccSJustin.Lee1@Dell.com 	}
12609771b8ccSJustin.Lee1@Dell.com 
1261138635ccSGavin Shan out:
1262138635ccSGavin Shan 	ncsi_free_request(nr);
1263138635ccSGavin Shan 	return ret;
1264138635ccSGavin Shan }
1265