xref: /openbmc/linux/net/ncsi/ncsi-rsp.c (revision 8d951a75d022d94a05f5fa74217670a981e8302d)
1138635ccSGavin Shan /*
2138635ccSGavin Shan  * Copyright Gavin Shan, IBM Corporation 2016.
3138635ccSGavin Shan  *
4138635ccSGavin Shan  * This program is free software; you can redistribute it and/or modify
5138635ccSGavin Shan  * it under the terms of the GNU General Public License as published by
6138635ccSGavin Shan  * the Free Software Foundation; either version 2 of the License, or
7138635ccSGavin Shan  * (at your option) any later version.
8138635ccSGavin Shan  */
9138635ccSGavin Shan 
10138635ccSGavin Shan #include <linux/module.h>
11138635ccSGavin Shan #include <linux/kernel.h>
12138635ccSGavin Shan #include <linux/init.h>
13138635ccSGavin Shan #include <linux/netdevice.h>
14138635ccSGavin Shan #include <linux/skbuff.h>
15138635ccSGavin Shan 
16138635ccSGavin Shan #include <net/ncsi.h>
17138635ccSGavin Shan #include <net/net_namespace.h>
18138635ccSGavin Shan #include <net/sock.h>
199771b8ccSJustin.Lee1@Dell.com #include <net/genetlink.h>
20138635ccSGavin Shan 
21138635ccSGavin Shan #include "internal.h"
22138635ccSGavin Shan #include "ncsi-pkt.h"
239771b8ccSJustin.Lee1@Dell.com #include "ncsi-netlink.h"
24138635ccSGavin Shan 
25138635ccSGavin Shan static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
26138635ccSGavin Shan 				 unsigned short payload)
27138635ccSGavin Shan {
28138635ccSGavin Shan 	struct ncsi_rsp_pkt_hdr *h;
29138635ccSGavin Shan 	u32 checksum;
30138635ccSGavin Shan 	__be32 *pchecksum;
31138635ccSGavin Shan 
32138635ccSGavin Shan 	/* Check NCSI packet header. We don't need validate
33138635ccSGavin Shan 	 * the packet type, which should have been checked
34138635ccSGavin Shan 	 * before calling this function.
35138635ccSGavin Shan 	 */
36138635ccSGavin Shan 	h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp);
379771b8ccSJustin.Lee1@Dell.com 
389771b8ccSJustin.Lee1@Dell.com 	if (h->common.revision != NCSI_PKT_REVISION) {
399771b8ccSJustin.Lee1@Dell.com 		netdev_dbg(nr->ndp->ndev.dev,
409771b8ccSJustin.Lee1@Dell.com 			   "NCSI: unsupported header revision\n");
41138635ccSGavin Shan 		return -EINVAL;
429771b8ccSJustin.Lee1@Dell.com 	}
439771b8ccSJustin.Lee1@Dell.com 	if (ntohs(h->common.length) != payload) {
449771b8ccSJustin.Lee1@Dell.com 		netdev_dbg(nr->ndp->ndev.dev,
459771b8ccSJustin.Lee1@Dell.com 			   "NCSI: payload length mismatched\n");
46138635ccSGavin Shan 		return -EINVAL;
479771b8ccSJustin.Lee1@Dell.com 	}
48138635ccSGavin Shan 
49138635ccSGavin Shan 	/* Check on code and reason */
50138635ccSGavin Shan 	if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED ||
519771b8ccSJustin.Lee1@Dell.com 	    ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) {
529771b8ccSJustin.Lee1@Dell.com 		netdev_dbg(nr->ndp->ndev.dev,
539771b8ccSJustin.Lee1@Dell.com 			   "NCSI: non zero response/reason code\n");
549771b8ccSJustin.Lee1@Dell.com 		return -EPERM;
559771b8ccSJustin.Lee1@Dell.com 	}
56138635ccSGavin Shan 
57138635ccSGavin Shan 	/* Validate checksum, which might be zeroes if the
58138635ccSGavin Shan 	 * sender doesn't support checksum according to NCSI
59138635ccSGavin Shan 	 * specification.
60138635ccSGavin Shan 	 */
61138635ccSGavin Shan 	pchecksum = (__be32 *)((void *)(h + 1) + payload - 4);
62138635ccSGavin Shan 	if (ntohl(*pchecksum) == 0)
63138635ccSGavin Shan 		return 0;
64138635ccSGavin Shan 
65138635ccSGavin Shan 	checksum = ncsi_calculate_checksum((unsigned char *)h,
66138635ccSGavin Shan 					   sizeof(*h) + payload - 4);
679771b8ccSJustin.Lee1@Dell.com 
689771b8ccSJustin.Lee1@Dell.com 	if (*pchecksum != htonl(checksum)) {
699771b8ccSJustin.Lee1@Dell.com 		netdev_dbg(nr->ndp->ndev.dev, "NCSI: checksum mismatched\n");
70138635ccSGavin Shan 		return -EINVAL;
719771b8ccSJustin.Lee1@Dell.com 	}
72138635ccSGavin Shan 
73138635ccSGavin Shan 	return 0;
74138635ccSGavin Shan }
75138635ccSGavin Shan 
76138635ccSGavin Shan static int ncsi_rsp_handler_cis(struct ncsi_request *nr)
77138635ccSGavin Shan {
78138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
79138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
80138635ccSGavin Shan 	struct ncsi_package *np;
81138635ccSGavin Shan 	struct ncsi_channel *nc;
82138635ccSGavin Shan 	unsigned char id;
83138635ccSGavin Shan 
84138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
85138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, &nc);
86138635ccSGavin Shan 	if (!nc) {
87e6f44ed6SGavin Shan 		if (ndp->flags & NCSI_DEV_PROBED)
88e6f44ed6SGavin Shan 			return -ENXIO;
89e6f44ed6SGavin Shan 
90138635ccSGavin Shan 		id = NCSI_CHANNEL_INDEX(rsp->rsp.common.channel);
91138635ccSGavin Shan 		nc = ncsi_add_channel(np, id);
92138635ccSGavin Shan 	}
93138635ccSGavin Shan 
94138635ccSGavin Shan 	return nc ? 0 : -ENODEV;
95138635ccSGavin Shan }
96138635ccSGavin Shan 
97138635ccSGavin Shan static int ncsi_rsp_handler_sp(struct ncsi_request *nr)
98138635ccSGavin Shan {
99138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
100138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
101138635ccSGavin Shan 	struct ncsi_package *np;
102138635ccSGavin Shan 	unsigned char id;
103138635ccSGavin Shan 
104138635ccSGavin Shan 	/* Add the package if it's not existing. Otherwise,
105138635ccSGavin Shan 	 * to change the state of its child channels.
106138635ccSGavin Shan 	 */
107138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
108138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
109138635ccSGavin Shan 				      &np, NULL);
110138635ccSGavin Shan 	if (!np) {
111e6f44ed6SGavin Shan 		if (ndp->flags & NCSI_DEV_PROBED)
112e6f44ed6SGavin Shan 			return -ENXIO;
113e6f44ed6SGavin Shan 
114138635ccSGavin Shan 		id = NCSI_PACKAGE_INDEX(rsp->rsp.common.channel);
115138635ccSGavin Shan 		np = ncsi_add_package(ndp, id);
116138635ccSGavin Shan 		if (!np)
117138635ccSGavin Shan 			return -ENODEV;
118138635ccSGavin Shan 	}
119138635ccSGavin Shan 
120138635ccSGavin Shan 	return 0;
121138635ccSGavin Shan }
122138635ccSGavin Shan 
123138635ccSGavin Shan static int ncsi_rsp_handler_dp(struct ncsi_request *nr)
124138635ccSGavin Shan {
125138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
126138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
127138635ccSGavin Shan 	struct ncsi_package *np;
128138635ccSGavin Shan 	struct ncsi_channel *nc;
129138635ccSGavin Shan 	unsigned long flags;
130138635ccSGavin Shan 
131138635ccSGavin Shan 	/* Find the package */
132138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
133138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
134138635ccSGavin Shan 				      &np, NULL);
135138635ccSGavin Shan 	if (!np)
136138635ccSGavin Shan 		return -ENODEV;
137138635ccSGavin Shan 
138138635ccSGavin Shan 	/* Change state of all channels attached to the package */
139138635ccSGavin Shan 	NCSI_FOR_EACH_CHANNEL(np, nc) {
140138635ccSGavin Shan 		spin_lock_irqsave(&nc->lock, flags);
141138635ccSGavin Shan 		nc->state = NCSI_CHANNEL_INACTIVE;
142138635ccSGavin Shan 		spin_unlock_irqrestore(&nc->lock, flags);
143138635ccSGavin Shan 	}
144138635ccSGavin Shan 
145138635ccSGavin Shan 	return 0;
146138635ccSGavin Shan }
147138635ccSGavin Shan 
148138635ccSGavin Shan static int ncsi_rsp_handler_ec(struct ncsi_request *nr)
149138635ccSGavin Shan {
150138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
151138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
152138635ccSGavin Shan 	struct ncsi_channel *nc;
153138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
154138635ccSGavin Shan 
155138635ccSGavin Shan 	/* Find the package and channel */
156138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
157138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
158138635ccSGavin Shan 				      NULL, &nc);
159138635ccSGavin Shan 	if (!nc)
160138635ccSGavin Shan 		return -ENODEV;
161138635ccSGavin Shan 
162138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_ENABLE];
163138635ccSGavin Shan 	if (ncm->enable)
16404bad8bdSSamuel Mendoza-Jonas 		return 0;
165138635ccSGavin Shan 
166138635ccSGavin Shan 	ncm->enable = 1;
167138635ccSGavin Shan 	return 0;
168138635ccSGavin Shan }
169138635ccSGavin Shan 
170138635ccSGavin Shan static int ncsi_rsp_handler_dc(struct ncsi_request *nr)
171138635ccSGavin Shan {
172138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
173138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
174138635ccSGavin Shan 	struct ncsi_channel *nc;
175138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
176138635ccSGavin Shan 	int ret;
177138635ccSGavin Shan 
178138635ccSGavin Shan 	ret = ncsi_validate_rsp_pkt(nr, 4);
179138635ccSGavin Shan 	if (ret)
180138635ccSGavin Shan 		return ret;
181138635ccSGavin Shan 
182138635ccSGavin Shan 	/* Find the package and channel */
183138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
184138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
185138635ccSGavin Shan 				      NULL, &nc);
186138635ccSGavin Shan 	if (!nc)
187138635ccSGavin Shan 		return -ENODEV;
188138635ccSGavin Shan 
189138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_ENABLE];
190138635ccSGavin Shan 	if (!ncm->enable)
19104bad8bdSSamuel Mendoza-Jonas 		return 0;
192138635ccSGavin Shan 
193138635ccSGavin Shan 	ncm->enable = 0;
194138635ccSGavin Shan 	return 0;
195138635ccSGavin Shan }
196138635ccSGavin Shan 
197138635ccSGavin Shan static int ncsi_rsp_handler_rc(struct ncsi_request *nr)
198138635ccSGavin Shan {
199138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
200138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
201138635ccSGavin Shan 	struct ncsi_channel *nc;
202138635ccSGavin Shan 	unsigned long flags;
203138635ccSGavin Shan 
204138635ccSGavin Shan 	/* Find the package and channel */
205138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
206138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
207138635ccSGavin Shan 				      NULL, &nc);
208138635ccSGavin Shan 	if (!nc)
209138635ccSGavin Shan 		return -ENODEV;
210138635ccSGavin Shan 
211138635ccSGavin Shan 	/* Update state for the specified channel */
212138635ccSGavin Shan 	spin_lock_irqsave(&nc->lock, flags);
213138635ccSGavin Shan 	nc->state = NCSI_CHANNEL_INACTIVE;
214138635ccSGavin Shan 	spin_unlock_irqrestore(&nc->lock, flags);
215138635ccSGavin Shan 
216138635ccSGavin Shan 	return 0;
217138635ccSGavin Shan }
218138635ccSGavin Shan 
219138635ccSGavin Shan static int ncsi_rsp_handler_ecnt(struct ncsi_request *nr)
220138635ccSGavin Shan {
221138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
222138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
223138635ccSGavin Shan 	struct ncsi_channel *nc;
224138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
225138635ccSGavin Shan 
226138635ccSGavin Shan 	/* Find the package and channel */
227138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
228138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
229138635ccSGavin Shan 				      NULL, &nc);
230138635ccSGavin Shan 	if (!nc)
231138635ccSGavin Shan 		return -ENODEV;
232138635ccSGavin Shan 
233138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
234138635ccSGavin Shan 	if (ncm->enable)
23504bad8bdSSamuel Mendoza-Jonas 		return 0;
236138635ccSGavin Shan 
237138635ccSGavin Shan 	ncm->enable = 1;
238138635ccSGavin Shan 	return 0;
239138635ccSGavin Shan }
240138635ccSGavin Shan 
241138635ccSGavin Shan static int ncsi_rsp_handler_dcnt(struct ncsi_request *nr)
242138635ccSGavin Shan {
243138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
244138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
245138635ccSGavin Shan 	struct ncsi_channel *nc;
246138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
247138635ccSGavin Shan 
248138635ccSGavin Shan 	/* Find the package and channel */
249138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
250138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
251138635ccSGavin Shan 				      NULL, &nc);
252138635ccSGavin Shan 	if (!nc)
253138635ccSGavin Shan 		return -ENODEV;
254138635ccSGavin Shan 
255138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
256138635ccSGavin Shan 	if (!ncm->enable)
25704bad8bdSSamuel Mendoza-Jonas 		return 0;
258138635ccSGavin Shan 
259*8d951a75SSamuel Mendoza-Jonas 	ncm->enable = 0;
260138635ccSGavin Shan 	return 0;
261138635ccSGavin Shan }
262138635ccSGavin Shan 
263138635ccSGavin Shan static int ncsi_rsp_handler_ae(struct ncsi_request *nr)
264138635ccSGavin Shan {
265138635ccSGavin Shan 	struct ncsi_cmd_ae_pkt *cmd;
266138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
267138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
268138635ccSGavin Shan 	struct ncsi_channel *nc;
269138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
270138635ccSGavin Shan 
271138635ccSGavin Shan 	/* Find the package and channel */
272138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
273138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
274138635ccSGavin Shan 				      NULL, &nc);
275138635ccSGavin Shan 	if (!nc)
276138635ccSGavin Shan 		return -ENODEV;
277138635ccSGavin Shan 
278138635ccSGavin Shan 	/* Check if the AEN has been enabled */
279138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_AEN];
280138635ccSGavin Shan 	if (ncm->enable)
28104bad8bdSSamuel Mendoza-Jonas 		return 0;
282138635ccSGavin Shan 
283138635ccSGavin Shan 	/* Update to AEN configuration */
284138635ccSGavin Shan 	cmd = (struct ncsi_cmd_ae_pkt *)skb_network_header(nr->cmd);
285138635ccSGavin Shan 	ncm->enable = 1;
286138635ccSGavin Shan 	ncm->data[0] = cmd->mc_id;
287138635ccSGavin Shan 	ncm->data[1] = ntohl(cmd->mode);
288138635ccSGavin Shan 
289138635ccSGavin Shan 	return 0;
290138635ccSGavin Shan }
291138635ccSGavin Shan 
292138635ccSGavin Shan static int ncsi_rsp_handler_sl(struct ncsi_request *nr)
293138635ccSGavin Shan {
294138635ccSGavin Shan 	struct ncsi_cmd_sl_pkt *cmd;
295138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
296138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
297138635ccSGavin Shan 	struct ncsi_channel *nc;
298138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
299138635ccSGavin Shan 
300138635ccSGavin Shan 	/* Find the package and channel */
301138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
302138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
303138635ccSGavin Shan 				      NULL, &nc);
304138635ccSGavin Shan 	if (!nc)
305138635ccSGavin Shan 		return -ENODEV;
306138635ccSGavin Shan 
307138635ccSGavin Shan 	cmd = (struct ncsi_cmd_sl_pkt *)skb_network_header(nr->cmd);
308138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_LINK];
309138635ccSGavin Shan 	ncm->data[0] = ntohl(cmd->mode);
310138635ccSGavin Shan 	ncm->data[1] = ntohl(cmd->oem_mode);
311138635ccSGavin Shan 
312138635ccSGavin Shan 	return 0;
313138635ccSGavin Shan }
314138635ccSGavin Shan 
315138635ccSGavin Shan static int ncsi_rsp_handler_gls(struct ncsi_request *nr)
316138635ccSGavin Shan {
317138635ccSGavin Shan 	struct ncsi_rsp_gls_pkt *rsp;
318138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
319138635ccSGavin Shan 	struct ncsi_channel *nc;
320138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
321e6f44ed6SGavin Shan 	unsigned long flags;
322138635ccSGavin Shan 
323138635ccSGavin Shan 	/* Find the package and channel */
324138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gls_pkt *)skb_network_header(nr->rsp);
325138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
326138635ccSGavin Shan 				      NULL, &nc);
327138635ccSGavin Shan 	if (!nc)
328138635ccSGavin Shan 		return -ENODEV;
329138635ccSGavin Shan 
330138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_LINK];
331138635ccSGavin Shan 	ncm->data[2] = ntohl(rsp->status);
332138635ccSGavin Shan 	ncm->data[3] = ntohl(rsp->other);
333138635ccSGavin Shan 	ncm->data[4] = ntohl(rsp->oem_status);
334138635ccSGavin Shan 
335a0509cbeSGavin Shan 	if (nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN)
336e6f44ed6SGavin Shan 		return 0;
337e6f44ed6SGavin Shan 
338e6f44ed6SGavin Shan 	/* Reset the channel monitor if it has been enabled */
339e6f44ed6SGavin Shan 	spin_lock_irqsave(&nc->lock, flags);
34083afdc6aSGavin Shan 	nc->monitor.state = NCSI_CHANNEL_MONITOR_START;
341e6f44ed6SGavin Shan 	spin_unlock_irqrestore(&nc->lock, flags);
342e6f44ed6SGavin Shan 
343138635ccSGavin Shan 	return 0;
344138635ccSGavin Shan }
345138635ccSGavin Shan 
346138635ccSGavin Shan static int ncsi_rsp_handler_svf(struct ncsi_request *nr)
347138635ccSGavin Shan {
348138635ccSGavin Shan 	struct ncsi_cmd_svf_pkt *cmd;
349138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
350138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
351138635ccSGavin Shan 	struct ncsi_channel *nc;
352062b3e1bSSamuel Mendoza-Jonas 	struct ncsi_channel_vlan_filter *ncf;
353062b3e1bSSamuel Mendoza-Jonas 	unsigned long flags;
354062b3e1bSSamuel Mendoza-Jonas 	void *bitmap;
355138635ccSGavin Shan 
356138635ccSGavin Shan 	/* Find the package and channel */
357138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
358138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
359138635ccSGavin Shan 				      NULL, &nc);
360138635ccSGavin Shan 	if (!nc)
361138635ccSGavin Shan 		return -ENODEV;
362138635ccSGavin Shan 
363138635ccSGavin Shan 	cmd = (struct ncsi_cmd_svf_pkt *)skb_network_header(nr->cmd);
364062b3e1bSSamuel Mendoza-Jonas 	ncf = &nc->vlan_filter;
365990a9d49SDan Carpenter 	if (cmd->index == 0 || cmd->index > ncf->n_vids)
366138635ccSGavin Shan 		return -ERANGE;
367138635ccSGavin Shan 
368062b3e1bSSamuel Mendoza-Jonas 	/* Add or remove the VLAN filter. Remember HW indexes from 1 */
369062b3e1bSSamuel Mendoza-Jonas 	spin_lock_irqsave(&nc->lock, flags);
370062b3e1bSSamuel Mendoza-Jonas 	bitmap = &ncf->bitmap;
371138635ccSGavin Shan 	if (!(cmd->enable & 0x1)) {
372062b3e1bSSamuel Mendoza-Jonas 		if (test_and_clear_bit(cmd->index - 1, bitmap))
373062b3e1bSSamuel Mendoza-Jonas 			ncf->vids[cmd->index - 1] = 0;
374138635ccSGavin Shan 	} else {
375062b3e1bSSamuel Mendoza-Jonas 		set_bit(cmd->index - 1, bitmap);
376062b3e1bSSamuel Mendoza-Jonas 		ncf->vids[cmd->index - 1] = ntohs(cmd->vlan);
377138635ccSGavin Shan 	}
378062b3e1bSSamuel Mendoza-Jonas 	spin_unlock_irqrestore(&nc->lock, flags);
379138635ccSGavin Shan 
380062b3e1bSSamuel Mendoza-Jonas 	return 0;
381138635ccSGavin Shan }
382138635ccSGavin Shan 
383138635ccSGavin Shan static int ncsi_rsp_handler_ev(struct ncsi_request *nr)
384138635ccSGavin Shan {
385138635ccSGavin Shan 	struct ncsi_cmd_ev_pkt *cmd;
386138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
387138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
388138635ccSGavin Shan 	struct ncsi_channel *nc;
389138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
390138635ccSGavin Shan 
391138635ccSGavin Shan 	/* Find the package and channel */
392138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
393138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
394138635ccSGavin Shan 				      NULL, &nc);
395138635ccSGavin Shan 	if (!nc)
396138635ccSGavin Shan 		return -ENODEV;
397138635ccSGavin Shan 
398138635ccSGavin Shan 	/* Check if VLAN mode has been enabled */
399138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_VLAN];
400138635ccSGavin Shan 	if (ncm->enable)
40104bad8bdSSamuel Mendoza-Jonas 		return 0;
402138635ccSGavin Shan 
403138635ccSGavin Shan 	/* Update to VLAN mode */
404138635ccSGavin Shan 	cmd = (struct ncsi_cmd_ev_pkt *)skb_network_header(nr->cmd);
405138635ccSGavin Shan 	ncm->enable = 1;
406138635ccSGavin Shan 	ncm->data[0] = ntohl(cmd->mode);
407138635ccSGavin Shan 
408138635ccSGavin Shan 	return 0;
409138635ccSGavin Shan }
410138635ccSGavin Shan 
411138635ccSGavin Shan static int ncsi_rsp_handler_dv(struct ncsi_request *nr)
412138635ccSGavin Shan {
413138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
414138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
415138635ccSGavin Shan 	struct ncsi_channel *nc;
416138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
417138635ccSGavin Shan 
418138635ccSGavin Shan 	/* Find the package and channel */
419138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
420138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
421138635ccSGavin Shan 				      NULL, &nc);
422138635ccSGavin Shan 	if (!nc)
423138635ccSGavin Shan 		return -ENODEV;
424138635ccSGavin Shan 
425138635ccSGavin Shan 	/* Check if VLAN mode has been enabled */
426138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_VLAN];
427138635ccSGavin Shan 	if (!ncm->enable)
42804bad8bdSSamuel Mendoza-Jonas 		return 0;
429138635ccSGavin Shan 
430138635ccSGavin Shan 	/* Update to VLAN mode */
431138635ccSGavin Shan 	ncm->enable = 0;
432138635ccSGavin Shan 	return 0;
433138635ccSGavin Shan }
434138635ccSGavin Shan 
435138635ccSGavin Shan static int ncsi_rsp_handler_sma(struct ncsi_request *nr)
436138635ccSGavin Shan {
437138635ccSGavin Shan 	struct ncsi_cmd_sma_pkt *cmd;
438138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
439138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
440138635ccSGavin Shan 	struct ncsi_channel *nc;
441062b3e1bSSamuel Mendoza-Jonas 	struct ncsi_channel_mac_filter *ncf;
442062b3e1bSSamuel Mendoza-Jonas 	unsigned long flags;
443138635ccSGavin Shan 	void *bitmap;
444062b3e1bSSamuel Mendoza-Jonas 	bool enabled;
445062b3e1bSSamuel Mendoza-Jonas 	int index;
446062b3e1bSSamuel Mendoza-Jonas 
447138635ccSGavin Shan 
448138635ccSGavin Shan 	/* Find the package and channel */
449138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
450138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
451138635ccSGavin Shan 				      NULL, &nc);
452138635ccSGavin Shan 	if (!nc)
453138635ccSGavin Shan 		return -ENODEV;
454138635ccSGavin Shan 
455138635ccSGavin Shan 	/* According to NCSI spec 1.01, the mixed filter table
456138635ccSGavin Shan 	 * isn't supported yet.
457138635ccSGavin Shan 	 */
458138635ccSGavin Shan 	cmd = (struct ncsi_cmd_sma_pkt *)skb_network_header(nr->cmd);
459062b3e1bSSamuel Mendoza-Jonas 	enabled = cmd->at_e & 0x1;
460062b3e1bSSamuel Mendoza-Jonas 	ncf = &nc->mac_filter;
461062b3e1bSSamuel Mendoza-Jonas 	bitmap = &ncf->bitmap;
462138635ccSGavin Shan 
463990a9d49SDan Carpenter 	if (cmd->index == 0 ||
464990a9d49SDan Carpenter 	    cmd->index > ncf->n_uc + ncf->n_mc + ncf->n_mixed)
465138635ccSGavin Shan 		return -ERANGE;
466138635ccSGavin Shan 
467062b3e1bSSamuel Mendoza-Jonas 	index = (cmd->index - 1) * ETH_ALEN;
468062b3e1bSSamuel Mendoza-Jonas 	spin_lock_irqsave(&nc->lock, flags);
469062b3e1bSSamuel Mendoza-Jonas 	if (enabled) {
470062b3e1bSSamuel Mendoza-Jonas 		set_bit(cmd->index - 1, bitmap);
471062b3e1bSSamuel Mendoza-Jonas 		memcpy(&ncf->addrs[index], cmd->mac, ETH_ALEN);
472138635ccSGavin Shan 	} else {
473062b3e1bSSamuel Mendoza-Jonas 		clear_bit(cmd->index - 1, bitmap);
474062b3e1bSSamuel Mendoza-Jonas 		memset(&ncf->addrs[index], 0, ETH_ALEN);
475138635ccSGavin Shan 	}
476062b3e1bSSamuel Mendoza-Jonas 	spin_unlock_irqrestore(&nc->lock, flags);
477138635ccSGavin Shan 
478138635ccSGavin Shan 	return 0;
479138635ccSGavin Shan }
480138635ccSGavin Shan 
481138635ccSGavin Shan static int ncsi_rsp_handler_ebf(struct ncsi_request *nr)
482138635ccSGavin Shan {
483138635ccSGavin Shan 	struct ncsi_cmd_ebf_pkt *cmd;
484138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
485138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
486138635ccSGavin Shan 	struct ncsi_channel *nc;
487138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
488138635ccSGavin Shan 
489138635ccSGavin Shan 	/* Find the package and channel */
490138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
491138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc);
492138635ccSGavin Shan 	if (!nc)
493138635ccSGavin Shan 		return -ENODEV;
494138635ccSGavin Shan 
495138635ccSGavin Shan 	/* Check if broadcast filter has been enabled */
496138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_BC];
497138635ccSGavin Shan 	if (ncm->enable)
49804bad8bdSSamuel Mendoza-Jonas 		return 0;
499138635ccSGavin Shan 
500138635ccSGavin Shan 	/* Update to broadcast filter mode */
501138635ccSGavin Shan 	cmd = (struct ncsi_cmd_ebf_pkt *)skb_network_header(nr->cmd);
502138635ccSGavin Shan 	ncm->enable = 1;
503138635ccSGavin Shan 	ncm->data[0] = ntohl(cmd->mode);
504138635ccSGavin Shan 
505138635ccSGavin Shan 	return 0;
506138635ccSGavin Shan }
507138635ccSGavin Shan 
508138635ccSGavin Shan static int ncsi_rsp_handler_dbf(struct ncsi_request *nr)
509138635ccSGavin Shan {
510138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
511138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
512138635ccSGavin Shan 	struct ncsi_channel *nc;
513138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
514138635ccSGavin Shan 
515138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
516138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
517138635ccSGavin Shan 				      NULL, &nc);
518138635ccSGavin Shan 	if (!nc)
519138635ccSGavin Shan 		return -ENODEV;
520138635ccSGavin Shan 
521138635ccSGavin Shan 	/* Check if broadcast filter isn't enabled */
522138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_BC];
523138635ccSGavin Shan 	if (!ncm->enable)
52404bad8bdSSamuel Mendoza-Jonas 		return 0;
525138635ccSGavin Shan 
526138635ccSGavin Shan 	/* Update to broadcast filter mode */
527138635ccSGavin Shan 	ncm->enable = 0;
528138635ccSGavin Shan 	ncm->data[0] = 0;
529138635ccSGavin Shan 
530138635ccSGavin Shan 	return 0;
531138635ccSGavin Shan }
532138635ccSGavin Shan 
533138635ccSGavin Shan static int ncsi_rsp_handler_egmf(struct ncsi_request *nr)
534138635ccSGavin Shan {
535138635ccSGavin Shan 	struct ncsi_cmd_egmf_pkt *cmd;
536138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
537138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
538138635ccSGavin Shan 	struct ncsi_channel *nc;
539138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
540138635ccSGavin Shan 
541138635ccSGavin Shan 	/* Find the channel */
542138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
543138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
544138635ccSGavin Shan 				      NULL, &nc);
545138635ccSGavin Shan 	if (!nc)
546138635ccSGavin Shan 		return -ENODEV;
547138635ccSGavin Shan 
548138635ccSGavin Shan 	/* Check if multicast filter has been enabled */
549138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_MC];
550138635ccSGavin Shan 	if (ncm->enable)
55104bad8bdSSamuel Mendoza-Jonas 		return 0;
552138635ccSGavin Shan 
553138635ccSGavin Shan 	/* Update to multicast filter mode */
554138635ccSGavin Shan 	cmd = (struct ncsi_cmd_egmf_pkt *)skb_network_header(nr->cmd);
555138635ccSGavin Shan 	ncm->enable = 1;
556138635ccSGavin Shan 	ncm->data[0] = ntohl(cmd->mode);
557138635ccSGavin Shan 
558138635ccSGavin Shan 	return 0;
559138635ccSGavin Shan }
560138635ccSGavin Shan 
561138635ccSGavin Shan static int ncsi_rsp_handler_dgmf(struct ncsi_request *nr)
562138635ccSGavin Shan {
563138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
564138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
565138635ccSGavin Shan 	struct ncsi_channel *nc;
566138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
567138635ccSGavin Shan 
568138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
569138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
570138635ccSGavin Shan 				      NULL, &nc);
571138635ccSGavin Shan 	if (!nc)
572138635ccSGavin Shan 		return -ENODEV;
573138635ccSGavin Shan 
574138635ccSGavin Shan 	/* Check if multicast filter has been enabled */
575138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_MC];
576138635ccSGavin Shan 	if (!ncm->enable)
57704bad8bdSSamuel Mendoza-Jonas 		return 0;
578138635ccSGavin Shan 
579138635ccSGavin Shan 	/* Update to multicast filter mode */
580138635ccSGavin Shan 	ncm->enable = 0;
581138635ccSGavin Shan 	ncm->data[0] = 0;
582138635ccSGavin Shan 
583138635ccSGavin Shan 	return 0;
584138635ccSGavin Shan }
585138635ccSGavin Shan 
586138635ccSGavin Shan static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
587138635ccSGavin Shan {
588138635ccSGavin Shan 	struct ncsi_cmd_snfc_pkt *cmd;
589138635ccSGavin Shan 	struct ncsi_rsp_pkt *rsp;
590138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
591138635ccSGavin Shan 	struct ncsi_channel *nc;
592138635ccSGavin Shan 	struct ncsi_channel_mode *ncm;
593138635ccSGavin Shan 
594138635ccSGavin Shan 	/* Find the channel */
595138635ccSGavin Shan 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
596138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
597138635ccSGavin Shan 				      NULL, &nc);
598138635ccSGavin Shan 	if (!nc)
599138635ccSGavin Shan 		return -ENODEV;
600138635ccSGavin Shan 
601138635ccSGavin Shan 	/* Check if flow control has been enabled */
602138635ccSGavin Shan 	ncm = &nc->modes[NCSI_MODE_FC];
603138635ccSGavin Shan 	if (ncm->enable)
60404bad8bdSSamuel Mendoza-Jonas 		return 0;
605138635ccSGavin Shan 
606138635ccSGavin Shan 	/* Update to flow control mode */
607138635ccSGavin Shan 	cmd = (struct ncsi_cmd_snfc_pkt *)skb_network_header(nr->cmd);
608138635ccSGavin Shan 	ncm->enable = 1;
609138635ccSGavin Shan 	ncm->data[0] = cmd->mode;
610138635ccSGavin Shan 
611138635ccSGavin Shan 	return 0;
612138635ccSGavin Shan }
613138635ccSGavin Shan 
614cb10c7c0SVijay Khemka /* Response handler for Broadcom command Get Mac Address */
615cb10c7c0SVijay Khemka static int ncsi_rsp_handler_oem_bcm_gma(struct ncsi_request *nr)
616cb10c7c0SVijay Khemka {
617cb10c7c0SVijay Khemka 	struct ncsi_dev_priv *ndp = nr->ndp;
618cb10c7c0SVijay Khemka 	struct net_device *ndev = ndp->ndev.dev;
619cb10c7c0SVijay Khemka 	const struct net_device_ops *ops = ndev->netdev_ops;
620cb10c7c0SVijay Khemka 	struct ncsi_rsp_oem_pkt *rsp;
621cb10c7c0SVijay Khemka 	struct sockaddr saddr;
622cb10c7c0SVijay Khemka 	int ret = 0;
623cb10c7c0SVijay Khemka 
624cb10c7c0SVijay Khemka 	/* Get the response header */
625cb10c7c0SVijay Khemka 	rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
626cb10c7c0SVijay Khemka 
627cb10c7c0SVijay Khemka 	saddr.sa_family = ndev->type;
628cb10c7c0SVijay Khemka 	ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
629cb10c7c0SVijay Khemka 	memcpy(saddr.sa_data, &rsp->data[BCM_MAC_ADDR_OFFSET], ETH_ALEN);
630cb10c7c0SVijay Khemka 	/* Increase mac address by 1 for BMC's address */
631cb10c7c0SVijay Khemka 	saddr.sa_data[ETH_ALEN - 1]++;
632cb10c7c0SVijay Khemka 	ret = ops->ndo_set_mac_address(ndev, &saddr);
633cb10c7c0SVijay Khemka 	if (ret < 0)
634cb10c7c0SVijay Khemka 		netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n");
635cb10c7c0SVijay Khemka 
636cb10c7c0SVijay Khemka 	return ret;
637cb10c7c0SVijay Khemka }
638cb10c7c0SVijay Khemka 
639cb10c7c0SVijay Khemka /* Response handler for Broadcom card */
640cb10c7c0SVijay Khemka static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr)
641cb10c7c0SVijay Khemka {
642cb10c7c0SVijay Khemka 	struct ncsi_rsp_oem_bcm_pkt *bcm;
643cb10c7c0SVijay Khemka 	struct ncsi_rsp_oem_pkt *rsp;
644cb10c7c0SVijay Khemka 
645cb10c7c0SVijay Khemka 	/* Get the response header */
646cb10c7c0SVijay Khemka 	rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
647cb10c7c0SVijay Khemka 	bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data);
648cb10c7c0SVijay Khemka 
649cb10c7c0SVijay Khemka 	if (bcm->type == NCSI_OEM_BCM_CMD_GMA)
650cb10c7c0SVijay Khemka 		return ncsi_rsp_handler_oem_bcm_gma(nr);
651cb10c7c0SVijay Khemka 	return 0;
652cb10c7c0SVijay Khemka }
653cb10c7c0SVijay Khemka 
654fb4ee675SVijay Khemka static struct ncsi_rsp_oem_handler {
655fb4ee675SVijay Khemka 	unsigned int	mfr_id;
656fb4ee675SVijay Khemka 	int		(*handler)(struct ncsi_request *nr);
657fb4ee675SVijay Khemka } ncsi_rsp_oem_handlers[] = {
658fb4ee675SVijay Khemka 	{ NCSI_OEM_MFR_MLX_ID, NULL },
659cb10c7c0SVijay Khemka 	{ NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm }
660fb4ee675SVijay Khemka };
661fb4ee675SVijay Khemka 
662fb4ee675SVijay Khemka /* Response handler for OEM command */
663fb4ee675SVijay Khemka static int ncsi_rsp_handler_oem(struct ncsi_request *nr)
664fb4ee675SVijay Khemka {
665fb4ee675SVijay Khemka 	struct ncsi_rsp_oem_handler *nrh = NULL;
666cb10c7c0SVijay Khemka 	struct ncsi_rsp_oem_pkt *rsp;
667fb4ee675SVijay Khemka 	unsigned int mfr_id, i;
668fb4ee675SVijay Khemka 
669fb4ee675SVijay Khemka 	/* Get the response header */
670fb4ee675SVijay Khemka 	rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
671fb4ee675SVijay Khemka 	mfr_id = ntohl(rsp->mfr_id);
672fb4ee675SVijay Khemka 
673fb4ee675SVijay Khemka 	/* Check for manufacturer id and Find the handler */
674fb4ee675SVijay Khemka 	for (i = 0; i < ARRAY_SIZE(ncsi_rsp_oem_handlers); i++) {
675fb4ee675SVijay Khemka 		if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) {
676fb4ee675SVijay Khemka 			if (ncsi_rsp_oem_handlers[i].handler)
677fb4ee675SVijay Khemka 				nrh = &ncsi_rsp_oem_handlers[i];
678fb4ee675SVijay Khemka 			else
679fb4ee675SVijay Khemka 				nrh = NULL;
680fb4ee675SVijay Khemka 
681fb4ee675SVijay Khemka 			break;
682fb4ee675SVijay Khemka 		}
683fb4ee675SVijay Khemka 	}
684fb4ee675SVijay Khemka 
685fb4ee675SVijay Khemka 	if (!nrh) {
686fb4ee675SVijay Khemka 		netdev_err(nr->ndp->ndev.dev, "Received unrecognized OEM packet with MFR-ID (0x%x)\n",
687fb4ee675SVijay Khemka 			   mfr_id);
688fb4ee675SVijay Khemka 		return -ENOENT;
689fb4ee675SVijay Khemka 	}
690fb4ee675SVijay Khemka 
691fb4ee675SVijay Khemka 	/* Process the packet */
692fb4ee675SVijay Khemka 	return nrh->handler(nr);
693fb4ee675SVijay Khemka }
694fb4ee675SVijay Khemka 
695138635ccSGavin Shan static int ncsi_rsp_handler_gvi(struct ncsi_request *nr)
696138635ccSGavin Shan {
697138635ccSGavin Shan 	struct ncsi_rsp_gvi_pkt *rsp;
698138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
699138635ccSGavin Shan 	struct ncsi_channel *nc;
700138635ccSGavin Shan 	struct ncsi_channel_version *ncv;
701138635ccSGavin Shan 	int i;
702138635ccSGavin Shan 
703138635ccSGavin Shan 	/* Find the channel */
704138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gvi_pkt *)skb_network_header(nr->rsp);
705138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
706138635ccSGavin Shan 				      NULL, &nc);
707138635ccSGavin Shan 	if (!nc)
708138635ccSGavin Shan 		return -ENODEV;
709138635ccSGavin Shan 
710138635ccSGavin Shan 	/* Update to channel's version info */
711138635ccSGavin Shan 	ncv = &nc->version;
712138635ccSGavin Shan 	ncv->version = ntohl(rsp->ncsi_version);
713138635ccSGavin Shan 	ncv->alpha2 = rsp->alpha2;
714138635ccSGavin Shan 	memcpy(ncv->fw_name, rsp->fw_name, 12);
715138635ccSGavin Shan 	ncv->fw_version = ntohl(rsp->fw_version);
716138635ccSGavin Shan 	for (i = 0; i < ARRAY_SIZE(ncv->pci_ids); i++)
717138635ccSGavin Shan 		ncv->pci_ids[i] = ntohs(rsp->pci_ids[i]);
718138635ccSGavin Shan 	ncv->mf_id = ntohl(rsp->mf_id);
719138635ccSGavin Shan 
720138635ccSGavin Shan 	return 0;
721138635ccSGavin Shan }
722138635ccSGavin Shan 
723138635ccSGavin Shan static int ncsi_rsp_handler_gc(struct ncsi_request *nr)
724138635ccSGavin Shan {
725138635ccSGavin Shan 	struct ncsi_rsp_gc_pkt *rsp;
726138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
727138635ccSGavin Shan 	struct ncsi_channel *nc;
728062b3e1bSSamuel Mendoza-Jonas 	size_t size;
729138635ccSGavin Shan 
730138635ccSGavin Shan 	/* Find the channel */
731138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gc_pkt *)skb_network_header(nr->rsp);
732138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
733138635ccSGavin Shan 				      NULL, &nc);
734138635ccSGavin Shan 	if (!nc)
735138635ccSGavin Shan 		return -ENODEV;
736138635ccSGavin Shan 
737138635ccSGavin Shan 	/* Update channel's capabilities */
738138635ccSGavin Shan 	nc->caps[NCSI_CAP_GENERIC].cap = ntohl(rsp->cap) &
739138635ccSGavin Shan 					 NCSI_CAP_GENERIC_MASK;
740138635ccSGavin Shan 	nc->caps[NCSI_CAP_BC].cap = ntohl(rsp->bc_cap) &
741138635ccSGavin Shan 				    NCSI_CAP_BC_MASK;
742138635ccSGavin Shan 	nc->caps[NCSI_CAP_MC].cap = ntohl(rsp->mc_cap) &
743138635ccSGavin Shan 				    NCSI_CAP_MC_MASK;
744138635ccSGavin Shan 	nc->caps[NCSI_CAP_BUFFER].cap = ntohl(rsp->buf_cap);
745138635ccSGavin Shan 	nc->caps[NCSI_CAP_AEN].cap = ntohl(rsp->aen_cap) &
746138635ccSGavin Shan 				     NCSI_CAP_AEN_MASK;
747138635ccSGavin Shan 	nc->caps[NCSI_CAP_VLAN].cap = rsp->vlan_mode &
748138635ccSGavin Shan 				      NCSI_CAP_VLAN_MASK;
749138635ccSGavin Shan 
750062b3e1bSSamuel Mendoza-Jonas 	size = (rsp->uc_cnt + rsp->mc_cnt + rsp->mixed_cnt) * ETH_ALEN;
751b0949618SSamuel Mendoza-Jonas 	nc->mac_filter.addrs = kzalloc(size, GFP_ATOMIC);
752062b3e1bSSamuel Mendoza-Jonas 	if (!nc->mac_filter.addrs)
753138635ccSGavin Shan 		return -ENOMEM;
754062b3e1bSSamuel Mendoza-Jonas 	nc->mac_filter.n_uc = rsp->uc_cnt;
755062b3e1bSSamuel Mendoza-Jonas 	nc->mac_filter.n_mc = rsp->mc_cnt;
756062b3e1bSSamuel Mendoza-Jonas 	nc->mac_filter.n_mixed = rsp->mixed_cnt;
757138635ccSGavin Shan 
758062b3e1bSSamuel Mendoza-Jonas 	nc->vlan_filter.vids = kcalloc(rsp->vlan_cnt,
759062b3e1bSSamuel Mendoza-Jonas 				       sizeof(*nc->vlan_filter.vids),
760b0949618SSamuel Mendoza-Jonas 				       GFP_ATOMIC);
761062b3e1bSSamuel Mendoza-Jonas 	if (!nc->vlan_filter.vids)
762062b3e1bSSamuel Mendoza-Jonas 		return -ENOMEM;
763062b3e1bSSamuel Mendoza-Jonas 	/* Set VLAN filters active so they are cleared in the first
764062b3e1bSSamuel Mendoza-Jonas 	 * configuration state
76521acf630SSamuel Mendoza-Jonas 	 */
766062b3e1bSSamuel Mendoza-Jonas 	nc->vlan_filter.bitmap = U64_MAX;
767062b3e1bSSamuel Mendoza-Jonas 	nc->vlan_filter.n_vids = rsp->vlan_cnt;
768138635ccSGavin Shan 
769138635ccSGavin Shan 	return 0;
770138635ccSGavin Shan }
771138635ccSGavin Shan 
772138635ccSGavin Shan static int ncsi_rsp_handler_gp(struct ncsi_request *nr)
773138635ccSGavin Shan {
774062b3e1bSSamuel Mendoza-Jonas 	struct ncsi_channel_vlan_filter *ncvf;
775062b3e1bSSamuel Mendoza-Jonas 	struct ncsi_channel_mac_filter *ncmf;
776138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
777062b3e1bSSamuel Mendoza-Jonas 	struct ncsi_rsp_gp_pkt *rsp;
778138635ccSGavin Shan 	struct ncsi_channel *nc;
779062b3e1bSSamuel Mendoza-Jonas 	unsigned short enable;
780138635ccSGavin Shan 	unsigned char *pdata;
781062b3e1bSSamuel Mendoza-Jonas 	unsigned long flags;
782062b3e1bSSamuel Mendoza-Jonas 	void *bitmap;
783062b3e1bSSamuel Mendoza-Jonas 	int i;
784138635ccSGavin Shan 
785138635ccSGavin Shan 	/* Find the channel */
786138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gp_pkt *)skb_network_header(nr->rsp);
787138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
788138635ccSGavin Shan 				      NULL, &nc);
789138635ccSGavin Shan 	if (!nc)
790138635ccSGavin Shan 		return -ENODEV;
791138635ccSGavin Shan 
792138635ccSGavin Shan 	/* Modes with explicit enabled indications */
793138635ccSGavin Shan 	if (ntohl(rsp->valid_modes) & 0x1) {	/* BC filter mode */
794138635ccSGavin Shan 		nc->modes[NCSI_MODE_BC].enable = 1;
795138635ccSGavin Shan 		nc->modes[NCSI_MODE_BC].data[0] = ntohl(rsp->bc_mode);
796138635ccSGavin Shan 	}
797138635ccSGavin Shan 	if (ntohl(rsp->valid_modes) & 0x2)	/* Channel enabled */
798138635ccSGavin Shan 		nc->modes[NCSI_MODE_ENABLE].enable = 1;
799138635ccSGavin Shan 	if (ntohl(rsp->valid_modes) & 0x4)	/* Channel Tx enabled */
800138635ccSGavin Shan 		nc->modes[NCSI_MODE_TX_ENABLE].enable = 1;
801138635ccSGavin Shan 	if (ntohl(rsp->valid_modes) & 0x8)	/* MC filter mode */
802138635ccSGavin Shan 		nc->modes[NCSI_MODE_MC].enable = 1;
803138635ccSGavin Shan 
804138635ccSGavin Shan 	/* Modes without explicit enabled indications */
805138635ccSGavin Shan 	nc->modes[NCSI_MODE_LINK].enable = 1;
806138635ccSGavin Shan 	nc->modes[NCSI_MODE_LINK].data[0] = ntohl(rsp->link_mode);
807138635ccSGavin Shan 	nc->modes[NCSI_MODE_VLAN].enable = 1;
808138635ccSGavin Shan 	nc->modes[NCSI_MODE_VLAN].data[0] = rsp->vlan_mode;
809138635ccSGavin Shan 	nc->modes[NCSI_MODE_FC].enable = 1;
810138635ccSGavin Shan 	nc->modes[NCSI_MODE_FC].data[0] = rsp->fc_mode;
811138635ccSGavin Shan 	nc->modes[NCSI_MODE_AEN].enable = 1;
812138635ccSGavin Shan 	nc->modes[NCSI_MODE_AEN].data[0] = ntohl(rsp->aen_mode);
813138635ccSGavin Shan 
814138635ccSGavin Shan 	/* MAC addresses filter table */
815138635ccSGavin Shan 	pdata = (unsigned char *)rsp + 48;
816138635ccSGavin Shan 	enable = rsp->mac_enable;
817062b3e1bSSamuel Mendoza-Jonas 	ncmf = &nc->mac_filter;
818062b3e1bSSamuel Mendoza-Jonas 	spin_lock_irqsave(&nc->lock, flags);
819062b3e1bSSamuel Mendoza-Jonas 	bitmap = &ncmf->bitmap;
820138635ccSGavin Shan 	for (i = 0; i < rsp->mac_cnt; i++, pdata += 6) {
821138635ccSGavin Shan 		if (!(enable & (0x1 << i)))
822062b3e1bSSamuel Mendoza-Jonas 			clear_bit(i, bitmap);
823062b3e1bSSamuel Mendoza-Jonas 		else
824062b3e1bSSamuel Mendoza-Jonas 			set_bit(i, bitmap);
825138635ccSGavin Shan 
826062b3e1bSSamuel Mendoza-Jonas 		memcpy(&ncmf->addrs[i * ETH_ALEN], pdata, ETH_ALEN);
827138635ccSGavin Shan 	}
828062b3e1bSSamuel Mendoza-Jonas 	spin_unlock_irqrestore(&nc->lock, flags);
829138635ccSGavin Shan 
830138635ccSGavin Shan 	/* VLAN filter table */
831138635ccSGavin Shan 	enable = ntohs(rsp->vlan_enable);
832062b3e1bSSamuel Mendoza-Jonas 	ncvf = &nc->vlan_filter;
833062b3e1bSSamuel Mendoza-Jonas 	bitmap = &ncvf->bitmap;
834062b3e1bSSamuel Mendoza-Jonas 	spin_lock_irqsave(&nc->lock, flags);
835138635ccSGavin Shan 	for (i = 0; i < rsp->vlan_cnt; i++, pdata += 2) {
836138635ccSGavin Shan 		if (!(enable & (0x1 << i)))
837062b3e1bSSamuel Mendoza-Jonas 			clear_bit(i, bitmap);
838062b3e1bSSamuel Mendoza-Jonas 		else
839062b3e1bSSamuel Mendoza-Jonas 			set_bit(i, bitmap);
840138635ccSGavin Shan 
841062b3e1bSSamuel Mendoza-Jonas 		ncvf->vids[i] = ntohs(*(__be16 *)pdata);
842138635ccSGavin Shan 	}
843062b3e1bSSamuel Mendoza-Jonas 	spin_unlock_irqrestore(&nc->lock, flags);
844138635ccSGavin Shan 
845138635ccSGavin Shan 	return 0;
846138635ccSGavin Shan }
847138635ccSGavin Shan 
848138635ccSGavin Shan static int ncsi_rsp_handler_gcps(struct ncsi_request *nr)
849138635ccSGavin Shan {
850138635ccSGavin Shan 	struct ncsi_rsp_gcps_pkt *rsp;
851138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
852138635ccSGavin Shan 	struct ncsi_channel *nc;
853138635ccSGavin Shan 	struct ncsi_channel_stats *ncs;
854138635ccSGavin Shan 
855138635ccSGavin Shan 	/* Find the channel */
856138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gcps_pkt *)skb_network_header(nr->rsp);
857138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
858138635ccSGavin Shan 				      NULL, &nc);
859138635ccSGavin Shan 	if (!nc)
860138635ccSGavin Shan 		return -ENODEV;
861138635ccSGavin Shan 
862138635ccSGavin Shan 	/* Update HNC's statistics */
863138635ccSGavin Shan 	ncs = &nc->stats;
864138635ccSGavin Shan 	ncs->hnc_cnt_hi         = ntohl(rsp->cnt_hi);
865138635ccSGavin Shan 	ncs->hnc_cnt_lo         = ntohl(rsp->cnt_lo);
866138635ccSGavin Shan 	ncs->hnc_rx_bytes       = ntohl(rsp->rx_bytes);
867138635ccSGavin Shan 	ncs->hnc_tx_bytes       = ntohl(rsp->tx_bytes);
868138635ccSGavin Shan 	ncs->hnc_rx_uc_pkts     = ntohl(rsp->rx_uc_pkts);
869138635ccSGavin Shan 	ncs->hnc_rx_mc_pkts     = ntohl(rsp->rx_mc_pkts);
870138635ccSGavin Shan 	ncs->hnc_rx_bc_pkts     = ntohl(rsp->rx_bc_pkts);
871138635ccSGavin Shan 	ncs->hnc_tx_uc_pkts     = ntohl(rsp->tx_uc_pkts);
872138635ccSGavin Shan 	ncs->hnc_tx_mc_pkts     = ntohl(rsp->tx_mc_pkts);
873138635ccSGavin Shan 	ncs->hnc_tx_bc_pkts     = ntohl(rsp->tx_bc_pkts);
874138635ccSGavin Shan 	ncs->hnc_fcs_err        = ntohl(rsp->fcs_err);
875138635ccSGavin Shan 	ncs->hnc_align_err      = ntohl(rsp->align_err);
876138635ccSGavin Shan 	ncs->hnc_false_carrier  = ntohl(rsp->false_carrier);
877138635ccSGavin Shan 	ncs->hnc_runt_pkts      = ntohl(rsp->runt_pkts);
878138635ccSGavin Shan 	ncs->hnc_jabber_pkts    = ntohl(rsp->jabber_pkts);
879138635ccSGavin Shan 	ncs->hnc_rx_pause_xon   = ntohl(rsp->rx_pause_xon);
880138635ccSGavin Shan 	ncs->hnc_rx_pause_xoff  = ntohl(rsp->rx_pause_xoff);
881138635ccSGavin Shan 	ncs->hnc_tx_pause_xon   = ntohl(rsp->tx_pause_xon);
882138635ccSGavin Shan 	ncs->hnc_tx_pause_xoff  = ntohl(rsp->tx_pause_xoff);
883138635ccSGavin Shan 	ncs->hnc_tx_s_collision = ntohl(rsp->tx_s_collision);
884138635ccSGavin Shan 	ncs->hnc_tx_m_collision = ntohl(rsp->tx_m_collision);
885138635ccSGavin Shan 	ncs->hnc_l_collision    = ntohl(rsp->l_collision);
886138635ccSGavin Shan 	ncs->hnc_e_collision    = ntohl(rsp->e_collision);
887138635ccSGavin Shan 	ncs->hnc_rx_ctl_frames  = ntohl(rsp->rx_ctl_frames);
888138635ccSGavin Shan 	ncs->hnc_rx_64_frames   = ntohl(rsp->rx_64_frames);
889138635ccSGavin Shan 	ncs->hnc_rx_127_frames  = ntohl(rsp->rx_127_frames);
890138635ccSGavin Shan 	ncs->hnc_rx_255_frames  = ntohl(rsp->rx_255_frames);
891138635ccSGavin Shan 	ncs->hnc_rx_511_frames  = ntohl(rsp->rx_511_frames);
892138635ccSGavin Shan 	ncs->hnc_rx_1023_frames = ntohl(rsp->rx_1023_frames);
893138635ccSGavin Shan 	ncs->hnc_rx_1522_frames = ntohl(rsp->rx_1522_frames);
894138635ccSGavin Shan 	ncs->hnc_rx_9022_frames = ntohl(rsp->rx_9022_frames);
895138635ccSGavin Shan 	ncs->hnc_tx_64_frames   = ntohl(rsp->tx_64_frames);
896138635ccSGavin Shan 	ncs->hnc_tx_127_frames  = ntohl(rsp->tx_127_frames);
897138635ccSGavin Shan 	ncs->hnc_tx_255_frames  = ntohl(rsp->tx_255_frames);
898138635ccSGavin Shan 	ncs->hnc_tx_511_frames  = ntohl(rsp->tx_511_frames);
899138635ccSGavin Shan 	ncs->hnc_tx_1023_frames = ntohl(rsp->tx_1023_frames);
900138635ccSGavin Shan 	ncs->hnc_tx_1522_frames = ntohl(rsp->tx_1522_frames);
901138635ccSGavin Shan 	ncs->hnc_tx_9022_frames = ntohl(rsp->tx_9022_frames);
902138635ccSGavin Shan 	ncs->hnc_rx_valid_bytes = ntohl(rsp->rx_valid_bytes);
903138635ccSGavin Shan 	ncs->hnc_rx_runt_pkts   = ntohl(rsp->rx_runt_pkts);
904138635ccSGavin Shan 	ncs->hnc_rx_jabber_pkts = ntohl(rsp->rx_jabber_pkts);
905138635ccSGavin Shan 
906138635ccSGavin Shan 	return 0;
907138635ccSGavin Shan }
908138635ccSGavin Shan 
909138635ccSGavin Shan static int ncsi_rsp_handler_gns(struct ncsi_request *nr)
910138635ccSGavin Shan {
911138635ccSGavin Shan 	struct ncsi_rsp_gns_pkt *rsp;
912138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
913138635ccSGavin Shan 	struct ncsi_channel *nc;
914138635ccSGavin Shan 	struct ncsi_channel_stats *ncs;
915138635ccSGavin Shan 
916138635ccSGavin Shan 	/* Find the channel */
917138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gns_pkt *)skb_network_header(nr->rsp);
918138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
919138635ccSGavin Shan 				      NULL, &nc);
920138635ccSGavin Shan 	if (!nc)
921138635ccSGavin Shan 		return -ENODEV;
922138635ccSGavin Shan 
923138635ccSGavin Shan 	/* Update HNC's statistics */
924138635ccSGavin Shan 	ncs = &nc->stats;
925138635ccSGavin Shan 	ncs->ncsi_rx_cmds       = ntohl(rsp->rx_cmds);
926138635ccSGavin Shan 	ncs->ncsi_dropped_cmds  = ntohl(rsp->dropped_cmds);
927138635ccSGavin Shan 	ncs->ncsi_cmd_type_errs = ntohl(rsp->cmd_type_errs);
928138635ccSGavin Shan 	ncs->ncsi_cmd_csum_errs = ntohl(rsp->cmd_csum_errs);
929138635ccSGavin Shan 	ncs->ncsi_rx_pkts       = ntohl(rsp->rx_pkts);
930138635ccSGavin Shan 	ncs->ncsi_tx_pkts       = ntohl(rsp->tx_pkts);
931138635ccSGavin Shan 	ncs->ncsi_tx_aen_pkts   = ntohl(rsp->tx_aen_pkts);
932138635ccSGavin Shan 
933138635ccSGavin Shan 	return 0;
934138635ccSGavin Shan }
935138635ccSGavin Shan 
936138635ccSGavin Shan static int ncsi_rsp_handler_gnpts(struct ncsi_request *nr)
937138635ccSGavin Shan {
938138635ccSGavin Shan 	struct ncsi_rsp_gnpts_pkt *rsp;
939138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
940138635ccSGavin Shan 	struct ncsi_channel *nc;
941138635ccSGavin Shan 	struct ncsi_channel_stats *ncs;
942138635ccSGavin Shan 
943138635ccSGavin Shan 	/* Find the channel */
944138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gnpts_pkt *)skb_network_header(nr->rsp);
945138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
946138635ccSGavin Shan 				      NULL, &nc);
947138635ccSGavin Shan 	if (!nc)
948138635ccSGavin Shan 		return -ENODEV;
949138635ccSGavin Shan 
950138635ccSGavin Shan 	/* Update HNC's statistics */
951138635ccSGavin Shan 	ncs = &nc->stats;
952138635ccSGavin Shan 	ncs->pt_tx_pkts        = ntohl(rsp->tx_pkts);
953138635ccSGavin Shan 	ncs->pt_tx_dropped     = ntohl(rsp->tx_dropped);
954138635ccSGavin Shan 	ncs->pt_tx_channel_err = ntohl(rsp->tx_channel_err);
955138635ccSGavin Shan 	ncs->pt_tx_us_err      = ntohl(rsp->tx_us_err);
956138635ccSGavin Shan 	ncs->pt_rx_pkts        = ntohl(rsp->rx_pkts);
957138635ccSGavin Shan 	ncs->pt_rx_dropped     = ntohl(rsp->rx_dropped);
958138635ccSGavin Shan 	ncs->pt_rx_channel_err = ntohl(rsp->rx_channel_err);
959138635ccSGavin Shan 	ncs->pt_rx_us_err      = ntohl(rsp->rx_us_err);
960138635ccSGavin Shan 	ncs->pt_rx_os_err      = ntohl(rsp->rx_os_err);
961138635ccSGavin Shan 
962138635ccSGavin Shan 	return 0;
963138635ccSGavin Shan }
964138635ccSGavin Shan 
965138635ccSGavin Shan static int ncsi_rsp_handler_gps(struct ncsi_request *nr)
966138635ccSGavin Shan {
967138635ccSGavin Shan 	struct ncsi_rsp_gps_pkt *rsp;
968138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
969138635ccSGavin Shan 	struct ncsi_package *np;
970138635ccSGavin Shan 
971138635ccSGavin Shan 	/* Find the package */
972138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gps_pkt *)skb_network_header(nr->rsp);
973138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
974138635ccSGavin Shan 				      &np, NULL);
975138635ccSGavin Shan 	if (!np)
976138635ccSGavin Shan 		return -ENODEV;
977138635ccSGavin Shan 
978138635ccSGavin Shan 	return 0;
979138635ccSGavin Shan }
980138635ccSGavin Shan 
981138635ccSGavin Shan static int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr)
982138635ccSGavin Shan {
983138635ccSGavin Shan 	struct ncsi_rsp_gpuuid_pkt *rsp;
984138635ccSGavin Shan 	struct ncsi_dev_priv *ndp = nr->ndp;
985138635ccSGavin Shan 	struct ncsi_package *np;
986138635ccSGavin Shan 
987138635ccSGavin Shan 	/* Find the package */
988138635ccSGavin Shan 	rsp = (struct ncsi_rsp_gpuuid_pkt *)skb_network_header(nr->rsp);
989138635ccSGavin Shan 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
990138635ccSGavin Shan 				      &np, NULL);
991138635ccSGavin Shan 	if (!np)
992138635ccSGavin Shan 		return -ENODEV;
993138635ccSGavin Shan 
994138635ccSGavin Shan 	memcpy(np->uuid, rsp->uuid, sizeof(rsp->uuid));
995138635ccSGavin Shan 
996138635ccSGavin Shan 	return 0;
997138635ccSGavin Shan }
998138635ccSGavin Shan 
9999771b8ccSJustin.Lee1@Dell.com static int ncsi_rsp_handler_netlink(struct ncsi_request *nr)
10009771b8ccSJustin.Lee1@Dell.com {
10019771b8ccSJustin.Lee1@Dell.com 	struct ncsi_dev_priv *ndp = nr->ndp;
10029771b8ccSJustin.Lee1@Dell.com 	struct ncsi_rsp_pkt *rsp;
10039771b8ccSJustin.Lee1@Dell.com 	struct ncsi_package *np;
10049771b8ccSJustin.Lee1@Dell.com 	struct ncsi_channel *nc;
10059771b8ccSJustin.Lee1@Dell.com 	int ret;
10069771b8ccSJustin.Lee1@Dell.com 
10079771b8ccSJustin.Lee1@Dell.com 	/* Find the package */
10089771b8ccSJustin.Lee1@Dell.com 	rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
10099771b8ccSJustin.Lee1@Dell.com 	ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
10109771b8ccSJustin.Lee1@Dell.com 				      &np, &nc);
10119771b8ccSJustin.Lee1@Dell.com 	if (!np)
10129771b8ccSJustin.Lee1@Dell.com 		return -ENODEV;
10139771b8ccSJustin.Lee1@Dell.com 
10149771b8ccSJustin.Lee1@Dell.com 	ret = ncsi_send_netlink_rsp(nr, np, nc);
10159771b8ccSJustin.Lee1@Dell.com 
10169771b8ccSJustin.Lee1@Dell.com 	return ret;
10179771b8ccSJustin.Lee1@Dell.com }
10189771b8ccSJustin.Lee1@Dell.com 
1019138635ccSGavin Shan static struct ncsi_rsp_handler {
1020138635ccSGavin Shan 	unsigned char	type;
1021138635ccSGavin Shan 	int             payload;
1022138635ccSGavin Shan 	int		(*handler)(struct ncsi_request *nr);
1023138635ccSGavin Shan } ncsi_rsp_handlers[] = {
1024138635ccSGavin Shan 	{ NCSI_PKT_RSP_CIS,     4, ncsi_rsp_handler_cis     },
1025138635ccSGavin Shan 	{ NCSI_PKT_RSP_SP,      4, ncsi_rsp_handler_sp      },
1026138635ccSGavin Shan 	{ NCSI_PKT_RSP_DP,      4, ncsi_rsp_handler_dp      },
1027138635ccSGavin Shan 	{ NCSI_PKT_RSP_EC,      4, ncsi_rsp_handler_ec      },
1028138635ccSGavin Shan 	{ NCSI_PKT_RSP_DC,      4, ncsi_rsp_handler_dc      },
1029138635ccSGavin Shan 	{ NCSI_PKT_RSP_RC,      4, ncsi_rsp_handler_rc      },
1030138635ccSGavin Shan 	{ NCSI_PKT_RSP_ECNT,    4, ncsi_rsp_handler_ecnt    },
1031138635ccSGavin Shan 	{ NCSI_PKT_RSP_DCNT,    4, ncsi_rsp_handler_dcnt    },
1032138635ccSGavin Shan 	{ NCSI_PKT_RSP_AE,      4, ncsi_rsp_handler_ae      },
1033138635ccSGavin Shan 	{ NCSI_PKT_RSP_SL,      4, ncsi_rsp_handler_sl      },
1034138635ccSGavin Shan 	{ NCSI_PKT_RSP_GLS,    16, ncsi_rsp_handler_gls     },
1035138635ccSGavin Shan 	{ NCSI_PKT_RSP_SVF,     4, ncsi_rsp_handler_svf     },
1036138635ccSGavin Shan 	{ NCSI_PKT_RSP_EV,      4, ncsi_rsp_handler_ev      },
1037138635ccSGavin Shan 	{ NCSI_PKT_RSP_DV,      4, ncsi_rsp_handler_dv      },
1038138635ccSGavin Shan 	{ NCSI_PKT_RSP_SMA,     4, ncsi_rsp_handler_sma     },
1039138635ccSGavin Shan 	{ NCSI_PKT_RSP_EBF,     4, ncsi_rsp_handler_ebf     },
1040138635ccSGavin Shan 	{ NCSI_PKT_RSP_DBF,     4, ncsi_rsp_handler_dbf     },
1041138635ccSGavin Shan 	{ NCSI_PKT_RSP_EGMF,    4, ncsi_rsp_handler_egmf    },
1042138635ccSGavin Shan 	{ NCSI_PKT_RSP_DGMF,    4, ncsi_rsp_handler_dgmf    },
1043138635ccSGavin Shan 	{ NCSI_PKT_RSP_SNFC,    4, ncsi_rsp_handler_snfc    },
10440a90e251SGavin Shan 	{ NCSI_PKT_RSP_GVI,    40, ncsi_rsp_handler_gvi     },
1045138635ccSGavin Shan 	{ NCSI_PKT_RSP_GC,     32, ncsi_rsp_handler_gc      },
1046138635ccSGavin Shan 	{ NCSI_PKT_RSP_GP,     -1, ncsi_rsp_handler_gp      },
1047138635ccSGavin Shan 	{ NCSI_PKT_RSP_GCPS,  172, ncsi_rsp_handler_gcps    },
1048138635ccSGavin Shan 	{ NCSI_PKT_RSP_GNS,   172, ncsi_rsp_handler_gns     },
1049138635ccSGavin Shan 	{ NCSI_PKT_RSP_GNPTS, 172, ncsi_rsp_handler_gnpts   },
1050138635ccSGavin Shan 	{ NCSI_PKT_RSP_GPS,     8, ncsi_rsp_handler_gps     },
1051fb4ee675SVijay Khemka 	{ NCSI_PKT_RSP_OEM,    -1, ncsi_rsp_handler_oem     },
1052138635ccSGavin Shan 	{ NCSI_PKT_RSP_PLDM,    0, NULL                     },
1053138635ccSGavin Shan 	{ NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid  }
1054138635ccSGavin Shan };
1055138635ccSGavin Shan 
1056138635ccSGavin Shan int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
1057138635ccSGavin Shan 		 struct packet_type *pt, struct net_device *orig_dev)
1058138635ccSGavin Shan {
1059138635ccSGavin Shan 	struct ncsi_rsp_handler *nrh = NULL;
1060138635ccSGavin Shan 	struct ncsi_dev *nd;
1061138635ccSGavin Shan 	struct ncsi_dev_priv *ndp;
1062138635ccSGavin Shan 	struct ncsi_request *nr;
1063138635ccSGavin Shan 	struct ncsi_pkt_hdr *hdr;
1064138635ccSGavin Shan 	unsigned long flags;
1065138635ccSGavin Shan 	int payload, i, ret;
1066138635ccSGavin Shan 
1067138635ccSGavin Shan 	/* Find the NCSI device */
1068138635ccSGavin Shan 	nd = ncsi_find_dev(dev);
1069138635ccSGavin Shan 	ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL;
1070138635ccSGavin Shan 	if (!ndp)
1071138635ccSGavin Shan 		return -ENODEV;
1072138635ccSGavin Shan 
10737a82ecf4SGavin Shan 	/* Check if it is AEN packet */
1074138635ccSGavin Shan 	hdr = (struct ncsi_pkt_hdr *)skb_network_header(skb);
10757a82ecf4SGavin Shan 	if (hdr->type == NCSI_PKT_AEN)
10767a82ecf4SGavin Shan 		return ncsi_aen_handler(ndp, skb);
10777a82ecf4SGavin Shan 
10787a82ecf4SGavin Shan 	/* Find the handler */
1079138635ccSGavin Shan 	for (i = 0; i < ARRAY_SIZE(ncsi_rsp_handlers); i++) {
1080138635ccSGavin Shan 		if (ncsi_rsp_handlers[i].type == hdr->type) {
1081138635ccSGavin Shan 			if (ncsi_rsp_handlers[i].handler)
1082138635ccSGavin Shan 				nrh = &ncsi_rsp_handlers[i];
1083138635ccSGavin Shan 			else
1084138635ccSGavin Shan 				nrh = NULL;
1085138635ccSGavin Shan 
1086138635ccSGavin Shan 			break;
1087138635ccSGavin Shan 		}
1088138635ccSGavin Shan 	}
1089138635ccSGavin Shan 
1090138635ccSGavin Shan 	if (!nrh) {
1091138635ccSGavin Shan 		netdev_err(nd->dev, "Received unrecognized packet (0x%x)\n",
1092138635ccSGavin Shan 			   hdr->type);
1093138635ccSGavin Shan 		return -ENOENT;
1094138635ccSGavin Shan 	}
1095138635ccSGavin Shan 
1096138635ccSGavin Shan 	/* Associate with the request */
1097138635ccSGavin Shan 	spin_lock_irqsave(&ndp->lock, flags);
1098138635ccSGavin Shan 	nr = &ndp->requests[hdr->id];
1099138635ccSGavin Shan 	if (!nr->used) {
1100138635ccSGavin Shan 		spin_unlock_irqrestore(&ndp->lock, flags);
1101138635ccSGavin Shan 		return -ENODEV;
1102138635ccSGavin Shan 	}
1103138635ccSGavin Shan 
1104138635ccSGavin Shan 	nr->rsp = skb;
1105138635ccSGavin Shan 	if (!nr->enabled) {
1106138635ccSGavin Shan 		spin_unlock_irqrestore(&ndp->lock, flags);
1107138635ccSGavin Shan 		ret = -ENOENT;
1108138635ccSGavin Shan 		goto out;
1109138635ccSGavin Shan 	}
1110138635ccSGavin Shan 
1111138635ccSGavin Shan 	/* Validate the packet */
1112138635ccSGavin Shan 	spin_unlock_irqrestore(&ndp->lock, flags);
1113138635ccSGavin Shan 	payload = nrh->payload;
1114138635ccSGavin Shan 	if (payload < 0)
1115138635ccSGavin Shan 		payload = ntohs(hdr->length);
1116138635ccSGavin Shan 	ret = ncsi_validate_rsp_pkt(nr, payload);
11179ef8690bSSamuel Mendoza-Jonas 	if (ret) {
11189ef8690bSSamuel Mendoza-Jonas 		netdev_warn(ndp->ndev.dev,
11199ef8690bSSamuel Mendoza-Jonas 			    "NCSI: 'bad' packet ignored for type 0x%x\n",
11209ef8690bSSamuel Mendoza-Jonas 			    hdr->type);
11219771b8ccSJustin.Lee1@Dell.com 
11229771b8ccSJustin.Lee1@Dell.com 		if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
11239771b8ccSJustin.Lee1@Dell.com 			if (ret == -EPERM)
11249771b8ccSJustin.Lee1@Dell.com 				goto out_netlink;
11259771b8ccSJustin.Lee1@Dell.com 			else
11269771b8ccSJustin.Lee1@Dell.com 				ncsi_send_netlink_err(ndp->ndev.dev,
11279771b8ccSJustin.Lee1@Dell.com 						      nr->snd_seq,
11289771b8ccSJustin.Lee1@Dell.com 						      nr->snd_portid,
11299771b8ccSJustin.Lee1@Dell.com 						      &nr->nlhdr,
11309771b8ccSJustin.Lee1@Dell.com 						      ret);
11319771b8ccSJustin.Lee1@Dell.com 		}
1132138635ccSGavin Shan 		goto out;
11339ef8690bSSamuel Mendoza-Jonas 	}
1134138635ccSGavin Shan 
1135138635ccSGavin Shan 	/* Process the packet */
1136138635ccSGavin Shan 	ret = nrh->handler(nr);
11379ef8690bSSamuel Mendoza-Jonas 	if (ret)
11389ef8690bSSamuel Mendoza-Jonas 		netdev_err(ndp->ndev.dev,
11399ef8690bSSamuel Mendoza-Jonas 			   "NCSI: Handler for packet type 0x%x returned %d\n",
11409ef8690bSSamuel Mendoza-Jonas 			   hdr->type, ret);
11419771b8ccSJustin.Lee1@Dell.com 
11429771b8ccSJustin.Lee1@Dell.com out_netlink:
11439771b8ccSJustin.Lee1@Dell.com 	if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
11449771b8ccSJustin.Lee1@Dell.com 		ret = ncsi_rsp_handler_netlink(nr);
11459771b8ccSJustin.Lee1@Dell.com 		if (ret) {
11469771b8ccSJustin.Lee1@Dell.com 			netdev_err(ndp->ndev.dev,
11479771b8ccSJustin.Lee1@Dell.com 				   "NCSI: Netlink handler for packet type 0x%x returned %d\n",
11489771b8ccSJustin.Lee1@Dell.com 				   hdr->type, ret);
11499771b8ccSJustin.Lee1@Dell.com 		}
11509771b8ccSJustin.Lee1@Dell.com 	}
11519771b8ccSJustin.Lee1@Dell.com 
1152138635ccSGavin Shan out:
1153138635ccSGavin Shan 	ncsi_free_request(nr);
1154138635ccSGavin Shan 	return ret;
1155138635ccSGavin Shan }
1156