[PATCH 04/10] net/ncsi: Package and channel management

Joel Stanley joel at jms.id.au
Fri Jul 1 00:05:24 AEST 2016


On Thu, Jun 30, 2016 at 7:57 PM, Gavin Shan <gwshan at linux.vnet.ibm.com> wrote:
> The available NCSI packages and channels are probed with help of
> NCSI command/response packets. One package and channel should be
> selected as active one by which the MC (Management Controller)
> can communicate with the far end and external network. The currently
> active channel should be disabled and another available channel should
> be selected as active one when AEN (Asychronous Event Notification)
> packets received.
>
> This introduces state machine and corresponding functions for above
> purposes. ncsi_start_dev() should be called after ncsi_register_dev()
> in network device driver. It probes all available NCSI packages and
> channels and selects the active one to provide service. ncsi_config_dev()
> and ncsi_suspend_dev() are going to be used when AEN (Asychronous
> Event Notification) packets are received.
>
> Signed-off-by: Gavin Shan <gwshan at linux.vnet.ibm.com>
> ---
>  net/ncsi/internal.h    |  34 ++++
>  net/ncsi/ncsi-manage.c | 475 +++++++++++++++++++++++++++++++++++++++++++++++++
>  net/ncsi/ncsi-rsp.c    |   6 +
>  3 files changed, 515 insertions(+)
>
> diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
> index d435f91..eeb092a 100644
> --- a/net/ncsi/internal.h
> +++ b/net/ncsi/internal.h
> @@ -203,9 +203,38 @@ struct ncsi_req {
>         bool                 nr_timer_enabled; /* Timer was started   */
>  };
>
> +enum {
> +       ncsi_dev_state_major            = 0xff00,
> +       ncsi_dev_state_minor            = 0x00ff,
> +       ncsi_dev_state_probe_deselect   = 0x0201,
> +       ncsi_dev_state_probe_package,
> +       ncsi_dev_state_probe_channel,
> +       ncsi_dev_state_probe_cis,
> +       ncsi_dev_state_probe_gvi,
> +       ncsi_dev_state_probe_gc,
> +       ncsi_dev_state_probe_gls,
> +       ncsi_dev_state_probe_dp,
> +       ncsi_dev_state_config_sp        = 0x0301,
> +       ncsi_dev_state_config_cis,
> +       ncsi_dev_state_config_sma,
> +       ncsi_dev_state_config_ebf,
> +       ncsi_dev_state_config_ecnt,
> +       ncsi_dev_state_config_ec,
> +       ncsi_dev_state_config_ae,
> +       ncsi_dev_state_config_gls,
> +       ncsi_dev_state_config_done,
> +       ncsi_dev_state_suspend_select   = 0x0401,
> +       ncsi_dev_state_suspend_dcnt,
> +       ncsi_dev_state_suspend_dc,
> +       ncsi_dev_state_suspend_deselect,
> +       ncsi_dev_state_suspend_done
> +};
> +
>  struct ncsi_dev_priv {
>         struct ncsi_dev     ndp_ndev;            /* NCSI device              */
>         int                 ndp_flags;           /* NCSI device flags        */
> +#define NCSI_DEV_FLAG_PROBED   0x1
> +#define NCSI_DEV_FLAG_RESHUFFLE        0x2
>         struct ncsi_package *ndp_active_package; /* Active NCSI package      */
>         struct ncsi_channel *ndp_active_channel; /* Active NCSI channel      */
>         atomic_t            ndp_package_num;     /* Number of packages       */
> @@ -214,6 +243,9 @@ struct ncsi_dev_priv {
>         atomic_t            ndp_last_req_idx;    /* Last used request ID     */
>         spinlock_t          ndp_req_lock;        /* Protect request table    */
>         struct ncsi_req     ndp_reqs[256];       /* Request table            */
> +       atomic_t            ndp_pending_reqs;    /* Pending commands         */
> +       struct work_struct  ndp_work;            /* Workqueue                */
> +       struct packet_type  ndp_ptype;           /* NCSI receive handler     */
>         struct list_head    ndp_node;
>  };
>
> @@ -264,6 +296,8 @@ void ncsi_find_package_and_channel(struct ncsi_dev_priv *ndp,
>  struct ncsi_req *ncsi_alloc_req(struct ncsi_dev_priv *ndp);
>  void ncsi_free_req(struct ncsi_req *nr, bool check, bool timeout);
>  struct ncsi_dev *ncsi_find_dev(struct net_device *dev);
> +int ncsi_config_dev(struct ncsi_dev *nd);
> +int ncsi_suspend_dev(struct ncsi_dev *nd);
>
>  /* Packet handlers */
>  int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca);
> diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
> index dab54bc..37f1b3d 100644
> --- a/net/ncsi/ncsi-manage.c
> +++ b/net/ncsi/ncsi-manage.c
> @@ -19,6 +19,7 @@
>  #include <net/sock.h>
>
>  #include "internal.h"
> +#include "ncsi-pkt.h"
>
>  LIST_HEAD(ncsi_dev_list);
>  DEFINE_SPINLOCK(ncsi_dev_lock);
> @@ -342,6 +343,9 @@ void ncsi_free_req(struct ncsi_req *nr, bool check, bool timeout)
>         nr->nr_used = false;
>         spin_unlock_irqrestore(&ndp->ndp_req_lock, flags);
>
> +       if (check && cmd && atomic_dec_return(&ndp->ndp_pending_reqs) == 0)
> +               schedule_work(&ndp->ndp_work);
> +
>         /* Release command and response */
>         consume_skb(cmd);
>         consume_skb(rsp);
> @@ -380,6 +384,417 @@ static void ncsi_req_timeout(unsigned long data)
>         ncsi_free_req(nr, true, true);
>  }
>
> +static void ncsi_dev_config(struct ncsi_dev_priv *ndp)
> +{
> +       struct ncsi_dev *nd = &ndp->ndp_ndev;
> +       struct net_device *dev = nd->nd_dev;
> +       struct ncsi_package *np = ndp->ndp_active_package;
> +       struct ncsi_channel *nc = ndp->ndp_active_channel;
> +       struct ncsi_cmd_arg nca;
> +       unsigned char index;
> +       int ret;
> +
> +       nca.nca_ndp = ndp;
> +       switch (nd->nd_state) {
> +       case ncsi_dev_state_config:
> +       case ncsi_dev_state_config_sp:
> +               atomic_set(&ndp->ndp_pending_reqs, 1);
> +
> +               /* Select the specific package */
> +               nca.nca_type = NCSI_PKT_CMD_SP;
> +               nca.nca_bytes[0] = 1;
> +               nca.nca_package = np->np_id;
> +               nca.nca_channel = 0x1f;
> +               ret = ncsi_xmit_cmd(&nca);
> +               if (ret)
> +                       goto error;
> +
> +               nd->nd_state = ncsi_dev_state_config_cis;
> +               break;
> +       case ncsi_dev_state_config_cis:
> +               atomic_set(&ndp->ndp_pending_reqs, 1);
> +
> +               /* Clear initial state */
> +               nca.nca_type = NCSI_PKT_CMD_CIS;
> +               nca.nca_package = np->np_id;
> +               nca.nca_channel = nc->nc_id;
> +               ret = ncsi_xmit_cmd(&nca);
> +               if (ret)
> +                       goto error;
> +
> +               nd->nd_state = ncsi_dev_state_config_sma;
> +               break;
> +       case ncsi_dev_state_config_sma:
> +       case ncsi_dev_state_config_ebf:
> +       case ncsi_dev_state_config_ecnt:
> +       case ncsi_dev_state_config_ec:
> +       case ncsi_dev_state_config_ae:
> +       case ncsi_dev_state_config_gls:
> +               atomic_set(&ndp->ndp_pending_reqs, 1);
> +
> +               nca.nca_package = np->np_id;
> +               nca.nca_channel = nc->nc_id;
> +
> +               /* Use first entry in unicast filter table. Note that
> +                * the MAC filter table starts from entry 1 instead of
> +                * 0.
> +                */
> +               if (nd->nd_state == ncsi_dev_state_config_sma) {
> +                       nca.nca_type = NCSI_PKT_CMD_SMA;
> +                       for (index = 0; index < 6; index++)
> +                               nca.nca_bytes[index] = dev->dev_addr[index];
> +                       nca.nca_bytes[6] = 0x1;
> +                       nca.nca_bytes[7] = 0x1;
> +                       nd->nd_state = ncsi_dev_state_config_ebf;
> +               } else if (nd->nd_state == ncsi_dev_state_config_ebf) {
> +                       nca.nca_type = NCSI_PKT_CMD_EBF;
> +                       nca.nca_dwords[0] = nc->nc_caps[NCSI_CAP_BC].ncc_cap;
> +                       nd->nd_state = ncsi_dev_state_config_ecnt;
> +               } else if (nd->nd_state == ncsi_dev_state_config_ecnt) {
> +                       nca.nca_type = NCSI_PKT_CMD_ECNT;
> +                       nd->nd_state = ncsi_dev_state_config_ec;
> +               } else if (nd->nd_state == ncsi_dev_state_config_ec) {
> +                       nca.nca_type = NCSI_PKT_CMD_EC;
> +                       nd->nd_state = ncsi_dev_state_config_ae;
> +               } else if (nd->nd_state == ncsi_dev_state_config_ae) {
> +                       nca.nca_type = NCSI_PKT_CMD_AE;
> +                       nca.nca_bytes[0] = 0;
> +                       nca.nca_dwords[1] = 0x7;
> +                       nd->nd_state = ncsi_dev_state_config_gls;
> +               } else if (nd->nd_state == ncsi_dev_state_config_gls) {
> +                       nca.nca_type = NCSI_PKT_CMD_GLS;
> +                       nd->nd_state = ncsi_dev_state_config_done;
> +               }
> +
> +               ret = ncsi_xmit_cmd(&nca);
> +               if (ret)
> +                       goto error;
> +               break;
> +       case ncsi_dev_state_config_done:
> +               nd->nd_state = ncsi_dev_state_functional;
> +               nd->nd_link_up = 0;
> +               if (nc->nc_modes[NCSI_MODE_LINK].ncm_data[2] & 0x1)
> +                       nd->nd_link_up = 1;
> +
> +               nd->nd_handler(nd);
> +               ndp->ndp_flags &= ~NCSI_DEV_FLAG_RESHUFFLE;
> +
> +               break;
> +       default:
> +               pr_warn("NCSI: Wrong NCSI dev state 0x%x in config\n",
> +                       nd->nd_state);
> +       }
> +
> +       return;
> +
> +error:
> +       nd->nd_state = ncsi_dev_state_functional;
> +       nd->nd_link_up = 0;
> +       ndp->ndp_flags &= ~NCSI_DEV_FLAG_RESHUFFLE;
> +       nd->nd_handler(nd);
> +}
> +
> +static void ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
> +{
> +       struct ncsi_dev *nd;
> +       struct ncsi_package *np;
> +       struct ncsi_channel *nc;
> +       struct ncsi_channel_mode *ncm;
> +
> +       nd = &ndp->ndp_ndev;
> +       ndp->ndp_active_package = NULL;
> +       ndp->ndp_active_channel = NULL;
> +       NCSI_FOR_EACH_PACKAGE(ndp, np) {
> +               NCSI_FOR_EACH_CHANNEL(np, nc) {
> +                       if (!ndp->ndp_active_channel) {
> +                               ndp->ndp_active_package = np;
> +                               ndp->ndp_active_channel = nc;
> +                       }
> +
> +                       ncm = &nc->nc_modes[NCSI_MODE_LINK];
> +                       if (ncm->ncm_data[2] & 0x1) {
> +                               ndp->ndp_active_package = np;
> +                               ndp->ndp_active_channel = nc;
> +                               goto configure;
> +                       }
> +               }
> +       }
> +
> +configure:
> +       if (!ndp->ndp_active_channel) {
> +               nd->nd_state = ncsi_dev_state_functional;
> +               nd->nd_link_up = 0;
> +               nd->nd_handler(nd);
> +       } else {
> +               nd->nd_state = ncsi_dev_state_config;
> +               ncsi_dev_config(ndp);
> +       }
> +}
> +
> +static void ncsi_dev_probe(struct ncsi_dev_priv *ndp)
> +{
> +       struct ncsi_dev *nd = &ndp->ndp_ndev;
> +       struct ncsi_package *np;
> +       struct ncsi_channel *nc;
> +       struct ncsi_cmd_arg nca;
> +       unsigned char index;
> +       int ret;
> +
> +       nca.nca_ndp = ndp;
> +       switch (nd->nd_state) {
> +       case ncsi_dev_state_probe:
> +               nd->nd_state = ncsi_dev_state_probe_deselect;
> +               /* Fall through */
> +       case ncsi_dev_state_probe_deselect:
> +               atomic_set(&ndp->ndp_pending_reqs, 8);
> +
> +               /* Deselect all possible packages */
> +               nca.nca_type = NCSI_PKT_CMD_DP;
> +               nca.nca_channel = 0x1f;
> +               for (index = 0; index < 8; index++) {
> +                       nca.nca_package = index;
> +                       ret = ncsi_xmit_cmd(&nca);
> +                       if (ret)
> +                               goto error;
> +               }
> +
> +               nd->nd_state = ncsi_dev_state_probe_package;
> +               break;
> +       case ncsi_dev_state_probe_package:
> +               atomic_set(&ndp->ndp_pending_reqs, 16);
> +
> +               /* Select all possible packages */
> +               nca.nca_type = NCSI_PKT_CMD_SP;
> +               nca.nca_bytes[0] = 1;
> +               nca.nca_channel = 0x1f;
> +               for (index = 0; index < 8; index++) {
> +                       nca.nca_package = index;
> +                       ret = ncsi_xmit_cmd(&nca);
> +                       if (ret)
> +                               goto error;
> +               }
> +
> +               /* Disable all possible packages */
> +               nca.nca_type = NCSI_PKT_CMD_DP;
> +               for (index = 0; index < 8; index++) {
> +                       nca.nca_package = index;
> +                       ret = ncsi_xmit_cmd(&nca);
> +                       if (ret)
> +                               goto error;
> +               }
> +
> +               nd->nd_state = ncsi_dev_state_probe_channel;
> +               break;
> +       case ncsi_dev_state_probe_channel:
> +               if (!ndp->ndp_active_package)
> +                       ndp->ndp_active_package = list_first_or_null_rcu(
> +                                                       &ndp->ndp_packages,
> +                                                       struct ncsi_package,
> +                                                       np_node);
> +               else if (list_is_last(&ndp->ndp_active_package->np_node,
> +                                     &ndp->ndp_packages))
> +                       ndp->ndp_active_package = NULL;
> +               else
> +                       ndp->ndp_active_package = list_next_entry(
> +                                                       ndp->ndp_active_package,
> +                                                       np_node);
> +
> +               /* All available packages and channels are enumerated. The
> +                * enumeration happens for once when the NCSI interface is
> +                * started. So we need continue to start the interface after
> +                * the enumeration.
> +                *
> +                * We have to choose an active channel before configuring it.
> +                * Note that we possibly don't have active channel in extreme
> +                * situation.
> +                */
> +               if (!ndp->ndp_active_package) {
> +                       ndp->ndp_flags |= NCSI_DEV_FLAG_PROBED;
> +                       ncsi_choose_active_channel(ndp);
> +                       return;
> +               }
> +
> +               /* Select the active package */
> +               atomic_set(&ndp->ndp_pending_reqs, 1);
> +               nca.nca_type = NCSI_PKT_CMD_SP;
> +               nca.nca_bytes[0] = 1;
> +               nca.nca_package = ndp->ndp_active_package->np_id;
> +               nca.nca_channel = 0x1f;
> +               ret = ncsi_xmit_cmd(&nca);
> +               if (ret)
> +                       goto error;
> +
> +               nd->nd_state = ncsi_dev_state_probe_cis;
> +               break;
> +       case ncsi_dev_state_probe_cis:
> +               atomic_set(&ndp->ndp_pending_reqs, 0x20);
> +
> +               /* Clear initial state */
> +               nca.nca_type = NCSI_PKT_CMD_CIS;
> +               nca.nca_package = ndp->ndp_active_package->np_id;
> +               for (index = 0; index < 0x20; index++) {
> +                       nca.nca_channel = index;
> +                       ret = ncsi_xmit_cmd(&nca);
> +                       if (ret)
> +                               goto error;
> +               }
> +
> +               nd->nd_state = ncsi_dev_state_probe_gvi;
> +               break;
> +       case ncsi_dev_state_probe_gvi:
> +       case ncsi_dev_state_probe_gc:
> +       case ncsi_dev_state_probe_gls:
> +               np = ndp->ndp_active_package;
> +               atomic_set(&ndp->ndp_pending_reqs,
> +                          atomic_read(&np->np_channel_num));
> +
> +               /* Retrieve version, capability or link status */
> +               if (nd->nd_state == ncsi_dev_state_probe_gvi)
> +                       nca.nca_type = NCSI_PKT_CMD_GVI;
> +               else if (nd->nd_state == ncsi_dev_state_probe_gc)
> +                       nca.nca_type = NCSI_PKT_CMD_GC;
> +               else
> +                       nca.nca_type = NCSI_PKT_CMD_GLS;
> +
> +               nca.nca_package = np->np_id;
> +               NCSI_FOR_EACH_CHANNEL(np, nc) {
> +                       nca.nca_channel = nc->nc_id;
> +                       ret = ncsi_xmit_cmd(&nca);
> +                       if (ret)
> +                               goto error;
> +               }
> +
> +               if (nd->nd_state == ncsi_dev_state_probe_gvi)
> +                       nd->nd_state = ncsi_dev_state_probe_gc;
> +               else if (nd->nd_state == ncsi_dev_state_probe_gc)
> +                       nd->nd_state = ncsi_dev_state_probe_gls;
> +               else
> +                       nd->nd_state = ncsi_dev_state_probe_dp;
> +               break;
> +       case ncsi_dev_state_probe_dp:
> +               atomic_set(&ndp->ndp_pending_reqs, 1);
> +
> +               /* Deselect the active package */
> +               nca.nca_type = NCSI_PKT_CMD_DP;
> +               nca.nca_package = ndp->ndp_active_package->np_id;
> +               nca.nca_channel = 0x1f;
> +               ret = ncsi_xmit_cmd(&nca);
> +               if (ret)
> +                       goto error;
> +
> +               /* Scan channels in next package */
> +               nd->nd_state = ncsi_dev_state_probe_channel;
> +               break;
> +       default:
> +               pr_warn("NCSI: Wrong NCSI dev state 0x%0x in enumeration\n",
> +                       nd->nd_state);
> +       }
> +
> +       return;
> +error:
> +       nd->nd_state = ncsi_dev_state_functional;
> +       nd->nd_link_up = 0;
> +       nd->nd_handler(nd);
> +}
> +
> +static void ncsi_dev_suspend(struct ncsi_dev_priv *ndp)
> +{
> +       struct ncsi_dev *nd = &ndp->ndp_ndev;
> +       struct ncsi_package *np;
> +       struct ncsi_channel *nc;
> +       struct ncsi_cmd_arg nca;
> +       int ret;
> +
> +       nca.nca_ndp = ndp;
> +       switch (nd->nd_state) {
> +       case ncsi_dev_state_suspend:
> +               /* If there're no active channel, we're done */
> +               if (!ndp->ndp_active_channel) {
> +                       nd->nd_state = ncsi_dev_state_functional;
> +
> +                       if (ndp->ndp_flags & NCSI_DEV_FLAG_RESHUFFLE) {
> +                               ndp->ndp_flags &= ~NCSI_DEV_FLAG_RESHUFFLE;
> +                               ncsi_choose_active_channel(ndp);
> +                       }
> +
> +                       return;
> +               }
> +
> +               nd->nd_state = ncsi_dev_state_suspend_select;
> +               /* Fall through */
> +       case ncsi_dev_state_suspend_select:
> +       case ncsi_dev_state_suspend_dcnt:
> +       case ncsi_dev_state_suspend_dc:
> +       case ncsi_dev_state_suspend_deselect:
> +               atomic_set(&ndp->ndp_pending_reqs, 1);
> +
> +               np = ndp->ndp_active_package;
> +               nc = ndp->ndp_active_channel;
> +               nca.nca_package = np->np_id;
> +               if (nd->nd_state == ncsi_dev_state_suspend_select) {
> +                       nca.nca_type = NCSI_PKT_CMD_SP;
> +                       nca.nca_channel = 0x1f;
> +                       nca.nca_bytes[0] = 1;
> +                       nd->nd_state = ncsi_dev_state_suspend_dcnt;
> +               } else if (nd->nd_state == ncsi_dev_state_suspend_dcnt) {
> +                       nca.nca_type = NCSI_PKT_CMD_DCNT;
> +                       nca.nca_channel = nc->nc_id;
> +                       nd->nd_state = ncsi_dev_state_suspend_dc;
> +               } else if (nd->nd_state == ncsi_dev_state_suspend_dc) {
> +                       nca.nca_type = NCSI_PKT_CMD_DC;
> +                       nca.nca_channel = nc->nc_id;
> +                       nca.nca_bytes[0] = 1;
> +                       nd->nd_state = ncsi_dev_state_suspend_deselect;
> +               } else if (nd->nd_state == ncsi_dev_state_suspend_deselect) {
> +                       nca.nca_type = NCSI_PKT_CMD_DP;
> +                       nca.nca_channel = 0x1f;
> +                       nd->nd_state = ncsi_dev_state_suspend_done;
> +               }
> +
> +               ret = ncsi_xmit_cmd(&nca);
> +               if (ret) {
> +                       nd->nd_state = ncsi_dev_state_functional;
> +                       return;
> +               }
> +
> +               break;
> +       case ncsi_dev_state_suspend_done:
> +               nd->nd_state = ncsi_dev_state_functional;
> +
> +               if (ndp->ndp_flags & NCSI_DEV_FLAG_RESHUFFLE) {
> +                       ndp->ndp_flags &= ~NCSI_DEV_FLAG_RESHUFFLE;
> +                       ncsi_choose_active_channel(ndp);
> +               }
> +
> +               break;
> +       default:
> +               pr_warn("NCSI: Wrong NCSI dev state 0x%x in suspend\n",
> +                       nd->nd_state);
> +       }
> +}
> +
> +static void ncsi_dev_work(struct work_struct *work)
> +{
> +       struct ncsi_dev_priv *ndp = container_of(work, struct ncsi_dev_priv,
> +                                                ndp_work);
> +       struct ncsi_dev *nd = &ndp->ndp_ndev;
> +
> +       switch (nd->nd_state & ncsi_dev_state_major) {
> +       case ncsi_dev_state_probe:
> +               ncsi_dev_probe(ndp);
> +               break;
> +       case ncsi_dev_state_suspend:
> +               ncsi_dev_suspend(ndp);
> +               break;
> +       case ncsi_dev_state_config:
> +               ncsi_dev_config(ndp);
> +               break;
> +       default:
> +               pr_warn("NCSI: Wrong NCSI dev state 0x%x in workqueue\n",
> +                       nd->nd_state);
> +       }
> +}
> +
>  struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
>                                    void (*handler)(struct ncsi_dev *ndev))
>  {
> @@ -414,19 +829,79 @@ struct ncsi_dev *ncsi_register_dev(struct net_device *dev,
>                             (unsigned long)&ndp->ndp_reqs[idx]);
>         }
>
> +       atomic_set(&ndp->ndp_pending_reqs, 0);
> +       INIT_WORK(&ndp->ndp_work, ncsi_dev_work);
> +
>         spin_lock(&ncsi_dev_lock);
>         list_add_tail_rcu(&ndp->ndp_node, &ncsi_dev_list);
>         spin_unlock(&ncsi_dev_lock);
>
> +       /* Register NCSI packet Rx handler */
> +       ndp->ndp_ptype.type = cpu_to_be16(ETH_P_NCSI);
> +       ndp->ndp_ptype.func = ncsi_rcv_rsp;
> +       ndp->ndp_ptype.dev = dev;
> +       dev_add_pack(&ndp->ndp_ptype);
> +
>         return nd;
>  }
>  EXPORT_SYMBOL_GPL(ncsi_register_dev);
>
> +int ncsi_start_dev(struct ncsi_dev *nd)
> +{
> +       struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
> +
> +       if (nd->nd_state != ncsi_dev_state_registered &&
> +           nd->nd_state != ncsi_dev_state_functional)
> +               return -ENOTTY;
> +
> +       if (!(ndp->ndp_flags & NCSI_DEV_FLAG_PROBED)) {
> +               nd->nd_state = ncsi_dev_state_probe;
> +               schedule_work(&ndp->ndp_work);
> +               return 0;
> +       }
> +
> +       /* Choose active package and channel */
> +       ncsi_choose_active_channel(ndp);
> +       if (!ndp->ndp_active_channel)
> +               return -ENXIO;
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL_GPL(ncsi_start_dev);
> +
> +int ncsi_config_dev(struct ncsi_dev *nd)
> +{
> +       struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
> +
> +       if (nd->nd_state != ncsi_dev_state_functional)
> +               return -ENOTTY;
> +
> +       nd->nd_state = ncsi_dev_state_config;
> +       schedule_work(&ndp->ndp_work);
> +
> +       return 0;
> +}
> +
> +int ncsi_suspend_dev(struct ncsi_dev *nd)
> +{
> +       struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
> +
> +       if (nd->nd_state != ncsi_dev_state_functional)
> +               return -ENOTTY;
> +
> +       nd->nd_state = ncsi_dev_state_suspend;
> +       schedule_work(&ndp->ndp_work);
> +
> +       return 0;
> +}
> +
>  void ncsi_unregister_dev(struct ncsi_dev *nd)
>  {
>         struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
>         struct ncsi_package *np, *tmp;
>
> +       dev_remove_pack(&ndp->ndp_ptype);
> +
>         spin_lock(&ndp->ndp_package_lock);
>         list_for_each_entry_safe(np, tmp, &ndp->ndp_packages, np_node)
>                 ncsi_release_package(np);
> diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
> index 257079fc..92dcbf4 100644
> --- a/net/ncsi/ncsi-rsp.c
> +++ b/net/ncsi/ncsi-rsp.c
> @@ -88,6 +88,9 @@ static int ncsi_rsp_handler_cis(struct ncsi_req *nr)
>         rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->nr_rsp);
>         ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, &nc);
>         if (!nc) {
> +               if (ndp->ndp_flags & NCSI_DEV_FLAG_PROBED)
> +                       return -ENXIO;
> +
>                 id = NCSI_CHANNEL_INDEX(rsp->rsp.common.channel);
>                 nc = ncsi_add_channel(np, id);
>         } else if (nc->nc_state == ncsi_channel_state_deselected_initial) {
> @@ -119,6 +122,9 @@ static int ncsi_rsp_handler_sp(struct ncsi_req *nr)
>         ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
>                                       &np, NULL);
>         if (!np) {
> +               if (ndp->ndp_flags & NCSI_DEV_FLAG_PROBED)
> +                       return -ENXIO;
> +
>                 id = NCSI_PACKAGE_INDEX(rsp->rsp.common.channel);
>                 np = ncsi_add_package(ndp, id);
>                 if (!np)
> --
> 2.1.0
>


More information about the openbmc mailing list