Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 13 Jun 2014 05:38:32 +0000 (22:38 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 13 Jun 2014 05:38:32 +0000 (22:38 -0700)
Pull SCSI target updates from Nicholas Bellinger:
 "The highlights this round include:

   - Add support for T10 PI pass-through between vhost-scsi +
     virtio-scsi (MST + Paolo + MKP + nab)
   - Add support for T10 PI in qla2xxx target mode (Quinn + MKP + hch +
     nab, merged through scsi.git)
   - Add support for percpu-ida pre-allocation in qla2xxx target code
     (Quinn + nab)
   - A number of iser-target fixes related to hardening the network
     portal shutdown path (Sagi + Slava)
   - Fix response length residual handling for a number of control CDBs
     (Roland + Christophe V.)
   - Various iscsi RFC conformance fixes in the CHAP authentication path
     (Tejas and Calsoft folks + nab)
   - Return TASK_SET_FULL status for tcm_fc(FCoE) DataIn + Response
     failures (Vasu + Jun + nab)
   - Fix long-standing ABORT_TASK + session reset hang (nab)
   - Convert iser-initiator + iser-target to include T10 bytes into EDTL
     (Sagi + Or + MKP + Mike Christie)
   - Fix NULL pointer dereference regression related to XCOPY introduced
     in v3.15 + CC'ed to v3.12.y (nab)"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (34 commits)
  target: Fix NULL pointer dereference for XCOPY in target_put_sess_cmd
  vhost-scsi: Include prot_bytes into expected data transfer length
  TARGET/sbc,loopback: Adjust command data length in case pi exists on the wire
  libiscsi, iser: Adjust data_length to include protection information
  scsi_cmnd: Introduce scsi_transfer_length helper
  target: Report correct response length for some commands
  target/sbc: Check that the LBA and number of blocks are correct in VERIFY
  target/sbc: Remove sbc_check_valid_sectors()
  Target/iscsi: Fix sendtargets response pdu for iser transport
  Target/iser: Fix a wrong dereference in case discovery session is over iser
  iscsi-target: Fix ABORT_TASK + connection reset iscsi_queue_req memory leak
  target: Use complete_all for se_cmd->t_transport_stop_comp
  target: Set CMD_T_ACTIVE bit for Task Management Requests
  target: cleanup some boolean tests
  target/spc: Simplify INQUIRY EVPD=0x80
  tcm_fc: Generate TASK_SET_FULL status for response failures
  tcm_fc: Generate TASK_SET_FULL status for DataIN failures
  iscsi-target: Reject mutual authentication with reflected CHAP_C
  iscsi-target: Remove no-op from iscsit_tpg_del_portal_group
  iscsi-target: Fix CHAP_A parameter list handling
  ...

30 files changed:
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/scsi/Kconfig
drivers/scsi/libiscsi.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/qla2xxx/tcm_qla2xxx.h
drivers/scsi/virtio_scsi.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_auth.c
drivers/target/iscsi/iscsi_target_auth.h
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_parameters.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/iscsi/iscsi_target_tpg.h
drivers/target/loopback/tcm_loop.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_transport.c
drivers/target/target_core_xcopy.c
drivers/target/tcm_fc/tfc_cmd.c
drivers/target/tcm_fc/tfc_io.c
drivers/vhost/scsi.c
include/linux/virtio_scsi.h
include/scsi/scsi_cmnd.h
include/target/iscsi/iscsi_transport.h
include/target/target_core_backend.h

index 2e2d903db838f75e6105a88f875de8acf3667162..8d44a4060634c084971f6755aa246ff384c9a40a 100644 (file)
 #include "iscsi_iser.h"
 
 /* Register user buffer memory and initialize passive rdma
- *  dto descriptor. Total data size is stored in
- *  iser_task->data[ISER_DIR_IN].data_len
+ *  dto descriptor. Data size is stored in
+ *  task->data[ISER_DIR_IN].data_len, Protection size
+ *  os stored in task->prot[ISER_DIR_IN].data_len
  */
-static int iser_prepare_read_cmd(struct iscsi_task *task,
-                                unsigned int edtl)
+static int iser_prepare_read_cmd(struct iscsi_task *task)
 
 {
        struct iscsi_iser_task *iser_task = task->dd_data;
@@ -73,14 +73,6 @@ static int iser_prepare_read_cmd(struct iscsi_task *task,
                        return err;
        }
 
-       if (edtl > iser_task->data[ISER_DIR_IN].data_len) {
-               iser_err("Total data length: %ld, less than EDTL: "
-                        "%d, in READ cmd BHS itt: %d, conn: 0x%p\n",
-                        iser_task->data[ISER_DIR_IN].data_len, edtl,
-                        task->itt, iser_task->ib_conn);
-               return -EINVAL;
-       }
-
        err = device->iser_reg_rdma_mem(iser_task, ISER_DIR_IN);
        if (err) {
                iser_err("Failed to set up Data-IN RDMA\n");
@@ -100,8 +92,9 @@ static int iser_prepare_read_cmd(struct iscsi_task *task,
 }
 
 /* Register user buffer memory and initialize passive rdma
- *  dto descriptor. Total data size is stored in
- *  task->data[ISER_DIR_OUT].data_len
+ *  dto descriptor. Data size is stored in
+ *  task->data[ISER_DIR_OUT].data_len, Protection size
+ *  is stored at task->prot[ISER_DIR_OUT].data_len
  */
 static int
 iser_prepare_write_cmd(struct iscsi_task *task,
@@ -135,14 +128,6 @@ iser_prepare_write_cmd(struct iscsi_task *task,
                        return err;
        }
 
-       if (edtl > iser_task->data[ISER_DIR_OUT].data_len) {
-               iser_err("Total data length: %ld, less than EDTL: %d, "
-                        "in WRITE cmd BHS itt: %d, conn: 0x%p\n",
-                        iser_task->data[ISER_DIR_OUT].data_len,
-                        edtl, task->itt, task->conn);
-               return -EINVAL;
-       }
-
        err = device->iser_reg_rdma_mem(iser_task, ISER_DIR_OUT);
        if (err != 0) {
                iser_err("Failed to register write cmd RDMA mem\n");
@@ -417,11 +402,12 @@ int iser_send_command(struct iscsi_conn *conn,
        if (scsi_prot_sg_count(sc)) {
                prot_buf->buf  = scsi_prot_sglist(sc);
                prot_buf->size = scsi_prot_sg_count(sc);
-               prot_buf->data_len = sc->prot_sdb->length;
+               prot_buf->data_len = data_buf->data_len >>
+                                    ilog2(sc->device->sector_size) * 8;
        }
 
        if (hdr->flags & ISCSI_FLAG_CMD_READ) {
-               err = iser_prepare_read_cmd(task, edtl);
+               err = iser_prepare_read_cmd(task);
                if (err)
                        goto send_command_error;
        }
index b9d647468b99e66ed44c4a1176744ef5eefdbc82..d4c7928a0f36143844f3ca0b4735f9c22a1c148a 100644 (file)
@@ -663,8 +663,9 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
 
        pi_support = np->tpg_np->tpg->tpg_attrib.t10_pi;
        if (pi_support && !device->pi_capable) {
-               pr_err("Protection information requested but not supported\n");
-               ret = -EINVAL;
+               pr_err("Protection information requested but not supported, "
+                      "rejecting connect request\n");
+               ret = rdma_reject(cma_id, NULL, 0);
                goto out_mr;
        }
 
@@ -787,14 +788,12 @@ isert_disconnect_work(struct work_struct *work)
                isert_put_conn(isert_conn);
                return;
        }
-       if (!isert_conn->logout_posted) {
-               pr_debug("Calling rdma_disconnect for !logout_posted from"
-                        " isert_disconnect_work\n");
+
+       if (isert_conn->disconnect) {
+               /* Send DREQ/DREP towards our initiator */
                rdma_disconnect(isert_conn->conn_cm_id);
-               mutex_unlock(&isert_conn->conn_mutex);
-               iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
-               goto wake_up;
        }
+
        mutex_unlock(&isert_conn->conn_mutex);
 
 wake_up:
@@ -803,10 +802,11 @@ wake_up:
 }
 
 static void
-isert_disconnected_handler(struct rdma_cm_id *cma_id)
+isert_disconnected_handler(struct rdma_cm_id *cma_id, bool disconnect)
 {
        struct isert_conn *isert_conn = (struct isert_conn *)cma_id->context;
 
+       isert_conn->disconnect = disconnect;
        INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work);
        schedule_work(&isert_conn->conn_logout_work);
 }
@@ -815,29 +815,28 @@ static int
 isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
 {
        int ret = 0;
+       bool disconnect = false;
 
        pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n",
                 event->event, event->status, cma_id->context, cma_id);
 
        switch (event->event) {
        case RDMA_CM_EVENT_CONNECT_REQUEST:
-               pr_debug("RDMA_CM_EVENT_CONNECT_REQUEST: >>>>>>>>>>>>>>>\n");
                ret = isert_connect_request(cma_id, event);
                break;
        case RDMA_CM_EVENT_ESTABLISHED:
-               pr_debug("RDMA_CM_EVENT_ESTABLISHED >>>>>>>>>>>>>>\n");
                isert_connected_handler(cma_id);
                break;
-       case RDMA_CM_EVENT_DISCONNECTED:
-               pr_debug("RDMA_CM_EVENT_DISCONNECTED: >>>>>>>>>>>>>>\n");
-               isert_disconnected_handler(cma_id);
-               break;
-       case RDMA_CM_EVENT_DEVICE_REMOVAL:
-       case RDMA_CM_EVENT_ADDR_CHANGE:
+       case RDMA_CM_EVENT_ADDR_CHANGE:    /* FALLTHRU */
+       case RDMA_CM_EVENT_DISCONNECTED:   /* FALLTHRU */
+       case RDMA_CM_EVENT_DEVICE_REMOVAL: /* FALLTHRU */
+               disconnect = true;
+       case RDMA_CM_EVENT_TIMEWAIT_EXIT:  /* FALLTHRU */
+               isert_disconnected_handler(cma_id, disconnect);
                break;
        case RDMA_CM_EVENT_CONNECT_ERROR:
        default:
-               pr_err("Unknown RDMA CMA event: %d\n", event->event);
+               pr_err("Unhandled RDMA CMA event: %d\n", event->event);
                break;
        }
 
@@ -1054,7 +1053,9 @@ isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
        }
        if (!login->login_failed) {
                if (login->login_complete) {
-                       if (isert_conn->conn_device->use_fastreg) {
+                       if (!conn->sess->sess_ops->SessionType &&
+                           isert_conn->conn_device->use_fastreg) {
+                               /* Normal Session and fastreg is used */
                                u8 pi_support = login->np->tpg_np->tpg->tpg_attrib.t10_pi;
 
                                ret = isert_conn_create_fastreg_pool(isert_conn,
@@ -1824,11 +1825,8 @@ isert_do_control_comp(struct work_struct *work)
                break;
        case ISTATE_SEND_LOGOUTRSP:
                pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
-               /*
-                * Call atomic_dec(&isert_conn->post_send_buf_count)
-                * from isert_wait_conn()
-                */
-               isert_conn->logout_posted = true;
+
+               atomic_dec(&isert_conn->post_send_buf_count);
                iscsit_logout_post_handler(cmd, cmd->conn);
                break;
        case ISTATE_SEND_TEXTRSP:
@@ -2034,6 +2032,8 @@ isert_cq_rx_comp_err(struct isert_conn *isert_conn)
        isert_conn->state = ISER_CONN_DOWN;
        mutex_unlock(&isert_conn->conn_mutex);
 
+       iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
+
        complete(&isert_conn->conn_wait_comp_err);
 }
 
@@ -2320,7 +2320,7 @@ isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
        int rc;
 
        isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
-       rc = iscsit_build_text_rsp(cmd, conn, hdr);
+       rc = iscsit_build_text_rsp(cmd, conn, hdr, ISCSI_INFINIBAND);
        if (rc < 0)
                return rc;
 
@@ -3156,9 +3156,14 @@ accept_wait:
                return -ENODEV;
 
        spin_lock_bh(&np->np_thread_lock);
-       if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+       if (np->np_thread_state >= ISCSI_NP_THREAD_RESET) {
                spin_unlock_bh(&np->np_thread_lock);
-               pr_debug("ISCSI_NP_THREAD_RESET for isert_accept_np\n");
+               pr_debug("np_thread_state %d for isert_accept_np\n",
+                        np->np_thread_state);
+               /**
+                * No point in stalling here when np_thread
+                * is in state RESET/SHUTDOWN/EXIT - bail
+                **/
                return -ENODEV;
        }
        spin_unlock_bh(&np->np_thread_lock);
@@ -3208,15 +3213,9 @@ static void isert_wait_conn(struct iscsi_conn *conn)
        struct isert_conn *isert_conn = conn->context;
 
        pr_debug("isert_wait_conn: Starting \n");
-       /*
-        * Decrement post_send_buf_count for special case when called
-        * from isert_do_control_comp() -> iscsit_logout_post_handler()
-        */
-       mutex_lock(&isert_conn->conn_mutex);
-       if (isert_conn->logout_posted)
-               atomic_dec(&isert_conn->post_send_buf_count);
 
-       if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
+       mutex_lock(&isert_conn->conn_mutex);
+       if (isert_conn->conn_cm_id) {
                pr_debug("Calling rdma_disconnect from isert_wait_conn\n");
                rdma_disconnect(isert_conn->conn_cm_id);
        }
@@ -3293,6 +3292,7 @@ destroy_rx_wq:
 
 static void __exit isert_exit(void)
 {
+       flush_scheduled_work();
        destroy_workqueue(isert_comp_wq);
        destroy_workqueue(isert_rx_wq);
        iscsit_unregister_transport(&iser_target_transport);
index da6612e6800004b0984880d54ef57bcaab1b0be1..04f51f7bf614735b47d782b2ffa97d417e25fcd5 100644 (file)
@@ -116,7 +116,6 @@ struct isert_device;
 
 struct isert_conn {
        enum iser_conn_state    state;
-       bool                    logout_posted;
        int                     post_recv_buf_count;
        atomic_t                post_send_buf_count;
        u32                     responder_resources;
@@ -151,6 +150,7 @@ struct isert_conn {
 #define ISERT_COMP_BATCH_COUNT 8
        int                     conn_comp_batch;
        struct llist_head       conn_comp_llist;
+       bool                    disconnect;
 };
 
 #define ISERT_MAX_CQ 64
index 02832d64d9187ea0ece202820bd11e1902979cdb..baca5897039fcaf23ea001b69eaef368564762c9 100644 (file)
@@ -1773,6 +1773,7 @@ config SCSI_BFA_FC
 config SCSI_VIRTIO
        tristate "virtio-scsi support"
        depends on VIRTIO
+       select BLK_DEV_INTEGRITY
        help
           This is the virtual HBA driver for virtio.  If the kernel will
           be used in a virtual machine, say Y or M.
index ecd7bd304efebb51ce99580e7810edb6a3cf84be..3d1bc67bac9dc58ac11b9785694e568b3c3ab285 100644 (file)
@@ -338,7 +338,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
        struct iscsi_session *session = conn->session;
        struct scsi_cmnd *sc = task->sc;
        struct iscsi_scsi_req *hdr;
-       unsigned hdrlength, cmd_len;
+       unsigned hdrlength, cmd_len, transfer_length;
        itt_t itt;
        int rc;
 
@@ -391,11 +391,11 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
        if (scsi_get_prot_op(sc) != SCSI_PROT_NORMAL)
                task->protected = true;
 
+       transfer_length = scsi_transfer_length(sc);
+       hdr->data_length = cpu_to_be32(transfer_length);
        if (sc->sc_data_direction == DMA_TO_DEVICE) {
-               unsigned out_len = scsi_out(sc)->length;
                struct iscsi_r2t_info *r2t = &task->unsol_r2t;
 
-               hdr->data_length = cpu_to_be32(out_len);
                hdr->flags |= ISCSI_FLAG_CMD_WRITE;
                /*
                 * Write counters:
@@ -414,18 +414,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
                memset(r2t, 0, sizeof(*r2t));
 
                if (session->imm_data_en) {
-                       if (out_len >= session->first_burst)
+                       if (transfer_length >= session->first_burst)
                                task->imm_count = min(session->first_burst,
                                                        conn->max_xmit_dlength);
                        else
-                               task->imm_count = min(out_len,
-                                                       conn->max_xmit_dlength);
+                               task->imm_count = min(transfer_length,
+                                                     conn->max_xmit_dlength);
                        hton24(hdr->dlength, task->imm_count);
                } else
                        zero_data(hdr->dlength);
 
                if (!session->initial_r2t_en) {
-                       r2t->data_length = min(session->first_burst, out_len) -
+                       r2t->data_length = min(session->first_burst,
+                                              transfer_length) -
                                               task->imm_count;
                        r2t->data_offset = task->imm_count;
                        r2t->ttt = cpu_to_be32(ISCSI_RESERVED_TAG);
@@ -438,7 +439,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
        } else {
                hdr->flags |= ISCSI_FLAG_CMD_FINAL;
                zero_data(hdr->dlength);
-               hdr->data_length = cpu_to_be32(scsi_in(sc)->length);
 
                if (sc->sc_data_direction == DMA_FROM_DEVICE)
                        hdr->flags |= ISCSI_FLAG_CMD_READ;
@@ -466,7 +466,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
                          scsi_bidi_cmnd(sc) ? "bidirectional" :
                          sc->sc_data_direction == DMA_TO_DEVICE ?
                          "write" : "read", conn->id, sc, sc->cmnd[0],
-                         task->itt, scsi_bufflen(sc),
+                         task->itt, transfer_length,
                          scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0,
                          session->cmdsn,
                          session->max_cmdsn - session->exp_cmdsn + 1);
index b1d10f9935c7caac0f85cc7cdb17ccee12c9e8df..8d85ed8d89170265647938f5bfe9fc8f8d77d185 100644 (file)
@@ -104,7 +104,6 @@ static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha,
 /*
  * Global Variables
  */
-static struct kmem_cache *qla_tgt_cmd_cachep;
 static struct kmem_cache *qla_tgt_mgmt_cmd_cachep;
 static mempool_t *qla_tgt_mgmt_cmd_mempool;
 static struct workqueue_struct *qla_tgt_wq;
@@ -2705,6 +2704,8 @@ done:
 
 void qlt_free_cmd(struct qla_tgt_cmd *cmd)
 {
+       struct qla_tgt_sess *sess = cmd->sess;
+
        ql_dbg(ql_dbg_tgt, cmd->vha, 0xe074,
            "%s: se_cmd[%p] ox_id %04x\n",
            __func__, &cmd->se_cmd,
@@ -2713,7 +2714,12 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd)
        BUG_ON(cmd->sg_mapped);
        if (unlikely(cmd->free_sg))
                kfree(cmd->sg);
-       kmem_cache_free(qla_tgt_cmd_cachep, cmd);
+
+       if (!sess || !sess->se_sess) {
+               WARN_ON(1);
+               return;
+       }
+       percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
 }
 EXPORT_SYMBOL(qlt_free_cmd);
 
@@ -3075,13 +3081,12 @@ static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *,
 /*
  * Process context for I/O path into tcm_qla2xxx code
  */
-static void qlt_do_work(struct work_struct *work)
+static void __qlt_do_work(struct qla_tgt_cmd *cmd)
 {
-       struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
        scsi_qla_host_t *vha = cmd->vha;
        struct qla_hw_data *ha = vha->hw;
        struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
-       struct qla_tgt_sess *sess = NULL;
+       struct qla_tgt_sess *sess = cmd->sess;
        struct atio_from_isp *atio = &cmd->atio;
        unsigned char *cdb;
        unsigned long flags;
@@ -3091,41 +3096,6 @@ static void qlt_do_work(struct work_struct *work)
        if (tgt->tgt_stop)
                goto out_term;
 
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
-           atio->u.isp24.fcp_hdr.s_id);
-       /* Do kref_get() before dropping qla_hw_data->hardware_lock. */
-       if (sess)
-               kref_get(&sess->se_sess->sess_kref);
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-       if (unlikely(!sess)) {
-               uint8_t *s_id = atio->u.isp24.fcp_hdr.s_id;
-
-               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022,
-                       "qla_target(%d): Unable to find wwn login"
-                       " (s_id %x:%x:%x), trying to create it manually\n",
-                       vha->vp_idx, s_id[0], s_id[1], s_id[2]);
-
-               if (atio->u.raw.entry_count > 1) {
-                       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023,
-                               "Dropping multy entry cmd %p\n", cmd);
-                       goto out_term;
-               }
-
-               mutex_lock(&vha->vha_tgt.tgt_mutex);
-               sess = qlt_make_local_sess(vha, s_id);
-               /* sess has an extra creation ref. */
-               mutex_unlock(&vha->vha_tgt.tgt_mutex);
-
-               if (!sess)
-                       goto out_term;
-       }
-
-       cmd->sess = sess;
-       cmd->loop_id = sess->loop_id;
-       cmd->conf_compl_supported = sess->conf_compl_supported;
-
        cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
        cmd->tag = atio->u.isp24.exchange_addr;
        cmd->unpacked_lun = scsilun_to_int(
@@ -3153,8 +3123,8 @@ static void qlt_do_work(struct work_struct *work)
                cmd, &cmd->se_cmd, cmd->unpacked_lun, cmd->tag, data_length,
                cmd->atio.u.isp24.fcp_hdr.ox_id);
 
-       ret = vha->hw->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length,
-           fcp_task_attr, data_dir, bidi);
+       ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length,
+                                         fcp_task_attr, data_dir, bidi);
        if (ret != 0)
                goto out_term;
        /*
@@ -3173,17 +3143,114 @@ out_term:
         */
        spin_lock_irqsave(&ha->hardware_lock, flags);
        qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
-       kmem_cache_free(qla_tgt_cmd_cachep, cmd);
-       if (sess)
+       percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
+       ha->tgt.tgt_ops->put_sess(sess);
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void qlt_do_work(struct work_struct *work)
+{
+       struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+
+       __qlt_do_work(cmd);
+}
+
+static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
+                                      struct qla_tgt_sess *sess,
+                                      struct atio_from_isp *atio)
+{
+       struct se_session *se_sess = sess->se_sess;
+       struct qla_tgt_cmd *cmd;
+       int tag;
+
+       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
+       if (tag < 0)
+               return NULL;
+
+       cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag];
+       memset(cmd, 0, sizeof(struct qla_tgt_cmd));
+
+       memcpy(&cmd->atio, atio, sizeof(*atio));
+       cmd->state = QLA_TGT_STATE_NEW;
+       cmd->tgt = vha->vha_tgt.qla_tgt;
+       cmd->vha = vha;
+       cmd->se_cmd.map_tag = tag;
+       cmd->sess = sess;
+       cmd->loop_id = sess->loop_id;
+       cmd->conf_compl_supported = sess->conf_compl_supported;
+
+       return cmd;
+}
+
+static void qlt_send_busy(struct scsi_qla_host *, struct atio_from_isp *,
+                         uint16_t);
+
+static void qlt_create_sess_from_atio(struct work_struct *work)
+{
+       struct qla_tgt_sess_op *op = container_of(work,
+                                       struct qla_tgt_sess_op, work);
+       scsi_qla_host_t *vha = op->vha;
+       struct qla_hw_data *ha = vha->hw;
+       struct qla_tgt_sess *sess;
+       struct qla_tgt_cmd *cmd;
+       unsigned long flags;
+       uint8_t *s_id = op->atio.u.isp24.fcp_hdr.s_id;
+
+       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022,
+               "qla_target(%d): Unable to find wwn login"
+               " (s_id %x:%x:%x), trying to create it manually\n",
+               vha->vp_idx, s_id[0], s_id[1], s_id[2]);
+
+       if (op->atio.u.raw.entry_count > 1) {
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023,
+                       "Dropping multy entry atio %p\n", &op->atio);
+               goto out_term;
+       }
+
+       mutex_lock(&vha->vha_tgt.tgt_mutex);
+       sess = qlt_make_local_sess(vha, s_id);
+       /* sess has an extra creation ref. */
+       mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+       if (!sess)
+               goto out_term;
+       /*
+        * Now obtain a pre-allocated session tag using the original op->atio
+        * packet header, and dispatch into __qlt_do_work() using the existing
+        * process context.
+        */
+       cmd = qlt_get_tag(vha, sess, &op->atio);
+       if (!cmd) {
+               spin_lock_irqsave(&ha->hardware_lock, flags);
+               qlt_send_busy(vha, &op->atio, SAM_STAT_BUSY);
                ha->tgt.tgt_ops->put_sess(sess);
+               spin_unlock_irqrestore(&ha->hardware_lock, flags);
+               kfree(op);
+               return;
+       }
+       /*
+        * __qlt_do_work() will call ha->tgt.tgt_ops->put_sess() to release
+        * the extra reference taken above by qlt_make_local_sess()
+        */
+       __qlt_do_work(cmd);
+       kfree(op);
+       return;
+
+out_term:
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       qlt_send_term_exchange(vha, NULL, &op->atio, 1);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
+       kfree(op);
+
 }
 
 /* ha->hardware_lock supposed to be held on entry */
 static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
        struct atio_from_isp *atio)
 {
+       struct qla_hw_data *ha = vha->hw;
        struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
+       struct qla_tgt_sess *sess;
        struct qla_tgt_cmd *cmd;
 
        if (unlikely(tgt->tgt_stop)) {
@@ -3192,18 +3259,31 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
                return -EFAULT;
        }
 
-       cmd = kmem_cache_zalloc(qla_tgt_cmd_cachep, GFP_ATOMIC);
+       sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id);
+       if (unlikely(!sess)) {
+               struct qla_tgt_sess_op *op = kzalloc(sizeof(struct qla_tgt_sess_op),
+                                                    GFP_ATOMIC);
+               if (!op)
+                       return -ENOMEM;
+
+               memcpy(&op->atio, atio, sizeof(*atio));
+               INIT_WORK(&op->work, qlt_create_sess_from_atio);
+               queue_work(qla_tgt_wq, &op->work);
+               return 0;
+       }
+       /*
+        * Do kref_get() before returning + dropping qla_hw_data->hardware_lock.
+        */
+       kref_get(&sess->se_sess->sess_kref);
+
+       cmd = qlt_get_tag(vha, sess, atio);
        if (!cmd) {
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05e,
                    "qla_target(%d): Allocation of cmd failed\n", vha->vp_idx);
+               ha->tgt.tgt_ops->put_sess(sess);
                return -ENOMEM;
        }
 
-       memcpy(&cmd->atio, atio, sizeof(*atio));
-       cmd->state = QLA_TGT_STATE_NEW;
-       cmd->tgt = vha->vha_tgt.qla_tgt;
-       cmd->vha = vha;
-
        INIT_WORK(&cmd->work, qlt_do_work);
        queue_work(qla_tgt_wq, &cmd->work);
        return 0;
@@ -5501,23 +5581,13 @@ int __init qlt_init(void)
        if (!QLA_TGT_MODE_ENABLED())
                return 0;
 
-       qla_tgt_cmd_cachep = kmem_cache_create("qla_tgt_cmd_cachep",
-           sizeof(struct qla_tgt_cmd), __alignof__(struct qla_tgt_cmd), 0,
-           NULL);
-       if (!qla_tgt_cmd_cachep) {
-               ql_log(ql_log_fatal, NULL, 0xe06c,
-                   "kmem_cache_create for qla_tgt_cmd_cachep failed\n");
-               return -ENOMEM;
-       }
-
        qla_tgt_mgmt_cmd_cachep = kmem_cache_create("qla_tgt_mgmt_cmd_cachep",
            sizeof(struct qla_tgt_mgmt_cmd), __alignof__(struct
            qla_tgt_mgmt_cmd), 0, NULL);
        if (!qla_tgt_mgmt_cmd_cachep) {
                ql_log(ql_log_fatal, NULL, 0xe06d,
                    "kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n");
-               ret = -ENOMEM;
-               goto out;
+               return -ENOMEM;
        }
 
        qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab,
@@ -5545,8 +5615,6 @@ out_cmd_mempool:
        mempool_destroy(qla_tgt_mgmt_cmd_mempool);
 out_mgmt_cmd_cachep:
        kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
-out:
-       kmem_cache_destroy(qla_tgt_cmd_cachep);
        return ret;
 }
 
@@ -5558,5 +5626,4 @@ void qlt_exit(void)
        destroy_workqueue(qla_tgt_wq);
        mempool_destroy(qla_tgt_mgmt_cmd_mempool);
        kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
-       kmem_cache_destroy(qla_tgt_cmd_cachep);
 }
index f873e10451d29758ffd65b87a7b400af301e38c7..5c9f185a8ebd8384df5d4d4010e27c9574001238 100644 (file)
@@ -870,6 +870,12 @@ struct qla_tgt {
        struct list_head tgt_list_entry;
 };
 
+struct qla_tgt_sess_op {
+       struct scsi_qla_host *vha;
+       struct atio_from_isp atio;
+       struct work_struct work;
+};
+
 /*
  * Equivilant to IT Nexus (Initiator-Target)
  */
index 896cb23adb77f2e0fcb32de955a4c1c1ec5c035a..e2beab962096cd10d18cf1df63920c79fad216b3 100644 (file)
@@ -1501,6 +1501,8 @@ static int tcm_qla2xxx_check_initiator_node_acl(
        struct qla_tgt_sess *sess = qla_tgt_sess;
        unsigned char port_name[36];
        unsigned long flags;
+       int num_tags = (ha->fw_xcb_count) ? ha->fw_xcb_count :
+                      TCM_QLA2XXX_DEFAULT_TAGS;
 
        lport = vha->vha_tgt.target_lport_ptr;
        if (!lport) {
@@ -1518,7 +1520,9 @@ static int tcm_qla2xxx_check_initiator_node_acl(
        }
        se_tpg = &tpg->se_tpg;
 
-       se_sess = transport_init_session(TARGET_PROT_NORMAL);
+       se_sess = transport_init_session_tags(num_tags,
+                                             sizeof(struct qla_tgt_cmd),
+                                             TARGET_PROT_NORMAL);
        if (IS_ERR(se_sess)) {
                pr_err("Unable to initialize struct se_session\n");
                return PTR_ERR(se_sess);
index 33aaac8c7d5936bbdd3e2d9f934f2c92f2083331..10c002145648cfb2deeda14c0d83568025ec5bef 100644 (file)
@@ -4,6 +4,11 @@
 #define TCM_QLA2XXX_VERSION    "v0.1"
 /* length of ASCII WWPNs including pad */
 #define TCM_QLA2XXX_NAMELEN    32
+/*
+ * Number of pre-allocated per-session tags, based upon the worst-case
+ * per port number of iocbs
+ */
+#define TCM_QLA2XXX_DEFAULT_TAGS 2088
 
 #include "qla_target.h"
 
index 99fdb94039442b50694e66d53f63cab55a5efdae..89ee5929eb6de4060536e89885aba5f13f19577c 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/virtio_config.h>
 #include <linux/virtio_scsi.h>
 #include <linux/cpu.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
@@ -37,6 +38,7 @@ struct virtio_scsi_cmd {
        struct completion *comp;
        union {
                struct virtio_scsi_cmd_req       cmd;
+               struct virtio_scsi_cmd_req_pi    cmd_pi;
                struct virtio_scsi_ctrl_tmf_req  tmf;
                struct virtio_scsi_ctrl_an_req   an;
        } req;
@@ -399,7 +401,7 @@ static int virtscsi_add_cmd(struct virtqueue *vq,
                            size_t req_size, size_t resp_size)
 {
        struct scsi_cmnd *sc = cmd->sc;
-       struct scatterlist *sgs[4], req, resp;
+       struct scatterlist *sgs[6], req, resp;
        struct sg_table *out, *in;
        unsigned out_num = 0, in_num = 0;
 
@@ -417,16 +419,24 @@ static int virtscsi_add_cmd(struct virtqueue *vq,
        sgs[out_num++] = &req;
 
        /* Data-out buffer.  */
-       if (out)
+       if (out) {
+               /* Place WRITE protection SGLs before Data OUT payload */
+               if (scsi_prot_sg_count(sc))
+                       sgs[out_num++] = scsi_prot_sglist(sc);
                sgs[out_num++] = out->sgl;
+       }
 
        /* Response header.  */
        sg_init_one(&resp, &cmd->resp, resp_size);
        sgs[out_num + in_num++] = &resp;
 
        /* Data-in buffer */
-       if (in)
+       if (in) {
+               /* Place READ protection SGLs before Data IN payload */
+               if (scsi_prot_sg_count(sc))
+                       sgs[out_num + in_num++] = scsi_prot_sglist(sc);
                sgs[out_num + in_num++] = in->sgl;
+       }
 
        return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_ATOMIC);
 }
@@ -451,12 +461,45 @@ static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq,
        return err;
 }
 
+static void virtio_scsi_init_hdr(struct virtio_scsi_cmd_req *cmd,
+                                struct scsi_cmnd *sc)
+{
+       cmd->lun[0] = 1;
+       cmd->lun[1] = sc->device->id;
+       cmd->lun[2] = (sc->device->lun >> 8) | 0x40;
+       cmd->lun[3] = sc->device->lun & 0xff;
+       cmd->tag = (unsigned long)sc;
+       cmd->task_attr = VIRTIO_SCSI_S_SIMPLE;
+       cmd->prio = 0;
+       cmd->crn = 0;
+}
+
+static void virtio_scsi_init_hdr_pi(struct virtio_scsi_cmd_req_pi *cmd_pi,
+                                   struct scsi_cmnd *sc)
+{
+       struct request *rq = sc->request;
+       struct blk_integrity *bi;
+
+       virtio_scsi_init_hdr((struct virtio_scsi_cmd_req *)cmd_pi, sc);
+
+       if (!rq || !scsi_prot_sg_count(sc))
+               return;
+
+       bi = blk_get_integrity(rq->rq_disk);
+
+       if (sc->sc_data_direction == DMA_TO_DEVICE)
+               cmd_pi->pi_bytesout = blk_rq_sectors(rq) * bi->tuple_size;
+       else if (sc->sc_data_direction == DMA_FROM_DEVICE)
+               cmd_pi->pi_bytesin = blk_rq_sectors(rq) * bi->tuple_size;
+}
+
 static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
                                 struct virtio_scsi_vq *req_vq,
                                 struct scsi_cmnd *sc)
 {
        struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
        struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc);
+       int req_size;
 
        BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize);
 
@@ -468,22 +511,20 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
 
        memset(cmd, 0, sizeof(*cmd));
        cmd->sc = sc;
-       cmd->req.cmd = (struct virtio_scsi_cmd_req){
-               .lun[0] = 1,
-               .lun[1] = sc->device->id,
-               .lun[2] = (sc->device->lun >> 8) | 0x40,
-               .lun[3] = sc->device->lun & 0xff,
-               .tag = (unsigned long)sc,
-               .task_attr = VIRTIO_SCSI_S_SIMPLE,
-               .prio = 0,
-               .crn = 0,
-       };
 
        BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE);
-       memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len);
 
-       if (virtscsi_kick_cmd(req_vq, cmd,
-                             sizeof cmd->req.cmd, sizeof cmd->resp.cmd) != 0)
+       if (virtio_has_feature(vscsi->vdev, VIRTIO_SCSI_F_T10_PI)) {
+               virtio_scsi_init_hdr_pi(&cmd->req.cmd_pi, sc);
+               memcpy(cmd->req.cmd_pi.cdb, sc->cmnd, sc->cmd_len);
+               req_size = sizeof(cmd->req.cmd_pi);
+       } else {
+               virtio_scsi_init_hdr(&cmd->req.cmd, sc);
+               memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len);
+               req_size = sizeof(cmd->req.cmd);
+       }
+
+       if (virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)) != 0)
                return SCSI_MLQUEUE_HOST_BUSY;
        return 0;
 }
@@ -820,7 +861,7 @@ static int virtscsi_probe(struct virtio_device *vdev)
 {
        struct Scsi_Host *shost;
        struct virtio_scsi *vscsi;
-       int err;
+       int err, host_prot;
        u32 sg_elems, num_targets;
        u32 cmd_per_lun;
        u32 num_queues;
@@ -870,6 +911,16 @@ static int virtscsi_probe(struct virtio_device *vdev)
        shost->max_id = num_targets;
        shost->max_channel = 0;
        shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE;
+
+       if (virtio_has_feature(vdev, VIRTIO_SCSI_F_T10_PI)) {
+               host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION |
+                           SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION |
+                           SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION;
+
+               scsi_host_set_prot(shost, host_prot);
+               scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
+       }
+
        err = scsi_add_host(shost, &vdev->dev);
        if (err)
                goto scsi_add_host_failed;
@@ -939,6 +990,7 @@ static struct virtio_device_id id_table[] = {
 static unsigned int features[] = {
        VIRTIO_SCSI_F_HOTPLUG,
        VIRTIO_SCSI_F_CHANGE,
+       VIRTIO_SCSI_F_T10_PI,
 };
 
 static struct virtio_driver virtio_scsi_driver = {
index 9189bc0a87aef18df10bf2c0003d2c1e4c0bc65a..5663f4d19d028120ef51efb689dbff39d47e9e4c 100644 (file)
@@ -300,7 +300,7 @@ bool iscsit_check_np_match(
                port = ntohs(sock_in->sin_port);
        }
 
-       if ((ip_match == true) && (np->np_port == port) &&
+       if (ip_match && (np->np_port == port) &&
            (np->np_network_transport == network_transport))
                return true;
 
@@ -325,7 +325,7 @@ static struct iscsi_np *iscsit_get_np(
                }
 
                match = iscsit_check_np_match(sockaddr, np, network_transport);
-               if (match == true) {
+               if (match) {
                        /*
                         * Increment the np_exports reference count now to
                         * prevent iscsit_del_np() below from being called
@@ -1121,7 +1121,7 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
        /*
         * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
         */
-       if (dump_payload == true)
+       if (dump_payload)
                goto after_immediate_data;
 
        immed_ret = iscsit_handle_immediate_data(cmd, hdr,
@@ -3390,7 +3390,9 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np)
 
 #define SENDTARGETS_BUF_LIMIT 32768U
 
-static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
+static int
+iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
+                                 enum iscsit_transport_type network_transport)
 {
        char *payload = NULL;
        struct iscsi_conn *conn = cmd->conn;
@@ -3467,6 +3469,9 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
                                struct iscsi_np *np = tpg_np->tpg_np;
                                bool inaddr_any = iscsit_check_inaddr_any(np);
 
+                               if (np->np_network_transport != network_transport)
+                                       continue;
+
                                if (!target_name_printed) {
                                        len = sprintf(buf, "TargetName=%s",
                                                      tiqn->tiqn);
@@ -3485,10 +3490,8 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
 
                                len = sprintf(buf, "TargetAddress="
                                        "%s:%hu,%hu",
-                                       (inaddr_any == false) ?
-                                               np->np_ip : conn->local_ip,
-                                       (inaddr_any == false) ?
-                                               np->np_port : conn->local_port,
+                                       inaddr_any ? conn->local_ip : np->np_ip,
+                                       inaddr_any ? conn->local_port : np->np_port,
                                        tpg->tpgt);
                                len += 1;
 
@@ -3520,11 +3523,12 @@ eob:
 
 int
 iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
-                     struct iscsi_text_rsp *hdr)
+                     struct iscsi_text_rsp *hdr,
+                     enum iscsit_transport_type network_transport)
 {
        int text_length, padding;
 
-       text_length = iscsit_build_sendtargets_response(cmd);
+       text_length = iscsit_build_sendtargets_response(cmd, network_transport);
        if (text_length < 0)
                return text_length;
 
@@ -3562,7 +3566,7 @@ static int iscsit_send_text_rsp(
        u32 tx_size = 0;
        int text_length, iov_count = 0, rc;
 
-       rc = iscsit_build_text_rsp(cmd, conn, hdr);
+       rc = iscsit_build_text_rsp(cmd, conn, hdr, ISCSI_TCP);
        if (rc < 0)
                return rc;
 
@@ -4234,8 +4238,6 @@ int iscsit_close_connection(
        if (conn->conn_transport->iscsit_wait_conn)
                conn->conn_transport->iscsit_wait_conn(conn);
 
-       iscsit_free_queue_reqs_for_conn(conn);
-
        /*
         * During Connection recovery drop unacknowledged out of order
         * commands for this connection, and prepare the other commands
@@ -4252,6 +4254,7 @@ int iscsit_close_connection(
                iscsit_clear_ooo_cmdsns_for_conn(conn);
                iscsit_release_commands_from_conn(conn);
        }
+       iscsit_free_queue_reqs_for_conn(conn);
 
        /*
         * Handle decrementing session or connection usage count if
index de77d9aa22c6329b41d515a157e49d54451edf50..19b842c3e0b39222e125c04f165fccbcf68f338d 100644 (file)
@@ -71,6 +71,40 @@ static void chap_gen_challenge(
                        challenge_asciihex);
 }
 
+static int chap_check_algorithm(const char *a_str)
+{
+       char *tmp, *orig, *token;
+
+       tmp = kstrdup(a_str, GFP_KERNEL);
+       if (!tmp) {
+               pr_err("Memory allocation failed for CHAP_A temporary buffer\n");
+               return CHAP_DIGEST_UNKNOWN;
+       }
+       orig = tmp;
+
+       token = strsep(&tmp, "=");
+       if (!token)
+               goto out;
+
+       if (strcmp(token, "CHAP_A")) {
+               pr_err("Unable to locate CHAP_A key\n");
+               goto out;
+       }
+       while (token) {
+               token = strsep(&tmp, ",");
+               if (!token)
+                       goto out;
+
+               if (!strncmp(token, "5", 1)) {
+                       pr_debug("Selected MD5 Algorithm\n");
+                       kfree(orig);
+                       return CHAP_DIGEST_MD5;
+               }
+       }
+out:
+       kfree(orig);
+       return CHAP_DIGEST_UNKNOWN;
+}
 
 static struct iscsi_chap *chap_server_open(
        struct iscsi_conn *conn,
@@ -79,6 +113,7 @@ static struct iscsi_chap *chap_server_open(
        char *aic_str,
        unsigned int *aic_len)
 {
+       int ret;
        struct iscsi_chap *chap;
 
        if (!(auth->naf_flags & NAF_USERID_SET) ||
@@ -93,21 +128,24 @@ static struct iscsi_chap *chap_server_open(
                return NULL;
 
        chap = conn->auth_protocol;
-       /*
-        * We only support MD5 MDA presently.
-        */
-       if (strncmp(a_str, "CHAP_A=5", 8)) {
-               pr_err("CHAP_A is not MD5.\n");
+       ret = chap_check_algorithm(a_str);
+       switch (ret) {
+       case CHAP_DIGEST_MD5:
+               pr_debug("[server] Got CHAP_A=5\n");
+               /*
+                * Send back CHAP_A set to MD5.
+               */
+               *aic_len = sprintf(aic_str, "CHAP_A=5");
+               *aic_len += 1;
+               chap->digest_type = CHAP_DIGEST_MD5;
+               pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type);
+               break;
+       case CHAP_DIGEST_UNKNOWN:
+       default:
+               pr_err("Unsupported CHAP_A value\n");
                return NULL;
        }
-       pr_debug("[server] Got CHAP_A=5\n");
-       /*
-        * Send back CHAP_A set to MD5.
-        */
-       *aic_len = sprintf(aic_str, "CHAP_A=5");
-       *aic_len += 1;
-       chap->digest_type = CHAP_DIGEST_MD5;
-       pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type);
+
        /*
         * Set Identifier.
         */
@@ -313,6 +351,16 @@ static int chap_server_compute_md5(
                pr_err("Unable to convert incoming challenge\n");
                goto out;
        }
+       /*
+        * During mutual authentication, the CHAP_C generated by the
+        * initiator must not match the original CHAP_C generated by
+        * the target.
+        */
+       if (!memcmp(challenge_binhex, chap->challenge, CHAP_CHALLENGE_LENGTH)) {
+               pr_err("initiator CHAP_C matches target CHAP_C, failing"
+                      " login attempt\n");
+               goto out;
+       }
        /*
         * Generate CHAP_N and CHAP_R for mutual authentication.
         */
index 2f463c09626d9232df18fd391daf716440ee543a..d22f7b96a06ca98aa3bd83f669d92eb686cfcec9 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ISCSI_CHAP_H_
 #define _ISCSI_CHAP_H_
 
+#define CHAP_DIGEST_UNKNOWN    0
 #define CHAP_DIGEST_MD5                5
 #define CHAP_DIGEST_SHA                6
 
index d9b1d88e1ad382f07ff8d64c5374b3caaac3a3ce..fecb69535a1583abe6f70f663f1ecd18142c555f 100644 (file)
@@ -1145,7 +1145,7 @@ iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t)
 void iscsi_target_login_sess_out(struct iscsi_conn *conn,
                struct iscsi_np *np, bool zero_tsih, bool new_sess)
 {
-       if (new_sess == false)
+       if (!new_sess)
                goto old_sess_out;
 
        pr_err("iSCSI Login negotiation failed.\n");
index 75b685960e80d31e2d6e19439a98257fea41ab15..62a095f36bf2f78b77d2a9b75cea99b9c2f14ecb 100644 (file)
@@ -404,7 +404,7 @@ static void iscsi_target_sk_data_ready(struct sock *sk)
        }
 
        rc = schedule_delayed_work(&conn->login_work, 0);
-       if (rc == false) {
+       if (!rc) {
                pr_debug("iscsi_target_sk_data_ready, schedule_delayed_work"
                         " got false\n");
        }
@@ -513,7 +513,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work)
        state = (tpg->tpg_state == TPG_STATE_ACTIVE);
        spin_unlock(&tpg->tpg_state_lock);
 
-       if (state == false) {
+       if (!state) {
                pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n");
                iscsi_target_restore_sock_callbacks(conn);
                iscsi_target_login_drop(conn, login);
@@ -528,7 +528,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work)
                state = iscsi_target_sk_state_check(sk);
                read_unlock_bh(&sk->sk_callback_lock);
 
-               if (state == false) {
+               if (!state) {
                        pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n");
                        iscsi_target_restore_sock_callbacks(conn);
                        iscsi_target_login_drop(conn, login);
@@ -773,6 +773,12 @@ static int iscsi_target_handle_csg_zero(
                }
 
                goto do_auth;
+       } else if (!payload_length) {
+               pr_err("Initiator sent zero length security payload,"
+                      " login failed\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                                   ISCSI_LOGIN_STATUS_AUTH_FAILED);
+               return -1;
        }
 
        if (login->first_request)
index 4d2e23fc76fda72be2b7ec59c801f0696a8470e3..02f9de26f38ab930b9810a20abaf8b972f42f93d 100644 (file)
@@ -474,10 +474,10 @@ int iscsi_set_keys_to_negotiate(
                if (!strcmp(param->name, AUTHMETHOD)) {
                        SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, HEADERDIGEST)) {
-                       if (iser == false)
+                       if (!iser)
                                SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, DATADIGEST)) {
-                       if (iser == false)
+                       if (!iser)
                                SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, MAXCONNECTIONS)) {
                        SET_PSTATE_NEGOTIATE(param);
@@ -497,7 +497,7 @@ int iscsi_set_keys_to_negotiate(
                } else if (!strcmp(param->name, IMMEDIATEDATA)) {
                        SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
-                       if (iser == false)
+                       if (!iser)
                                SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
                        continue;
@@ -528,13 +528,13 @@ int iscsi_set_keys_to_negotiate(
                } else if (!strcmp(param->name, OFMARKINT)) {
                        SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, RDMAEXTENSIONS)) {
-                       if (iser == true)
+                       if (iser)
                                SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) {
-                       if (iser == true)
+                       if (iser)
                                SET_PSTATE_NEGOTIATE(param);
                } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) {
-                       if (iser == true)
+                       if (iser)
                                SET_PSTATE_NEGOTIATE(param);
                }
        }
@@ -1605,7 +1605,7 @@ int iscsi_decode_text_input(
 
        tmpbuf = kzalloc(length + 1, GFP_KERNEL);
        if (!tmpbuf) {
-               pr_err("Unable to allocate memory for tmpbuf.\n");
+               pr_err("Unable to allocate %u + 1 bytes for tmpbuf.\n", length);
                return -1;
        }
 
index 1431e8400d28b41c4ca21fc0563a8e3df1b7828a..c3cb5c15efdaa4fe1e5ea2c4a90cd6eb0e167a15 100644 (file)
@@ -189,7 +189,7 @@ static void iscsit_clear_tpg_np_login_thread(
        iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg, shutdown);
 }
 
-void iscsit_clear_tpg_np_login_threads(
+static void iscsit_clear_tpg_np_login_threads(
        struct iscsi_portal_group *tpg,
        bool shutdown)
 {
@@ -276,8 +276,6 @@ int iscsit_tpg_del_portal_group(
        tpg->tpg_state = TPG_STATE_INACTIVE;
        spin_unlock(&tpg->tpg_state_lock);
 
-       iscsit_clear_tpg_np_login_threads(tpg, true);
-
        if (iscsit_release_sessions_for_tpg(tpg, force) < 0) {
                pr_err("Unable to delete iSCSI Target Portal Group:"
                        " %hu while active sessions exist, and force=0\n",
@@ -453,7 +451,7 @@ static bool iscsit_tpg_check_network_portal(
 
                        match = iscsit_check_np_match(sockaddr, np,
                                                network_transport);
-                       if (match == true)
+                       if (match)
                                break;
                }
                spin_unlock(&tpg->tpg_np_lock);
@@ -475,7 +473,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
 
        if (!tpg_np_parent) {
                if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr,
-                               network_transport) == true) {
+                               network_transport)) {
                        pr_err("Network Portal: %s already exists on a"
                                " different TPG on %s\n", ip_str,
                                tpg->tpg_tiqn->tiqn);
index 0a182f2aa8a25ea07cad39ac58a0d954010abd8b..e7265337bc43c1f4cf789d4e4c980d8fdbd6add6 100644 (file)
@@ -8,7 +8,6 @@ extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *,
                        struct iscsi_np *, struct iscsi_tpg_np **);
 extern int iscsit_get_tpg(struct iscsi_portal_group *);
 extern void iscsit_put_tpg(struct iscsi_portal_group *);
-extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *, bool);
 extern void iscsit_tpg_dump_params(struct iscsi_portal_group *);
 extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *);
 extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *,
index 73ab75ddaf42e9b3fc8e378cf3ae3669d1e040e8..6d2f37578b29cc0509d3898b7910bb35cd9d484c 100644 (file)
@@ -179,7 +179,7 @@ static void tcm_loop_submission_work(struct work_struct *work)
        struct tcm_loop_hba *tl_hba;
        struct tcm_loop_tpg *tl_tpg;
        struct scatterlist *sgl_bidi = NULL;
-       u32 sgl_bidi_count = 0;
+       u32 sgl_bidi_count = 0, transfer_length;
        int rc;
 
        tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host);
@@ -213,12 +213,21 @@ static void tcm_loop_submission_work(struct work_struct *work)
 
        }
 
-       if (!scsi_prot_sg_count(sc) && scsi_get_prot_op(sc) != SCSI_PROT_NORMAL)
+       transfer_length = scsi_transfer_length(sc);
+       if (!scsi_prot_sg_count(sc) &&
+           scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) {
                se_cmd->prot_pto = true;
+               /*
+                * loopback transport doesn't support
+                * WRITE_GENERATE, READ_STRIP protection
+                * information operations, go ahead unprotected.
+                */
+               transfer_length = scsi_bufflen(sc);
+       }
 
        rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd,
                        &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun,
-                       scsi_bufflen(sc), tcm_loop_sam_attr(sc),
+                       transfer_length, tcm_loop_sam_attr(sc),
                        sc->sc_data_direction, 0,
                        scsi_sglist(sc), scsi_sg_count(sc),
                        sgl_bidi, sgl_bidi_count,
index e0229592ec5509656aed292970af719be1f9111d..bd78d9235ac645678aeaacc3a564c1c4c13c5742 100644 (file)
@@ -81,7 +81,7 @@ sbc_emulate_readcapacity(struct se_cmd *cmd)
                transport_kunmap_data_sg(cmd);
        }
 
-       target_complete_cmd(cmd, GOOD);
+       target_complete_cmd_with_length(cmd, GOOD, 8);
        return 0;
 }
 
@@ -137,7 +137,7 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
                transport_kunmap_data_sg(cmd);
        }
 
-       target_complete_cmd(cmd, GOOD);
+       target_complete_cmd_with_length(cmd, GOOD, 32);
        return 0;
 }
 
@@ -176,24 +176,6 @@ static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors)
        return cmd->se_dev->dev_attrib.block_size * sectors;
 }
 
-static int sbc_check_valid_sectors(struct se_cmd *cmd)
-{
-       struct se_device *dev = cmd->se_dev;
-       unsigned long long end_lba;
-       u32 sectors;
-
-       sectors = cmd->data_length / dev->dev_attrib.block_size;
-       end_lba = dev->transport->get_blocks(dev) + 1;
-
-       if (cmd->t_task_lba + sectors > end_lba) {
-               pr_err("target: lba %llu, sectors %u exceeds end lba %llu\n",
-                       cmd->t_task_lba, sectors, end_lba);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static inline u32 transport_get_sectors_6(unsigned char *cdb)
 {
        /*
@@ -665,8 +647,19 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
 
        cmd->prot_type = dev->dev_attrib.pi_prot_type;
        cmd->prot_length = dev->prot_length * sectors;
-       pr_debug("%s: prot_type=%d, prot_length=%d prot_op=%d prot_checks=%d\n",
-                __func__, cmd->prot_type, cmd->prot_length,
+
+       /**
+        * In case protection information exists over the wire
+        * we modify command data length to describe pure data.
+        * The actual transfer length is data length + protection
+        * length
+        **/
+       if (protect)
+               cmd->data_length = sectors * dev->dev_attrib.block_size;
+
+       pr_debug("%s: prot_type=%d, data_length=%d, prot_length=%d "
+                "prot_op=%d prot_checks=%d\n",
+                __func__, cmd->prot_type, cmd->data_length, cmd->prot_length,
                 cmd->prot_op, cmd->prot_checks);
 
        return true;
@@ -877,15 +870,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                break;
        case SYNCHRONIZE_CACHE:
        case SYNCHRONIZE_CACHE_16:
-               if (!ops->execute_sync_cache) {
-                       size = 0;
-                       cmd->execute_cmd = sbc_emulate_noop;
-                       break;
-               }
-
-               /*
-                * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE
-                */
                if (cdb[0] == SYNCHRONIZE_CACHE) {
                        sectors = transport_get_sectors_10(cdb);
                        cmd->t_task_lba = transport_lba_32(cdb);
@@ -893,18 +877,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                        sectors = transport_get_sectors_16(cdb);
                        cmd->t_task_lba = transport_lba_64(cdb);
                }
-
-               size = sbc_get_size(cmd, sectors);
-
-               /*
-                * Check to ensure that LBA + Range does not exceed past end of
-                * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
-                */
-               if (cmd->t_task_lba || sectors) {
-                       if (sbc_check_valid_sectors(cmd) < 0)
-                               return TCM_ADDRESS_OUT_OF_RANGE;
+               if (ops->execute_sync_cache) {
+                       cmd->execute_cmd = ops->execute_sync_cache;
+                       goto check_lba;
                }
-               cmd->execute_cmd = ops->execute_sync_cache;
+               size = 0;
+               cmd->execute_cmd = sbc_emulate_noop;
                break;
        case UNMAP:
                if (!ops->execute_unmap)
@@ -947,8 +925,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                break;
        case VERIFY:
                size = 0;
+               sectors = transport_get_sectors_10(cdb);
+               cmd->t_task_lba = transport_lba_32(cdb);
                cmd->execute_cmd = sbc_emulate_noop;
-               break;
+               goto check_lba;
        case REZERO_UNIT:
        case SEEK_6:
        case SEEK_10:
@@ -988,7 +968,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                                dev->dev_attrib.hw_max_sectors);
                        return TCM_INVALID_CDB_FIELD;
                }
-
+check_lba:
                end_lba = dev->transport->get_blocks(dev) + 1;
                if (cmd->t_task_lba + sectors > end_lba) {
                        pr_err("cmd exceeds last lba %llu "
index 8653666612a802f5cbfcde2c4d82ac7d20ca9294..6cd7222738fc4697f8c1be7c337ef7418fd09075 100644 (file)
@@ -129,15 +129,10 @@ static sense_reason_t
 spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
 {
        struct se_device *dev = cmd->se_dev;
-       u16 len = 0;
+       u16 len;
 
        if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) {
-               u32 unit_serial_len;
-
-               unit_serial_len = strlen(dev->t10_wwn.unit_serial);
-               unit_serial_len++; /* For NULL Terminator */
-
-               len += sprintf(&buf[4], "%s", dev->t10_wwn.unit_serial);
+               len = sprintf(&buf[4], "%s", dev->t10_wwn.unit_serial);
                len++; /* Extra Byte for NULL Terminator */
                buf[3] = len;
        }
@@ -721,6 +716,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
        unsigned char *buf;
        sense_reason_t ret;
        int p;
+       int len = 0;
 
        buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
        if (!buf) {
@@ -742,6 +738,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
                }
 
                ret = spc_emulate_inquiry_std(cmd, buf);
+               len = buf[4] + 5;
                goto out;
        }
 
@@ -749,6 +746,7 @@ spc_emulate_inquiry(struct se_cmd *cmd)
                if (cdb[2] == evpd_handlers[p].page) {
                        buf[1] = cdb[2];
                        ret = evpd_handlers[p].emulate(cmd, buf);
+                       len = get_unaligned_be16(&buf[2]) + 4;
                        goto out;
                }
        }
@@ -765,7 +763,7 @@ out:
        kfree(buf);
 
        if (!ret)
-               target_complete_cmd(cmd, GOOD);
+               target_complete_cmd_with_length(cmd, GOOD, len);
        return ret;
 }
 
@@ -1103,7 +1101,7 @@ set_length:
                transport_kunmap_data_sg(cmd);
        }
 
-       target_complete_cmd(cmd, GOOD);
+       target_complete_cmd_with_length(cmd, GOOD, length);
        return 0;
 }
 
@@ -1279,7 +1277,7 @@ done:
        buf[3] = (lun_count & 0xff);
        transport_kunmap_data_sg(cmd);
 
-       target_complete_cmd(cmd, GOOD);
+       target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8);
        return 0;
 }
 EXPORT_SYMBOL(spc_emulate_report_luns);
index 2179feed0d63aa83017dff321ddc86c11e8432d4..7fa62fc93e0b52d70ac49c67f5455a139935f55c 100644 (file)
@@ -504,7 +504,7 @@ void transport_deregister_session(struct se_session *se_sess)
         * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group
         * removal context.
         */
-       if (se_nacl && comp_nacl == true)
+       if (se_nacl && comp_nacl)
                target_put_nacl(se_nacl);
 
        transport_free_session(se_sess);
@@ -562,7 +562,7 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists,
 
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-               complete(&cmd->t_transport_stop_comp);
+               complete_all(&cmd->t_transport_stop_comp);
                return 1;
        }
 
@@ -687,7 +687,7 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
        if (cmd->transport_state & CMD_T_ABORTED &&
            cmd->transport_state & CMD_T_STOP) {
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-               complete(&cmd->t_transport_stop_comp);
+               complete_all(&cmd->t_transport_stop_comp);
                return;
        } else if (!success) {
                INIT_WORK(&cmd->work, target_complete_failure_work);
@@ -703,6 +703,23 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
 }
 EXPORT_SYMBOL(target_complete_cmd);
 
+void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length)
+{
+       if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) {
+               if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
+                       cmd->residual_count += cmd->data_length - length;
+               } else {
+                       cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
+                       cmd->residual_count = cmd->data_length - length;
+               }
+
+               cmd->data_length = length;
+       }
+
+       target_complete_cmd(cmd, scsi_status);
+}
+EXPORT_SYMBOL(target_complete_cmd_with_length);
+
 static void target_add_to_state_list(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
@@ -1761,7 +1778,7 @@ void target_execute_cmd(struct se_cmd *cmd)
                        cmd->se_tfo->get_task_tag(cmd));
 
                spin_unlock_irq(&cmd->t_state_lock);
-               complete(&cmd->t_transport_stop_comp);
+               complete_all(&cmd->t_transport_stop_comp);
                return;
        }
 
@@ -2363,7 +2380,7 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
         * fabric acknowledgement that requires two target_put_sess_cmd()
         * invocations before se_cmd descriptor release.
         */
-       if (ack_kref == true) {
+       if (ack_kref) {
                kref_get(&se_cmd->cmd_kref);
                se_cmd->se_cmd_flags |= SCF_ACK_KREF;
        }
@@ -2407,6 +2424,10 @@ static void target_release_cmd_kref(struct kref *kref)
  */
 int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
 {
+       if (!se_sess) {
+               se_cmd->se_tfo->release_cmd(se_cmd);
+               return 1;
+       }
        return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref,
                        &se_sess->sess_cmd_lock);
 }
@@ -2934,6 +2955,12 @@ static void target_tmr_work(struct work_struct *work)
 int transport_generic_handle_tmr(
        struct se_cmd *cmd)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       cmd->transport_state |= CMD_T_ACTIVE;
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
        INIT_WORK(&cmd->work, target_tmr_work);
        queue_work(cmd->se_dev->tmr_wq, &cmd->work);
        return 0;
index 669c536fd959575da69816e4a8714b5f78a362c7..e9186cdf35e962d12abe59429370306579e9a25d 100644 (file)
@@ -70,7 +70,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
        unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn;
        int rc;
 
-       if (src == true)
+       if (src)
                dev_wwn = &xop->dst_tid_wwn[0];
        else
                dev_wwn = &xop->src_tid_wwn[0];
@@ -88,7 +88,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op
                if (rc != 0)
                        continue;
 
-               if (src == true) {
+               if (src) {
                        xop->dst_dev = se_dev;
                        pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located"
                                " se_dev\n", xop->dst_dev);
@@ -166,7 +166,7 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op
                return -EINVAL;
        }
 
-       if (src == true) {
+       if (src) {
                memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
                /*
                 * Determine if the source designator matches the local device
@@ -236,7 +236,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
                        /*
                         * Assume target descriptors are in source -> destination order..
                         */
-                       if (src == true)
+                       if (src)
                                src = false;
                        else
                                src = true;
@@ -560,7 +560,7 @@ static int target_xcopy_init_pt_lun(
         * reservations.  The pt_cmd->se_lun pointer will be setup from within
         * target_xcopy_setup_pt_port()
         */
-       if (remote_port == false) {
+       if (!remote_port) {
                pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH;
                return 0;
        }
index f5fd515b2bee266dd9c8279ea804bc7372d955f3..be0c0d08c56a91ff9acc97e8db92868c39c25f0c 100644 (file)
@@ -128,6 +128,7 @@ int ft_queue_status(struct se_cmd *se_cmd)
        struct fc_lport *lport;
        struct fc_exch *ep;
        size_t len;
+       int rc;
 
        if (cmd->aborted)
                return 0;
@@ -137,9 +138,10 @@ int ft_queue_status(struct se_cmd *se_cmd)
        len = sizeof(*fcp) + se_cmd->scsi_sense_length;
        fp = fc_frame_alloc(lport, len);
        if (!fp) {
-               /* XXX shouldn't just drop it - requeue and retry? */
-               return 0;
+               se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
+               return -ENOMEM;
        }
+
        fcp = fc_frame_payload_get(fp, len);
        memset(fcp, 0, len);
        fcp->resp.fr_status = se_cmd->scsi_status;
@@ -170,7 +172,18 @@ int ft_queue_status(struct se_cmd *se_cmd)
        fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP,
                       FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0);
 
-       lport->tt.seq_send(lport, cmd->seq, fp);
+       rc = lport->tt.seq_send(lport, cmd->seq, fp);
+       if (rc) {
+               pr_info_ratelimited("%s: Failed to send response frame %p, "
+                                   "xid <0x%x>\n", __func__, fp, ep->xid);
+               /*
+                * Generate a TASK_SET_FULL status to notify the initiator
+                * to reduce it's queue_depth after the se_cmd response has
+                * been re-queued by target-core.
+                */
+               se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
+               return -ENOMEM;
+       }
        lport->tt.exch_done(cmd->seq);
        return 0;
 }
index e415af32115a80bd7927627e826731b2c8b461c3..97b486c3dda136a21824d02ea0f70c828b214d46 100644 (file)
@@ -82,6 +82,10 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
 
        if (cmd->aborted)
                return 0;
+
+       if (se_cmd->scsi_status == SAM_STAT_TASK_SET_FULL)
+               goto queue_status;
+
        ep = fc_seq_exch(cmd->seq);
        lport = ep->lp;
        cmd->seq = lport->tt.seq_start_next(cmd->seq);
@@ -178,14 +182,23 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
                               FC_TYPE_FCP, f_ctl, fh_off);
                error = lport->tt.seq_send(lport, seq, fp);
                if (error) {
-                       /* XXX For now, initiator will retry */
-                       pr_err_ratelimited("%s: Failed to send frame %p, "
+                       pr_info_ratelimited("%s: Failed to send frame %p, "
                                                "xid <0x%x>, remaining %zu, "
                                                "lso_max <0x%x>\n",
                                                __func__, fp, ep->xid,
                                                remaining, lport->lso_max);
+                       /*
+                        * Go ahead and set TASK_SET_FULL status ignoring the
+                        * rest of the DataIN, and immediately attempt to
+                        * send the response via ft_queue_status() in order
+                        * to notify the initiator that it should reduce it's
+                        * per LUN queue_depth.
+                        */
+                       se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL;
+                       break;
                }
        }
+queue_status:
        return ft_queue_status(se_cmd);
 }
 
index e9c280f55819fae38704cc43dfad33be6c8c40cf..4f4ffa4c604e081755a3b77dba0fccb24c6ded7d 100644 (file)
@@ -57,7 +57,8 @@
 #define TCM_VHOST_MAX_CDB_SIZE 32
 #define TCM_VHOST_DEFAULT_TAGS 256
 #define TCM_VHOST_PREALLOC_SGLS 2048
-#define TCM_VHOST_PREALLOC_PAGES 2048
+#define TCM_VHOST_PREALLOC_UPAGES 2048
+#define TCM_VHOST_PREALLOC_PROT_SGLS 512
 
 struct vhost_scsi_inflight {
        /* Wait for the flush operation to finish */
@@ -79,10 +80,12 @@ struct tcm_vhost_cmd {
        u64 tvc_tag;
        /* The number of scatterlists associated with this cmd */
        u32 tvc_sgl_count;
+       u32 tvc_prot_sgl_count;
        /* Saved unpacked SCSI LUN for tcm_vhost_submission_work() */
        u32 tvc_lun;
        /* Pointer to the SGL formatted memory from virtio-scsi */
        struct scatterlist *tvc_sgl;
+       struct scatterlist *tvc_prot_sgl;
        struct page **tvc_upages;
        /* Pointer to response */
        struct virtio_scsi_cmd_resp __user *tvc_resp;
@@ -166,7 +169,8 @@ enum {
 };
 
 enum {
-       VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG)
+       VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) |
+                                              (1ULL << VIRTIO_SCSI_F_T10_PI)
 };
 
 #define VHOST_SCSI_MAX_TARGET  256
@@ -456,12 +460,16 @@ static void tcm_vhost_release_cmd(struct se_cmd *se_cmd)
        struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
                                struct tcm_vhost_cmd, tvc_se_cmd);
        struct se_session *se_sess = se_cmd->se_sess;
+       int i;
 
        if (tv_cmd->tvc_sgl_count) {
-               u32 i;
                for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
                        put_page(sg_page(&tv_cmd->tvc_sgl[i]));
        }
+       if (tv_cmd->tvc_prot_sgl_count) {
+               for (i = 0; i < tv_cmd->tvc_prot_sgl_count; i++)
+                       put_page(sg_page(&tv_cmd->tvc_prot_sgl[i]));
+       }
 
        tcm_vhost_put_inflight(tv_cmd->inflight);
        percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag);
@@ -713,16 +721,14 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
 }
 
 static struct tcm_vhost_cmd *
-vhost_scsi_get_tag(struct vhost_virtqueue *vq,
-                       struct tcm_vhost_tpg *tpg,
-                       struct virtio_scsi_cmd_req *v_req,
-                       u32 exp_data_len,
-                       int data_direction)
+vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct tcm_vhost_tpg *tpg,
+                  unsigned char *cdb, u64 scsi_tag, u16 lun, u8 task_attr,
+                  u32 exp_data_len, int data_direction)
 {
        struct tcm_vhost_cmd *cmd;
        struct tcm_vhost_nexus *tv_nexus;
        struct se_session *se_sess;
-       struct scatterlist *sg;
+       struct scatterlist *sg, *prot_sg;
        struct page **pages;
        int tag;
 
@@ -741,19 +747,24 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq,
 
        cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag];
        sg = cmd->tvc_sgl;
+       prot_sg = cmd->tvc_prot_sgl;
        pages = cmd->tvc_upages;
        memset(cmd, 0, sizeof(struct tcm_vhost_cmd));
 
        cmd->tvc_sgl = sg;
+       cmd->tvc_prot_sgl = prot_sg;
        cmd->tvc_upages = pages;
        cmd->tvc_se_cmd.map_tag = tag;
-       cmd->tvc_tag = v_req->tag;
-       cmd->tvc_task_attr = v_req->task_attr;
+       cmd->tvc_tag = scsi_tag;
+       cmd->tvc_lun = lun;
+       cmd->tvc_task_attr = task_attr;
        cmd->tvc_exp_data_len = exp_data_len;
        cmd->tvc_data_direction = data_direction;
        cmd->tvc_nexus = tv_nexus;
        cmd->inflight = tcm_vhost_get_inflight(vq);
 
+       memcpy(cmd->tvc_cdb, cdb, TCM_VHOST_MAX_CDB_SIZE);
+
        return cmd;
 }
 
@@ -767,35 +778,28 @@ vhost_scsi_map_to_sgl(struct tcm_vhost_cmd *tv_cmd,
                      struct scatterlist *sgl,
                      unsigned int sgl_count,
                      struct iovec *iov,
-                     int write)
+                     struct page **pages,
+                     bool write)
 {
        unsigned int npages = 0, pages_nr, offset, nbytes;
        struct scatterlist *sg = sgl;
        void __user *ptr = iov->iov_base;
        size_t len = iov->iov_len;
-       struct page **pages;
        int ret, i;
 
-       if (sgl_count > TCM_VHOST_PREALLOC_SGLS) {
-               pr_err("vhost_scsi_map_to_sgl() psgl_count: %u greater than"
-                      " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n",
-                       sgl_count, TCM_VHOST_PREALLOC_SGLS);
-               return -ENOBUFS;
-       }
-
        pages_nr = iov_num_pages(iov);
-       if (pages_nr > sgl_count)
+       if (pages_nr > sgl_count) {
+               pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than"
+                      " sgl_count: %u\n", pages_nr, sgl_count);
                return -ENOBUFS;
-
-       if (pages_nr > TCM_VHOST_PREALLOC_PAGES) {
+       }
+       if (pages_nr > TCM_VHOST_PREALLOC_UPAGES) {
                pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than"
-                      " preallocated TCM_VHOST_PREALLOC_PAGES: %u\n",
-                       pages_nr, TCM_VHOST_PREALLOC_PAGES);
+                      " preallocated TCM_VHOST_PREALLOC_UPAGES: %u\n",
+                       pages_nr, TCM_VHOST_PREALLOC_UPAGES);
                return -ENOBUFS;
        }
 
-       pages = tv_cmd->tvc_upages;
-
        ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages);
        /* No pages were pinned */
        if (ret < 0)
@@ -825,33 +829,32 @@ out:
 static int
 vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd,
                          struct iovec *iov,
-                         unsigned int niov,
-                         int write)
+                         int niov,
+                         bool write)
 {
-       int ret;
-       unsigned int i;
-       u32 sgl_count;
-       struct scatterlist *sg;
+       struct scatterlist *sg = cmd->tvc_sgl;
+       unsigned int sgl_count = 0;
+       int ret, i;
 
-       /*
-        * Find out how long sglist needs to be
-        */
-       sgl_count = 0;
        for (i = 0; i < niov; i++)
                sgl_count += iov_num_pages(&iov[i]);
 
-       /* TODO overflow checking */
+       if (sgl_count > TCM_VHOST_PREALLOC_SGLS) {
+               pr_err("vhost_scsi_map_iov_to_sgl() sgl_count: %u greater than"
+                       " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n",
+                       sgl_count, TCM_VHOST_PREALLOC_SGLS);
+               return -ENOBUFS;
+       }
 
-       sg = cmd->tvc_sgl;
        pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count);
        sg_init_table(sg, sgl_count);
-
        cmd->tvc_sgl_count = sgl_count;
 
-       pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count);
+       pr_debug("Mapping iovec %p for %u pages\n", &iov[0], sgl_count);
+
        for (i = 0; i < niov; i++) {
                ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i],
-                                           write);
+                                           cmd->tvc_upages, write);
                if (ret < 0) {
                        for (i = 0; i < cmd->tvc_sgl_count; i++)
                                put_page(sg_page(&cmd->tvc_sgl[i]));
@@ -859,31 +862,70 @@ vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd,
                        cmd->tvc_sgl_count = 0;
                        return ret;
                }
-
                sg += ret;
                sgl_count -= ret;
        }
        return 0;
 }
 
+static int
+vhost_scsi_map_iov_to_prot(struct tcm_vhost_cmd *cmd,
+                          struct iovec *iov,
+                          int niov,
+                          bool write)
+{
+       struct scatterlist *prot_sg = cmd->tvc_prot_sgl;
+       unsigned int prot_sgl_count = 0;
+       int ret, i;
+
+       for (i = 0; i < niov; i++)
+               prot_sgl_count += iov_num_pages(&iov[i]);
+
+       if (prot_sgl_count > TCM_VHOST_PREALLOC_PROT_SGLS) {
+               pr_err("vhost_scsi_map_iov_to_prot() sgl_count: %u greater than"
+                       " preallocated TCM_VHOST_PREALLOC_PROT_SGLS: %u\n",
+                       prot_sgl_count, TCM_VHOST_PREALLOC_PROT_SGLS);
+               return -ENOBUFS;
+       }
+
+       pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__,
+                prot_sg, prot_sgl_count);
+       sg_init_table(prot_sg, prot_sgl_count);
+       cmd->tvc_prot_sgl_count = prot_sgl_count;
+
+       for (i = 0; i < niov; i++) {
+               ret = vhost_scsi_map_to_sgl(cmd, prot_sg, prot_sgl_count, &iov[i],
+                                           cmd->tvc_upages, write);
+               if (ret < 0) {
+                       for (i = 0; i < cmd->tvc_prot_sgl_count; i++)
+                               put_page(sg_page(&cmd->tvc_prot_sgl[i]));
+
+                       cmd->tvc_prot_sgl_count = 0;
+                       return ret;
+               }
+               prot_sg += ret;
+               prot_sgl_count -= ret;
+       }
+       return 0;
+}
+
 static void tcm_vhost_submission_work(struct work_struct *work)
 {
        struct tcm_vhost_cmd *cmd =
                container_of(work, struct tcm_vhost_cmd, work);
        struct tcm_vhost_nexus *tv_nexus;
        struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
-       struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL;
-       int rc, sg_no_bidi = 0;
+       struct scatterlist *sg_ptr, *sg_prot_ptr = NULL;
+       int rc;
 
+       /* FIXME: BIDI operation */
        if (cmd->tvc_sgl_count) {
                sg_ptr = cmd->tvc_sgl;
-/* FIXME: Fix BIDI operation in tcm_vhost_submission_work() */
-#if 0
-               if (se_cmd->se_cmd_flags & SCF_BIDI) {
-                       sg_bidi_ptr = NULL;
-                       sg_no_bidi = 0;
-               }
-#endif
+
+               if (cmd->tvc_prot_sgl_count)
+                       sg_prot_ptr = cmd->tvc_prot_sgl;
+               else
+                       se_cmd->prot_pto = true;
        } else {
                sg_ptr = NULL;
        }
@@ -894,7 +936,7 @@ static void tcm_vhost_submission_work(struct work_struct *work)
                        cmd->tvc_lun, cmd->tvc_exp_data_len,
                        cmd->tvc_task_attr, cmd->tvc_data_direction,
                        TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count,
-                       sg_bidi_ptr, sg_no_bidi, NULL, 0);
+                       NULL, 0, sg_prot_ptr, cmd->tvc_prot_sgl_count);
        if (rc < 0) {
                transport_send_check_condition_and_sense(se_cmd,
                                TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
@@ -926,12 +968,18 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
 {
        struct tcm_vhost_tpg **vs_tpg;
        struct virtio_scsi_cmd_req v_req;
+       struct virtio_scsi_cmd_req_pi v_req_pi;
        struct tcm_vhost_tpg *tpg;
        struct tcm_vhost_cmd *cmd;
-       u32 exp_data_len, data_first, data_num, data_direction;
+       u64 tag;
+       u32 exp_data_len, data_first, data_num, data_direction, prot_first;
        unsigned out, in, i;
-       int head, ret;
-       u8 target;
+       int head, ret, data_niov, prot_niov, prot_bytes;
+       size_t req_size;
+       u16 lun;
+       u8 *target, *lunp, task_attr;
+       bool hdr_pi;
+       void *req, *cdb;
 
        mutex_lock(&vq->mutex);
        /*
@@ -962,7 +1010,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                        break;
                }
 
-/* FIXME: BIDI operation */
+               /* FIXME: BIDI operation */
                if (out == 1 && in == 1) {
                        data_direction = DMA_NONE;
                        data_first = 0;
@@ -992,29 +1040,38 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                        break;
                }
 
-               if (unlikely(vq->iov[0].iov_len != sizeof(v_req))) {
-                       vq_err(vq, "Expecting virtio_scsi_cmd_req, got %zu"
-                               " bytes\n", vq->iov[0].iov_len);
+               if (vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI)) {
+                       req = &v_req_pi;
+                       lunp = &v_req_pi.lun[0];
+                       target = &v_req_pi.lun[1];
+                       req_size = sizeof(v_req_pi);
+                       hdr_pi = true;
+               } else {
+                       req = &v_req;
+                       lunp = &v_req.lun[0];
+                       target = &v_req.lun[1];
+                       req_size = sizeof(v_req);
+                       hdr_pi = false;
+               }
+
+               if (unlikely(vq->iov[0].iov_len < req_size)) {
+                       pr_err("Expecting virtio-scsi header: %zu, got %zu\n",
+                              req_size, vq->iov[0].iov_len);
                        break;
                }
-               pr_debug("Calling __copy_from_user: vq->iov[0].iov_base: %p,"
-                       " len: %zu\n", vq->iov[0].iov_base, sizeof(v_req));
-               ret = __copy_from_user(&v_req, vq->iov[0].iov_base,
-                               sizeof(v_req));
+               ret = memcpy_fromiovecend(req, &vq->iov[0], 0, req_size);
                if (unlikely(ret)) {
                        vq_err(vq, "Faulted on virtio_scsi_cmd_req\n");
                        break;
                }
 
                /* virtio-scsi spec requires byte 0 of the lun to be 1 */
-               if (unlikely(v_req.lun[0] != 1)) {
+               if (unlikely(*lunp != 1)) {
                        vhost_scsi_send_bad_target(vs, vq, head, out);
                        continue;
                }
 
-               /* Extract the tpgt */
-               target = v_req.lun[1];
-               tpg = ACCESS_ONCE(vs_tpg[target]);
+               tpg = ACCESS_ONCE(vs_tpg[*target]);
 
                /* Target does not exist, fail the request */
                if (unlikely(!tpg)) {
@@ -1022,17 +1079,79 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                        continue;
                }
 
+               data_niov = data_num;
+               prot_niov = prot_first = prot_bytes = 0;
+               /*
+                * Determine if any protection information iovecs are preceeding
+                * the actual data payload, and adjust data_first + data_niov
+                * values accordingly for vhost_scsi_map_iov_to_sgl() below.
+                *
+                * Also extract virtio_scsi header bits for vhost_scsi_get_tag()
+                */
+               if (hdr_pi) {
+                       if (v_req_pi.pi_bytesout) {
+                               if (data_direction != DMA_TO_DEVICE) {
+                                       vq_err(vq, "Received non zero do_pi_niov"
+                                               ", but wrong data_direction\n");
+                                       goto err_cmd;
+                               }
+                               prot_bytes = v_req_pi.pi_bytesout;
+                       } else if (v_req_pi.pi_bytesin) {
+                               if (data_direction != DMA_FROM_DEVICE) {
+                                       vq_err(vq, "Received non zero di_pi_niov"
+                                               ", but wrong data_direction\n");
+                                       goto err_cmd;
+                               }
+                               prot_bytes = v_req_pi.pi_bytesin;
+                       }
+                       if (prot_bytes) {
+                               int tmp = 0;
+
+                               for (i = 0; i < data_num; i++) {
+                                       tmp += vq->iov[data_first + i].iov_len;
+                                       prot_niov++;
+                                       if (tmp >= prot_bytes)
+                                               break;
+                               }
+                               prot_first = data_first;
+                               data_first += prot_niov;
+                               data_niov = data_num - prot_niov;
+                       }
+                       tag = v_req_pi.tag;
+                       task_attr = v_req_pi.task_attr;
+                       cdb = &v_req_pi.cdb[0];
+                       lun = ((v_req_pi.lun[2] << 8) | v_req_pi.lun[3]) & 0x3FFF;
+               } else {
+                       tag = v_req.tag;
+                       task_attr = v_req.task_attr;
+                       cdb = &v_req.cdb[0];
+                       lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
+               }
                exp_data_len = 0;
-               for (i = 0; i < data_num; i++)
+               for (i = 0; i < data_niov; i++)
                        exp_data_len += vq->iov[data_first + i].iov_len;
+               /*
+                * Check that the recieved CDB size does not exceeded our
+                * hardcoded max for vhost-scsi
+                *
+                * TODO what if cdb was too small for varlen cdb header?
+                */
+               if (unlikely(scsi_command_size(cdb) > TCM_VHOST_MAX_CDB_SIZE)) {
+                       vq_err(vq, "Received SCSI CDB with command_size: %d that"
+                               " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
+                               scsi_command_size(cdb), TCM_VHOST_MAX_CDB_SIZE);
+                       goto err_cmd;
+               }
 
-               cmd = vhost_scsi_get_tag(vq, tpg, &v_req,
-                                        exp_data_len, data_direction);
+               cmd = vhost_scsi_get_tag(vq, tpg, cdb, tag, lun, task_attr,
+                                        exp_data_len + prot_bytes,
+                                        data_direction);
                if (IS_ERR(cmd)) {
                        vq_err(vq, "vhost_scsi_get_tag failed %ld\n",
                                        PTR_ERR(cmd));
                        goto err_cmd;
                }
+
                pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction"
                        ": %d\n", cmd, exp_data_len, data_direction);
 
@@ -1040,40 +1159,28 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                cmd->tvc_vq = vq;
                cmd->tvc_resp = vq->iov[out].iov_base;
 
-               /*
-                * Copy in the recieved CDB descriptor into cmd->tvc_cdb
-                * that will be used by tcm_vhost_new_cmd_map() and down into
-                * target_setup_cmd_from_cdb()
-                */
-               memcpy(cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE);
-               /*
-                * Check that the recieved CDB size does not exceeded our
-                * hardcoded max for tcm_vhost
-                */
-               /* TODO what if cdb was too small for varlen cdb header? */
-               if (unlikely(scsi_command_size(cmd->tvc_cdb) >
-                                       TCM_VHOST_MAX_CDB_SIZE)) {
-                       vq_err(vq, "Received SCSI CDB with command_size: %d that"
-                               " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
-                               scsi_command_size(cmd->tvc_cdb),
-                               TCM_VHOST_MAX_CDB_SIZE);
-                       goto err_free;
-               }
-               cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
-
                pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
                        cmd->tvc_cdb[0], cmd->tvc_lun);
 
+               if (prot_niov) {
+                       ret = vhost_scsi_map_iov_to_prot(cmd,
+                                       &vq->iov[prot_first], prot_niov,
+                                       data_direction == DMA_FROM_DEVICE);
+                       if (unlikely(ret)) {
+                               vq_err(vq, "Failed to map iov to"
+                                       " prot_sgl\n");
+                               goto err_free;
+                       }
+               }
                if (data_direction != DMA_NONE) {
                        ret = vhost_scsi_map_iov_to_sgl(cmd,
-                                       &vq->iov[data_first], data_num,
+                                       &vq->iov[data_first], data_niov,
                                        data_direction == DMA_FROM_DEVICE);
                        if (unlikely(ret)) {
                                vq_err(vq, "Failed to map iov to sgl\n");
                                goto err_free;
                        }
                }
-
                /*
                 * Save the descriptor from vhost_get_vq_desc() to be used to
                 * complete the virtio-scsi request in TCM callback context via
@@ -1716,6 +1823,7 @@ static void tcm_vhost_free_cmd_map_res(struct tcm_vhost_nexus *nexus,
                tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i];
 
                kfree(tv_cmd->tvc_sgl);
+               kfree(tv_cmd->tvc_prot_sgl);
                kfree(tv_cmd->tvc_upages);
        }
 }
@@ -1750,7 +1858,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
        tv_nexus->tvn_se_sess = transport_init_session_tags(
                                        TCM_VHOST_DEFAULT_TAGS,
                                        sizeof(struct tcm_vhost_cmd),
-                                       TARGET_PROT_NORMAL);
+                                       TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS);
        if (IS_ERR(tv_nexus->tvn_se_sess)) {
                mutex_unlock(&tpg->tv_tpg_mutex);
                kfree(tv_nexus);
@@ -1769,12 +1877,20 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
                }
 
                tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) *
-                                       TCM_VHOST_PREALLOC_PAGES, GFP_KERNEL);
+                                       TCM_VHOST_PREALLOC_UPAGES, GFP_KERNEL);
                if (!tv_cmd->tvc_upages) {
                        mutex_unlock(&tpg->tv_tpg_mutex);
                        pr_err("Unable to allocate tv_cmd->tvc_upages\n");
                        goto out;
                }
+
+               tv_cmd->tvc_prot_sgl = kzalloc(sizeof(struct scatterlist) *
+                                       TCM_VHOST_PREALLOC_PROT_SGLS, GFP_KERNEL);
+               if (!tv_cmd->tvc_prot_sgl) {
+                       mutex_unlock(&tpg->tv_tpg_mutex);
+                       pr_err("Unable to allocate tv_cmd->tvc_prot_sgl\n");
+                       goto out;
+               }
        }
        /*
         * Since we are running in 'demo mode' this call with generate a
index 4195b97a3def6a84574519da4a6fe37b7e954406..de429d1f4357a89d2a6a9506611a93a6c201fdc6 100644 (file)
@@ -35,11 +35,23 @@ struct virtio_scsi_cmd_req {
        u8 lun[8];              /* Logical Unit Number */
        u64 tag;                /* Command identifier */
        u8 task_attr;           /* Task attribute */
-       u8 prio;
+       u8 prio;                /* SAM command priority field */
        u8 crn;
        u8 cdb[VIRTIO_SCSI_CDB_SIZE];
 } __packed;
 
+/* SCSI command request, followed by protection information */
+struct virtio_scsi_cmd_req_pi {
+       u8 lun[8];              /* Logical Unit Number */
+       u64 tag;                /* Command identifier */
+       u8 task_attr;           /* Task attribute */
+       u8 prio;                /* SAM command priority field */
+       u8 crn;
+       u32 pi_bytesout;        /* DataOUT PI Number of bytes */
+       u32 pi_bytesin;         /* DataIN PI Number of bytes */
+       u8 cdb[VIRTIO_SCSI_CDB_SIZE];
+} __packed;
+
 /* Response, followed by sense data and data-in */
 struct virtio_scsi_cmd_resp {
        u32 sense_len;          /* Sense data length */
@@ -97,6 +109,7 @@ struct virtio_scsi_config {
 #define VIRTIO_SCSI_F_INOUT                    0
 #define VIRTIO_SCSI_F_HOTPLUG                  1
 #define VIRTIO_SCSI_F_CHANGE                   2
+#define VIRTIO_SCSI_F_T10_PI                   3
 
 /* Response codes */
 #define VIRTIO_SCSI_S_OK                       0
index e016e2ac38df8f6c570980a4624e9ccaefd0dd5e..42ed789ebafcf9ab04c759d7ef167e981aab2bc6 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/scatterlist.h>
+#include <scsi/scsi_device.h>
 
 struct Scsi_Host;
 struct scsi_device;
@@ -315,4 +316,20 @@ static inline void set_driver_byte(struct scsi_cmnd *cmd, char status)
        cmd->result = (cmd->result & 0x00ffffff) | (status << 24);
 }
 
+static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd)
+{
+       unsigned int xfer_len = blk_rq_bytes(scmd->request);
+       unsigned int prot_op = scsi_get_prot_op(scmd);
+       unsigned int sector_size = scmd->device->sector_size;
+
+       switch (prot_op) {
+       case SCSI_PROT_NORMAL:
+       case SCSI_PROT_WRITE_STRIP:
+       case SCSI_PROT_READ_INSERT:
+               return xfer_len;
+       }
+
+       return xfer_len + (xfer_len >> ilog2(sector_size)) * 8;
+}
+
 #endif /* _SCSI_SCSI_CMND_H */
index 33b487b5da92dc76f549df5d09a3852518c14159..daef9daa500c11f0ff7d92151fafbf9080a80e02 100644 (file)
@@ -70,7 +70,8 @@ extern void iscsit_build_nopin_rsp(struct iscsi_cmd *, struct iscsi_conn *,
 extern void iscsit_build_task_mgt_rsp(struct iscsi_cmd *, struct iscsi_conn *,
                                struct iscsi_tm_rsp *);
 extern int iscsit_build_text_rsp(struct iscsi_cmd *, struct iscsi_conn *,
-                               struct iscsi_text_rsp *);
+                               struct iscsi_text_rsp *,
+                               enum iscsit_transport_type);
 extern void iscsit_build_reject(struct iscsi_cmd *, struct iscsi_conn *,
                                struct iscsi_reject *);
 extern int iscsit_build_logout_rsp(struct iscsi_cmd *, struct iscsi_conn *,
index 3a1c1eea1fffcaee767d4bef1a8ea2700f1884e2..9adc1bca1178ba36482f63bf8cef1444045f7709 100644 (file)
@@ -59,6 +59,7 @@ int   transport_subsystem_register(struct se_subsystem_api *);
 void   transport_subsystem_release(struct se_subsystem_api *);
 
 void   target_complete_cmd(struct se_cmd *, u8);
+void   target_complete_cmd_with_length(struct se_cmd *, u8, int);
 
 sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size);
 sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd);