Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 12 Sep 2015 02:00:42 +0000 (19:00 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 12 Sep 2015 02:00:42 +0000 (19:00 -0700)
Pull SCSI target updates from Nicholas Bellinger:
 "Here are the outstanding target-pending updates for v4.3-rc1.

  Mostly bug-fixes and minor changes this round.  The fallout from the
  big v4.2-rc1 RCU conversion have (thus far) been minimal.

  The highlights this round include:

   - Move sense handling routines into scsi_common code (Sagi)

   - Return ABORTED_COMMAND sense key for PI errors (Sagi)

   - Add tpg_enabled_sendtargets attribute for disabled iscsi-target
     discovery (David)

   - Shrink target struct se_cmd by rearranging fields (Roland)

   - Drop iSCSI use of mutex around max_cmd_sn increment (Roland)

   - Replace iSCSI __kernel_sockaddr_storage with sockaddr_storage (Andy +
     Chris)

   - Honor fabric max_data_sg_nents I/O transfer limit (Arun + Himanshu +
     nab)

   - Fix EXTENDED_COPY >= v4.1 regression OOPsen (Alex + nab)"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (37 commits)
  target: use stringify.h instead of own definition
  target/user: Fix UFLAG_UNKNOWN_OP handling
  target: Remove no-op conditional
  target/user: Remove unused variable
  target: Fix max_cmd_sn increment w/o cmdsn mutex regressions
  target: Attach EXTENDED_COPY local I/O descriptors to xcopy_pt_sess
  target/qla2xxx: Honor max_data_sg_nents I/O transfer limit
  target/iscsi: Replace __kernel_sockaddr_storage with sockaddr_storage
  target/iscsi: Replace conn->login_ip with login_sockaddr
  target/iscsi: Keep local_ip as the actual sockaddr
  target/iscsi: Fix np_ip bracket issue by removing np_ip
  target: Drop iSCSI use of mutex around max_cmd_sn increment
  qla2xxx: Update tcm_qla2xxx module description to 24xx+
  iscsi-target: Add tpg_enabled_sendtargets for disabled discovery
  drivers: target: Drop unlikely before IS_ERR(_OR_NULL)
  target: check DPO/FUA usage for COMPARE AND WRITE
  target: Shrink struct se_cmd by rearranging fields
  target: Remove cmd->se_ordered_id (unused except debug log lines)
  target: add support for START_STOP_UNIT SCSI opcode
  target: improve unsupported opcode message
  ...

1  2 
drivers/infiniband/ulp/isert/ib_isert.c
drivers/scsi/libiscsi.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/scsi_error.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_login.h
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/target_core_hba.c
drivers/target/target_core_spc.c
include/target/iscsi/iscsi_target_core.h

index dc439a40da3f48e091efffda54ed8bd07790c2b2,20a0a46294567ba634869fe5a970f8d00ac73427..403bd29443b8e7d06ac1a16cdae826088af98efe
@@@ -235,7 -235,7 +235,7 @@@ isert_alloc_rx_descriptors(struct isert
                rx_sg = &rx_desc->rx_sg;
                rx_sg->addr = rx_desc->dma_addr;
                rx_sg->length = ISER_RX_PAYLOAD_SIZE;
 -              rx_sg->lkey = device->mr->lkey;
 +              rx_sg->lkey = device->pd->local_dma_lkey;
        }
  
        isert_conn->rx_desc_head = 0;
@@@ -385,12 -385,22 +385,12 @@@ isert_create_device_ib_res(struct isert
                goto out_cq;
        }
  
 -      device->mr = ib_get_dma_mr(device->pd, IB_ACCESS_LOCAL_WRITE);
 -      if (IS_ERR(device->mr)) {
 -              ret = PTR_ERR(device->mr);
 -              isert_err("failed to create dma mr, device %p, ret=%d\n",
 -                        device, ret);
 -              goto out_mr;
 -      }
 -
        /* Check signature cap */
        device->pi_capable = dev_attr->device_cap_flags &
                             IB_DEVICE_SIGNATURE_HANDOVER ? true : false;
  
        return 0;
  
 -out_mr:
 -      ib_dealloc_pd(device->pd);
  out_cq:
        isert_free_comps(device);
        return ret;
@@@ -401,6 -411,7 +401,6 @@@ isert_free_device_ib_res(struct isert_d
  {
        isert_info("device %p\n", device);
  
 -      ib_dereg_mr(device->mr);
        ib_dealloc_pd(device->pd);
        isert_free_comps(device);
  }
@@@ -480,7 -491,7 +480,7 @@@ isert_conn_free_fastreg_pool(struct ise
                if (fr_desc->pi_ctx) {
                        ib_free_fast_reg_page_list(fr_desc->pi_ctx->prot_frpl);
                        ib_dereg_mr(fr_desc->pi_ctx->prot_mr);
 -                      ib_destroy_mr(fr_desc->pi_ctx->sig_mr);
 +                      ib_dereg_mr(fr_desc->pi_ctx->sig_mr);
                        kfree(fr_desc->pi_ctx);
                }
                kfree(fr_desc);
@@@ -497,6 -508,7 +497,6 @@@ isert_create_pi_ctx(struct fast_reg_des
                    struct ib_device *device,
                    struct ib_pd *pd)
  {
 -      struct ib_mr_init_attr mr_init_attr;
        struct pi_context *pi_ctx;
        int ret;
  
                goto err_pi_ctx;
        }
  
 -      pi_ctx->prot_mr = ib_alloc_fast_reg_mr(pd, ISCSI_ISER_SG_TABLESIZE);
 +      pi_ctx->prot_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG,
 +                                    ISCSI_ISER_SG_TABLESIZE);
        if (IS_ERR(pi_ctx->prot_mr)) {
                isert_err("Failed to allocate prot frmr err=%ld\n",
                          PTR_ERR(pi_ctx->prot_mr));
        }
        desc->ind |= ISERT_PROT_KEY_VALID;
  
 -      memset(&mr_init_attr, 0, sizeof(mr_init_attr));
 -      mr_init_attr.max_reg_descriptors = 2;
 -      mr_init_attr.flags |= IB_MR_SIGNATURE_EN;
 -      pi_ctx->sig_mr = ib_create_mr(pd, &mr_init_attr);
 +      pi_ctx->sig_mr = ib_alloc_mr(pd, IB_MR_TYPE_SIGNATURE, 2);
        if (IS_ERR(pi_ctx->sig_mr)) {
                isert_err("Failed to allocate signature enabled mr err=%ld\n",
                          PTR_ERR(pi_ctx->sig_mr));
@@@ -563,8 -577,7 +563,8 @@@ isert_create_fr_desc(struct ib_device *
                return PTR_ERR(fr_desc->data_frpl);
        }
  
 -      fr_desc->data_mr = ib_alloc_fast_reg_mr(pd, ISCSI_ISER_SG_TABLESIZE);
 +      fr_desc->data_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG,
 +                                     ISCSI_ISER_SG_TABLESIZE);
        if (IS_ERR(fr_desc->data_mr)) {
                isert_err("Failed to allocate data frmr err=%ld\n",
                          PTR_ERR(fr_desc->data_mr));
@@@ -762,17 -775,6 +762,17 @@@ isert_connect_request(struct rdma_cm_i
        ret = isert_rdma_post_recvl(isert_conn);
        if (ret)
                goto out_conn_dev;
 +      /*
 +       * Obtain the second reference now before isert_rdma_accept() to
 +       * ensure that any initiator generated REJECT CM event that occurs
 +       * asynchronously won't drop the last reference until the error path
 +       * in iscsi_target_login_sess_out() does it's ->iscsit_free_conn() ->
 +       * isert_free_conn() -> isert_put_conn() -> kref_put().
 +       */
 +      if (!kref_get_unless_zero(&isert_conn->kref)) {
 +              isert_warn("conn %p connect_release is running\n", isert_conn);
 +              goto out_conn_dev;
 +      }
  
        ret = isert_rdma_accept(isert_conn);
        if (ret)
@@@ -834,6 -836,11 +834,6 @@@ isert_connected_handler(struct rdma_cm_
  
        isert_info("conn %p\n", isert_conn);
  
 -      if (!kref_get_unless_zero(&isert_conn->kref)) {
 -              isert_warn("conn %p connect_release is running\n", isert_conn);
 -              return;
 -      }
 -
        mutex_lock(&isert_conn->mutex);
        if (isert_conn->state != ISER_CONN_FULL_FEATURE)
                isert_conn->state = ISER_CONN_UP;
@@@ -1079,8 -1086,8 +1079,8 @@@ isert_create_send_desc(struct isert_con
        tx_desc->num_sge = 1;
        tx_desc->isert_cmd = isert_cmd;
  
 -      if (tx_desc->tx_sg[0].lkey != device->mr->lkey) {
 -              tx_desc->tx_sg[0].lkey = device->mr->lkey;
 +      if (tx_desc->tx_sg[0].lkey != device->pd->local_dma_lkey) {
 +              tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey;
                isert_dbg("tx_desc %p lkey mismatch, fixing\n", tx_desc);
        }
  }
@@@ -1103,7 -1110,7 +1103,7 @@@ isert_init_tx_hdrs(struct isert_conn *i
        tx_desc->dma_addr = dma_addr;
        tx_desc->tx_sg[0].addr  = tx_desc->dma_addr;
        tx_desc->tx_sg[0].length = ISER_HEADERS_LEN;
 -      tx_desc->tx_sg[0].lkey = device->mr->lkey;
 +      tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey;
  
        isert_dbg("Setup tx_sg[0].addr: 0x%llx length: %u lkey: 0x%x\n",
                  tx_desc->tx_sg[0].addr, tx_desc->tx_sg[0].length,
@@@ -1136,7 -1143,7 +1136,7 @@@ isert_rdma_post_recvl(struct isert_con
        memset(&sge, 0, sizeof(struct ib_sge));
        sge.addr = isert_conn->login_req_dma;
        sge.length = ISER_RX_LOGIN_SIZE;
 -      sge.lkey = isert_conn->device->mr->lkey;
 +      sge.lkey = isert_conn->device->pd->local_dma_lkey;
  
        isert_dbg("Setup sge: addr: %llx length: %d 0x%08x\n",
                sge.addr, sge.length, sge.lkey);
@@@ -1186,7 -1193,7 +1186,7 @@@ isert_put_login_tx(struct iscsi_conn *c
  
                tx_dsg->addr    = isert_conn->login_rsp_dma;
                tx_dsg->length  = length;
 -              tx_dsg->lkey    = isert_conn->device->mr->lkey;
 +              tx_dsg->lkey    = isert_conn->device->pd->local_dma_lkey;
                tx_desc->num_sge = 2;
        }
        if (!login->login_failed) {
@@@ -2203,7 -2210,7 +2203,7 @@@ isert_put_response(struct iscsi_conn *c
                isert_cmd->pdu_buf_len = pdu_len;
                tx_dsg->addr    = isert_cmd->pdu_buf_dma;
                tx_dsg->length  = pdu_len;
 -              tx_dsg->lkey    = device->mr->lkey;
 +              tx_dsg->lkey    = device->pd->local_dma_lkey;
                isert_cmd->tx_desc.num_sge = 2;
        }
  
@@@ -2331,7 -2338,7 +2331,7 @@@ isert_put_reject(struct iscsi_cmd *cmd
        isert_cmd->pdu_buf_len = ISCSI_HDR_LEN;
        tx_dsg->addr    = isert_cmd->pdu_buf_dma;
        tx_dsg->length  = ISCSI_HDR_LEN;
 -      tx_dsg->lkey    = device->mr->lkey;
 +      tx_dsg->lkey    = device->pd->local_dma_lkey;
        isert_cmd->tx_desc.num_sge = 2;
  
        isert_init_send_wr(isert_conn, isert_cmd, send_wr);
@@@ -2372,7 -2379,7 +2372,7 @@@ isert_put_text_rsp(struct iscsi_cmd *cm
                isert_cmd->pdu_buf_len = txt_rsp_len;
                tx_dsg->addr    = isert_cmd->pdu_buf_dma;
                tx_dsg->length  = txt_rsp_len;
 -              tx_dsg->lkey    = device->mr->lkey;
 +              tx_dsg->lkey    = device->pd->local_dma_lkey;
                isert_cmd->tx_desc.num_sge = 2;
        }
        isert_init_send_wr(isert_conn, isert_cmd, send_wr);
@@@ -2413,7 -2420,7 +2413,7 @@@ isert_build_rdma_wr(struct isert_conn *
                ib_sge->addr = ib_sg_dma_address(ib_dev, tmp_sg) + page_off;
                ib_sge->length = min_t(u32, data_left,
                                ib_sg_dma_len(ib_dev, tmp_sg) - page_off);
 -              ib_sge->lkey = device->mr->lkey;
 +              ib_sge->lkey = device->pd->local_dma_lkey;
  
                isert_dbg("RDMA ib_sge: addr: 0x%llx  length: %u lkey: %x\n",
                          ib_sge->addr, ib_sge->length, ib_sge->lkey);
@@@ -2587,7 -2594,7 +2587,7 @@@ isert_fast_reg_mr(struct isert_conn *is
        u32 page_off;
  
        if (mem->dma_nents == 1) {
 -              sge->lkey = device->mr->lkey;
 +              sge->lkey = device->pd->local_dma_lkey;
                sge->addr = ib_sg_dma_address(ib_dev, &mem->sg[0]);
                sge->length = ib_sg_dma_len(ib_dev, &mem->sg[0]);
                isert_dbg("sge: addr: 0x%llx  length: %u lkey: %x\n",
@@@ -3095,7 -3102,7 +3095,7 @@@ out
  
  static int
  isert_setup_np(struct iscsi_np *np,
-              struct __kernel_sockaddr_storage *ksockaddr)
+              struct sockaddr_storage *ksockaddr)
  {
        struct isert_np *isert_np;
        struct rdma_cm_id *isert_lid;
         * in iscsi_target_configfs.c code..
         */
        memcpy(&np->np_sockaddr, ksockaddr,
-              sizeof(struct __kernel_sockaddr_storage));
+              sizeof(struct sockaddr_storage));
  
        isert_lid = isert_setup_id(isert_np);
        if (IS_ERR(isert_lid)) {
@@@ -3199,32 -3206,11 +3199,11 @@@ isert_set_conn_info(struct iscsi_np *np
  {
        struct rdma_cm_id *cm_id = isert_conn->cm_id;
        struct rdma_route *cm_route = &cm_id->route;
-       struct sockaddr_in *sock_in;
-       struct sockaddr_in6 *sock_in6;
  
        conn->login_family = np->np_sockaddr.ss_family;
  
-       if (np->np_sockaddr.ss_family == AF_INET6) {
-               sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.dst_addr;
-               snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
-                        &sock_in6->sin6_addr.in6_u);
-               conn->login_port = ntohs(sock_in6->sin6_port);
-               sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.src_addr;
-               snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
-                        &sock_in6->sin6_addr.in6_u);
-               conn->local_port = ntohs(sock_in6->sin6_port);
-       } else {
-               sock_in = (struct sockaddr_in *)&cm_route->addr.dst_addr;
-               sprintf(conn->login_ip, "%pI4",
-                       &sock_in->sin_addr.s_addr);
-               conn->login_port = ntohs(sock_in->sin_port);
-               sock_in = (struct sockaddr_in *)&cm_route->addr.src_addr;
-               sprintf(conn->local_ip, "%pI4",
-                       &sock_in->sin_addr.s_addr);
-               conn->local_port = ntohs(sock_in->sin_port);
-       }
+       conn->login_sockaddr = cm_route->addr.dst_addr;
+       conn->local_sockaddr = cm_route->addr.src_addr;
  }
  
  static int
diff --combined drivers/scsi/libiscsi.c
index 98d9bb6ff725ff46621a408bdf1f208175e21daf,bb5ca7f3d16d1c282e6588df9329b732a9fc5a75..33c74d3436c947a7f11ca22498206f6efa97fcc2
@@@ -853,12 -853,9 +853,9 @@@ static void iscsi_scsi_cmd_rsp(struct i
                                     SAM_STAT_CHECK_CONDITION;
                        scsi_build_sense_buffer(1, sc->sense_buffer,
                                                ILLEGAL_REQUEST, 0x10, ascq);
-                       sc->sense_buffer[7] = 0xc; /* Additional sense length */
-                       sc->sense_buffer[8] = 0;   /* Information desc type */
-                       sc->sense_buffer[9] = 0xa; /* Additional desc length */
-                       sc->sense_buffer[10] = 0x80; /* Validity bit */
-                       put_unaligned_be64(sector, &sc->sense_buffer[12]);
+                       scsi_set_sense_information(sc->sense_buffer,
+                                                  SCSI_SENSE_BUFFERSIZE,
+                                                  sector);
                        goto out;
                }
        }
@@@ -2941,10 -2938,10 +2938,10 @@@ void iscsi_conn_teardown(struct iscsi_c
  {
        struct iscsi_conn *conn = cls_conn->dd_data;
        struct iscsi_session *session = conn->session;
 -      unsigned long flags;
  
        del_timer_sync(&conn->transport_timer);
  
 +      mutex_lock(&session->eh_mutex);
        spin_lock_bh(&session->frwd_lock);
        conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
        if (session->leadconn == conn) {
        }
        spin_unlock_bh(&session->frwd_lock);
  
 -      /*
 -       * Block until all in-progress commands for this connection
 -       * time out or fail.
 -       */
 -      for (;;) {
 -              spin_lock_irqsave(session->host->host_lock, flags);
 -              if (!atomic_read(&session->host->host_busy)) { /* OK for ERL == 0 */
 -                      spin_unlock_irqrestore(session->host->host_lock, flags);
 -                      break;
 -              }
 -              spin_unlock_irqrestore(session->host->host_lock, flags);
 -              msleep_interruptible(500);
 -              iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): "
 -                                "host_busy %d host_failed %d\n",
 -                                atomic_read(&session->host->host_busy),
 -                                session->host->host_failed);
 -              /*
 -               * force eh_abort() to unblock
 -               */
 -              wake_up(&conn->ehwait);
 -      }
 -
        /* flush queued up work because we free the connection below */
        iscsi_suspend_tx(conn);
  
        if (session->leadconn == conn)
                session->leadconn = NULL;
        spin_unlock_bh(&session->frwd_lock);
 +      mutex_unlock(&session->eh_mutex);
  
        iscsi_destroy_conn(cls_conn);
  }
index 7ed7bae6172b21ab43453ebfc3af7f2d72aec200,edeb3aefa6fee38d8b18bbe60d3927c8770613a1..ac65cb7b48861b81dc1daa0ea531e506cb5752fa
@@@ -374,7 -374,7 +374,7 @@@ static int tcm_qla2xxx_write_pending(st
  {
        struct qla_tgt_cmd *cmd = container_of(se_cmd,
                                struct qla_tgt_cmd, se_cmd);
 -
 +      cmd->cmd_flags |= BIT_3;
        cmd->bufflen = se_cmd->data_length;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
  
@@@ -405,7 -405,7 +405,7 @@@ static int tcm_qla2xxx_write_pending_st
            se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) {
                spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
                wait_for_completion_timeout(&se_cmd->t_transport_stop_comp,
 -                                              3000);
 +                                          3 * HZ);
                return 0;
        }
        spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
@@@ -420,12 -420,6 +420,12 @@@ static void tcm_qla2xxx_set_default_nod
  
  static int tcm_qla2xxx_get_cmd_state(struct se_cmd *se_cmd)
  {
 +      if (!(se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
 +              struct qla_tgt_cmd *cmd = container_of(se_cmd,
 +                              struct qla_tgt_cmd, se_cmd);
 +              return cmd->state;
 +      }
 +
        return 0;
  }
  
@@@ -547,10 -541,12 +547,10 @@@ static int tcm_qla2xxx_queue_data_in(st
        cmd->cmd_flags |= BIT_4;
        cmd->bufflen = se_cmd->data_length;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
 -      cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED);
  
        cmd->sg_cnt = se_cmd->t_data_nents;
        cmd->sg = se_cmd->t_data_sg;
        cmd->offset = 0;
 -      cmd->cmd_flags |= BIT_3;
  
        cmd->prot_sg_cnt = se_cmd->t_prot_nents;
        cmd->prot_sg = se_cmd->t_prot_sg;
@@@ -575,6 -571,7 +575,6 @@@ static int tcm_qla2xxx_queue_status(str
        cmd->sg_cnt = 0;
        cmd->offset = 0;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
 -      cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED);
        if (cmd->cmd_flags &  BIT_5) {
                pr_crit("Bit_5 already set for cmd = %p.\n", cmd);
                dump_stack();
@@@ -639,7 -636,14 +639,7 @@@ static void tcm_qla2xxx_aborted_task(st
  {
        struct qla_tgt_cmd *cmd = container_of(se_cmd,
                                struct qla_tgt_cmd, se_cmd);
 -      struct scsi_qla_host *vha = cmd->vha;
 -      struct qla_hw_data *ha = vha->hw;
 -
 -      if (!cmd->sg_mapped)
 -              return;
 -
 -      pci_unmap_sg(ha->pdev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction);
 -      cmd->sg_mapped = 0;
 +      qlt_abort_cmd(cmd);
  }
  
  static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
@@@ -1145,7 -1149,9 +1145,7 @@@ static struct qla_tgt_sess *tcm_qla2xxx
                return NULL;
        }
  
 -      key = (((unsigned long)s_id[0] << 16) |
 -             ((unsigned long)s_id[1] << 8) |
 -             (unsigned long)s_id[2]);
 +      key = sid_to_key(s_id);
        pr_debug("find_sess_by_s_id: 0x%06x\n", key);
  
        se_nacl = btree_lookup32(&lport->lport_fcport_map, key);
@@@ -1180,7 -1186,9 +1180,7 @@@ static void tcm_qla2xxx_set_sess_by_s_i
        void *slot;
        int rc;
  
 -      key = (((unsigned long)s_id[0] << 16) |
 -             ((unsigned long)s_id[1] << 8) |
 -             (unsigned long)s_id[2]);
 +      key = sid_to_key(s_id);
        pr_debug("set_sess_by_s_id: %06x\n", key);
  
        slot = btree_lookup32(&lport->lport_fcport_map, key);
@@@ -1359,9 -1367,7 +1359,7 @@@ static void tcm_qla2xxx_free_session(st
        struct qla_hw_data *ha = tgt->ha;
        scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        struct se_session *se_sess;
-       struct se_node_acl *se_nacl;
        struct tcm_qla2xxx_lport *lport;
-       struct tcm_qla2xxx_nacl *nacl;
  
        BUG_ON(in_interrupt());
  
                dump_stack();
                return;
        }
-       se_nacl = se_sess->se_node_acl;
-       nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl);
  
        lport = vha->vha_tgt.target_lport_ptr;
        if (!lport) {
@@@ -1536,10 -1540,6 +1532,10 @@@ static void tcm_qla2xxx_update_sess(str
        }
  
        sess->conf_compl_supported = conf_compl_supported;
 +
 +      /* Reset logout parameters to default */
 +      sess->logout_on_delete = 1;
 +      sess->keep_nport_handle = 0;
  }
  
  /*
@@@ -1680,7 -1680,6 +1676,6 @@@ static int tcm_qla2xxx_lport_register_n
                        (struct tcm_qla2xxx_lport *)target_lport_ptr;
        struct tcm_qla2xxx_lport *base_lport =
                        (struct tcm_qla2xxx_lport *)base_vha->vha_tgt.target_lport_ptr;
-       struct tcm_qla2xxx_tpg *base_tpg;
        struct fc_vport_identifiers vport_id;
  
        if (!qla_tgt_mode_enabled(base_vha)) {
                pr_err("qla2xxx base_lport or tpg_1 not available\n");
                return -EPERM;
        }
-       base_tpg = base_lport->tpg_1;
  
        memset(&vport_id, 0, sizeof(vport_id));
        vport_id.port_name = npiv_wwpn;
@@@ -1810,6 -1808,11 +1804,11 @@@ static const struct target_core_fabric_
        .module                         = THIS_MODULE,
        .name                           = "qla2xxx",
        .node_acl_size                  = sizeof(struct tcm_qla2xxx_nacl),
+       /*
+        * XXX: Limit assumes single page per scatter-gather-list entry.
+        * Current maximum is ~4.9 MB per se_cmd->t_data_sg with PAGE_SIZE=4096
+        */
+       .max_data_sg_nents              = 1200,
        .get_fabric_name                = tcm_qla2xxx_get_fabric_name,
        .tpg_get_wwn                    = tcm_qla2xxx_get_fabric_wwn,
        .tpg_get_tag                    = tcm_qla2xxx_get_tag,
@@@ -1958,7 -1961,7 +1957,7 @@@ static void __exit tcm_qla2xxx_exit(voi
        tcm_qla2xxx_deregister_configfs();
  }
  
- MODULE_DESCRIPTION("TCM QLA2XXX series NPIV enabled fabric driver");
+ MODULE_DESCRIPTION("TCM QLA24XX+ series NPIV enabled fabric driver");
  MODULE_LICENSE("GPL");
  module_init(tcm_qla2xxx_init);
  module_exit(tcm_qla2xxx_exit);
index b616a6bef44a3f20adf8216e3a318d2ef2e2f91b,6e6b2d26d3ce473685711a9132ea9c3b5bb68c06..66a96cd98b975dcdbd5429cf02f069b52771fa84
  #include <scsi/scsi_device.h>
  #include <scsi/scsi_driver.h>
  #include <scsi/scsi_eh.h>
+ #include <scsi/scsi_common.h>
  #include <scsi/scsi_transport.h>
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_ioctl.h>
 +#include <scsi/scsi_dh.h>
  #include <scsi/sg.h>
  
  #include "scsi_priv.h"
@@@ -421,10 -421,6 +422,10 @@@ static void scsi_report_sense(struct sc
                        evt_type = SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED;
                        sdev_printk(KERN_WARNING, sdev,
                                    "Mode parameters changed");
 +              } else if (sshdr->asc == 0x2a && sshdr->ascq == 0x06) {
 +                      evt_type = SDEV_EVT_ALUA_STATE_CHANGE_REPORTED;
 +                      sdev_printk(KERN_WARNING, sdev,
 +                                  "Asymmetric access state changed");
                } else if (sshdr->asc == 0x2a && sshdr->ascq == 0x09) {
                        evt_type = SDEV_EVT_CAPACITY_CHANGE_REPORTED;
                        sdev_printk(KERN_WARNING, sdev,
@@@ -464,10 -460,11 +465,10 @@@ static int scsi_check_sense(struct scsi
        if (scsi_sense_is_deferred(&sshdr))
                return NEEDS_RETRY;
  
 -      if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh &&
 -                      sdev->scsi_dh_data->scsi_dh->check_sense) {
 +      if (sdev->handler && sdev->handler->check_sense) {
                int rc;
  
 -              rc = sdev->scsi_dh_data->scsi_dh->check_sense(sdev, &sshdr);
 +              rc = sdev->handler->check_sense(sdev, &sshdr);
                if (rc != SCSI_RETURN_NOT_HANDLED)
                        return rc;
                /* handler does not care. Drop down to default handling */
@@@ -947,7 -944,7 +948,7 @@@ void scsi_eh_prep_cmnd(struct scsi_cmn
                            scmd->sdb.length);
                scmd->sdb.table.sgl = &ses->sense_sgl;
                scmd->sc_data_direction = DMA_FROM_DEVICE;
 -              scmd->sdb.table.nents = 1;
 +              scmd->sdb.table.nents = scmd->sdb.table.orig_nents = 1;
                scmd->cmnd[0] = REQUEST_SENSE;
                scmd->cmnd[4] = scmd->sdb.length;
                scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
@@@ -1159,13 -1156,8 +1160,13 @@@ int scsi_eh_get_sense(struct list_head 
        struct Scsi_Host *shost;
        int rtn;
  
 +      /*
 +       * If SCSI_EH_ABORT_SCHEDULED has been set, it is timeout IO,
 +       * should not get sense.
 +       */
        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
                if ((scmd->eh_eflags & SCSI_EH_CANCEL_CMD) ||
 +                  (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) ||
                    SCSI_SENSE_VALID(scmd))
                        continue;
  
@@@ -2178,17 -2170,8 +2179,17 @@@ int scsi_error_handler(void *data
         * We never actually get interrupted because kthread_run
         * disables signal delivery for the created thread.
         */
 -      while (!kthread_should_stop()) {
 +      while (true) {
 +              /*
 +               * The sequence in kthread_stop() sets the stop flag first
 +               * then wakes the process.  To avoid missed wakeups, the task
 +               * should always be in a non running state before the stop
 +               * flag is checked
 +               */
                set_current_state(TASK_INTERRUPTIBLE);
 +              if (kthread_should_stop())
 +                      break;
 +
                if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
                    shost->host_failed != atomic_read(&shost->host_busy)) {
                        SCSI_LOG_ERROR_RECOVERY(1,
@@@ -2424,45 -2407,6 +2425,6 @@@ bool scsi_command_normalize_sense(cons
  }
  EXPORT_SYMBOL(scsi_command_normalize_sense);
  
- /**
-  * scsi_sense_desc_find - search for a given descriptor type in       descriptor sense data format.
-  * @sense_buffer:     byte array of descriptor format sense data
-  * @sb_len:           number of valid bytes in sense_buffer
-  * @desc_type:                value of descriptor type to find
-  *                    (e.g. 0 -> information)
-  *
-  * Notes:
-  *    only valid when sense data is in descriptor format
-  *
-  * Return value:
-  *    pointer to start of (first) descriptor if found else NULL
-  */
- const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
-                               int desc_type)
- {
-       int add_sen_len, add_len, desc_len, k;
-       const u8 * descp;
-       if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7])))
-               return NULL;
-       if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73))
-               return NULL;
-       add_sen_len = (add_sen_len < (sb_len - 8)) ?
-                       add_sen_len : (sb_len - 8);
-       descp = &sense_buffer[8];
-       for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
-               descp += desc_len;
-               add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
-               desc_len = add_len + 2;
-               if (descp[0] == desc_type)
-                       return descp;
-               if (add_len < 0) // short descriptor ??
-                       break;
-       }
-       return NULL;
- }
- EXPORT_SYMBOL(scsi_sense_desc_find);
  /**
   * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format)
   * @sense_buffer:     byte array of sense data
@@@ -2512,31 -2456,3 +2474,3 @@@ int scsi_get_sense_info_fld(const u8 * 
        }
  }
  EXPORT_SYMBOL(scsi_get_sense_info_fld);
- /**
-  * scsi_build_sense_buffer - build sense data in a buffer
-  * @desc:     Sense format (non zero == descriptor format,
-  *            0 == fixed format)
-  * @buf:      Where to build sense data
-  * @key:      Sense key
-  * @asc:      Additional sense code
-  * @ascq:     Additional sense code qualifier
-  *
-  **/
- void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)
- {
-       if (desc) {
-               buf[0] = 0x72;  /* descriptor, current */
-               buf[1] = key;
-               buf[2] = asc;
-               buf[3] = ascq;
-               buf[7] = 0;
-       } else {
-               buf[0] = 0x70;  /* fixed, current */
-               buf[2] = key;
-               buf[7] = 0xa;
-               buf[12] = asc;
-               buf[13] = ascq;
-       }
- }
- EXPORT_SYMBOL(scsi_build_sense_buffer);
index fd092909a4577a7c4a708516bf3344fee331ad84,a9257a083c39558331d483a5f52e1baa46a030f0..342a07c58d89400643b26236875d6ffa6a91062e
@@@ -269,14 -269,14 +269,14 @@@ int iscsit_deaccess_np(struct iscsi_np 
  }
  
  bool iscsit_check_np_match(
-       struct __kernel_sockaddr_storage *sockaddr,
+       struct sockaddr_storage *sockaddr,
        struct iscsi_np *np,
        int network_transport)
  {
        struct sockaddr_in *sock_in, *sock_in_e;
        struct sockaddr_in6 *sock_in6, *sock_in6_e;
        bool ip_match = false;
-       u16 port;
+       u16 port, port_e;
  
        if (sockaddr->ss_family == AF_INET6) {
                sock_in6 = (struct sockaddr_in6 *)sockaddr;
                        ip_match = true;
  
                port = ntohs(sock_in6->sin6_port);
+               port_e = ntohs(sock_in6_e->sin6_port);
        } else {
                sock_in = (struct sockaddr_in *)sockaddr;
                sock_in_e = (struct sockaddr_in *)&np->np_sockaddr;
                        ip_match = true;
  
                port = ntohs(sock_in->sin_port);
+               port_e = ntohs(sock_in_e->sin_port);
        }
  
-       if (ip_match && (np->np_port == port) &&
+       if (ip_match && (port_e == port) &&
            (np->np_network_transport == network_transport))
                return true;
  
   * Called with mutex np_lock held
   */
  static struct iscsi_np *iscsit_get_np(
-       struct __kernel_sockaddr_storage *sockaddr,
+       struct sockaddr_storage *sockaddr,
        int network_transport)
  {
        struct iscsi_np *np;
  }
  
  struct iscsi_np *iscsit_add_np(
-       struct __kernel_sockaddr_storage *sockaddr,
-       char *ip_str,
+       struct sockaddr_storage *sockaddr,
        int network_transport)
  {
-       struct sockaddr_in *sock_in;
-       struct sockaddr_in6 *sock_in6;
        struct iscsi_np *np;
        int ret;
  
        }
  
        np->np_flags |= NPF_IP_NETWORK;
-       if (sockaddr->ss_family == AF_INET6) {
-               sock_in6 = (struct sockaddr_in6 *)sockaddr;
-               snprintf(np->np_ip, IPV6_ADDRESS_SPACE, "%s", ip_str);
-               np->np_port = ntohs(sock_in6->sin6_port);
-       } else {
-               sock_in = (struct sockaddr_in *)sockaddr;
-               sprintf(np->np_ip, "%s", ip_str);
-               np->np_port = ntohs(sock_in->sin_port);
-       }
        np->np_network_transport = network_transport;
        spin_lock_init(&np->np_thread_lock);
        init_completion(&np->np_restart_comp);
        list_add_tail(&np->np_list, &g_np_list);
        mutex_unlock(&np_lock);
  
-       pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
-               np->np_ip, np->np_port, np->np_transport->name);
+       pr_debug("CORE[0] - Added Network Portal: %pISpc on %s\n",
+               &np->np_sockaddr, np->np_transport->name);
  
        return np;
  }
@@@ -481,8 -470,8 +470,8 @@@ int iscsit_del_np(struct iscsi_np *np
        list_del(&np->np_list);
        mutex_unlock(&np_lock);
  
-       pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
-               np->np_ip, np->np_port, np->np_transport->name);
+       pr_debug("CORE[0] - Removed Network Portal: %pISpc on %s\n",
+               &np->np_sockaddr, np->np_transport->name);
  
        iscsit_put_transport(np->np_transport);
        kfree(np);
@@@ -968,9 -957,9 +957,9 @@@ int iscsit_setup_scsi_cmd(struct iscsi_
                cmd->cmd_flags |= ICF_NON_IMMEDIATE_UNSOLICITED_DATA;
  
        conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
 -      if (hdr->flags & ISCSI_FLAG_CMD_READ) {
 +      if (hdr->flags & ISCSI_FLAG_CMD_READ)
                cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
 -      } else if (hdr->flags & ISCSI_FLAG_CMD_WRITE)
 +      else
                cmd->targ_xfer_tag = 0xFFFFFFFF;
        cmd->cmd_sn             = be32_to_cpu(hdr->cmdsn);
        cmd->exp_stat_sn        = be32_to_cpu(hdr->exp_statsn);
@@@ -1209,7 -1198,6 +1198,6 @@@ static u32 iscsit_do_crypto_hash_sg
        u8 *pad_bytes)
  {
        u32 data_crc;
-       u32 i;
        struct scatterlist *sg;
        unsigned int page_off;
  
        sg = cmd->first_data_sg;
        page_off = cmd->first_data_sg_off;
  
-       i = 0;
        while (data_length) {
-               u32 cur_len = min_t(u32, data_length, (sg[i].length - page_off));
+               u32 cur_len = min_t(u32, data_length, (sg->length - page_off));
  
-               crypto_hash_update(hash, &sg[i], cur_len);
+               crypto_hash_update(hash, sg, cur_len);
  
                data_length -= cur_len;
                page_off = 0;
-               i++;
+               /* iscsit_map_iovec has already checked for invalid sg pointers */
+               sg = sg_next(sg);
        }
  
        if (padding) {
@@@ -2556,7 -2544,7 +2544,7 @@@ static int iscsit_send_conn_drop_async_
        cmd->stat_sn            = conn->stat_sn++;
        hdr->statsn             = cpu_to_be32(cmd->stat_sn);
        hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
-       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
        hdr->async_event        = ISCSI_ASYNC_MSG_DROPPING_CONNECTION;
        hdr->param1             = cpu_to_be16(cmd->logout_cid);
        hdr->param2             = cpu_to_be16(conn->sess->sess_ops->DefaultTime2Wait);
@@@ -2628,7 -2616,7 +2616,7 @@@ iscsit_build_datain_pdu(struct iscsi_cm
                hdr->statsn             = cpu_to_be32(0xFFFFFFFF);
  
        hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
-       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
        hdr->datasn             = cpu_to_be32(datain->data_sn);
        hdr->offset             = cpu_to_be32(datain->offset);
  
@@@ -2839,7 -2827,7 +2827,7 @@@ iscsit_build_logout_rsp(struct iscsi_cm
  
        iscsit_increment_maxcmdsn(cmd, conn->sess);
        hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
-       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
  
        pr_debug("Built Logout Response ITT: 0x%08x StatSN:"
                " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n",
@@@ -2902,7 -2890,7 +2890,7 @@@ iscsit_build_nopin_rsp(struct iscsi_cm
                iscsit_increment_maxcmdsn(cmd, conn->sess);
  
        hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
-       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
  
        pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x,"
                " StatSN: 0x%08x, Length %u\n", (nopout_response) ?
@@@ -3049,7 -3037,7 +3037,7 @@@ static int iscsit_send_r2t
        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(conn->sess->max_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);
@@@ -3202,7 -3190,7 +3190,7 @@@ void iscsit_build_rsp_pdu(struct iscsi_
  
        iscsit_increment_maxcmdsn(cmd, conn->sess);
        hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
-       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
  
        pr_debug("Built SCSI Response, ITT: 0x%08x, StatSN: 0x%08x,"
                " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n",
@@@ -3321,7 -3309,7 +3309,7 @@@ iscsit_build_task_mgt_rsp(struct iscsi_
  
        iscsit_increment_maxcmdsn(cmd, conn->sess);
        hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
-       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
  
        pr_debug("Built Task Management Response ITT: 0x%08x,"
                " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n",
@@@ -3399,6 -3387,7 +3387,7 @@@ iscsit_build_sendtargets_response(struc
        int target_name_printed;
        unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */
        unsigned char *text_in = cmd->text_in_ptr, *text_ptr = NULL;
+       bool active;
  
        buffer_len = min(conn->conn_ops->MaxRecvDataSegmentLength,
                         SENDTARGETS_BUF_LIMIT);
                        }
  
                        spin_lock(&tpg->tpg_state_lock);
-                       if ((tpg->tpg_state == TPG_STATE_FREE) ||
-                           (tpg->tpg_state == TPG_STATE_INACTIVE)) {
-                               spin_unlock(&tpg->tpg_state_lock);
-                               continue;
-                       }
+                       active = (tpg->tpg_state == TPG_STATE_ACTIVE);
                        spin_unlock(&tpg->tpg_state_lock);
  
+                       if (!active && tpg->tpg_attrib.tpg_enabled_sendtargets)
+                               continue;
                        spin_lock(&tpg->tpg_np_lock);
                        list_for_each_entry(tpg_np, &tpg->tpg_gnp_list,
                                                tpg_np_list) {
                                struct iscsi_np *np = tpg_np->tpg_np;
                                bool inaddr_any = iscsit_check_inaddr_any(np);
-                               char *fmt_str;
+                               struct sockaddr_storage *sockaddr;
  
                                if (np->np_network_transport != network_transport)
                                        continue;
                                        }
                                }
  
-                               if (np->np_sockaddr.ss_family == AF_INET6)
-                                       fmt_str = "TargetAddress=[%s]:%hu,%hu";
+                               if (inaddr_any)
+                                       sockaddr = &conn->local_sockaddr;
                                else
-                                       fmt_str = "TargetAddress=%s:%hu,%hu";
+                                       sockaddr = &np->np_sockaddr;
  
-                               len = sprintf(buf, fmt_str,
-                                       inaddr_any ? conn->local_ip : np->np_ip,
-                                       np->np_port,
-                                       tpg->tpgt);
+                               len = sprintf(buf, "TargetAddress="
+                                             "%pISpc,%hu",
+                                             sockaddr,
+                                             tpg->tpgt);
                                len += 1;
  
                                if ((len + payload_len) > buffer_len) {
@@@ -3576,7 -3564,7 +3564,7 @@@ iscsit_build_text_rsp(struct iscsi_cmd 
         */
        cmd->maxcmdsn_inc = 0;
        hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
-       hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
  
        pr_debug("Built Text Response: ITT: 0x%08x, TTT: 0x%08x, StatSN: 0x%08x,"
                " Length: %u, CID: %hu F: %d C: %d\n", cmd->init_task_tag,
@@@ -3654,7 -3642,7 +3642,7 @@@ iscsit_build_reject(struct iscsi_cmd *c
        cmd->stat_sn            = conn->stat_sn++;
        hdr->statsn             = cpu_to_be32(cmd->stat_sn);
        hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
-       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
  
  }
  EXPORT_SYMBOL(iscsit_build_reject);
@@@ -3998,13 -3986,7 +3986,13 @@@ get_immediate
        }
  
  transport_err:
 -      iscsit_take_action_for_connection_exit(conn);
 +      /*
 +       * Avoid the normal connection failure code-path if this connection
 +       * is still within LOGIN mode, and iscsi_np process context is
 +       * responsible for cleaning up the early connection failure.
 +       */
 +      if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN)
 +              iscsit_take_action_for_connection_exit(conn);
  out:
        return 0;
  }
@@@ -4088,7 -4070,7 +4076,7 @@@ reject
  
  int iscsi_target_rx_thread(void *arg)
  {
 -      int ret;
 +      int ret, rc;
        u8 buffer[ISCSI_HDR_LEN], opcode;
        u32 checksum = 0, digest = 0;
        struct iscsi_conn *conn = arg;
         * 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)
 +              return 0;
  
        if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
                struct completion comp;
 -              int rc;
  
                init_completion(&comp);
                rc = wait_for_completion_interruptible(&comp);
@@@ -4544,18 -4520,7 +4532,18 @@@ static void iscsit_logout_post_handler_
        struct iscsi_conn *conn)
  {
        struct iscsi_session *sess = conn->sess;
 -      int sleep = cmpxchg(&conn->tx_thread_active, true, false);
 +      int sleep = 1;
 +      /*
 +       * Traditional iscsi/tcp will invoke this logic from TX thread
 +       * context during session logout, so clear tx_thread_active and
 +       * sleep if iscsit_close_connection() has not already occured.
 +       *
 +       * Since iser-target invokes this logic from it's own workqueue,
 +       * always sleep waiting for RX/TX thread shutdown to complete
 +       * within iscsit_close_connection().
 +       */
 +      if (conn->conn_transport->transport_type == ISCSI_TCP)
 +              sleep = cmpxchg(&conn->tx_thread_active, true, false);
  
        atomic_set(&conn->conn_logout_remove, 0);
        complete(&conn->conn_logout_comp);
  static void iscsit_logout_post_handler_samecid(
        struct iscsi_conn *conn)
  {
 -      int sleep = cmpxchg(&conn->tx_thread_active, true, false);
 +      int sleep = 1;
 +
 +      if (conn->conn_transport->transport_type == ISCSI_TCP)
 +              sleep = cmpxchg(&conn->tx_thread_active, true, false);
  
        atomic_set(&conn->conn_logout_remove, 0);
        complete(&conn->conn_logout_comp);
@@@ -4791,7 -4753,6 +4779,7 @@@ int iscsit_release_sessions_for_tpg(str
        struct iscsi_session *sess;
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
        struct se_session *se_sess, *se_sess_tmp;
 +      LIST_HEAD(free_list);
        int session_count = 0;
  
        spin_lock_bh(&se_tpg->session_lock);
                }
                atomic_set(&sess->session_reinstatement, 1);
                spin_unlock(&sess->conn_lock);
 -              spin_unlock_bh(&se_tpg->session_lock);
  
 -              iscsit_free_session(sess);
 -              spin_lock_bh(&se_tpg->session_lock);
 +              list_move_tail(&se_sess->sess_list, &free_list);
 +      }
 +      spin_unlock_bh(&se_tpg->session_lock);
 +
 +      list_for_each_entry_safe(se_sess, se_sess_tmp, &free_list, sess_list) {
 +              sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
  
 +              iscsit_free_session(sess);
                session_count++;
        }
 -      spin_unlock_bh(&se_tpg->session_lock);
  
        pr_debug("Released %d iSCSI Session(s) from Target Portal"
                        " Group: %hu\n", session_count, tpg->tpgt);
index 7e8f65e5448fdbda5645e3d5a836ad9f81408efa,fc7b79672d056cfd5910f474fc2e59cfe399f63b..96e78c823d13fa2f78feb6ff024fb468518be75b
@@@ -82,7 -82,6 +82,7 @@@ static struct iscsi_login *iscsi_login_
        init_completion(&conn->conn_logout_comp);
        init_completion(&conn->rx_half_close_comp);
        init_completion(&conn->tx_half_close_comp);
 +      init_completion(&conn->rx_login_comp);
        spin_lock_init(&conn->cmd_lock);
        spin_lock_init(&conn->conn_usage_lock);
        spin_lock_init(&conn->immed_queue_lock);
@@@ -331,7 -330,7 +331,7 @@@ static int iscsi_login_zero_tsih_s1
         * The FFP CmdSN window values will be allocated from the TPG's
         * Initiator Node's ACL once the login has been successfully completed.
         */
-       sess->max_cmd_sn        = be32_to_cpu(pdu->cmdsn);
+       atomic_set(&sess->max_cmd_sn, be32_to_cpu(pdu->cmdsn));
  
        sess->sess_ops = kzalloc(sizeof(struct iscsi_sess_ops), GFP_KERNEL);
        if (!sess->sess_ops) {
@@@ -645,7 -644,7 +645,7 @@@ static void iscsi_post_login_start_time
                iscsit_start_nopin_timer(conn);
  }
  
 -static int iscsit_start_kthreads(struct iscsi_conn *conn)
 +int iscsit_start_kthreads(struct iscsi_conn *conn)
  {
        int ret = 0;
  
  
        return 0;
  out_tx:
 +      send_sig(SIGINT, conn->tx_thread, 1);
        kthread_stop(conn->tx_thread);
        conn->tx_thread_active = false;
  out_bitmap:
        return ret;
  }
  
 -int iscsi_post_login_handler(
 +void iscsi_post_login_handler(
        struct iscsi_np *np,
        struct iscsi_conn *conn,
        u8 zero_tsih)
        struct se_session *se_sess = sess->se_sess;
        struct iscsi_portal_group *tpg = sess->tpg;
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
 -      int rc;
  
        iscsit_inc_conn_usage_count(conn);
  
                        stop_timer = 1;
                }
  
-               pr_debug("iSCSI Login successful on CID: %hu from %s to"
-                       " %s:%hu,%hu\n", conn->cid, conn->login_ip,
-                       conn->local_ip, conn->local_port, tpg->tpgt);
+               pr_debug("iSCSI Login successful on CID: %hu from %pISpc to"
+                       " %pISpc,%hu\n", conn->cid, &conn->login_sockaddr,
+                       &conn->local_sockaddr, tpg->tpgt);
  
                list_add_tail(&conn->conn_list, &sess->sess_conn_list);
                atomic_inc(&sess->nconn);
                        sess->sess_ops->InitiatorName);
                spin_unlock_bh(&sess->conn_lock);
  
 -              rc = iscsit_start_kthreads(conn);
 -              if (rc)
 -                      return rc;
 -
                iscsi_post_login_start_timers(conn);
                /*
                 * Determine CPU mask to ensure connection's RX and TX kthreads
                iscsit_thread_get_cpumask(conn);
                conn->conn_rx_reset_cpumask = 1;
                conn->conn_tx_reset_cpumask = 1;
 -
 +              /*
 +               * Wakeup the sleeping iscsi_target_rx_thread() now that
 +               * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state.
 +               */
 +              complete(&conn->rx_login_comp);
                iscsit_dec_conn_usage_count(conn);
 +
                if (stop_timer) {
                        spin_lock_bh(&se_tpg->session_lock);
                        iscsit_stop_time2retain_timer(sess);
                        spin_unlock_bh(&se_tpg->session_lock);
                }
                iscsit_dec_session_usage_count(sess);
 -              return 0;
 +              return;
        }
  
        iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1);
        pr_debug("Moving to TARG_SESS_STATE_LOGGED_IN.\n");
        sess->session_state = TARG_SESS_STATE_LOGGED_IN;
  
-       pr_debug("iSCSI Login successful on CID: %hu from %s to %s:%hu,%hu\n",
-               conn->cid, conn->login_ip, conn->local_ip, conn->local_port,
+       pr_debug("iSCSI Login successful on CID: %hu from %pISpc to %pISpc,%hu\n",
+               conn->cid, &conn->login_sockaddr, &conn->local_sockaddr,
                tpg->tpgt);
  
        spin_lock_bh(&sess->conn_lock);
                " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt);
        spin_unlock_bh(&se_tpg->session_lock);
  
 -      rc = iscsit_start_kthreads(conn);
 -      if (rc)
 -              return rc;
 -
        iscsi_post_login_start_timers(conn);
        /*
         * Determine CPU mask to ensure connection's RX and TX kthreads
        iscsit_thread_get_cpumask(conn);
        conn->conn_rx_reset_cpumask = 1;
        conn->conn_tx_reset_cpumask = 1;
 -
 +      /*
 +       * Wakeup the sleeping iscsi_target_rx_thread() now that
 +       * iscsi_conn is in TARG_CONN_STATE_LOGGED_IN state.
 +       */
 +      complete(&conn->rx_login_comp);
        iscsit_dec_conn_usage_count(conn);
 -
 -      return 0;
  }
  
  static void iscsi_handle_login_thread_timeout(unsigned long data)
        struct iscsi_np *np = (struct iscsi_np *) data;
  
        spin_lock_bh(&np->np_thread_lock);
-       pr_err("iSCSI Login timeout on Network Portal %s:%hu\n",
-                       np->np_ip, np->np_port);
+       pr_err("iSCSI Login timeout on Network Portal %pISpc\n",
+                       &np->np_sockaddr);
  
        if (np->np_login_timer_flags & ISCSI_TF_STOP) {
                spin_unlock_bh(&np->np_thread_lock);
@@@ -877,7 -877,7 +877,7 @@@ static void iscsi_stop_login_thread_tim
  
  int iscsit_setup_np(
        struct iscsi_np *np,
-       struct __kernel_sockaddr_storage *sockaddr)
+       struct sockaddr_storage *sockaddr)
  {
        struct socket *sock = NULL;
        int backlog = ISCSIT_TCP_BACKLOG, ret, opt = 0, len;
         * in iscsi_target_configfs.c code..
         */
        memcpy(&np->np_sockaddr, sockaddr,
-                       sizeof(struct __kernel_sockaddr_storage));
+                       sizeof(struct sockaddr_storage));
  
        if (sockaddr->ss_family == AF_INET6)
                len = sizeof(struct sockaddr_in6);
@@@ -975,7 -975,7 +975,7 @@@ fail
  
  int iscsi_target_setup_login_socket(
        struct iscsi_np *np,
-       struct __kernel_sockaddr_storage *sockaddr)
+       struct sockaddr_storage *sockaddr)
  {
        struct iscsit_transport *t;
        int rc;
@@@ -1015,44 -1015,42 +1015,42 @@@ int iscsit_accept_np(struct iscsi_np *n
                rc = conn->sock->ops->getname(conn->sock,
                                (struct sockaddr *)&sock_in6, &err, 1);
                if (!rc) {
-                       if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr))
-                               snprintf(conn->login_ip, sizeof(conn->login_ip), "[%pI6c]",
-                                       &sock_in6.sin6_addr.in6_u);
-                       else
-                               snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI4",
-                                       &sock_in6.sin6_addr.s6_addr32[3]);
-                       conn->login_port = ntohs(sock_in6.sin6_port);
+                       if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) {
+                               memcpy(&conn->login_sockaddr, &sock_in6, sizeof(sock_in6));
+                       } else {
+                               /* Pretend to be an ipv4 socket */
+                               sock_in.sin_family = AF_INET;
+                               sock_in.sin_port = sock_in6.sin6_port;
+                               memcpy(&sock_in.sin_addr, &sock_in6.sin6_addr.s6_addr32[3], 4);
+                               memcpy(&conn->login_sockaddr, &sock_in, sizeof(sock_in));
+                       }
                }
  
                rc = conn->sock->ops->getname(conn->sock,
                                (struct sockaddr *)&sock_in6, &err, 0);
                if (!rc) {
-                       if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr))
-                               snprintf(conn->local_ip, sizeof(conn->local_ip), "[%pI6c]",
-                                       &sock_in6.sin6_addr.in6_u);
-                       else
-                               snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI4",
-                                       &sock_in6.sin6_addr.s6_addr32[3]);
-                       conn->local_port = ntohs(sock_in6.sin6_port);
+                       if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) {
+                               memcpy(&conn->local_sockaddr, &sock_in6, sizeof(sock_in6));
+                       } else {
+                               /* Pretend to be an ipv4 socket */
+                               sock_in.sin_family = AF_INET;
+                               sock_in.sin_port = sock_in6.sin6_port;
+                               memcpy(&sock_in.sin_addr, &sock_in6.sin6_addr.s6_addr32[3], 4);
+                               memcpy(&conn->local_sockaddr, &sock_in, sizeof(sock_in));
+                       }
                }
        } else {
                memset(&sock_in, 0, sizeof(struct sockaddr_in));
  
                rc = conn->sock->ops->getname(conn->sock,
                                (struct sockaddr *)&sock_in, &err, 1);
-               if (!rc) {
-                       sprintf(conn->login_ip, "%pI4",
-                                       &sock_in.sin_addr.s_addr);
-                       conn->login_port = ntohs(sock_in.sin_port);
-               }
+               if (!rc)
+                       memcpy(&conn->login_sockaddr, &sock_in, sizeof(sock_in));
  
                rc = conn->sock->ops->getname(conn->sock,
                                (struct sockaddr *)&sock_in, &err, 0);
-               if (!rc) {
-                       sprintf(conn->local_ip, "%pI4",
-                                       &sock_in.sin_addr.s_addr);
-                       conn->local_port = ntohs(sock_in.sin_port);
-               }
+               if (!rc)
+                       memcpy(&conn->local_sockaddr, &sock_in, sizeof(sock_in));
        }
  
        return 0;
@@@ -1302,8 -1300,8 +1300,8 @@@ static int __iscsi_target_login_thread(
        spin_lock_bh(&np->np_thread_lock);
        if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
                spin_unlock_bh(&np->np_thread_lock);
-               pr_err("iSCSI Network Portal on %s:%hu currently not"
-                       " active.\n", np->np_ip, np->np_port);
+               pr_err("iSCSI Network Portal on %pISpc currently not"
+                       " active.\n", &np->np_sockaddr);
                iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
                                ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
                goto new_sess_out;
  
        conn->network_transport = np->np_network_transport;
  
-       pr_debug("Received iSCSI login request from %s on %s Network"
-               " Portal %s:%hu\n", conn->login_ip, np->np_transport->name,
-               conn->local_ip, conn->local_port);
+       pr_debug("Received iSCSI login request from %pISpc on %s Network"
+               " Portal %pISpc\n", &conn->login_sockaddr, np->np_transport->name,
+               &conn->local_sockaddr);
  
        pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
        conn->conn_state        = TARG_CONN_STATE_IN_LOGIN;
        if (ret < 0)
                goto new_sess_out;
  
 -      if (!conn->sess) {
 -              pr_err("struct iscsi_conn session pointer is NULL!\n");
 -              goto new_sess_out;
 -      }
 -
        iscsi_stop_login_thread_timer(np);
  
 -      if (signal_pending(current))
 -              goto new_sess_out;
 -
        if (ret == 1) {
                tpg_np = conn->tpg_np;
  
 -              ret = iscsi_post_login_handler(np, conn, zero_tsih);
 -              if (ret < 0)
 -                      goto new_sess_out;
 -
 +              iscsi_post_login_handler(np, conn, zero_tsih);
                iscsit_deaccess_np(np, tpg, tpg_np);
        }
  
index 57aa0d0fd820f330c271836ecdc02c5a067179b2,35aeffee068697e87d1ae5e3855b1fe11a69b7a0..b597aa2c61a1c60d2794610796ac156c220e43fe
@@@ -5,15 -5,14 +5,15 @@@ extern int iscsi_login_setup_crypto(str
  extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *);
  extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32);
  extern int iscsit_setup_np(struct iscsi_np *,
-                               struct __kernel_sockaddr_storage *);
+                               struct sockaddr_storage *);
  extern int iscsi_target_setup_login_socket(struct iscsi_np *,
-                               struct __kernel_sockaddr_storage *);
+                               struct sockaddr_storage *);
  extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *);
  extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
  extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
  extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
 -extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
 +extern int iscsit_start_kthreads(struct iscsi_conn *);
 +extern void iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
  extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *,
                                bool, bool);
  extern int iscsi_target_login_thread(void *);
index f9cde91418367071d08c3a3ebe08dc44a1a1abe3,4d08afe71e67a3f8cd27c075849bab2cea3e1698..5c964c09c89ff25e6076b272d4afff1a0466a372
@@@ -17,7 -17,6 +17,7 @@@
   ******************************************************************************/
  
  #include <linux/ctype.h>
 +#include <linux/kthread.h>
  #include <scsi/iscsi_proto.h>
  #include <target/target_core_base.h>
  #include <target/target_core_fabric.h>
@@@ -341,7 -340,6 +341,6 @@@ static int iscsi_target_check_first_req
  static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
  {
        u32 padding = 0;
-       struct iscsi_session *sess = conn->sess;
        struct iscsi_login_rsp *login_rsp;
  
        login_rsp = (struct iscsi_login_rsp *) login->rsp;
        login_rsp->itt                  = login->init_task_tag;
        login_rsp->statsn               = cpu_to_be32(conn->stat_sn++);
        login_rsp->exp_cmdsn            = cpu_to_be32(conn->sess->exp_cmd_sn);
-       login_rsp->max_cmdsn            = cpu_to_be32(conn->sess->max_cmd_sn);
+       login_rsp->max_cmdsn            = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
  
        pr_debug("Sending Login Response, Flags: 0x%02x, ITT: 0x%08x,"
                " ExpCmdSN; 0x%08x, MaxCmdSN: 0x%08x, StatSN: 0x%08x, Length:"
                ntohl(login_rsp->statsn), login->rsp_length);
  
        padding = ((-login->rsp_length) & 3);
 +      /*
 +       * Before sending the last login response containing the transition
 +       * bit for full-feature-phase, go ahead and start up TX/RX threads
 +       * now to avoid potential resource allocation failures after the
 +       * final login response has been sent.
 +       */
 +      if (login->login_complete) {
 +              int rc = iscsit_start_kthreads(conn);
 +              if (rc) {
 +                      iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
 +                                          ISCSI_LOGIN_STATUS_NO_RESOURCES);
 +                      return -1;
 +              }
 +      }
  
        if (conn->conn_transport->iscsit_put_login_tx(conn, login,
                                        login->rsp_length + padding) < 0)
 -              return -1;
 +              goto err;
  
        login->rsp_length               = 0;
-       mutex_lock(&sess->cmdsn_mutex);
-       login_rsp->exp_cmdsn            = cpu_to_be32(sess->exp_cmd_sn);
-       login_rsp->max_cmdsn            = cpu_to_be32(sess->max_cmd_sn);
-       mutex_unlock(&sess->cmdsn_mutex);
  
        return 0;
 +
 +err:
 +      if (login->login_complete) {
 +              if (conn->rx_thread && conn->rx_thread_active) {
 +                      send_sig(SIGINT, conn->rx_thread, 1);
 +                      kthread_stop(conn->rx_thread);
 +              }
 +              if (conn->tx_thread && conn->tx_thread_active) {
 +                      send_sig(SIGINT, conn->tx_thread, 1);
 +                      kthread_stop(conn->tx_thread);
 +              }
 +              spin_lock(&iscsit_global->ts_bitmap_lock);
 +              bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id,
 +                                    get_order(1));
 +              spin_unlock(&iscsit_global->ts_bitmap_lock);
 +      }
 +      return -1;
  }
  
  static void iscsi_target_sk_data_ready(struct sock *sk)
index be9cefc07407e80ef5dd7dfcbd8a0d025faf97f6,d746a3a4a623c306a533bed561a4ec07dd072141..9522960c7fddacf70c682326a38586f8562c4487
@@@ -84,16 -84,8 +84,16 @@@ void target_backend_unregister(const st
        list_for_each_entry(tb, &backend_list, list) {
                if (tb->ops == ops) {
                        list_del(&tb->list);
 +                      mutex_unlock(&backend_mutex);
 +                      /*
 +                       * Wait for any outstanding backend driver ->rcu_head
 +                       * callbacks to complete post TBO->free_device() ->
 +                       * call_rcu(), before allowing backend driver module
 +                       * unload of target_backend_ops->owner to proceed.
 +                       */
 +                      rcu_barrier();
                        kfree(tb);
 -                      break;
 +                      return;
                }
        }
        mutex_unlock(&backend_mutex);
@@@ -184,3 -176,8 +184,8 @@@ core_delete_hba(struct se_hba *hba
        kfree(hba);
        return 0;
  }
+ bool target_sense_desc_format(struct se_device *dev)
+ {
+       return dev->transport->get_blocks(dev) > U32_MAX;
+ }
index f87d4cef6d398c072e953e7eaa6b5d9d5b469d70,0e0456f6a28294036cdc835dbff1991f904fee96..9413e1a949e5bf9a63eb1f418a427440b1ad6132
@@@ -454,17 -454,10 +454,17 @@@ spc_emulate_evpd_86(struct se_cmd *cmd
                    cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE1_PROT)
                        buf[4] = 0x5;
                else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT ||
 -                      cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT)
 +                       cmd->se_sess->sess_prot_type == TARGET_DIF_TYPE3_PROT)
                        buf[4] = 0x4;
        }
  
 +      /* logical unit supports type 1 and type 3 protection */
 +      if ((dev->transport->get_device_type(dev) == TYPE_DISK) &&
 +          (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) &&
 +          (dev->dev_attrib.pi_prot_type || cmd->se_sess->sess_prot_type)) {
 +              buf[4] |= (0x3 << 3);
 +      }
 +
        /* Set HEADSUP, ORDSUP, SIMPSUP */
        buf[5] = 0x07;
  
@@@ -484,8 -477,8 +484,8 @@@ static sense_reason_
  spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
  {
        struct se_device *dev = cmd->se_dev;
-       int have_tp = 0;
-       int opt, min;
+       u32 mtl = 0;
+       int have_tp = 0, opt, min;
  
        /*
         * Following spc3r22 section 6.5.3 Block Limits VPD page, when
  
        /*
         * Set MAXIMUM TRANSFER LENGTH
+        *
+        * XXX: Currently assumes single PAGE_SIZE per scatterlist for fabrics
+        * enforcing maximum HW scatter-gather-list entry limit
         */
-       put_unaligned_be32(dev->dev_attrib.hw_max_sectors, &buf[8]);
+       if (cmd->se_tfo->max_data_sg_nents) {
+               mtl = (cmd->se_tfo->max_data_sg_nents * PAGE_SIZE) /
+                      dev->dev_attrib.block_size;
+       }
+       put_unaligned_be32(min_not_zero(mtl, dev->dev_attrib.hw_max_sectors), &buf[8]);
  
        /*
         * Set OPTIMAL TRANSFER LENGTH
@@@ -768,7 -768,12 +775,12 @@@ static int spc_modesense_control(struc
        if (pc == 1)
                goto out;
  
-       p[2] = 2;
+       /* GLTSD: No implicit save of log parameters */
+       p[2] = (1 << 1);
+       if (target_sense_desc_format(dev))
+               /* D_SENSE: Descriptor format sense data for 64bit sectors */
+               p[2] |= (1 << 2);
        /*
         * From spc4r23, 7.4.7 Control mode page
         *
@@@ -1151,6 -1156,7 +1163,7 @@@ static sense_reason_t spc_emulate_reque
        unsigned char *rbuf;
        u8 ua_asc = 0, ua_ascq = 0;
        unsigned char buf[SE_SENSE_BUF];
+       bool desc_format = target_sense_desc_format(cmd->se_dev);
  
        memset(buf, 0, SE_SENSE_BUF);
  
        if (!rbuf)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
  
-       if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) {
-               /*
-                * CURRENT ERROR, UNIT ATTENTION
-                */
-               buf[0] = 0x70;
-               buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
-               /*
-                * The Additional Sense Code (ASC) from the UNIT ATTENTION
-                */
-               buf[SPC_ASC_KEY_OFFSET] = ua_asc;
-               buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq;
-               buf[7] = 0x0A;
-       } else {
-               /*
-                * CURRENT ERROR, NO SENSE
-                */
-               buf[0] = 0x70;
-               buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE;
-               /*
-                * NO ADDITIONAL SENSE INFORMATION
-                */
-               buf[SPC_ASC_KEY_OFFSET] = 0x00;
-               buf[7] = 0x0A;
-       }
+       if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq))
+               scsi_build_sense_buffer(desc_format, buf, UNIT_ATTENTION,
+                                       ua_asc, ua_ascq);
+       else
+               scsi_build_sense_buffer(desc_format, buf, NO_SENSE, 0x0, 0x0);
  
        memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
        transport_kunmap_data_sg(cmd);
@@@ -1203,13 -1188,17 +1195,13 @@@ sense_reason_t spc_emulate_report_luns(
        struct se_dev_entry *deve;
        struct se_session *sess = cmd->se_sess;
        struct se_node_acl *nacl;
 +      struct scsi_lun slun;
        unsigned char *buf;
        u32 lun_count = 0, offset = 8;
 -
 -      if (cmd->data_length < 16) {
 -              pr_warn("REPORT LUNS allocation length %u too small\n",
 -                      cmd->data_length);
 -              return TCM_INVALID_CDB_FIELD;
 -      }
 +      __be32 len;
  
        buf = transport_kmap_data_sg(cmd);
 -      if (!buf)
 +      if (cmd->data_length && !buf)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
  
        /*
         * coming via a target_core_mod PASSTHROUGH op, and not through
         * a $FABRIC_MOD.  In that case, report LUN=0 only.
         */
 -      if (!sess) {
 -              int_to_scsilun(0, (struct scsi_lun *)&buf[offset]);
 -              lun_count = 1;
 +      if (!sess)
                goto done;
 -      }
 +
        nacl = sess->se_node_acl;
  
        rcu_read_lock();
                 * See SPC2-R20 7.19.
                 */
                lun_count++;
 -              if ((offset + 8) > cmd->data_length)
 +              if (offset >= cmd->data_length)
                        continue;
  
 -              int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]);
 +              int_to_scsilun(deve->mapped_lun, &slun);
 +              memcpy(buf + offset, &slun,
 +                     min(8u, cmd->data_length - offset));
                offset += 8;
        }
        rcu_read_unlock();
         * See SPC3 r07, page 159.
         */
  done:
 -      lun_count *= 8;
 -      buf[0] = ((lun_count >> 24) & 0xff);
 -      buf[1] = ((lun_count >> 16) & 0xff);
 -      buf[2] = ((lun_count >> 8) & 0xff);
 -      buf[3] = (lun_count & 0xff);
 -      transport_kunmap_data_sg(cmd);
 +      /*
 +       * If no LUNs are accessible, report virtual LUN 0.
 +       */
 +      if (lun_count == 0) {
 +              int_to_scsilun(0, &slun);
 +              if (cmd->data_length > 8)
 +                      memcpy(buf + offset, &slun,
 +                             min(8u, cmd->data_length - offset));
 +              lun_count = 1;
 +      }
 +
 +      if (buf) {
 +              len = cpu_to_be32(lun_count * 8);
 +              memcpy(buf, &len, min_t(int, sizeof len, cmd->data_length));
 +              transport_kunmap_data_sg(cmd);
 +      }
  
        target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8);
        return 0;
@@@ -1418,9 -1397,6 +1410,6 @@@ spc_parse_cdb(struct se_cmd *cmd, unsig
                }
                break;
        default:
-               pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode"
-                       " 0x%02x, sending CHECK_CONDITION.\n",
-                       cmd->se_tfo->get_fabric_name(), cdb[0]);
                return TCM_UNSUPPORTED_SCSI_OPCODE;
        }
  
index 0aedbb2c10e0451c162118988d6c070efcd9b629,84abe73450c5c3e828a278c0d6dc22009d5821ea..373d3342002bfefdc9911f7b3f5ac57af1826f9b
@@@ -62,6 -62,8 +62,8 @@@
  /* T10 protection information disabled by default */
  #define TA_DEFAULT_T10_PI             0
  #define TA_DEFAULT_FABRIC_PROT_TYPE   0
+ /* TPG status needs to be enabled to return sendtargets discovery endpoint info */
+ #define TA_DEFAULT_TPG_ENABLED_SENDTARGETS 1
  
  #define ISCSI_IOV_DATA_BUFFER         5
  
@@@ -517,7 -519,6 +519,6 @@@ struct iscsi_conn 
        u16                     cid;
        /* Remote TCP Port */
        u16                     login_port;
-       u16                     local_port;
        int                     net_size;
        int                     login_family;
        u32                     auth_id;
        u32                     exp_statsn;
        /* Per connection status sequence number */
        u32                     stat_sn;
- #define IPV6_ADDRESS_SPACE                            48
-       unsigned char           login_ip[IPV6_ADDRESS_SPACE];
-       unsigned char           local_ip[IPV6_ADDRESS_SPACE];
+       struct sockaddr_storage login_sockaddr;
+       struct sockaddr_storage local_sockaddr;
        int                     conn_usage_count;
        int                     conn_waiting_on_uc;
        atomic_t                check_immediate_queue;
        int                     bitmap_id;
        int                     rx_thread_active;
        struct task_struct      *rx_thread;
 +      struct completion       rx_login_comp;
        int                     tx_thread_active;
        struct task_struct      *tx_thread;
        /* list_head for session connection list */
@@@ -636,7 -635,7 +636,7 @@@ struct iscsi_session 
        /* session wide counter: expected command sequence number */
        u32                     exp_cmd_sn;
        /* session wide counter: maximum allowed command sequence number */
-       u32                     max_cmd_sn;
+       atomic_t                max_cmd_sn;
        struct list_head        sess_ooo_cmdsn_list;
  
        /* LIO specific session ID */
@@@ -764,6 -763,7 +764,7 @@@ struct iscsi_tpg_attrib 
        u32                     default_erl;
        u8                      t10_pi;
        u32                     fabric_prot_type;
+       u32                     tpg_enabled_sendtargets;
        struct iscsi_portal_group *tpg;
  };
  
@@@ -776,12 -776,10 +777,10 @@@ struct iscsi_np 
        enum iscsi_timer_flags_table np_login_timer_flags;
        u32                     np_exports;
        enum np_flags_table     np_flags;
-       unsigned char           np_ip[IPV6_ADDRESS_SPACE];
-       u16                     np_port;
        spinlock_t              np_thread_lock;
        struct completion       np_restart_comp;
        struct socket           *np_socket;
-       struct __kernel_sockaddr_storage np_sockaddr;
+       struct sockaddr_storage np_sockaddr;
        struct task_struct      *np_thread;
        struct timer_list       np_login_timer;
        void                    *np_context;