]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'target-merge/for-next-merge'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 8 Mar 2016 03:57:29 +0000 (14:57 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 8 Mar 2016 03:57:29 +0000 (14:57 +1100)
1  2 
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_configfs.c
drivers/target/iscsi/iscsi_target_login.c
include/target/iscsi/iscsi_target_core.h

index 1dac6c6111bf1593f2ac0b7ccb0bccc5f6af8bf0,646076e36bca9083e1080d7a82cb3ffc25f8f9f1..984a3cc26f86ddb7a194b4738a3dd7e018b0bc33
@@@ -404,6 -404,9 +404,9 @@@ enum 
        MAX_CTRL_QUEUES = NCHAN,      /* # of control Tx queues */
        MAX_RDMA_QUEUES = NCHAN,      /* # of streaming RDMA Rx queues */
        MAX_RDMA_CIQS = 32,        /* # of  RDMA concentrator IQs */
+       /* # of streaming iSCSIT Rx queues */
+       MAX_ISCSIT_QUEUES = MAX_OFLD_QSETS,
  };
  
  enum {
  enum {
        INGQ_EXTRAS = 2,        /* firmware event queue and */
                                /*   forwarded interrupts */
-       MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES
-                  + MAX_RDMA_CIQS + INGQ_EXTRAS,
+       MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES +
+                  MAX_RDMA_CIQS + MAX_ISCSIT_QUEUES + INGQ_EXTRAS,
  };
  
  struct adapter;
@@@ -508,6 -511,15 +511,15 @@@ struct pkt_gl 
  
  typedef int (*rspq_handler_t)(struct sge_rspq *q, const __be64 *rsp,
                              const struct pkt_gl *gl);
+ typedef void (*rspq_flush_handler_t)(struct sge_rspq *q);
+ /* LRO related declarations for ULD */
+ struct t4_lro_mgr {
+ #define MAX_LRO_SESSIONS              64
+       u8 lro_session_cnt;         /* # of sessions to aggregate */
+       unsigned long lro_pkts;     /* # of LRO super packets */
+       unsigned long lro_merged;   /* # of wire packets merged by LRO */
+       struct sk_buff_head lroq;   /* list of aggregated sessions */
+ };
  
  struct sge_rspq {                   /* state for an SGE response queue */
        struct napi_struct napi;
        struct adapter *adap;
        struct net_device *netdev;  /* associated net device */
        rspq_handler_t handler;
+       rspq_flush_handler_t flush_handler;
+       struct t4_lro_mgr lro_mgr;
  #ifdef CONFIG_NET_RX_BUSY_POLL
  #define CXGB_POLL_STATE_IDLE          0
  #define CXGB_POLL_STATE_NAPI          BIT(0) /* NAPI owns this poll */
@@@ -641,6 -655,7 +655,7 @@@ struct sge 
  
        struct sge_eth_rxq ethrxq[MAX_ETH_QSETS];
        struct sge_ofld_rxq iscsirxq[MAX_OFLD_QSETS];
+       struct sge_ofld_rxq iscsitrxq[MAX_ISCSIT_QUEUES];
        struct sge_ofld_rxq rdmarxq[MAX_RDMA_QUEUES];
        struct sge_ofld_rxq rdmaciq[MAX_RDMA_CIQS];
        struct sge_rspq fw_evtq ____cacheline_aligned_in_smp;
        u16 ethqsets;               /* # of active Ethernet queue sets */
        u16 ethtxq_rover;           /* Tx queue to clean up next */
        u16 iscsiqsets;              /* # of active iSCSI queue sets */
+       u16 niscsitq;               /* # of available iSCST Rx queues */
        u16 rdmaqs;                 /* # of available RDMA Rx queues */
        u16 rdmaciqs;               /* # of available RDMA concentrator IQs */
        u16 iscsi_rxq[MAX_OFLD_QSETS];
+       u16 iscsit_rxq[MAX_ISCSIT_QUEUES];
        u16 rdma_rxq[MAX_RDMA_QUEUES];
        u16 rdma_ciq[MAX_RDMA_CIQS];
        u16 timer_val[SGE_NTIMERS];
  
  #define for_each_ethrxq(sge, i) for (i = 0; i < (sge)->ethqsets; i++)
  #define for_each_iscsirxq(sge, i) for (i = 0; i < (sge)->iscsiqsets; i++)
+ #define for_each_iscsitrxq(sge, i) for (i = 0; i < (sge)->niscsitq; i++)
  #define for_each_rdmarxq(sge, i) for (i = 0; i < (sge)->rdmaqs; i++)
  #define for_each_rdmaciq(sge, i) for (i = 0; i < (sge)->rdmaciqs; i++)
  
@@@ -702,11 -720,6 +720,11 @@@ struct doorbell_stats 
        u32 db_full;
  };
  
 +struct hash_mac_addr {
 +      struct list_head list;
 +      u8 addr[ETH_ALEN];
 +};
 +
  struct adapter {
        void __iomem *regs;
        void __iomem *bar2;
        void *uld_handle[CXGB4_ULD_MAX];
        struct list_head list_node;
        struct list_head rcu_node;
 +      struct list_head mac_hlist; /* list of MAC addresses in MPS Hash */
  
+       void *iscsi_ppm;
        struct tid_info tids;
        void **tid_release_head;
        spinlock_t tid_release_lock;
@@@ -1113,7 -1127,8 +1133,8 @@@ int t4_mgmt_tx(struct adapter *adap, st
  int t4_ofld_send(struct adapter *adap, struct sk_buff *skb);
  int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
                     struct net_device *dev, int intr_idx,
-                    struct sge_fl *fl, rspq_handler_t hnd, int cong);
+                    struct sge_fl *fl, rspq_handler_t hnd,
+                    rspq_flush_handler_t flush_handler, int cong);
  int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
                         struct net_device *dev, struct netdev_queue *netdevq,
                         unsigned int iqid);
@@@ -1213,24 -1228,6 +1234,24 @@@ static inline int t4_wr_mbox_ns(struct 
        return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, false);
  }
  
 +/**
 + *    hash_mac_addr - return the hash value of a MAC address
 + *    @addr: the 48-bit Ethernet MAC address
 + *
 + *    Hashes a MAC address according to the hash function used by HW inexact
 + *    (hash) address matching.
 + */
 +static inline int hash_mac_addr(const u8 *addr)
 +{
 +      u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
 +      u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
 +
 +      a ^= b;
 +      a ^= (a >> 12);
 +      a ^= (a >> 6);
 +      return a & 0x3f;
 +}
 +
  void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
                       unsigned int data_reg, const u32 *vals,
                       unsigned int nregs, unsigned int start_idx);
@@@ -1413,9 -1410,6 +1434,9 @@@ int t4_set_rxmode(struct adapter *adap
  int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
                      unsigned int viid, bool free, unsigned int naddr,
                      const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok);
 +int t4_free_mac_filt(struct adapter *adap, unsigned int mbox,
 +                   unsigned int viid, unsigned int naddr,
 +                   const u8 **addr, bool sleep_ok);
  int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
                  int idx, const u8 *addr, bool persist, bool add_smt);
  int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid,
index adad73f7c8cd96137cc49d8c2c9dad33ec5eed6a,1a1f1c89660bc358bc39e716e6541a6ca4bdb10e..d1e3f0997d6b53d907d005c90ff90d9b1dae4f76
@@@ -227,7 -227,7 +227,7 @@@ static DEFINE_MUTEX(uld_mutex)
  static LIST_HEAD(adap_rcu_list);
  static DEFINE_SPINLOCK(adap_rcu_lock);
  static struct cxgb4_uld_info ulds[CXGB4_ULD_MAX];
- static const char *uld_str[] = { "RDMA", "iSCSI" };
+ static const char *const uld_str[] = { "RDMA", "iSCSI", "iSCSIT" };
  
  static void link_report(struct net_device *dev)
  {
@@@ -338,108 -338,84 +338,108 @@@ void t4_os_portmod_changed(const struc
                netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]);
  }
  
 +int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */
 +module_param(dbfifo_int_thresh, int, 0644);
 +MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold");
 +
  /*
 - * Configure the exact and hash address filters to handle a port's multicast
 - * and secondary unicast MAC addresses.
 + * usecs to sleep while draining the dbfifo
   */
 -static int set_addr_filters(const struct net_device *dev, bool sleep)
 +static int dbfifo_drain_delay = 1000;
 +module_param(dbfifo_drain_delay, int, 0644);
 +MODULE_PARM_DESC(dbfifo_drain_delay,
 +               "usecs to sleep while draining the dbfifo");
 +
 +static inline int cxgb4_set_addr_hash(struct port_info *pi)
  {
 +      struct adapter *adap = pi->adapter;
 +      u64 vec = 0;
 +      bool ucast = false;
 +      struct hash_mac_addr *entry;
 +
 +      /* Calculate the hash vector for the updated list and program it */
 +      list_for_each_entry(entry, &adap->mac_hlist, list) {
 +              ucast |= is_unicast_ether_addr(entry->addr);
 +              vec |= (1ULL << hash_mac_addr(entry->addr));
 +      }
 +      return t4_set_addr_hash(adap, adap->mbox, pi->viid, ucast,
 +                              vec, false);
 +}
 +
 +static int cxgb4_mac_sync(struct net_device *netdev, const u8 *mac_addr)
 +{
 +      struct port_info *pi = netdev_priv(netdev);
 +      struct adapter *adap = pi->adapter;
 +      int ret;
        u64 mhash = 0;
        u64 uhash = 0;
 -      bool free = true;
 -      u16 filt_idx[7];
 -      const u8 *addr[7];
 -      int ret, naddr = 0;
 -      const struct netdev_hw_addr *ha;
 -      int uc_cnt = netdev_uc_count(dev);
 -      int mc_cnt = netdev_mc_count(dev);
 -      const struct port_info *pi = netdev_priv(dev);
 -      unsigned int mb = pi->adapter->pf;
 -
 -      /* first do the secondary unicast addresses */
 -      netdev_for_each_uc_addr(ha, dev) {
 -              addr[naddr++] = ha->addr;
 -              if (--uc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
 -                      ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free,
 -                                      naddr, addr, filt_idx, &uhash, sleep);
 -                      if (ret < 0)
 -                              return ret;
 -
 -                      free = false;
 -                      naddr = 0;
 -              }
 +      bool free = false;
 +      bool ucast = is_unicast_ether_addr(mac_addr);
 +      const u8 *maclist[1] = {mac_addr};
 +      struct hash_mac_addr *new_entry;
 +
 +      ret = t4_alloc_mac_filt(adap, adap->mbox, pi->viid, free, 1, maclist,
 +                              NULL, ucast ? &uhash : &mhash, false);
 +      if (ret < 0)
 +              goto out;
 +      /* if hash != 0, then add the addr to hash addr list
 +       * so on the end we will calculate the hash for the
 +       * list and program it
 +       */
 +      if (uhash || mhash) {
 +              new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC);
 +              if (!new_entry)
 +                      return -ENOMEM;
 +              ether_addr_copy(new_entry->addr, mac_addr);
 +              list_add_tail(&new_entry->list, &adap->mac_hlist);
 +              ret = cxgb4_set_addr_hash(pi);
        }
 +out:
 +      return ret < 0 ? ret : 0;
 +}
  
 -      /* next set up the multicast addresses */
 -      netdev_for_each_mc_addr(ha, dev) {
 -              addr[naddr++] = ha->addr;
 -              if (--mc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
 -                      ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free,
 -                                      naddr, addr, filt_idx, &mhash, sleep);
 -                      if (ret < 0)
 -                              return ret;
 +static int cxgb4_mac_unsync(struct net_device *netdev, const u8 *mac_addr)
 +{
 +      struct port_info *pi = netdev_priv(netdev);
 +      struct adapter *adap = pi->adapter;
 +      int ret;
 +      const u8 *maclist[1] = {mac_addr};
 +      struct hash_mac_addr *entry, *tmp;
  
 -                      free = false;
 -                      naddr = 0;
 +      /* If the MAC address to be removed is in the hash addr
 +       * list, delete it from the list and update hash vector
 +       */
 +      list_for_each_entry_safe(entry, tmp, &adap->mac_hlist, list) {
 +              if (ether_addr_equal(entry->addr, mac_addr)) {
 +                      list_del(&entry->list);
 +                      kfree(entry);
 +                      return cxgb4_set_addr_hash(pi);
                }
        }
  
 -      return t4_set_addr_hash(pi->adapter, mb, pi->viid, uhash != 0,
 -                              uhash | mhash, sleep);
 +      ret = t4_free_mac_filt(adap, adap->mbox, pi->viid, 1, maclist, false);
 +      return ret < 0 ? -EINVAL : 0;
  }
  
 -int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */
 -module_param(dbfifo_int_thresh, int, 0644);
 -MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold");
 -
 -/*
 - * usecs to sleep while draining the dbfifo
 - */
 -static int dbfifo_drain_delay = 1000;
 -module_param(dbfifo_drain_delay, int, 0644);
 -MODULE_PARM_DESC(dbfifo_drain_delay,
 -               "usecs to sleep while draining the dbfifo");
 -
  /*
   * Set Rx properties of a port, such as promiscruity, address filters, and MTU.
   * If @mtu is -1 it is left unchanged.
   */
  static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
  {
 -      int ret;
        struct port_info *pi = netdev_priv(dev);
 +      struct adapter *adapter = pi->adapter;
  
 -      ret = set_addr_filters(dev, sleep_ok);
 -      if (ret == 0)
 -              ret = t4_set_rxmode(pi->adapter, pi->adapter->pf, pi->viid, mtu,
 -                                  (dev->flags & IFF_PROMISC) ? 1 : 0,
 -                                  (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1,
 -                                  sleep_ok);
 -      return ret;
 +      if (!(dev->flags & IFF_PROMISC)) {
 +              __dev_uc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync);
 +              if (!(dev->flags & IFF_ALLMULTI))
 +                      __dev_mc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync);
 +      }
 +
 +      return t4_set_rxmode(adapter, adapter->mbox, pi->viid, mtu,
 +                           (dev->flags & IFF_PROMISC) ? 1 : 0,
 +                           (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1,
 +                           sleep_ok);
  }
  
  /**
@@@ -664,6 -640,13 +664,13 @@@ out
        return 0;
  }
  
+ /* Flush the aggregated lro sessions */
+ static void uldrx_flush_handler(struct sge_rspq *q)
+ {
+       if (ulds[q->uld].lro_flush)
+               ulds[q->uld].lro_flush(&q->lro_mgr);
+ }
  /**
   *    uldrx_handler - response queue handler for ULD queues
   *    @q: the response queue that received the packet
@@@ -677,6 -660,7 +684,7 @@@ static int uldrx_handler(struct sge_rsp
                         const struct pkt_gl *gl)
  {
        struct sge_ofld_rxq *rxq = container_of(q, struct sge_ofld_rxq, rspq);
+       int ret;
  
        /* FW can send CPLs encapsulated in a CPL_FW4_MSG.
         */
            ((const struct cpl_fw4_msg *)(rsp + 1))->type == FW_TYPE_RSSCPL)
                rsp += 2;
  
-       if (ulds[q->uld].rx_handler(q->adap->uld_handle[q->uld], rsp, gl)) {
+       if (q->flush_handler)
+               ret = ulds[q->uld].lro_rx_handler(q->adap->uld_handle[q->uld],
+                                                 rsp, gl, &q->lro_mgr,
+                                                 &q->napi);
+       else
+               ret = ulds[q->uld].rx_handler(q->adap->uld_handle[q->uld],
+                                             rsp, gl);
+       if (ret) {
                rxq->stats.nomem++;
                return -1;
        }
        if (gl == NULL)
                rxq->stats.imm++;
        else if (gl == CXGB4_MSG_AN)
@@@ -754,6 -747,10 +771,10 @@@ static void name_msix_vecs(struct adapt
                snprintf(adap->msix_info[msi_idx++].desc, n, "%s-iscsi%d",
                         adap->port[0]->name, i);
  
+       for_each_iscsitrxq(&adap->sge, i)
+               snprintf(adap->msix_info[msi_idx++].desc, n, "%s-iSCSIT%d",
+                        adap->port[0]->name, i);
        for_each_rdmarxq(&adap->sge, i)
                snprintf(adap->msix_info[msi_idx++].desc, n, "%s-rdma%d",
                         adap->port[0]->name, i);
@@@ -767,6 -764,7 +788,7 @@@ static int request_msix_queue_irqs(stru
  {
        struct sge *s = &adap->sge;
        int err, ethqidx, iscsiqidx = 0, rdmaqidx = 0, rdmaciqqidx = 0;
+       int iscsitqidx = 0;
        int msi_index = 2;
  
        err = request_irq(adap->msix_info[1].vec, t4_sge_intr_msix, 0,
                        goto unwind;
                msi_index++;
        }
+       for_each_iscsitrxq(s, iscsitqidx) {
+               err = request_irq(adap->msix_info[msi_index].vec,
+                                 t4_sge_intr_msix, 0,
+                                 adap->msix_info[msi_index].desc,
+                                 &s->iscsitrxq[iscsitqidx].rspq);
+               if (err)
+                       goto unwind;
+               msi_index++;
+       }
        for_each_rdmarxq(s, rdmaqidx) {
                err = request_irq(adap->msix_info[msi_index].vec,
                                  t4_sge_intr_msix, 0,
@@@ -819,6 -826,9 +850,9 @@@ unwind
        while (--rdmaqidx >= 0)
                free_irq(adap->msix_info[--msi_index].vec,
                         &s->rdmarxq[rdmaqidx].rspq);
+       while (--iscsitqidx >= 0)
+               free_irq(adap->msix_info[--msi_index].vec,
+                        &s->iscsitrxq[iscsitqidx].rspq);
        while (--iscsiqidx >= 0)
                free_irq(adap->msix_info[--msi_index].vec,
                         &s->iscsirxq[iscsiqidx].rspq);
@@@ -840,6 -850,9 +874,9 @@@ static void free_msix_queue_irqs(struc
        for_each_iscsirxq(s, i)
                free_irq(adap->msix_info[msi_index++].vec,
                         &s->iscsirxq[i].rspq);
+       for_each_iscsitrxq(s, i)
+               free_irq(adap->msix_info[msi_index++].vec,
+                        &s->iscsitrxq[i].rspq);
        for_each_rdmarxq(s, i)
                free_irq(adap->msix_info[msi_index++].vec, &s->rdmarxq[i].rspq);
        for_each_rdmaciq(s, i)
@@@ -984,7 -997,7 +1021,7 @@@ static void enable_rx(struct adapter *a
  
  static int alloc_ofld_rxqs(struct adapter *adap, struct sge_ofld_rxq *q,
                           unsigned int nq, unsigned int per_chan, int msi_idx,
-                          u16 *ids)
+                          u16 *ids, bool lro)
  {
        int i, err;
  
                err = t4_sge_alloc_rxq(adap, &q->rspq, false,
                                       adap->port[i / per_chan],
                                       msi_idx, q->fl.size ? &q->fl : NULL,
-                                      uldrx_handler, 0);
+                                      uldrx_handler,
+                                      lro ? uldrx_flush_handler : NULL,
+                                      0);
                if (err)
                        return err;
                memset(&q->stats, 0, sizeof(q->stats));
@@@ -1024,7 -1039,7 +1063,7 @@@ static int setup_sge_queues(struct adap
                msi_idx = 1;         /* vector 0 is for non-queue interrupts */
        else {
                err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0,
-                                      NULL, NULL, -1);
+                                      NULL, NULL, NULL, -1);
                if (err)
                        return err;
                msi_idx = -((int)s->intrq.abs_id + 1);
         *    new/deleted queues.
         */
        err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0],
-                              msi_idx, NULL, fwevtq_handler, -1);
+                              msi_idx, NULL, fwevtq_handler, NULL, -1);
        if (err) {
  freeout:      t4_free_sge_resources(adap);
                return err;
                        err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev,
                                               msi_idx, &q->fl,
                                               t4_ethrx_handler,
+                                              NULL,
                                               t4_get_mps_bg_map(adap,
                                                                 pi->tx_chan));
                        if (err)
                        goto freeout;
        }
  
- #define ALLOC_OFLD_RXQS(firstq, nq, per_chan, ids) do { \
-       err = alloc_ofld_rxqs(adap, firstq, nq, per_chan, msi_idx, ids); \
+ #define ALLOC_OFLD_RXQS(firstq, nq, per_chan, ids, lro) do { \
+       err = alloc_ofld_rxqs(adap, firstq, nq, per_chan, msi_idx, ids, lro); \
        if (err) \
                goto freeout; \
        if (msi_idx > 0) \
                msi_idx += nq; \
  } while (0)
  
-       ALLOC_OFLD_RXQS(s->iscsirxq, s->iscsiqsets, j, s->iscsi_rxq);
-       ALLOC_OFLD_RXQS(s->rdmarxq, s->rdmaqs, 1, s->rdma_rxq);
+       ALLOC_OFLD_RXQS(s->iscsirxq, s->iscsiqsets, j, s->iscsi_rxq, false);
+       ALLOC_OFLD_RXQS(s->iscsitrxq, s->niscsitq, j, s->iscsit_rxq, true);
+       ALLOC_OFLD_RXQS(s->rdmarxq, s->rdmaqs, 1, s->rdma_rxq, false);
        j = s->rdmaciqs / adap->params.nports; /* rdmaq queues per channel */
-       ALLOC_OFLD_RXQS(s->rdmaciq, s->rdmaciqs, j, s->rdma_ciq);
+       ALLOC_OFLD_RXQS(s->rdmaciq, s->rdmaciqs, j, s->rdma_ciq, false);
  
  #undef ALLOC_OFLD_RXQS
  
@@@ -2430,6 -2447,9 +2471,9 @@@ static void uld_attach(struct adapter *
        } else if (uld == CXGB4_ULD_ISCSI) {
                lli.rxq_ids = adap->sge.iscsi_rxq;
                lli.nrxq = adap->sge.iscsiqsets;
+       } else if (uld == CXGB4_ULD_ISCSIT) {
+               lli.rxq_ids = adap->sge.iscsit_rxq;
+               lli.nrxq = adap->sge.niscsitq;
        }
        lli.ntxq = adap->sge.iscsiqsets;
        lli.nchan = adap->params.nports;
        lli.wr_cred = adap->params.ofldq_wr_cred;
        lli.adapter_type = adap->params.chip;
        lli.iscsi_iolen = MAXRXDATA_G(t4_read_reg(adap, TP_PARA_REG2_A));
+       lli.iscsi_tagmask = t4_read_reg(adap, ULP_RX_ISCSI_TAGMASK_A);
+       lli.iscsi_pgsz_order = t4_read_reg(adap, ULP_RX_ISCSI_PSZ_A);
+       lli.iscsi_llimit = t4_read_reg(adap, ULP_RX_ISCSI_LLIMIT_A);
+       lli.iscsi_ppm = &adap->iscsi_ppm;
        lli.cclk_ps = 1000000000 / adap->params.vpd.cclk;
        lli.udb_density = 1 << adap->params.sge.eq_qpp;
        lli.ucq_density = 1 << adap->params.sge.iq_qpp;
@@@ -2701,8 -2725,6 +2749,8 @@@ static int cxgb_up(struct adapter *adap
  #if IS_ENABLED(CONFIG_IPV6)
        update_clip(adap);
  #endif
 +      /* Initialize hash mac addr list*/
 +      INIT_LIST_HEAD(&adap->mac_hlist);
   out:
        return err;
   irq_err:
@@@ -4336,6 -4358,9 +4384,9 @@@ static void cfg_queues(struct adapter *
                s->rdmaciqs = (s->rdmaciqs / adap->params.nports) *
                                adap->params.nports;
                s->rdmaciqs = max_t(int, s->rdmaciqs, adap->params.nports);
+               if (!is_t4(adap->params.chip))
+                       s->niscsitq = s->iscsiqsets;
        }
  
        for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) {
                r->fl.size = 72;
        }
  
+       if (!is_t4(adap->params.chip)) {
+               for (i = 0; i < ARRAY_SIZE(s->iscsitrxq); i++) {
+                       struct sge_ofld_rxq *r = &s->iscsitrxq[i];
+                       init_rspq(adap, &r->rspq, 5, 1, 1024, 64);
+                       r->rspq.uld = CXGB4_ULD_ISCSIT;
+                       r->fl.size = 72;
+               }
+       }
        for (i = 0; i < ARRAY_SIZE(s->rdmarxq); i++) {
                struct sge_ofld_rxq *r = &s->rdmarxq[i];
  
@@@ -4436,9 -4471,13 +4497,13 @@@ static int enable_msix(struct adapter *
  
        want = s->max_ethqsets + EXTRA_VECS;
        if (is_offload(adap)) {
-               want += s->rdmaqs + s->rdmaciqs + s->iscsiqsets;
+               want += s->rdmaqs + s->rdmaciqs + s->iscsiqsets +
+                       s->niscsitq;
                /* need nchan for each possible ULD */
-               ofld_need = 3 * nchan;
+               if (is_t4(adap->params.chip))
+                       ofld_need = 3 * nchan;
+               else
+                       ofld_need = 4 * nchan;
        }
  #ifdef CONFIG_CHELSIO_T4_DCB
        /* For Data Center Bridging we need 8 Ethernet TX Priority Queues for
                if (allocated < want) {
                        s->rdmaqs = nchan;
                        s->rdmaciqs = nchan;
+                       if (!is_t4(adap->params.chip))
+                               s->niscsitq = nchan;
                }
  
                /* leftovers go to OFLD */
                i = allocated - EXTRA_VECS - s->max_ethqsets -
-                   s->rdmaqs - s->rdmaciqs;
+                   s->rdmaqs - s->rdmaciqs - s->niscsitq;
                s->iscsiqsets = (i / nchan) * nchan;  /* round down */
        }
        for (i = 0; i < allocated; ++i)
                adap->msix_info[i].vec = entries[i].vector;
index deca4a2956cc005fb8adce0b59a1c445699cce8d,3ba4b0cc8094b32d5717e4c5759ba075e19f9e01..13b144bcf725ec29d42dbdc1b33fc0c39c1fe919
@@@ -2157,8 -2157,11 +2157,11 @@@ static int process_responses(struct sge
  
        while (likely(budget_left)) {
                rc = (void *)q->cur_desc + (q->iqe_len - sizeof(*rc));
-               if (!is_new_response(rc, q))
+               if (!is_new_response(rc, q)) {
+                       if (q->flush_handler)
+                               q->flush_handler(q);
                        break;
+               }
  
                dma_rmb();
                rsp_type = RSPD_TYPE_G(rc->type_gen);
                budget_left--;
        }
  
 -      if (q->offset >= 0 && rxq->fl.size - rxq->fl.avail >= 16)
 +      if (q->offset >= 0 && fl_cap(&rxq->fl) - rxq->fl.avail >= 16)
                __refill_fl(q->adap, &rxq->fl);
        return budget - budget_left;
  }
@@@ -2544,7 -2547,8 +2547,8 @@@ static void __iomem *bar2_address(struc
   */
  int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
                     struct net_device *dev, int intr_idx,
-                    struct sge_fl *fl, rspq_handler_t hnd, int cong)
+                    struct sge_fl *fl, rspq_handler_t hnd,
+                    rspq_flush_handler_t flush_hnd, int cong)
  {
        int ret, flsz = 0;
        struct fw_iq_cmd c;
                                htonl(FW_IQ_CMD_FL0CNGCHMAP_V(cong) |
                                      FW_IQ_CMD_FL0CONGCIF_F |
                                      FW_IQ_CMD_FL0CONGEN_F);
 +              /* In T6, for egress queue type FL there is internal overhead
 +               * of 16B for header going into FLM module.  Hence the maximum
 +               * allowed burst size is 448 bytes.  For T4/T5, the hardware
 +               * doesn't coalesce fetch requests if more than 64 bytes of
 +               * Free List pointers are provided, so we use a 128-byte Fetch
 +               * Burst Minimum there (T6 implements coalescing so we can use
 +               * the smaller 64-byte value there).
 +               */
                c.fl0dcaen_to_fl0cidxfthresh =
 -                      htons(FW_IQ_CMD_FL0FBMIN_V(FETCHBURSTMIN_64B_X) |
 +                      htons(FW_IQ_CMD_FL0FBMIN_V(chip <= CHELSIO_T5 ?
 +                                                 FETCHBURSTMIN_128B_X :
 +                                                 FETCHBURSTMIN_64B_X) |
                              FW_IQ_CMD_FL0FBMAX_V((chip <= CHELSIO_T5) ?
                                                   FETCHBURSTMAX_512B_X :
                                                   FETCHBURSTMAX_256B_X));
        iq->size--;                           /* subtract status entry */
        iq->netdev = dev;
        iq->handler = hnd;
+       iq->flush_handler = flush_hnd;
+       memset(&iq->lro_mgr, 0, sizeof(struct t4_lro_mgr));
+       skb_queue_head_init(&iq->lro_mgr.lroq);
  
        /* set offset to -1 to distinguish ingress queues without FL */
        iq->offset = fl ? 0 : -1;
@@@ -2992,6 -2990,7 +3000,7 @@@ void t4_free_sge_resources(struct adapt
  
        /* clean up RDMA and iSCSI Rx queues */
        t4_free_ofld_rxqs(adap, adap->sge.iscsiqsets, adap->sge.iscsirxq);
+       t4_free_ofld_rxqs(adap, adap->sge.niscsitq, adap->sge.iscsitrxq);
        t4_free_ofld_rxqs(adap, adap->sge.rdmaqs, adap->sge.rdmarxq);
        t4_free_ofld_rxqs(adap, adap->sge.rdmaciqs, adap->sge.rdmaciq);
  
index 1d2d1da40c80a98ee0aa95c962952cadb46172de,a5641e2f45571756e6e07651c1ea433bd38e67f3..80417fc564d43fc6305a737e90a819080bbcdd8b
@@@ -51,6 -51,7 +51,7 @@@ enum 
        CPL_TX_PKT            = 0xE,
        CPL_L2T_WRITE_REQ     = 0x12,
        CPL_TID_RELEASE       = 0x1A,
+       CPL_TX_DATA_ISO       = 0x1F,
  
        CPL_CLOSE_LISTSRV_RPL = 0x20,
        CPL_L2T_WRITE_RPL     = 0x23,
@@@ -344,6 -345,87 +345,87 @@@ struct cpl_pass_open_rpl 
        u8 status;
  };
  
+ struct tcp_options {
+       __be16 mss;
+       __u8 wsf;
+ #if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8:4;
+       __u8 unknown:1;
+       __u8:1;
+       __u8 sack:1;
+       __u8 tstamp:1;
+ #else
+       __u8 tstamp:1;
+       __u8 sack:1;
+       __u8:1;
+       __u8 unknown:1;
+       __u8:4;
+ #endif
+ };
+ struct cpl_pass_accept_req {
+       union opcode_tid ot;
+       __be16 rsvd;
+       __be16 len;
+       __be32 hdr_len;
+       __be16 vlan;
+       __be16 l2info;
+       __be32 tos_stid;
+       struct tcp_options tcpopt;
+ };
+ /* cpl_pass_accept_req.hdr_len fields */
+ #define SYN_RX_CHAN_S    0
+ #define SYN_RX_CHAN_M    0xF
+ #define SYN_RX_CHAN_V(x) ((x) << SYN_RX_CHAN_S)
+ #define SYN_RX_CHAN_G(x) (((x) >> SYN_RX_CHAN_S) & SYN_RX_CHAN_M)
+ #define TCP_HDR_LEN_S    10
+ #define TCP_HDR_LEN_M    0x3F
+ #define TCP_HDR_LEN_V(x) ((x) << TCP_HDR_LEN_S)
+ #define TCP_HDR_LEN_G(x) (((x) >> TCP_HDR_LEN_S) & TCP_HDR_LEN_M)
+ #define IP_HDR_LEN_S    16
+ #define IP_HDR_LEN_M    0x3FF
+ #define IP_HDR_LEN_V(x) ((x) << IP_HDR_LEN_S)
+ #define IP_HDR_LEN_G(x) (((x) >> IP_HDR_LEN_S) & IP_HDR_LEN_M)
+ #define ETH_HDR_LEN_S    26
+ #define ETH_HDR_LEN_M    0x1F
+ #define ETH_HDR_LEN_V(x) ((x) << ETH_HDR_LEN_S)
+ #define ETH_HDR_LEN_G(x) (((x) >> ETH_HDR_LEN_S) & ETH_HDR_LEN_M)
+ /* cpl_pass_accept_req.l2info fields */
+ #define SYN_MAC_IDX_S    0
+ #define SYN_MAC_IDX_M    0x1FF
+ #define SYN_MAC_IDX_V(x) ((x) << SYN_MAC_IDX_S)
+ #define SYN_MAC_IDX_G(x) (((x) >> SYN_MAC_IDX_S) & SYN_MAC_IDX_M)
+ #define SYN_XACT_MATCH_S    9
+ #define SYN_XACT_MATCH_V(x) ((x) << SYN_XACT_MATCH_S)
+ #define SYN_XACT_MATCH_F    SYN_XACT_MATCH_V(1U)
+ #define SYN_INTF_S    12
+ #define SYN_INTF_M    0xF
+ #define SYN_INTF_V(x) ((x) << SYN_INTF_S)
+ #define SYN_INTF_G(x) (((x) >> SYN_INTF_S) & SYN_INTF_M)
+ enum {                     /* TCP congestion control algorithms */
+       CONG_ALG_RENO,
+       CONG_ALG_TAHOE,
+       CONG_ALG_NEWRENO,
+       CONG_ALG_HIGHSPEED
+ };
+ #define CONG_CNTRL_S    14
+ #define CONG_CNTRL_M    0x3
+ #define CONG_CNTRL_V(x) ((x) << CONG_CNTRL_S)
+ #define CONG_CNTRL_G(x) (((x) >> CONG_CNTRL_S) & CONG_CNTRL_M)
+ #define T5_ISS_S    18
+ #define T5_ISS_V(x) ((x) << T5_ISS_S)
+ #define T5_ISS_F    T5_ISS_V(1U)
  struct cpl_pass_accept_rpl {
        WR_HDR;
        union opcode_tid ot;
@@@ -818,6 -900,110 +900,110 @@@ struct cpl_iscsi_hdr 
  #define ISCSI_DDP_V(x) ((x) << ISCSI_DDP_S)
  #define ISCSI_DDP_F    ISCSI_DDP_V(1U)
  
+ struct cpl_rx_data_ddp {
+       union opcode_tid ot;
+       __be16 urg;
+       __be16 len;
+       __be32 seq;
+       union {
+               __be32 nxt_seq;
+               __be32 ddp_report;
+       };
+       __be32 ulp_crc;
+       __be32 ddpvld;
+ };
+ #define cpl_rx_iscsi_ddp cpl_rx_data_ddp
+ struct cpl_iscsi_data {
+       union opcode_tid ot;
+       __u8 rsvd0[2];
+       __be16 len;
+       __be32 seq;
+       __be16 urg;
+       __u8 rsvd1;
+       __u8 status;
+ };
+ struct cpl_tx_data_iso {
+       __be32 op_to_scsi;
+       __u8   reserved1;
+       __u8   ahs_len;
+       __be16 mpdu;
+       __be32 burst_size;
+       __be32 len;
+       __be32 reserved2_seglen_offset;
+       __be32 datasn_offset;
+       __be32 buffer_offset;
+       __be32 reserved3;
+       /* encapsulated CPL_TX_DATA follows here */
+ };
+ /* cpl_tx_data_iso.op_to_scsi fields */
+ #define CPL_TX_DATA_ISO_OP_S  24
+ #define CPL_TX_DATA_ISO_OP_M  0xff
+ #define CPL_TX_DATA_ISO_OP_V(x)       ((x) << CPL_TX_DATA_ISO_OP_S)
+ #define CPL_TX_DATA_ISO_OP_G(x)       \
+       (((x) >> CPL_TX_DATA_ISO_OP_S) & CPL_TX_DATA_ISO_OP_M)
+ #define CPL_TX_DATA_ISO_FIRST_S               23
+ #define CPL_TX_DATA_ISO_FIRST_M               0x1
+ #define CPL_TX_DATA_ISO_FIRST_V(x)    ((x) << CPL_TX_DATA_ISO_FIRST_S)
+ #define CPL_TX_DATA_ISO_FIRST_G(x)    \
+       (((x) >> CPL_TX_DATA_ISO_FIRST_S) & CPL_TX_DATA_ISO_FIRST_M)
+ #define CPL_TX_DATA_ISO_FIRST_F       CPL_TX_DATA_ISO_FIRST_V(1U)
+ #define CPL_TX_DATA_ISO_LAST_S                22
+ #define CPL_TX_DATA_ISO_LAST_M                0x1
+ #define CPL_TX_DATA_ISO_LAST_V(x)     ((x) << CPL_TX_DATA_ISO_LAST_S)
+ #define CPL_TX_DATA_ISO_LAST_G(x)     \
+       (((x) >> CPL_TX_DATA_ISO_LAST_S) & CPL_TX_DATA_ISO_LAST_M)
+ #define CPL_TX_DATA_ISO_LAST_F        CPL_TX_DATA_ISO_LAST_V(1U)
+ #define CPL_TX_DATA_ISO_CPLHDRLEN_S   21
+ #define CPL_TX_DATA_ISO_CPLHDRLEN_M   0x1
+ #define CPL_TX_DATA_ISO_CPLHDRLEN_V(x)        ((x) << CPL_TX_DATA_ISO_CPLHDRLEN_S)
+ #define CPL_TX_DATA_ISO_CPLHDRLEN_G(x)        \
+       (((x) >> CPL_TX_DATA_ISO_CPLHDRLEN_S) & CPL_TX_DATA_ISO_CPLHDRLEN_M)
+ #define CPL_TX_DATA_ISO_CPLHDRLEN_F   CPL_TX_DATA_ISO_CPLHDRLEN_V(1U)
+ #define CPL_TX_DATA_ISO_HDRCRC_S      20
+ #define CPL_TX_DATA_ISO_HDRCRC_M      0x1
+ #define CPL_TX_DATA_ISO_HDRCRC_V(x)   ((x) << CPL_TX_DATA_ISO_HDRCRC_S)
+ #define CPL_TX_DATA_ISO_HDRCRC_G(x)   \
+       (((x) >> CPL_TX_DATA_ISO_HDRCRC_S) & CPL_TX_DATA_ISO_HDRCRC_M)
+ #define CPL_TX_DATA_ISO_HDRCRC_F      CPL_TX_DATA_ISO_HDRCRC_V(1U)
+ #define CPL_TX_DATA_ISO_PLDCRC_S      19
+ #define CPL_TX_DATA_ISO_PLDCRC_M      0x1
+ #define CPL_TX_DATA_ISO_PLDCRC_V(x)   ((x) << CPL_TX_DATA_ISO_PLDCRC_S)
+ #define CPL_TX_DATA_ISO_PLDCRC_G(x)   \
+       (((x) >> CPL_TX_DATA_ISO_PLDCRC_S) & CPL_TX_DATA_ISO_PLDCRC_M)
+ #define CPL_TX_DATA_ISO_PLDCRC_F      CPL_TX_DATA_ISO_PLDCRC_V(1U)
+ #define CPL_TX_DATA_ISO_IMMEDIATE_S   18
+ #define CPL_TX_DATA_ISO_IMMEDIATE_M   0x1
+ #define CPL_TX_DATA_ISO_IMMEDIATE_V(x)        ((x) << CPL_TX_DATA_ISO_IMMEDIATE_S)
+ #define CPL_TX_DATA_ISO_IMMEDIATE_G(x)        \
+       (((x) >> CPL_TX_DATA_ISO_IMMEDIATE_S) & CPL_TX_DATA_ISO_IMMEDIATE_M)
+ #define CPL_TX_DATA_ISO_IMMEDIATE_F   CPL_TX_DATA_ISO_IMMEDIATE_V(1U)
+ #define CPL_TX_DATA_ISO_SCSI_S                16
+ #define CPL_TX_DATA_ISO_SCSI_M                0x3
+ #define CPL_TX_DATA_ISO_SCSI_V(x)     ((x) << CPL_TX_DATA_ISO_SCSI_S)
+ #define CPL_TX_DATA_ISO_SCSI_G(x)     \
+       (((x) >> CPL_TX_DATA_ISO_SCSI_S) & CPL_TX_DATA_ISO_SCSI_M)
+ /* cpl_tx_data_iso.reserved2_seglen_offset fields */
+ #define CPL_TX_DATA_ISO_SEGLEN_OFFSET_S               0
+ #define CPL_TX_DATA_ISO_SEGLEN_OFFSET_M               0xffffff
+ #define CPL_TX_DATA_ISO_SEGLEN_OFFSET_V(x)    \
+       ((x) << CPL_TX_DATA_ISO_SEGLEN_OFFSET_S)
+ #define CPL_TX_DATA_ISO_SEGLEN_OFFSET_G(x)    \
+       (((x) >> CPL_TX_DATA_ISO_SEGLEN_OFFSET_S) & \
+        CPL_TX_DATA_ISO_SEGLEN_OFFSET_M)
  struct cpl_rx_data {
        union opcode_tid ot;
        __be16 rsvd;
@@@ -854,6 -1040,15 +1040,15 @@@ struct cpl_rx_data_ack 
  #define RX_FORCE_ACK_V(x) ((x) << RX_FORCE_ACK_S)
  #define RX_FORCE_ACK_F    RX_FORCE_ACK_V(1U)
  
+ #define RX_DACK_MODE_S    29
+ #define RX_DACK_MODE_M    0x3
+ #define RX_DACK_MODE_V(x) ((x) << RX_DACK_MODE_S)
+ #define RX_DACK_MODE_G(x) (((x) >> RX_DACK_MODE_S) & RX_DACK_MODE_M)
+ #define RX_DACK_CHANGE_S    31
+ #define RX_DACK_CHANGE_V(x) ((x) << RX_DACK_CHANGE_S)
+ #define RX_DACK_CHANGE_F    RX_DACK_CHANGE_V(1U)
  struct cpl_rx_pkt {
        struct rss_header rsshdr;
        u8 opcode;
@@@ -1021,8 -1216,6 +1216,8 @@@ struct cpl_l2t_write_req 
  #define L2T_W_NOREPLY_V(x) ((x) << L2T_W_NOREPLY_S)
  #define L2T_W_NOREPLY_F    L2T_W_NOREPLY_V(1U)
  
 +#define CPL_L2T_VLAN_NONE 0xfff
 +
  struct cpl_l2t_write_rpl {
        union opcode_tid ot;
        u8 status;
@@@ -1090,6 -1283,12 +1285,12 @@@ struct cpl_fw4_ack 
        __be64 rsvd1;
  };
  
+ enum {
+       CPL_FW4_ACK_FLAGS_SEQVAL        = 0x1,  /* seqn valid */
+       CPL_FW4_ACK_FLAGS_CH            = 0x2,  /* channel change complete */
+       CPL_FW4_ACK_FLAGS_FLOWC         = 0x4,  /* fw_flowc_wr complete */
+ };
  struct cpl_fw6_msg {
        u8 opcode;
        u8 type;
@@@ -1115,6 -1314,17 +1316,17 @@@ struct cpl_fw6_msg_ofld_connection_wr_r
        __u8    rsvd[2];
  };
  
+ struct cpl_tx_data {
+       union opcode_tid ot;
+       __be32 len;
+       __be32 rsvd;
+       __be32 flags;
+ };
+ /* cpl_tx_data.flags field */
+ #define TX_FORCE_S    13
+ #define TX_FORCE_V(x) ((x) << TX_FORCE_S)
  enum {
        ULP_TX_MEM_READ = 2,
        ULP_TX_MEM_WRITE = 3,
@@@ -1143,6 -1353,11 +1355,11 @@@ struct ulptx_sgl 
        struct ulptx_sge_pair sge[0];
  };
  
+ struct ulptx_idata {
+       __be32 cmd_more;
+       __be32 len;
+ };
  #define ULPTX_NSGE_S    0
  #define ULPTX_NSGE_V(x) ((x) << ULPTX_NSGE_S)
  
index 961202f4e9aa4a2004f85d89f7a8a638f3898814,a3b939706acb0040400d2f9dc2bb994de8b3dfd8..801b080f7a57f2c19e049abed8a624a678996273
@@@ -16,9 -16,9 +16,9 @@@
   * GNU General Public License for more details.
   ******************************************************************************/
  
 +#include <crypto/hash.h>
  #include <linux/string.h>
  #include <linux/kthread.h>
 -#include <linux/crypto.h>
  #include <linux/completion.h>
  #include <linux/module.h>
  #include <linux/vmalloc.h>
@@@ -480,14 -480,16 +480,16 @@@ int iscsit_del_np(struct iscsi_np *np
  
  static int iscsit_immediate_queue(struct iscsi_conn *, struct iscsi_cmd *, int);
  static int iscsit_response_queue(struct iscsi_conn *, struct iscsi_cmd *, int);
+ static void iscsit_rx_pdu(struct iscsi_conn *);
  
static int iscsit_queue_rsp(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
+ int iscsit_queue_rsp(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
  {
        iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
        return 0;
  }
+ EXPORT_SYMBOL(iscsit_queue_rsp);
  
static void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
+ void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
  {
        bool scsi_cmd = (cmd->iscsi_opcode == ISCSI_OP_SCSI_CMD);
  
  
        __iscsit_free_cmd(cmd, scsi_cmd, true);
  }
+ EXPORT_SYMBOL(iscsit_aborted_task);
  
  static enum target_prot_op iscsit_get_sup_prot_ops(struct iscsi_conn *conn)
  {
@@@ -519,6 -522,7 +522,7 @@@ static struct iscsit_transport iscsi_ta
        .iscsit_queue_data_in   = iscsit_queue_rsp,
        .iscsit_queue_status    = iscsit_queue_rsp,
        .iscsit_aborted_task    = iscsit_aborted_task,
+       .iscsit_rx_pdu          = iscsit_rx_pdu,
        .iscsit_get_sup_prot_ops = iscsit_get_sup_prot_ops,
  };
  
@@@ -634,7 -638,7 +638,7 @@@ static void __exit iscsi_target_cleanup
        kfree(iscsit_global);
  }
  
static int iscsit_add_reject(
+ int iscsit_add_reject(
        struct iscsi_conn *conn,
        u8 reason,
        unsigned char *buf)
  
        return -1;
  }
+ EXPORT_SYMBOL(iscsit_add_reject);
  
  static int iscsit_add_reject_from_cmd(
        struct iscsi_cmd *cmd,
@@@ -719,6 -724,7 +724,7 @@@ int iscsit_reject_cmd(struct iscsi_cmd 
  {
        return iscsit_add_reject_from_cmd(cmd, reason, false, buf);
  }
+ EXPORT_SYMBOL(iscsit_reject_cmd);
  
  /*
   * Map some portion of the allocated scatterlist to an iovec, suitable for
@@@ -1190,7 -1196,7 +1196,7 @@@ iscsit_handle_scsi_cmd(struct iscsi_con
  }
  
  static u32 iscsit_do_crypto_hash_sg(
 -      struct hash_desc *hash,
 +      struct ahash_request *hash,
        struct iscsi_cmd *cmd,
        u32 data_offset,
        u32 data_length,
        struct scatterlist *sg;
        unsigned int page_off;
  
 -      crypto_hash_init(hash);
 +      crypto_ahash_init(hash);
  
        sg = cmd->first_data_sg;
        page_off = cmd->first_data_sg_off;
        while (data_length) {
                u32 cur_len = min_t(u32, data_length, (sg->length - page_off));
  
 -              crypto_hash_update(hash, sg, cur_len);
 +              ahash_request_set_crypt(hash, sg, NULL, cur_len);
 +              crypto_ahash_update(hash);
  
                data_length -= cur_len;
                page_off = 0;
                struct scatterlist pad_sg;
  
                sg_init_one(&pad_sg, pad_bytes, padding);
 -              crypto_hash_update(hash, &pad_sg, padding);
 +              ahash_request_set_crypt(hash, &pad_sg, (u8 *)&data_crc,
 +                                      padding);
 +              crypto_ahash_finup(hash);
 +      } else {
 +              ahash_request_set_crypt(hash, NULL, (u8 *)&data_crc, 0);
 +              crypto_ahash_final(hash);
        }
 -      crypto_hash_final(hash, (u8 *) &data_crc);
  
        return data_crc;
  }
  
  static void iscsit_do_crypto_hash_buf(
 -      struct hash_desc *hash,
 +      struct ahash_request *hash,
        const void *buf,
        u32 payload_length,
        u32 padding,
        u8 *pad_bytes,
        u8 *data_crc)
  {
 -      struct scatterlist sg;
 +      struct scatterlist sg[2];
  
 -      crypto_hash_init(hash);
 +      sg_init_table(sg, ARRAY_SIZE(sg));
 +      sg_set_buf(sg, buf, payload_length);
 +      sg_set_buf(sg + 1, pad_bytes, padding);
  
 -      sg_init_one(&sg, buf, payload_length);
 -      crypto_hash_update(hash, &sg, payload_length);
 +      ahash_request_set_crypt(hash, sg, data_crc, payload_length + padding);
  
 -      if (padding) {
 -              sg_init_one(&sg, pad_bytes, padding);
 -              crypto_hash_update(hash, &sg, padding);
 -      }
 -      crypto_hash_final(hash, data_crc);
 +      crypto_ahash_digest(hash);
  }
  
  int
@@@ -1424,7 -1428,7 +1430,7 @@@ iscsit_get_dataout(struct iscsi_conn *c
        if (conn->conn_ops->DataDigest) {
                u32 data_crc;
  
 -              data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd,
 +              data_crc = iscsit_do_crypto_hash_sg(conn->conn_rx_hash, cmd,
                                                    be32_to_cpu(hdr->offset),
                                                    payload_length, padding,
                                                    cmd->pad_bytes);
@@@ -1684,7 -1688,7 +1690,7 @@@ static int iscsit_handle_nop_out(struc
                }
  
                if (conn->conn_ops->DataDigest) {
 -                      iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
 +                      iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
                                        ping_data, payload_length,
                                        padding, cmd->pad_bytes,
                                        (u8 *)&data_crc);
@@@ -2103,7 -2107,7 +2109,7 @@@ iscsit_handle_text_cmd(struct iscsi_con
                        goto reject;
  
                if (conn->conn_ops->DataDigest) {
 -                      iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
 +                      iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
                                        text_in, payload_length,
                                        padding, (u8 *)&pad_bytes,
                                        (u8 *)&data_crc);
@@@ -2335,7 -2339,7 +2341,7 @@@ iscsit_handle_logout_cmd(struct iscsi_c
  }
  EXPORT_SYMBOL(iscsit_handle_logout_cmd);
  
static int iscsit_handle_snack(
+ int iscsit_handle_snack(
        struct iscsi_conn *conn,
        unsigned char *buf)
  {
  
        return 0;
  }
+ EXPORT_SYMBOL(iscsit_handle_snack);
  
  static void iscsit_rx_thread_wait_for_tcp(struct iscsi_conn *conn)
  {
@@@ -2442,7 -2447,7 +2449,7 @@@ static int iscsit_handle_immediate_data
        if (conn->conn_ops->DataDigest) {
                u32 data_crc;
  
 -              data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd,
 +              data_crc = iscsit_do_crypto_hash_sg(conn->conn_rx_hash, cmd,
                                                    cmd->write_data_done, length, padding,
                                                    cmd->pad_bytes);
  
@@@ -2528,16 -2533,11 +2535,11 @@@ static void iscsit_build_conn_drop_asyn
        iscsit_dec_conn_usage_count(conn_p);
  }
  
static int iscsit_send_conn_drop_async_message(
void iscsit_build_conn_drop_async_pdu(
        struct iscsi_cmd *cmd,
-       struct iscsi_conn *conn)
+       struct iscsi_conn *conn,
+       struct iscsi_async *hdr)
  {
-       struct iscsi_async *hdr;
-       cmd->tx_size = ISCSI_HDR_LEN;
-       cmd->iscsi_opcode = ISCSI_OP_ASYNC_EVENT;
-       hdr                     = (struct iscsi_async *) cmd->pdu;
        hdr->opcode             = ISCSI_OP_ASYNC_EVENT;
        hdr->flags              = ISCSI_FLAG_CMD_FINAL;
        cmd->init_task_tag      = RESERVED_ITT;
        hdr->param1             = cpu_to_be16(cmd->logout_cid);
        hdr->param2             = cpu_to_be16(conn->sess->sess_ops->DefaultTime2Wait);
        hdr->param3             = cpu_to_be16(conn->sess->sess_ops->DefaultTime2Retain);
+ }
+ EXPORT_SYMBOL(iscsit_build_conn_drop_async_pdu);
+ static int iscsit_send_conn_drop_async_message(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+ {
+       struct iscsi_async *hdr;
+       cmd->tx_size = ISCSI_HDR_LEN;
+       cmd->iscsi_opcode = ISCSI_OP_ASYNC_EVENT;
+       hdr                     = (struct iscsi_async *)cmd->pdu;
+       iscsit_build_conn_drop_async_pdu(cmd, conn, hdr);
  
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
  
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
  
                cmd->tx_size += ISCSI_CRC_LEN;
@@@ -2583,7 -2598,7 +2600,7 @@@ static void iscsit_tx_thread_wait_for_t
        }
  }
  
static void
+ void
  iscsit_build_datain_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
                        struct iscsi_datain *datain, struct iscsi_data_rsp *hdr,
                        bool set_statsn)
                cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn),
                ntohl(hdr->offset), datain->length, conn->cid);
  }
+ EXPORT_SYMBOL(iscsit_build_datain_pdu);
  
  static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
  {
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
  
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->pdu,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->pdu,
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
  
                iov[0].iov_len += ISCSI_CRC_LEN;
                                cmd->padding);
        }
        if (conn->conn_ops->DataDigest) {
 -              cmd->data_crc = iscsit_do_crypto_hash_sg(&conn->conn_tx_hash, cmd,
 +              cmd->data_crc = iscsit_do_crypto_hash_sg(conn->conn_tx_hash, cmd,
                         datain.offset, datain.length, cmd->padding, cmd->pad_bytes);
  
                iov[iov_count].iov_base = &cmd->data_crc;
@@@ -2859,7 -2875,7 +2877,7 @@@ iscsit_send_logout(struct iscsi_cmd *cm
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
  
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, &cmd->pdu[0],
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, &cmd->pdu[0],
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
  
                iov[0].iov_len += ISCSI_CRC_LEN;
@@@ -2917,7 -2933,7 +2935,7 @@@ static int iscsit_send_unsolicited_nopi
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
  
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
  
                tx_size += ISCSI_CRC_LEN;
@@@ -2965,7 -2981,7 +2983,7 @@@ iscsit_send_nopin(struct iscsi_cmd *cmd
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
  
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
  
                iov[0].iov_len += ISCSI_CRC_LEN;
                                " padding bytes.\n", padding);
                }
                if (conn->conn_ops->DataDigest) {
 -                      iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
 +                      iscsit_do_crypto_hash_buf(conn->conn_tx_hash,
                                cmd->buf_ptr, cmd->buf_ptr_size,
                                padding, (u8 *)&cmd->pad_bytes,
                                (u8 *)&cmd->data_crc);
        return 0;
  }
  
+ void iscsit_build_r2t_pdu(struct iscsi_cmd *cmd,
+                         struct iscsi_conn *conn,
+                         struct iscsi_r2t *r2t,
+                         struct iscsi_r2t_rsp *hdr)
+ {
+       hdr->opcode             = ISCSI_OP_R2T;
+       hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
+       int_to_scsilun(cmd->se_cmd.orig_fe_lun, (struct scsi_lun *)&hdr->lun);
+       hdr->itt                = cmd->init_task_tag;
+       hdr->ttt                = cpu_to_be32(r2t->targ_xfer_tag);
+       hdr->statsn             = cpu_to_be32(conn->stat_sn);
+       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32(
+                                 (u32)atomic_read(&conn->sess->max_cmd_sn));
+       hdr->r2tsn              = cpu_to_be32(r2t->r2t_sn);
+       hdr->data_offset        = cpu_to_be32(r2t->offset);
+       hdr->data_length        = cpu_to_be32(r2t->xfer_len);
+ }
+ EXPORT_SYMBOL(iscsit_build_r2t_pdu);
  static int iscsit_send_r2t(
        struct iscsi_cmd *cmd,
        struct iscsi_conn *conn)
  
        hdr                     = (struct iscsi_r2t_rsp *) cmd->pdu;
        memset(hdr, 0, ISCSI_HDR_LEN);
-       hdr->opcode             = ISCSI_OP_R2T;
-       hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
-       int_to_scsilun(cmd->se_cmd.orig_fe_lun,
-                       (struct scsi_lun *)&hdr->lun);
-       hdr->itt                = cmd->init_task_tag;
        r2t->targ_xfer_tag      = session_get_next_ttt(conn->sess);
-       hdr->ttt                = cpu_to_be32(r2t->targ_xfer_tag);
-       hdr->statsn             = cpu_to_be32(conn->stat_sn);
-       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
-       hdr->max_cmdsn          = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
-       hdr->r2tsn              = cpu_to_be32(r2t->r2t_sn);
-       hdr->data_offset        = cpu_to_be32(r2t->offset);
-       hdr->data_length        = cpu_to_be32(r2t->xfer_len);
+       iscsit_build_r2t_pdu(cmd, conn, r2t, hdr);
  
        cmd->iov_misc[0].iov_base       = cmd->pdu;
        cmd->iov_misc[0].iov_len        = ISCSI_HDR_LEN;
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
  
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
  
                cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN;
@@@ -3166,6 -3192,7 +3194,7 @@@ int iscsit_build_r2ts_for_cmd
  
        return 0;
  }
+ EXPORT_SYMBOL(iscsit_build_r2ts_for_cmd);
  
  void iscsit_build_rsp_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
                        bool inc_stat_sn, struct iscsi_scsi_rsp *hdr)
@@@ -3241,7 -3268,7 +3270,7 @@@ static int iscsit_send_response(struct 
                }
  
                if (conn->conn_ops->DataDigest) {
 -                      iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
 +                      iscsit_do_crypto_hash_buf(conn->conn_tx_hash,
                                cmd->sense_buffer,
                                (cmd->se_cmd.scsi_sense_length + padding),
                                0, NULL, (u8 *)&cmd->data_crc);
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
  
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->pdu,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->pdu,
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
  
                iov[0].iov_len += ISCSI_CRC_LEN;
@@@ -3334,7 -3361,7 +3363,7 @@@ iscsit_send_task_mgt_rsp(struct iscsi_c
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
  
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
  
                cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN;
@@@ -3603,7 -3630,7 +3632,7 @@@ static int iscsit_send_text_rsp
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
  
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
  
                iov[0].iov_len += ISCSI_CRC_LEN;
        }
  
        if (conn->conn_ops->DataDigest) {
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash,
                                cmd->buf_ptr, text_length,
                                0, NULL, (u8 *)&cmd->data_crc);
  
@@@ -3670,7 -3697,7 +3699,7 @@@ static int iscsit_send_reject
        if (conn->conn_ops->HeaderDigest) {
                u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
  
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
  
                iov[0].iov_len += ISCSI_CRC_LEN;
        }
  
        if (conn->conn_ops->DataDigest) {
 -              iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->buf_ptr,
 +              iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->buf_ptr,
                                ISCSI_HDR_LEN, 0, NULL, (u8 *)&cmd->data_crc);
  
                iov[iov_count].iov_base = &cmd->data_crc;
@@@ -3724,32 -3751,6 +3753,6 @@@ void iscsit_thread_get_cpumask(struct i
        cpumask_setall(conn->conn_cpumask);
  }
  
- static inline void iscsit_thread_check_cpumask(
-       struct iscsi_conn *conn,
-       struct task_struct *p,
-       int mode)
- {
-       /*
-        * mode == 1 signals iscsi_target_tx_thread() usage.
-        * mode == 0 signals iscsi_target_rx_thread() usage.
-        */
-       if (mode == 1) {
-               if (!conn->conn_tx_reset_cpumask)
-                       return;
-               conn->conn_tx_reset_cpumask = 0;
-       } else {
-               if (!conn->conn_rx_reset_cpumask)
-                       return;
-               conn->conn_rx_reset_cpumask = 0;
-       }
-       /*
-        * Update the CPU mask for this single kthread so that
-        * both TX and RX kthreads are scheduled to run on the
-        * same CPU.
-        */
-       set_cpus_allowed_ptr(p, conn->conn_cpumask);
- }
  static int
  iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
  {
@@@ -4087,36 -4088,12 +4090,12 @@@ static bool iscsi_target_check_conn_sta
        return ret;
  }
  
int iscsi_target_rx_thread(void *arg)
static void iscsit_rx_pdu(struct iscsi_conn *conn)
  {
-       int ret, rc;
+       int ret;
        u8 buffer[ISCSI_HDR_LEN], opcode;
        u32 checksum = 0, digest = 0;
-       struct iscsi_conn *conn = arg;
        struct kvec iov;
-       /*
-        * Allow ourselves to be interrupted by SIGINT so that a
-        * connection recovery / failure event can be triggered externally.
-        */
-       allow_signal(SIGINT);
-       /*
-        * Wait for iscsi_post_login_handler() to complete before allowing
-        * incoming iscsi/tcp socket I/O, and/or failing the connection.
-        */
-       rc = wait_for_completion_interruptible(&conn->rx_login_comp);
-       if (rc < 0 || iscsi_target_check_conn_state(conn))
-               return 0;
-       if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
-               struct completion comp;
-               init_completion(&comp);
-               rc = wait_for_completion_interruptible(&comp);
-               if (rc < 0)
-                       goto transport_err;
-               goto transport_err;
-       }
  
        while (!kthread_should_stop()) {
                /*
                ret = rx_data(conn, &iov, 1, ISCSI_HDR_LEN);
                if (ret != ISCSI_HDR_LEN) {
                        iscsit_rx_thread_wait_for_tcp(conn);
-                       goto transport_err;
+                       return;
                }
  
                if (conn->conn_ops->HeaderDigest) {
                        ret = rx_data(conn, &iov, 1, ISCSI_CRC_LEN);
                        if (ret != ISCSI_CRC_LEN) {
                                iscsit_rx_thread_wait_for_tcp(conn);
-                               goto transport_err;
+                               return;
                        }
  
 -                      iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
 +                      iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
                                        buffer, ISCSI_HDR_LEN,
                                        0, NULL, (u8 *)&checksum);
  
                }
  
                if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)
-                       goto transport_err;
+                       return;
  
                opcode = buffer[0] & ISCSI_OPCODE_MASK;
  
                        " while in Discovery Session, rejecting.\n", opcode);
                        iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
                                          buffer);
-                       goto transport_err;
+                       return;
                }
  
                ret = iscsi_target_rx_opcode(conn, buffer);
                if (ret < 0)
-                       goto transport_err;
+                       return;
        }
+ }
+ int iscsi_target_rx_thread(void *arg)
+ {
+       int rc;
+       struct iscsi_conn *conn = arg;
+       /*
+        * Allow ourselves to be interrupted by SIGINT so that a
+        * connection recovery / failure event can be triggered externally.
+        */
+       allow_signal(SIGINT);
+       /*
+        * Wait for iscsi_post_login_handler() to complete before allowing
+        * incoming iscsi/tcp socket I/O, and/or failing the connection.
+        */
+       rc = wait_for_completion_interruptible(&conn->rx_login_comp);
+       if (rc < 0 || iscsi_target_check_conn_state(conn))
+               return 0;
+       if (!conn->conn_transport->iscsit_rx_pdu)
+               return 0;
+       conn->conn_transport->iscsit_rx_pdu(conn);
  
- transport_err:
        if (!signal_pending(current))
                atomic_set(&conn->transport_failed, 1);
        iscsit_take_action_for_connection_exit(conn);
@@@ -4240,16 -4240,18 +4242,18 @@@ int iscsit_close_connection
        pr_debug("Closing iSCSI connection CID %hu on SID:"
                " %u\n", conn->cid, sess->sid);
        /*
-        * Always up conn_logout_comp for the traditional TCP case just in case
-        * the RX Thread in iscsi_target_rx_opcode() is sleeping and the logout
-        * response never got sent because the connection failed.
+        * Always up conn_logout_comp for the traditional TCP and TCP_CXGB4
+        * case just in case the RX Thread in iscsi_target_rx_opcode() is
+        * sleeping and the logout response never got sent because the
+        * connection failed.
         *
         * However for iser-target, isert_wait4logout() is using conn_logout_comp
         * to signal logout response TX interrupt completion.  Go ahead and skip
         * this for iser since isert_rx_opcode() does not wait on logout failure,
         * and to avoid iscsi_conn pointer dereference in iser-target code.
         */
-       if (conn->conn_transport->transport_type == ISCSI_TCP)
+       if ((conn->conn_transport->transport_type == ISCSI_TCP) ||
+           (conn->conn_transport->transport_type == ISCSI_TCP_CXGB4))
                complete(&conn->conn_logout_comp);
  
        if (!strcmp(current->comm, ISCSI_RX_THREAD_NAME)) {
         */
        iscsit_check_conn_usage_count(conn);
  
 -      if (conn->conn_rx_hash.tfm)
 -              crypto_free_hash(conn->conn_rx_hash.tfm);
 -      if (conn->conn_tx_hash.tfm)
 -              crypto_free_hash(conn->conn_tx_hash.tfm);
 +      ahash_request_free(conn->conn_tx_hash);
 +      if (conn->conn_rx_hash) {
 +              struct crypto_ahash *tfm;
 +
 +              tfm = crypto_ahash_reqtfm(conn->conn_rx_hash);
 +              ahash_request_free(conn->conn_rx_hash);
 +              crypto_free_ahash(tfm);
 +      }
  
        free_cpumask_var(conn->conn_cpumask);
  
@@@ -4556,7 -4554,8 +4560,8 @@@ static void iscsit_logout_post_handler_
         * always sleep waiting for RX/TX thread shutdown to complete
         * within iscsit_close_connection().
         */
-       if (conn->conn_transport->transport_type == ISCSI_TCP)
+       if ((conn->conn_transport->transport_type == ISCSI_TCP) ||
+           (conn->conn_transport->transport_type == ISCSI_TCP_CXGB4))
                sleep = cmpxchg(&conn->tx_thread_active, true, false);
  
        atomic_set(&conn->conn_logout_remove, 0);
@@@ -4573,7 -4572,8 +4578,8 @@@ static void iscsit_logout_post_handler_
  {
        int sleep = 1;
  
-       if (conn->conn_transport->transport_type == ISCSI_TCP)
+       if ((conn->conn_transport->transport_type == ISCSI_TCP) ||
+           (conn->conn_transport->transport_type == ISCSI_TCP_CXGB4))
                sleep = cmpxchg(&conn->tx_thread_active, true, false);
  
        atomic_set(&conn->conn_logout_remove, 0);
index a24443ba59ea04e452674403d014e507ea44b4d6,e09c891b5670815c19fedd8f6c8aaea8f268dcc9..5172debdcc66fa0eab83334584469f448c6d0d3c
@@@ -182,12 -182,91 +182,91 @@@ out
        return rc;
  }
  
+ static ssize_t lio_target_np_cxgb4_show(struct config_item *item, char *page)
+ {
+       struct iscsi_tpg_np *tpg_np = to_iscsi_tpg_np(item);
+       struct iscsi_tpg_np *tpg_np_cxgb4;
+       ssize_t rb;
+       tpg_np_cxgb4 = iscsit_tpg_locate_child_np(tpg_np, ISCSI_TCP_CXGB4);
+       if (tpg_np_cxgb4)
+               rb = sprintf(page, "1\n");
+       else
+               rb = sprintf(page, "0\n");
+       return rb;
+ }
+ static ssize_t lio_target_np_cxgb4_store(struct config_item *item,
+                                        const char *page, size_t count)
+ {
+       struct iscsi_tpg_np *tpg_np = to_iscsi_tpg_np(item);
+       struct iscsi_np *np;
+       struct iscsi_portal_group *tpg;
+       struct iscsi_tpg_np *tpg_np_cxgb4 = NULL;
+       u32 op;
+       int rc = 0;
+       rc = kstrtou32(page, 0, &op);
+       if (rc)
+               return rc;
+       if ((op != 1) && (op != 0)) {
+               pr_err("Illegal value for tpg_enable: %u\n", op);
+               return -EINVAL;
+       }
+       np = tpg_np->tpg_np;
+       if (!np) {
+               pr_err("Unable to locate struct iscsi_np from"
+                               " struct iscsi_tpg_np\n");
+               return -EINVAL;
+       }
+       tpg = tpg_np->tpg;
+       if (iscsit_get_tpg(tpg) < 0)
+               return -EINVAL;
+       if (op) {
+               rc = request_module("cxgbit");
+               if (rc != 0) {
+                       pr_warn("Unable to request_module for cxgbit\n");
+                       rc = 0;
+               }
+               tpg_np_cxgb4 = iscsit_tpg_add_network_portal(tpg,
+                                                            &np->np_sockaddr,
+                                                            tpg_np,
+                                                            ISCSI_TCP_CXGB4);
+               if (IS_ERR(tpg_np_cxgb4)) {
+                       rc = PTR_ERR(tpg_np_cxgb4);
+                       goto out;
+               }
+       } else {
+               tpg_np_cxgb4 = iscsit_tpg_locate_child_np(tpg_np,
+                                                         ISCSI_TCP_CXGB4);
+               if (tpg_np_cxgb4) {
+                       rc = iscsit_tpg_del_network_portal(tpg, tpg_np_cxgb4);
+                       if (rc < 0)
+                               goto out;
+               }
+       }
+       iscsit_put_tpg(tpg);
+       return count;
+ out:
+       iscsit_put_tpg(tpg);
+       return rc;
+ }
  CONFIGFS_ATTR(lio_target_np_, sctp);
  CONFIGFS_ATTR(lio_target_np_, iser);
+ CONFIGFS_ATTR(lio_target_np_, cxgb4);
  
  static struct configfs_attribute *lio_target_portal_attrs[] = {
        &lio_target_np_attr_sctp,
        &lio_target_np_attr_iser,
+       &lio_target_np_attr_cxgb4,
        NULL,
  };
  
@@@ -771,11 -850,21 +850,11 @@@ static int lio_target_init_nodeacl(stru
  {
        struct iscsi_node_acl *acl =
                container_of(se_nacl, struct iscsi_node_acl, se_node_acl);
 -      struct config_group *stats_cg = &se_nacl->acl_fabric_stat_group;
 -
 -      stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
 -                              GFP_KERNEL);
 -      if (!stats_cg->default_groups) {
 -              pr_err("Unable to allocate memory for"
 -                              " stats_cg->default_groups\n");
 -              return -ENOMEM;
 -      }
  
 -      stats_cg->default_groups[0] = &acl->node_stat_grps.iscsi_sess_stats_group;
 -      stats_cg->default_groups[1] = NULL;
        config_group_init_type_name(&acl->node_stat_grps.iscsi_sess_stats_group,
                        "iscsi_sess_stats", &iscsi_stat_sess_cit);
 -
 +      configfs_add_default_group(&acl->node_stat_grps.iscsi_sess_stats_group,
 +                      &se_nacl->acl_fabric_stat_group);
        return 0;
  }
  
@@@ -783,8 -872,17 +862,8 @@@ static void lio_target_cleanup_nodeacl
  {
        struct iscsi_node_acl *acl = container_of(se_nacl,
                        struct iscsi_node_acl, se_node_acl);
 -      struct config_item *df_item;
 -      struct config_group *stats_cg;
 -      int i;
 -
 -      stats_cg = &acl->se_node_acl.acl_fabric_stat_group;
 -      for (i = 0; stats_cg->default_groups[i]; i++) {
 -              df_item = &stats_cg->default_groups[i]->cg_item;
 -              stats_cg->default_groups[i] = NULL;
 -              config_item_put(df_item);
 -      }
 -      kfree(stats_cg->default_groups);
 +
 +      configfs_remove_default_groups(&acl->se_node_acl.acl_fabric_stat_group);
  }
  
  /* End items for lio_target_acl_cit */
@@@ -1241,37 -1339,42 +1320,37 @@@ static struct se_wwn *lio_target_call_c
        struct config_group *group,
        const char *name)
  {
 -      struct config_group *stats_cg;
        struct iscsi_tiqn *tiqn;
  
        tiqn = iscsit_add_tiqn((unsigned char *)name);
        if (IS_ERR(tiqn))
                return ERR_CAST(tiqn);
 -      /*
 -       * Setup struct iscsi_wwn_stat_grps for se_wwn->fabric_stat_group.
 -       */
 -      stats_cg = &tiqn->tiqn_wwn.fabric_stat_group;
 -
 -      stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 6,
 -                              GFP_KERNEL);
 -      if (!stats_cg->default_groups) {
 -              pr_err("Unable to allocate memory for"
 -                              " stats_cg->default_groups\n");
 -              iscsit_del_tiqn(tiqn);
 -              return ERR_PTR(-ENOMEM);
 -      }
  
 -      stats_cg->default_groups[0] = &tiqn->tiqn_stat_grps.iscsi_instance_group;
 -      stats_cg->default_groups[1] = &tiqn->tiqn_stat_grps.iscsi_sess_err_group;
 -      stats_cg->default_groups[2] = &tiqn->tiqn_stat_grps.iscsi_tgt_attr_group;
 -      stats_cg->default_groups[3] = &tiqn->tiqn_stat_grps.iscsi_login_stats_group;
 -      stats_cg->default_groups[4] = &tiqn->tiqn_stat_grps.iscsi_logout_stats_group;
 -      stats_cg->default_groups[5] = NULL;
        config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_instance_group,
                        "iscsi_instance", &iscsi_stat_instance_cit);
 +      configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_instance_group,
 +                      &tiqn->tiqn_wwn.fabric_stat_group);
 +
        config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_sess_err_group,
                        "iscsi_sess_err", &iscsi_stat_sess_err_cit);
 +      configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_sess_err_group,
 +                      &tiqn->tiqn_wwn.fabric_stat_group);
 +
        config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_tgt_attr_group,
                        "iscsi_tgt_attr", &iscsi_stat_tgt_attr_cit);
 +      configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_tgt_attr_group,
 +                      &tiqn->tiqn_wwn.fabric_stat_group);
 +
        config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_login_stats_group,
                        "iscsi_login_stats", &iscsi_stat_login_cit);
 +      configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_login_stats_group,
 +                      &tiqn->tiqn_wwn.fabric_stat_group);
 +
        config_group_init_type_name(&tiqn->tiqn_stat_grps.iscsi_logout_stats_group,
                        "iscsi_logout_stats", &iscsi_stat_logout_cit);
 +      configfs_add_default_group(&tiqn->tiqn_stat_grps.iscsi_logout_stats_group,
 +                      &tiqn->tiqn_wwn.fabric_stat_group);
 +
  
        pr_debug("LIO_Target_ConfigFS: REGISTER -> %s\n", tiqn->tiqn);
        pr_debug("LIO_Target_ConfigFS: REGISTER -> Allocated Node:"
@@@ -1283,8 -1386,17 +1362,8 @@@ static void lio_target_call_coredeltiqn
        struct se_wwn *wwn)
  {
        struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);
 -      struct config_item *df_item;
 -      struct config_group *stats_cg;
 -      int i;
 -
 -      stats_cg = &tiqn->tiqn_wwn.fabric_stat_group;
 -      for (i = 0; stats_cg->default_groups[i]; i++) {
 -              df_item = &stats_cg->default_groups[i]->cg_item;
 -              stats_cg->default_groups[i] = NULL;
 -              config_item_put(df_item);
 -      }
 -      kfree(stats_cg->default_groups);
 +
 +      configfs_remove_default_groups(&tiqn->tiqn_wwn.fabric_stat_group);
  
        pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s\n",
                        tiqn->tiqn);
index 8436d56c5f0c377e07caa7e0b1766051c11cf929,83c364378d4c4e58bee7fe028afde137ef731fba..a09498f16690c88581a00b154e5136b9002fae61
@@@ -16,9 -16,9 +16,9 @@@
   * GNU General Public License for more details.
   ******************************************************************************/
  
 +#include <crypto/hash.h>
  #include <linux/string.h>
  #include <linux/kthread.h>
 -#include <linux/crypto.h>
  #include <linux/idr.h>
  #include <scsi/iscsi_proto.h>
  #include <target/target_core_base.h>
@@@ -115,36 -115,27 +115,36 @@@ out_login
   */
  int iscsi_login_setup_crypto(struct iscsi_conn *conn)
  {
 +      struct crypto_ahash *tfm;
 +
        /*
         * Setup slicing by CRC32C algorithm for RX and TX libcrypto contexts
         * which will default to crc32c_intel.ko for cpu_has_xmm4_2, or fallback
         * to software 1x8 byte slicing from crc32c.ko
         */
 -      conn->conn_rx_hash.flags = 0;
 -      conn->conn_rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
 -                                              CRYPTO_ALG_ASYNC);
 -      if (IS_ERR(conn->conn_rx_hash.tfm)) {
 -              pr_err("crypto_alloc_hash() failed for conn_rx_tfm\n");
 +      tfm = crypto_alloc_ahash("crc32c", 0, CRYPTO_ALG_ASYNC);
 +      if (IS_ERR(tfm)) {
 +              pr_err("crypto_alloc_ahash() failed\n");
                return -ENOMEM;
        }
  
 -      conn->conn_tx_hash.flags = 0;
 -      conn->conn_tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
 -                                              CRYPTO_ALG_ASYNC);
 -      if (IS_ERR(conn->conn_tx_hash.tfm)) {
 -              pr_err("crypto_alloc_hash() failed for conn_tx_tfm\n");
 -              crypto_free_hash(conn->conn_rx_hash.tfm);
 +      conn->conn_rx_hash = ahash_request_alloc(tfm, GFP_KERNEL);
 +      if (!conn->conn_rx_hash) {
 +              pr_err("ahash_request_alloc() failed for conn_rx_hash\n");
 +              crypto_free_ahash(tfm);
 +              return -ENOMEM;
 +      }
 +      ahash_request_set_callback(conn->conn_rx_hash, 0, NULL, NULL);
 +
 +      conn->conn_tx_hash = ahash_request_alloc(tfm, GFP_KERNEL);
 +      if (!conn->conn_tx_hash) {
 +              pr_err("ahash_request_alloc() failed for conn_tx_hash\n");
 +              ahash_request_free(conn->conn_rx_hash);
 +              conn->conn_rx_hash = NULL;
 +              crypto_free_ahash(tfm);
                return -ENOMEM;
        }
 +      ahash_request_set_callback(conn->conn_tx_hash, 0, NULL, NULL);
  
        return 0;
  }
@@@ -258,7 -249,7 +258,7 @@@ static void iscsi_login_set_conn_values
        mutex_unlock(&auth_id_lock);
  }
  
static __printf(2, 3) int iscsi_change_param_sprintf(
+ __printf(2, 3) int iscsi_change_param_sprintf(
        struct iscsi_conn *conn,
        const char *fmt, ...)
  {
  
        return 0;
  }
+ EXPORT_SYMBOL(iscsi_change_param_sprintf);
  
  /*
   *    This is the leading connection of a new session,
@@@ -1183,14 -1175,10 +1184,14 @@@ old_sess_out
                iscsit_dec_session_usage_count(conn->sess);
        }
  
 -      if (!IS_ERR(conn->conn_rx_hash.tfm))
 -              crypto_free_hash(conn->conn_rx_hash.tfm);
 -      if (!IS_ERR(conn->conn_tx_hash.tfm))
 -              crypto_free_hash(conn->conn_tx_hash.tfm);
 +      ahash_request_free(conn->conn_tx_hash);
 +      if (conn->conn_rx_hash) {
 +              struct crypto_ahash *tfm;
 +
 +              tfm = crypto_ahash_reqtfm(conn->conn_rx_hash);
 +              ahash_request_free(conn->conn_rx_hash);
 +              crypto_free_ahash(tfm);
 +      }
  
        free_cpumask_var(conn->conn_cpumask);
  
@@@ -1387,6 -1375,16 +1388,16 @@@ static int __iscsi_target_login_thread(
                        goto old_sess_out;
        }
  
+       if (conn->conn_transport->iscsit_validate_params) {
+               ret = conn->conn_transport->iscsit_validate_params(conn);
+               if (ret < 0) {
+                       if (zero_tsih)
+                               goto new_sess_out;
+                       else
+                               goto old_sess_out;
+               }
+       }
        ret = iscsi_target_start_negotiation(login, conn);
        if (ret < 0)
                goto new_sess_out;
index c3371fa548cb9b3b30c563e89de65e9fce7fb585,7ca3cce7da50694d5960320fa3c573c6e3a26d7f..68e47fd8ea106e137741c5c17d0fc4f3b17fd428
@@@ -74,6 -74,7 +74,7 @@@ enum iscsit_transport_type 
        ISCSI_IWARP_TCP                         = 3,
        ISCSI_IWARP_SCTP                        = 4,
        ISCSI_INFINIBAND                        = 5,
+       ISCSI_TCP_CXGB4                         = 6,
  };
  
  /* RFC-3720 7.1.4  Standard Connection State Diagram for a Target */
@@@ -570,8 -571,8 +571,8 @@@ struct iscsi_conn 
        spinlock_t              response_queue_lock;
        spinlock_t              state_lock;
        /* libcrypto RX and TX contexts for crc32c */
 -      struct hash_desc        conn_rx_hash;
 -      struct hash_desc        conn_tx_hash;
 +      struct ahash_request    *conn_rx_hash;
 +      struct ahash_request    *conn_tx_hash;
        /* Used for scheduling TX and RX connection kthreads */
        cpumask_var_t           conn_cpumask;
        unsigned int            conn_rx_reset_cpumask:1;
@@@ -890,4 -891,30 +891,30 @@@ static inline u32 session_get_next_ttt(
  }
  
  extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
+ static inline void iscsit_thread_check_cpumask(
+       struct iscsi_conn *conn,
+       struct task_struct *p,
+       int mode)
+ {
+       /*
+        * mode == 1 signals iscsi_target_tx_thread() usage.
+        * mode == 0 signals iscsi_target_rx_thread() usage.
+        */
+       if (mode == 1) {
+               if (!conn->conn_tx_reset_cpumask)
+                       return;
+               conn->conn_tx_reset_cpumask = 0;
+       } else {
+               if (!conn->conn_rx_reset_cpumask)
+                       return;
+               conn->conn_rx_reset_cpumask = 0;
+       }
+       /*
+        * Update the CPU mask for this single kthread so that
+        * both TX and RX kthreads are scheduled to run on the
+        * same CPU.
+        */
+       set_cpus_allowed_ptr(p, conn->conn_cpumask);
+ }
  #endif /* ISCSI_TARGET_CORE_H */