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