diff options
30 files changed, 728 insertions, 364 deletions
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 2e2d903db838..8d44a4060634 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c | |||
| @@ -41,11 +41,11 @@ | |||
| 41 | #include "iscsi_iser.h" | 41 | #include "iscsi_iser.h" |
| 42 | 42 | ||
| 43 | /* Register user buffer memory and initialize passive rdma | 43 | /* Register user buffer memory and initialize passive rdma |
| 44 | * dto descriptor. Total data size is stored in | 44 | * dto descriptor. Data size is stored in |
| 45 | * iser_task->data[ISER_DIR_IN].data_len | 45 | * task->data[ISER_DIR_IN].data_len, Protection size |
| 46 | * os stored in task->prot[ISER_DIR_IN].data_len | ||
| 46 | */ | 47 | */ |
| 47 | static int iser_prepare_read_cmd(struct iscsi_task *task, | 48 | static int iser_prepare_read_cmd(struct iscsi_task *task) |
| 48 | unsigned int edtl) | ||
| 49 | 49 | ||
| 50 | { | 50 | { |
| 51 | struct iscsi_iser_task *iser_task = task->dd_data; | 51 | struct iscsi_iser_task *iser_task = task->dd_data; |
| @@ -73,14 +73,6 @@ static int iser_prepare_read_cmd(struct iscsi_task *task, | |||
| 73 | return err; | 73 | return err; |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | if (edtl > iser_task->data[ISER_DIR_IN].data_len) { | ||
| 77 | iser_err("Total data length: %ld, less than EDTL: " | ||
| 78 | "%d, in READ cmd BHS itt: %d, conn: 0x%p\n", | ||
| 79 | iser_task->data[ISER_DIR_IN].data_len, edtl, | ||
| 80 | task->itt, iser_task->ib_conn); | ||
| 81 | return -EINVAL; | ||
| 82 | } | ||
| 83 | |||
| 84 | err = device->iser_reg_rdma_mem(iser_task, ISER_DIR_IN); | 76 | err = device->iser_reg_rdma_mem(iser_task, ISER_DIR_IN); |
| 85 | if (err) { | 77 | if (err) { |
| 86 | iser_err("Failed to set up Data-IN RDMA\n"); | 78 | iser_err("Failed to set up Data-IN RDMA\n"); |
| @@ -100,8 +92,9 @@ static int iser_prepare_read_cmd(struct iscsi_task *task, | |||
| 100 | } | 92 | } |
| 101 | 93 | ||
| 102 | /* Register user buffer memory and initialize passive rdma | 94 | /* Register user buffer memory and initialize passive rdma |
| 103 | * dto descriptor. Total data size is stored in | 95 | * dto descriptor. Data size is stored in |
| 104 | * task->data[ISER_DIR_OUT].data_len | 96 | * task->data[ISER_DIR_OUT].data_len, Protection size |
| 97 | * is stored at task->prot[ISER_DIR_OUT].data_len | ||
| 105 | */ | 98 | */ |
| 106 | static int | 99 | static int |
| 107 | iser_prepare_write_cmd(struct iscsi_task *task, | 100 | iser_prepare_write_cmd(struct iscsi_task *task, |
| @@ -135,14 +128,6 @@ iser_prepare_write_cmd(struct iscsi_task *task, | |||
| 135 | return err; | 128 | return err; |
| 136 | } | 129 | } |
| 137 | 130 | ||
| 138 | if (edtl > iser_task->data[ISER_DIR_OUT].data_len) { | ||
| 139 | iser_err("Total data length: %ld, less than EDTL: %d, " | ||
| 140 | "in WRITE cmd BHS itt: %d, conn: 0x%p\n", | ||
| 141 | iser_task->data[ISER_DIR_OUT].data_len, | ||
| 142 | edtl, task->itt, task->conn); | ||
| 143 | return -EINVAL; | ||
| 144 | } | ||
| 145 | |||
| 146 | err = device->iser_reg_rdma_mem(iser_task, ISER_DIR_OUT); | 131 | err = device->iser_reg_rdma_mem(iser_task, ISER_DIR_OUT); |
| 147 | if (err != 0) { | 132 | if (err != 0) { |
| 148 | iser_err("Failed to register write cmd RDMA mem\n"); | 133 | iser_err("Failed to register write cmd RDMA mem\n"); |
| @@ -417,11 +402,12 @@ int iser_send_command(struct iscsi_conn *conn, | |||
| 417 | if (scsi_prot_sg_count(sc)) { | 402 | if (scsi_prot_sg_count(sc)) { |
| 418 | prot_buf->buf = scsi_prot_sglist(sc); | 403 | prot_buf->buf = scsi_prot_sglist(sc); |
| 419 | prot_buf->size = scsi_prot_sg_count(sc); | 404 | prot_buf->size = scsi_prot_sg_count(sc); |
| 420 | prot_buf->data_len = sc->prot_sdb->length; | 405 | prot_buf->data_len = data_buf->data_len >> |
| 406 | ilog2(sc->device->sector_size) * 8; | ||
| 421 | } | 407 | } |
| 422 | 408 | ||
| 423 | if (hdr->flags & ISCSI_FLAG_CMD_READ) { | 409 | if (hdr->flags & ISCSI_FLAG_CMD_READ) { |
| 424 | err = iser_prepare_read_cmd(task, edtl); | 410 | err = iser_prepare_read_cmd(task); |
| 425 | if (err) | 411 | if (err) |
| 426 | goto send_command_error; | 412 | goto send_command_error; |
| 427 | } | 413 | } |
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index b9d647468b99..d4c7928a0f36 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c | |||
| @@ -663,8 +663,9 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) | |||
| 663 | 663 | ||
| 664 | pi_support = np->tpg_np->tpg->tpg_attrib.t10_pi; | 664 | pi_support = np->tpg_np->tpg->tpg_attrib.t10_pi; |
| 665 | if (pi_support && !device->pi_capable) { | 665 | if (pi_support && !device->pi_capable) { |
| 666 | pr_err("Protection information requested but not supported\n"); | 666 | pr_err("Protection information requested but not supported, " |
| 667 | ret = -EINVAL; | 667 | "rejecting connect request\n"); |
| 668 | ret = rdma_reject(cma_id, NULL, 0); | ||
| 668 | goto out_mr; | 669 | goto out_mr; |
| 669 | } | 670 | } |
| 670 | 671 | ||
| @@ -787,14 +788,12 @@ isert_disconnect_work(struct work_struct *work) | |||
| 787 | isert_put_conn(isert_conn); | 788 | isert_put_conn(isert_conn); |
| 788 | return; | 789 | return; |
| 789 | } | 790 | } |
| 790 | if (!isert_conn->logout_posted) { | 791 | |
| 791 | pr_debug("Calling rdma_disconnect for !logout_posted from" | 792 | if (isert_conn->disconnect) { |
| 792 | " isert_disconnect_work\n"); | 793 | /* Send DREQ/DREP towards our initiator */ |
| 793 | rdma_disconnect(isert_conn->conn_cm_id); | 794 | rdma_disconnect(isert_conn->conn_cm_id); |
| 794 | mutex_unlock(&isert_conn->conn_mutex); | ||
| 795 | iscsit_cause_connection_reinstatement(isert_conn->conn, 0); | ||
| 796 | goto wake_up; | ||
| 797 | } | 795 | } |
| 796 | |||
| 798 | mutex_unlock(&isert_conn->conn_mutex); | 797 | mutex_unlock(&isert_conn->conn_mutex); |
| 799 | 798 | ||
| 800 | wake_up: | 799 | wake_up: |
| @@ -803,10 +802,11 @@ wake_up: | |||
| 803 | } | 802 | } |
| 804 | 803 | ||
| 805 | static void | 804 | static void |
| 806 | isert_disconnected_handler(struct rdma_cm_id *cma_id) | 805 | isert_disconnected_handler(struct rdma_cm_id *cma_id, bool disconnect) |
| 807 | { | 806 | { |
| 808 | struct isert_conn *isert_conn = (struct isert_conn *)cma_id->context; | 807 | struct isert_conn *isert_conn = (struct isert_conn *)cma_id->context; |
| 809 | 808 | ||
| 809 | isert_conn->disconnect = disconnect; | ||
| 810 | INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work); | 810 | INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work); |
| 811 | schedule_work(&isert_conn->conn_logout_work); | 811 | schedule_work(&isert_conn->conn_logout_work); |
| 812 | } | 812 | } |
| @@ -815,29 +815,28 @@ static int | |||
| 815 | isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) | 815 | isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) |
| 816 | { | 816 | { |
| 817 | int ret = 0; | 817 | int ret = 0; |
| 818 | bool disconnect = false; | ||
| 818 | 819 | ||
| 819 | pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n", | 820 | pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n", |
| 820 | event->event, event->status, cma_id->context, cma_id); | 821 | event->event, event->status, cma_id->context, cma_id); |
| 821 | 822 | ||
| 822 | switch (event->event) { | 823 | switch (event->event) { |
| 823 | case RDMA_CM_EVENT_CONNECT_REQUEST: | 824 | case RDMA_CM_EVENT_CONNECT_REQUEST: |
| 824 | pr_debug("RDMA_CM_EVENT_CONNECT_REQUEST: >>>>>>>>>>>>>>>\n"); | ||
| 825 | ret = isert_connect_request(cma_id, event); | 825 | ret = isert_connect_request(cma_id, event); |
| 826 | break; | 826 | break; |
| 827 | case RDMA_CM_EVENT_ESTABLISHED: | 827 | case RDMA_CM_EVENT_ESTABLISHED: |
| 828 | pr_debug("RDMA_CM_EVENT_ESTABLISHED >>>>>>>>>>>>>>\n"); | ||
| 829 | isert_connected_handler(cma_id); | 828 | isert_connected_handler(cma_id); |
| 830 | break; | 829 | break; |
| 831 | case RDMA_CM_EVENT_DISCONNECTED: | 830 | case RDMA_CM_EVENT_ADDR_CHANGE: /* FALLTHRU */ |
| 832 | pr_debug("RDMA_CM_EVENT_DISCONNECTED: >>>>>>>>>>>>>>\n"); | 831 | case RDMA_CM_EVENT_DISCONNECTED: /* FALLTHRU */ |
| 833 | isert_disconnected_handler(cma_id); | 832 | case RDMA_CM_EVENT_DEVICE_REMOVAL: /* FALLTHRU */ |
| 834 | break; | 833 | disconnect = true; |
| 835 | case RDMA_CM_EVENT_DEVICE_REMOVAL: | 834 | case RDMA_CM_EVENT_TIMEWAIT_EXIT: /* FALLTHRU */ |
| 836 | case RDMA_CM_EVENT_ADDR_CHANGE: | 835 | isert_disconnected_handler(cma_id, disconnect); |
| 837 | break; | 836 | break; |
| 838 | case RDMA_CM_EVENT_CONNECT_ERROR: | 837 | case RDMA_CM_EVENT_CONNECT_ERROR: |
| 839 | default: | 838 | default: |
| 840 | pr_err("Unknown RDMA CMA event: %d\n", event->event); | 839 | pr_err("Unhandled RDMA CMA event: %d\n", event->event); |
| 841 | break; | 840 | break; |
| 842 | } | 841 | } |
| 843 | 842 | ||
| @@ -1054,7 +1053,9 @@ isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login, | |||
| 1054 | } | 1053 | } |
| 1055 | if (!login->login_failed) { | 1054 | if (!login->login_failed) { |
| 1056 | if (login->login_complete) { | 1055 | if (login->login_complete) { |
| 1057 | if (isert_conn->conn_device->use_fastreg) { | 1056 | if (!conn->sess->sess_ops->SessionType && |
| 1057 | isert_conn->conn_device->use_fastreg) { | ||
| 1058 | /* Normal Session and fastreg is used */ | ||
| 1058 | u8 pi_support = login->np->tpg_np->tpg->tpg_attrib.t10_pi; | 1059 | u8 pi_support = login->np->tpg_np->tpg->tpg_attrib.t10_pi; |
| 1059 | 1060 | ||
| 1060 | ret = isert_conn_create_fastreg_pool(isert_conn, | 1061 | ret = isert_conn_create_fastreg_pool(isert_conn, |
| @@ -1824,11 +1825,8 @@ isert_do_control_comp(struct work_struct *work) | |||
| 1824 | break; | 1825 | break; |
| 1825 | case ISTATE_SEND_LOGOUTRSP: | 1826 | case ISTATE_SEND_LOGOUTRSP: |
| 1826 | pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n"); | 1827 | pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n"); |
| 1827 | /* | 1828 | |
| 1828 | * Call atomic_dec(&isert_conn->post_send_buf_count) | 1829 | atomic_dec(&isert_conn->post_send_buf_count); |
| 1829 | * from isert_wait_conn() | ||
| 1830 | */ | ||
| 1831 | isert_conn->logout_posted = true; | ||
| 1832 | iscsit_logout_post_handler(cmd, cmd->conn); | 1830 | iscsit_logout_post_handler(cmd, cmd->conn); |
| 1833 | break; | 1831 | break; |
| 1834 | case ISTATE_SEND_TEXTRSP: | 1832 | case ISTATE_SEND_TEXTRSP: |
| @@ -2034,6 +2032,8 @@ isert_cq_rx_comp_err(struct isert_conn *isert_conn) | |||
| 2034 | isert_conn->state = ISER_CONN_DOWN; | 2032 | isert_conn->state = ISER_CONN_DOWN; |
| 2035 | mutex_unlock(&isert_conn->conn_mutex); | 2033 | mutex_unlock(&isert_conn->conn_mutex); |
| 2036 | 2034 | ||
| 2035 | iscsit_cause_connection_reinstatement(isert_conn->conn, 0); | ||
| 2036 | |||
| 2037 | complete(&isert_conn->conn_wait_comp_err); | 2037 | complete(&isert_conn->conn_wait_comp_err); |
| 2038 | } | 2038 | } |
| 2039 | 2039 | ||
| @@ -2320,7 +2320,7 @@ isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn) | |||
| 2320 | int rc; | 2320 | int rc; |
| 2321 | 2321 | ||
| 2322 | isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); | 2322 | isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); |
| 2323 | rc = iscsit_build_text_rsp(cmd, conn, hdr); | 2323 | rc = iscsit_build_text_rsp(cmd, conn, hdr, ISCSI_INFINIBAND); |
| 2324 | if (rc < 0) | 2324 | if (rc < 0) |
| 2325 | return rc; | 2325 | return rc; |
| 2326 | 2326 | ||
| @@ -3156,9 +3156,14 @@ accept_wait: | |||
| 3156 | return -ENODEV; | 3156 | return -ENODEV; |
| 3157 | 3157 | ||
| 3158 | spin_lock_bh(&np->np_thread_lock); | 3158 | spin_lock_bh(&np->np_thread_lock); |
| 3159 | if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { | 3159 | if (np->np_thread_state >= ISCSI_NP_THREAD_RESET) { |
| 3160 | spin_unlock_bh(&np->np_thread_lock); | 3160 | spin_unlock_bh(&np->np_thread_lock); |
| 3161 | pr_debug("ISCSI_NP_THREAD_RESET for isert_accept_np\n"); | 3161 | pr_debug("np_thread_state %d for isert_accept_np\n", |
| 3162 | np->np_thread_state); | ||
| 3163 | /** | ||
| 3164 | * No point in stalling here when np_thread | ||
| 3165 | * is in state RESET/SHUTDOWN/EXIT - bail | ||
| 3166 | **/ | ||
| 3162 | return -ENODEV; | 3167 | return -ENODEV; |
| 3163 | } | 3168 | } |
| 3164 | spin_unlock_bh(&np->np_thread_lock); | 3169 | spin_unlock_bh(&np->np_thread_lock); |
| @@ -3208,15 +3213,9 @@ static void isert_wait_conn(struct iscsi_conn *conn) | |||
| 3208 | struct isert_conn *isert_conn = conn->context; | 3213 | struct isert_conn *isert_conn = conn->context; |
| 3209 | 3214 | ||
| 3210 | pr_debug("isert_wait_conn: Starting \n"); | 3215 | pr_debug("isert_wait_conn: Starting \n"); |
| 3211 | /* | ||
| 3212 | * Decrement post_send_buf_count for special case when called | ||
| 3213 | * from isert_do_control_comp() -> iscsit_logout_post_handler() | ||
| 3214 | */ | ||
| 3215 | mutex_lock(&isert_conn->conn_mutex); | ||
| 3216 | if (isert_conn->logout_posted) | ||
| 3217 | atomic_dec(&isert_conn->post_send_buf_count); | ||
| 3218 | 3216 | ||
| 3219 | if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) { | 3217 | mutex_lock(&isert_conn->conn_mutex); |
| 3218 | if (isert_conn->conn_cm_id) { | ||
| 3220 | pr_debug("Calling rdma_disconnect from isert_wait_conn\n"); | 3219 | pr_debug("Calling rdma_disconnect from isert_wait_conn\n"); |
| 3221 | rdma_disconnect(isert_conn->conn_cm_id); | 3220 | rdma_disconnect(isert_conn->conn_cm_id); |
| 3222 | } | 3221 | } |
| @@ -3293,6 +3292,7 @@ destroy_rx_wq: | |||
| 3293 | 3292 | ||
| 3294 | static void __exit isert_exit(void) | 3293 | static void __exit isert_exit(void) |
| 3295 | { | 3294 | { |
| 3295 | flush_scheduled_work(); | ||
| 3296 | destroy_workqueue(isert_comp_wq); | 3296 | destroy_workqueue(isert_comp_wq); |
| 3297 | destroy_workqueue(isert_rx_wq); | 3297 | destroy_workqueue(isert_rx_wq); |
| 3298 | iscsit_unregister_transport(&iser_target_transport); | 3298 | iscsit_unregister_transport(&iser_target_transport); |
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h index da6612e68000..04f51f7bf614 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.h +++ b/drivers/infiniband/ulp/isert/ib_isert.h | |||
| @@ -116,7 +116,6 @@ struct isert_device; | |||
| 116 | 116 | ||
| 117 | struct isert_conn { | 117 | struct isert_conn { |
| 118 | enum iser_conn_state state; | 118 | enum iser_conn_state state; |
| 119 | bool logout_posted; | ||
| 120 | int post_recv_buf_count; | 119 | int post_recv_buf_count; |
| 121 | atomic_t post_send_buf_count; | 120 | atomic_t post_send_buf_count; |
| 122 | u32 responder_resources; | 121 | u32 responder_resources; |
| @@ -151,6 +150,7 @@ struct isert_conn { | |||
| 151 | #define ISERT_COMP_BATCH_COUNT 8 | 150 | #define ISERT_COMP_BATCH_COUNT 8 |
| 152 | int conn_comp_batch; | 151 | int conn_comp_batch; |
| 153 | struct llist_head conn_comp_llist; | 152 | struct llist_head conn_comp_llist; |
| 153 | bool disconnect; | ||
| 154 | }; | 154 | }; |
| 155 | 155 | ||
| 156 | #define ISERT_MAX_CQ 64 | 156 | #define ISERT_MAX_CQ 64 |
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 02832d64d918..baca5897039f 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
| @@ -1773,6 +1773,7 @@ config SCSI_BFA_FC | |||
| 1773 | config SCSI_VIRTIO | 1773 | config SCSI_VIRTIO |
| 1774 | tristate "virtio-scsi support" | 1774 | tristate "virtio-scsi support" |
| 1775 | depends on VIRTIO | 1775 | depends on VIRTIO |
| 1776 | select BLK_DEV_INTEGRITY | ||
| 1776 | help | 1777 | help |
| 1777 | This is the virtual HBA driver for virtio. If the kernel will | 1778 | This is the virtual HBA driver for virtio. If the kernel will |
| 1778 | be used in a virtual machine, say Y or M. | 1779 | be used in a virtual machine, say Y or M. |
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index ecd7bd304efe..3d1bc67bac9d 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
| @@ -338,7 +338,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
| 338 | struct iscsi_session *session = conn->session; | 338 | struct iscsi_session *session = conn->session; |
| 339 | struct scsi_cmnd *sc = task->sc; | 339 | struct scsi_cmnd *sc = task->sc; |
| 340 | struct iscsi_scsi_req *hdr; | 340 | struct iscsi_scsi_req *hdr; |
| 341 | unsigned hdrlength, cmd_len; | 341 | unsigned hdrlength, cmd_len, transfer_length; |
| 342 | itt_t itt; | 342 | itt_t itt; |
| 343 | int rc; | 343 | int rc; |
| 344 | 344 | ||
| @@ -391,11 +391,11 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
| 391 | if (scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) | 391 | if (scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) |
| 392 | task->protected = true; | 392 | task->protected = true; |
| 393 | 393 | ||
| 394 | transfer_length = scsi_transfer_length(sc); | ||
| 395 | hdr->data_length = cpu_to_be32(transfer_length); | ||
| 394 | if (sc->sc_data_direction == DMA_TO_DEVICE) { | 396 | if (sc->sc_data_direction == DMA_TO_DEVICE) { |
| 395 | unsigned out_len = scsi_out(sc)->length; | ||
| 396 | struct iscsi_r2t_info *r2t = &task->unsol_r2t; | 397 | struct iscsi_r2t_info *r2t = &task->unsol_r2t; |
| 397 | 398 | ||
| 398 | hdr->data_length = cpu_to_be32(out_len); | ||
| 399 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; | 399 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; |
| 400 | /* | 400 | /* |
| 401 | * Write counters: | 401 | * Write counters: |
| @@ -414,18 +414,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
| 414 | memset(r2t, 0, sizeof(*r2t)); | 414 | memset(r2t, 0, sizeof(*r2t)); |
| 415 | 415 | ||
| 416 | if (session->imm_data_en) { | 416 | if (session->imm_data_en) { |
| 417 | if (out_len >= session->first_burst) | 417 | if (transfer_length >= session->first_burst) |
| 418 | task->imm_count = min(session->first_burst, | 418 | task->imm_count = min(session->first_burst, |
| 419 | conn->max_xmit_dlength); | 419 | conn->max_xmit_dlength); |
| 420 | else | 420 | else |
| 421 | task->imm_count = min(out_len, | 421 | task->imm_count = min(transfer_length, |
| 422 | conn->max_xmit_dlength); | 422 | conn->max_xmit_dlength); |
| 423 | hton24(hdr->dlength, task->imm_count); | 423 | hton24(hdr->dlength, task->imm_count); |
| 424 | } else | 424 | } else |
| 425 | zero_data(hdr->dlength); | 425 | zero_data(hdr->dlength); |
| 426 | 426 | ||
| 427 | if (!session->initial_r2t_en) { | 427 | if (!session->initial_r2t_en) { |
| 428 | r2t->data_length = min(session->first_burst, out_len) - | 428 | r2t->data_length = min(session->first_burst, |
| 429 | transfer_length) - | ||
| 429 | task->imm_count; | 430 | task->imm_count; |
| 430 | r2t->data_offset = task->imm_count; | 431 | r2t->data_offset = task->imm_count; |
| 431 | r2t->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); | 432 | r2t->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); |
| @@ -438,7 +439,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
| 438 | } else { | 439 | } else { |
| 439 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 440 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
| 440 | zero_data(hdr->dlength); | 441 | zero_data(hdr->dlength); |
| 441 | hdr->data_length = cpu_to_be32(scsi_in(sc)->length); | ||
| 442 | 442 | ||
| 443 | if (sc->sc_data_direction == DMA_FROM_DEVICE) | 443 | if (sc->sc_data_direction == DMA_FROM_DEVICE) |
| 444 | hdr->flags |= ISCSI_FLAG_CMD_READ; | 444 | hdr->flags |= ISCSI_FLAG_CMD_READ; |
| @@ -466,7 +466,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
| 466 | scsi_bidi_cmnd(sc) ? "bidirectional" : | 466 | scsi_bidi_cmnd(sc) ? "bidirectional" : |
| 467 | sc->sc_data_direction == DMA_TO_DEVICE ? | 467 | sc->sc_data_direction == DMA_TO_DEVICE ? |
| 468 | "write" : "read", conn->id, sc, sc->cmnd[0], | 468 | "write" : "read", conn->id, sc, sc->cmnd[0], |
| 469 | task->itt, scsi_bufflen(sc), | 469 | task->itt, transfer_length, |
| 470 | scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, | 470 | scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, |
| 471 | session->cmdsn, | 471 | session->cmdsn, |
| 472 | session->max_cmdsn - session->exp_cmdsn + 1); | 472 | session->max_cmdsn - session->exp_cmdsn + 1); |
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index b1d10f9935c7..8d85ed8d8917 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c | |||
| @@ -104,7 +104,6 @@ static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha, | |||
| 104 | /* | 104 | /* |
| 105 | * Global Variables | 105 | * Global Variables |
| 106 | */ | 106 | */ |
| 107 | static struct kmem_cache *qla_tgt_cmd_cachep; | ||
| 108 | static struct kmem_cache *qla_tgt_mgmt_cmd_cachep; | 107 | static struct kmem_cache *qla_tgt_mgmt_cmd_cachep; |
| 109 | static mempool_t *qla_tgt_mgmt_cmd_mempool; | 108 | static mempool_t *qla_tgt_mgmt_cmd_mempool; |
| 110 | static struct workqueue_struct *qla_tgt_wq; | 109 | static struct workqueue_struct *qla_tgt_wq; |
| @@ -2705,6 +2704,8 @@ done: | |||
| 2705 | 2704 | ||
| 2706 | void qlt_free_cmd(struct qla_tgt_cmd *cmd) | 2705 | void qlt_free_cmd(struct qla_tgt_cmd *cmd) |
| 2707 | { | 2706 | { |
| 2707 | struct qla_tgt_sess *sess = cmd->sess; | ||
| 2708 | |||
| 2708 | ql_dbg(ql_dbg_tgt, cmd->vha, 0xe074, | 2709 | ql_dbg(ql_dbg_tgt, cmd->vha, 0xe074, |
| 2709 | "%s: se_cmd[%p] ox_id %04x\n", | 2710 | "%s: se_cmd[%p] ox_id %04x\n", |
| 2710 | __func__, &cmd->se_cmd, | 2711 | __func__, &cmd->se_cmd, |
| @@ -2713,7 +2714,12 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd) | |||
| 2713 | BUG_ON(cmd->sg_mapped); | 2714 | BUG_ON(cmd->sg_mapped); |
| 2714 | if (unlikely(cmd->free_sg)) | 2715 | if (unlikely(cmd->free_sg)) |
| 2715 | kfree(cmd->sg); | 2716 | kfree(cmd->sg); |
| 2716 | kmem_cache_free(qla_tgt_cmd_cachep, cmd); | 2717 | |
| 2718 | if (!sess || !sess->se_sess) { | ||
| 2719 | WARN_ON(1); | ||
| 2720 | return; | ||
| 2721 | } | ||
| 2722 | percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag); | ||
| 2717 | } | 2723 | } |
| 2718 | EXPORT_SYMBOL(qlt_free_cmd); | 2724 | EXPORT_SYMBOL(qlt_free_cmd); |
| 2719 | 2725 | ||
| @@ -3075,13 +3081,12 @@ static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *, | |||
| 3075 | /* | 3081 | /* |
| 3076 | * Process context for I/O path into tcm_qla2xxx code | 3082 | * Process context for I/O path into tcm_qla2xxx code |
| 3077 | */ | 3083 | */ |
| 3078 | static void qlt_do_work(struct work_struct *work) | 3084 | static void __qlt_do_work(struct qla_tgt_cmd *cmd) |
| 3079 | { | 3085 | { |
| 3080 | struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); | ||
| 3081 | scsi_qla_host_t *vha = cmd->vha; | 3086 | scsi_qla_host_t *vha = cmd->vha; |
| 3082 | struct qla_hw_data *ha = vha->hw; | 3087 | struct qla_hw_data *ha = vha->hw; |
| 3083 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; | 3088 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; |
| 3084 | struct qla_tgt_sess *sess = NULL; | 3089 | struct qla_tgt_sess *sess = cmd->sess; |
| 3085 | struct atio_from_isp *atio = &cmd->atio; | 3090 | struct atio_from_isp *atio = &cmd->atio; |
| 3086 | unsigned char *cdb; | 3091 | unsigned char *cdb; |
| 3087 | unsigned long flags; | 3092 | unsigned long flags; |
| @@ -3091,41 +3096,6 @@ static void qlt_do_work(struct work_struct *work) | |||
| 3091 | if (tgt->tgt_stop) | 3096 | if (tgt->tgt_stop) |
| 3092 | goto out_term; | 3097 | goto out_term; |
| 3093 | 3098 | ||
| 3094 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
| 3095 | sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, | ||
| 3096 | atio->u.isp24.fcp_hdr.s_id); | ||
| 3097 | /* Do kref_get() before dropping qla_hw_data->hardware_lock. */ | ||
| 3098 | if (sess) | ||
| 3099 | kref_get(&sess->se_sess->sess_kref); | ||
| 3100 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
| 3101 | |||
| 3102 | if (unlikely(!sess)) { | ||
| 3103 | uint8_t *s_id = atio->u.isp24.fcp_hdr.s_id; | ||
| 3104 | |||
| 3105 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022, | ||
| 3106 | "qla_target(%d): Unable to find wwn login" | ||
| 3107 | " (s_id %x:%x:%x), trying to create it manually\n", | ||
| 3108 | vha->vp_idx, s_id[0], s_id[1], s_id[2]); | ||
| 3109 | |||
| 3110 | if (atio->u.raw.entry_count > 1) { | ||
| 3111 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023, | ||
| 3112 | "Dropping multy entry cmd %p\n", cmd); | ||
| 3113 | goto out_term; | ||
| 3114 | } | ||
| 3115 | |||
| 3116 | mutex_lock(&vha->vha_tgt.tgt_mutex); | ||
| 3117 | sess = qlt_make_local_sess(vha, s_id); | ||
| 3118 | /* sess has an extra creation ref. */ | ||
| 3119 | mutex_unlock(&vha->vha_tgt.tgt_mutex); | ||
| 3120 | |||
| 3121 | if (!sess) | ||
| 3122 | goto out_term; | ||
| 3123 | } | ||
| 3124 | |||
| 3125 | cmd->sess = sess; | ||
| 3126 | cmd->loop_id = sess->loop_id; | ||
| 3127 | cmd->conf_compl_supported = sess->conf_compl_supported; | ||
| 3128 | |||
| 3129 | cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; | 3099 | cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; |
| 3130 | cmd->tag = atio->u.isp24.exchange_addr; | 3100 | cmd->tag = atio->u.isp24.exchange_addr; |
| 3131 | cmd->unpacked_lun = scsilun_to_int( | 3101 | cmd->unpacked_lun = scsilun_to_int( |
| @@ -3153,8 +3123,8 @@ static void qlt_do_work(struct work_struct *work) | |||
| 3153 | cmd, &cmd->se_cmd, cmd->unpacked_lun, cmd->tag, data_length, | 3123 | cmd, &cmd->se_cmd, cmd->unpacked_lun, cmd->tag, data_length, |
| 3154 | cmd->atio.u.isp24.fcp_hdr.ox_id); | 3124 | cmd->atio.u.isp24.fcp_hdr.ox_id); |
| 3155 | 3125 | ||
| 3156 | ret = vha->hw->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length, | 3126 | ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length, |
| 3157 | fcp_task_attr, data_dir, bidi); | 3127 | fcp_task_attr, data_dir, bidi); |
| 3158 | if (ret != 0) | 3128 | if (ret != 0) |
| 3159 | goto out_term; | 3129 | goto out_term; |
| 3160 | /* | 3130 | /* |
| @@ -3173,17 +3143,114 @@ out_term: | |||
| 3173 | */ | 3143 | */ |
| 3174 | spin_lock_irqsave(&ha->hardware_lock, flags); | 3144 | spin_lock_irqsave(&ha->hardware_lock, flags); |
| 3175 | qlt_send_term_exchange(vha, NULL, &cmd->atio, 1); | 3145 | qlt_send_term_exchange(vha, NULL, &cmd->atio, 1); |
| 3176 | kmem_cache_free(qla_tgt_cmd_cachep, cmd); | 3146 | percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag); |
| 3177 | if (sess) | 3147 | ha->tgt.tgt_ops->put_sess(sess); |
| 3148 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
| 3149 | } | ||
| 3150 | |||
| 3151 | static void qlt_do_work(struct work_struct *work) | ||
| 3152 | { | ||
| 3153 | struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); | ||
| 3154 | |||
| 3155 | __qlt_do_work(cmd); | ||
| 3156 | } | ||
| 3157 | |||
| 3158 | static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha, | ||
| 3159 | struct qla_tgt_sess *sess, | ||
| 3160 | struct atio_from_isp *atio) | ||
| 3161 | { | ||
| 3162 | struct se_session *se_sess = sess->se_sess; | ||
| 3163 | struct qla_tgt_cmd *cmd; | ||
| 3164 | int tag; | ||
| 3165 | |||
| 3166 | tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); | ||
| 3167 | if (tag < 0) | ||
| 3168 | return NULL; | ||
| 3169 | |||
| 3170 | cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; | ||
| 3171 | memset(cmd, 0, sizeof(struct qla_tgt_cmd)); | ||
| 3172 | |||
| 3173 | memcpy(&cmd->atio, atio, sizeof(*atio)); | ||
| 3174 | cmd->state = QLA_TGT_STATE_NEW; | ||
| 3175 | cmd->tgt = vha->vha_tgt.qla_tgt; | ||
| 3176 | cmd->vha = vha; | ||
| 3177 | cmd->se_cmd.map_tag = tag; | ||
| 3178 | cmd->sess = sess; | ||
| 3179 | cmd->loop_id = sess->loop_id; | ||
| 3180 | cmd->conf_compl_supported = sess->conf_compl_supported; | ||
| 3181 | |||
| 3182 | return cmd; | ||
| 3183 | } | ||
| 3184 | |||
| 3185 | static void qlt_send_busy(struct scsi_qla_host *, struct atio_from_isp *, | ||
| 3186 | uint16_t); | ||
| 3187 | |||
| 3188 | static void qlt_create_sess_from_atio(struct work_struct *work) | ||
| 3189 | { | ||
| 3190 | struct qla_tgt_sess_op *op = container_of(work, | ||
| 3191 | struct qla_tgt_sess_op, work); | ||
| 3192 | scsi_qla_host_t *vha = op->vha; | ||
| 3193 | struct qla_hw_data *ha = vha->hw; | ||
| 3194 | struct qla_tgt_sess *sess; | ||
| 3195 | struct qla_tgt_cmd *cmd; | ||
| 3196 | unsigned long flags; | ||
| 3197 | uint8_t *s_id = op->atio.u.isp24.fcp_hdr.s_id; | ||
| 3198 | |||
| 3199 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022, | ||
| 3200 | "qla_target(%d): Unable to find wwn login" | ||
| 3201 | " (s_id %x:%x:%x), trying to create it manually\n", | ||
| 3202 | vha->vp_idx, s_id[0], s_id[1], s_id[2]); | ||
| 3203 | |||
| 3204 | if (op->atio.u.raw.entry_count > 1) { | ||
| 3205 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023, | ||
| 3206 | "Dropping multy entry atio %p\n", &op->atio); | ||
| 3207 | goto out_term; | ||
| 3208 | } | ||
| 3209 | |||
| 3210 | mutex_lock(&vha->vha_tgt.tgt_mutex); | ||
| 3211 | sess = qlt_make_local_sess(vha, s_id); | ||
| 3212 | /* sess has an extra creation ref. */ | ||
| 3213 | mutex_unlock(&vha->vha_tgt.tgt_mutex); | ||
| 3214 | |||
| 3215 | if (!sess) | ||
| 3216 | goto out_term; | ||
| 3217 | /* | ||
| 3218 | * Now obtain a pre-allocated session tag using the original op->atio | ||
| 3219 | * packet header, and dispatch into __qlt_do_work() using the existing | ||
| 3220 | * process context. | ||
| 3221 | */ | ||
| 3222 | cmd = qlt_get_tag(vha, sess, &op->atio); | ||
| 3223 | if (!cmd) { | ||
| 3224 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
| 3225 | qlt_send_busy(vha, &op->atio, SAM_STAT_BUSY); | ||
| 3178 | ha->tgt.tgt_ops->put_sess(sess); | 3226 | ha->tgt.tgt_ops->put_sess(sess); |
| 3227 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
| 3228 | kfree(op); | ||
| 3229 | return; | ||
| 3230 | } | ||
| 3231 | /* | ||
| 3232 | * __qlt_do_work() will call ha->tgt.tgt_ops->put_sess() to release | ||
| 3233 | * the extra reference taken above by qlt_make_local_sess() | ||
| 3234 | */ | ||
| 3235 | __qlt_do_work(cmd); | ||
| 3236 | kfree(op); | ||
| 3237 | return; | ||
| 3238 | |||
| 3239 | out_term: | ||
| 3240 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
| 3241 | qlt_send_term_exchange(vha, NULL, &op->atio, 1); | ||
| 3179 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 3242 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
| 3243 | kfree(op); | ||
| 3244 | |||
| 3180 | } | 3245 | } |
| 3181 | 3246 | ||
| 3182 | /* ha->hardware_lock supposed to be held on entry */ | 3247 | /* ha->hardware_lock supposed to be held on entry */ |
| 3183 | static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, | 3248 | static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, |
| 3184 | struct atio_from_isp *atio) | 3249 | struct atio_from_isp *atio) |
| 3185 | { | 3250 | { |
| 3251 | struct qla_hw_data *ha = vha->hw; | ||
| 3186 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; | 3252 | struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; |
| 3253 | struct qla_tgt_sess *sess; | ||
| 3187 | struct qla_tgt_cmd *cmd; | 3254 | struct qla_tgt_cmd *cmd; |
| 3188 | 3255 | ||
| 3189 | if (unlikely(tgt->tgt_stop)) { | 3256 | if (unlikely(tgt->tgt_stop)) { |
| @@ -3192,18 +3259,31 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, | |||
| 3192 | return -EFAULT; | 3259 | return -EFAULT; |
| 3193 | } | 3260 | } |
| 3194 | 3261 | ||
| 3195 | cmd = kmem_cache_zalloc(qla_tgt_cmd_cachep, GFP_ATOMIC); | 3262 | sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id); |
| 3263 | if (unlikely(!sess)) { | ||
| 3264 | struct qla_tgt_sess_op *op = kzalloc(sizeof(struct qla_tgt_sess_op), | ||
| 3265 | GFP_ATOMIC); | ||
| 3266 | if (!op) | ||
| 3267 | return -ENOMEM; | ||
| 3268 | |||
| 3269 | memcpy(&op->atio, atio, sizeof(*atio)); | ||
| 3270 | INIT_WORK(&op->work, qlt_create_sess_from_atio); | ||
| 3271 | queue_work(qla_tgt_wq, &op->work); | ||
| 3272 | return 0; | ||
| 3273 | } | ||
| 3274 | /* | ||
| 3275 | * Do kref_get() before returning + dropping qla_hw_data->hardware_lock. | ||
| 3276 | */ | ||
| 3277 | kref_get(&sess->se_sess->sess_kref); | ||
| 3278 | |||
| 3279 | cmd = qlt_get_tag(vha, sess, atio); | ||
| 3196 | if (!cmd) { | 3280 | if (!cmd) { |
| 3197 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05e, | 3281 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05e, |
| 3198 | "qla_target(%d): Allocation of cmd failed\n", vha->vp_idx); | 3282 | "qla_target(%d): Allocation of cmd failed\n", vha->vp_idx); |
| 3283 | ha->tgt.tgt_ops->put_sess(sess); | ||
| 3199 | return -ENOMEM; | 3284 | return -ENOMEM; |
| 3200 | } | 3285 | } |
| 3201 | 3286 | ||
| 3202 | memcpy(&cmd->atio, atio, sizeof(*atio)); | ||
| 3203 | cmd->state = QLA_TGT_STATE_NEW; | ||
| 3204 | cmd->tgt = vha->vha_tgt.qla_tgt; | ||
| 3205 | cmd->vha = vha; | ||
| 3206 | |||
| 3207 | INIT_WORK(&cmd->work, qlt_do_work); | 3287 | INIT_WORK(&cmd->work, qlt_do_work); |
| 3208 | queue_work(qla_tgt_wq, &cmd->work); | 3288 | queue_work(qla_tgt_wq, &cmd->work); |
| 3209 | return 0; | 3289 | return 0; |
| @@ -5501,23 +5581,13 @@ int __init qlt_init(void) | |||
| 5501 | if (!QLA_TGT_MODE_ENABLED()) | 5581 | if (!QLA_TGT_MODE_ENABLED()) |
| 5502 | return 0; | 5582 | return 0; |
| 5503 | 5583 | ||
| 5504 | qla_tgt_cmd_cachep = kmem_cache_create("qla_tgt_cmd_cachep", | ||
| 5505 | sizeof(struct qla_tgt_cmd), __alignof__(struct qla_tgt_cmd), 0, | ||
| 5506 | NULL); | ||
| 5507 | if (!qla_tgt_cmd_cachep) { | ||
| 5508 | ql_log(ql_log_fatal, NULL, 0xe06c, | ||
| 5509 | "kmem_cache_create for qla_tgt_cmd_cachep failed\n"); | ||
| 5510 | return -ENOMEM; | ||
| 5511 | } | ||
| 5512 | |||
| 5513 | qla_tgt_mgmt_cmd_cachep = kmem_cache_create("qla_tgt_mgmt_cmd_cachep", | 5584 | qla_tgt_mgmt_cmd_cachep = kmem_cache_create("qla_tgt_mgmt_cmd_cachep", |
| 5514 | sizeof(struct qla_tgt_mgmt_cmd), __alignof__(struct | 5585 | sizeof(struct qla_tgt_mgmt_cmd), __alignof__(struct |
| 5515 | qla_tgt_mgmt_cmd), 0, NULL); | 5586 | qla_tgt_mgmt_cmd), 0, NULL); |
| 5516 | if (!qla_tgt_mgmt_cmd_cachep) { | 5587 | if (!qla_tgt_mgmt_cmd_cachep) { |
| 5517 | ql_log(ql_log_fatal, NULL, 0xe06d, | 5588 | ql_log(ql_log_fatal, NULL, 0xe06d, |
| 5518 | "kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n"); | 5589 | "kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n"); |
| 5519 | ret = -ENOMEM; | 5590 | return -ENOMEM; |
| 5520 | goto out; | ||
| 5521 | } | 5591 | } |
| 5522 | 5592 | ||
| 5523 | qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab, | 5593 | qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab, |
| @@ -5545,8 +5615,6 @@ out_cmd_mempool: | |||
| 5545 | mempool_destroy(qla_tgt_mgmt_cmd_mempool); | 5615 | mempool_destroy(qla_tgt_mgmt_cmd_mempool); |
| 5546 | out_mgmt_cmd_cachep: | 5616 | out_mgmt_cmd_cachep: |
| 5547 | kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); | 5617 | kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); |
| 5548 | out: | ||
| 5549 | kmem_cache_destroy(qla_tgt_cmd_cachep); | ||
| 5550 | return ret; | 5618 | return ret; |
| 5551 | } | 5619 | } |
| 5552 | 5620 | ||
| @@ -5558,5 +5626,4 @@ void qlt_exit(void) | |||
| 5558 | destroy_workqueue(qla_tgt_wq); | 5626 | destroy_workqueue(qla_tgt_wq); |
| 5559 | mempool_destroy(qla_tgt_mgmt_cmd_mempool); | 5627 | mempool_destroy(qla_tgt_mgmt_cmd_mempool); |
| 5560 | kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); | 5628 | kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); |
| 5561 | kmem_cache_destroy(qla_tgt_cmd_cachep); | ||
| 5562 | } | 5629 | } |
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index f873e10451d2..5c9f185a8ebd 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h | |||
| @@ -870,6 +870,12 @@ struct qla_tgt { | |||
| 870 | struct list_head tgt_list_entry; | 870 | struct list_head tgt_list_entry; |
| 871 | }; | 871 | }; |
| 872 | 872 | ||
| 873 | struct qla_tgt_sess_op { | ||
| 874 | struct scsi_qla_host *vha; | ||
| 875 | struct atio_from_isp atio; | ||
| 876 | struct work_struct work; | ||
| 877 | }; | ||
| 878 | |||
| 873 | /* | 879 | /* |
| 874 | * Equivilant to IT Nexus (Initiator-Target) | 880 | * Equivilant to IT Nexus (Initiator-Target) |
| 875 | */ | 881 | */ |
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 896cb23adb77..e2beab962096 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c | |||
| @@ -1501,6 +1501,8 @@ static int tcm_qla2xxx_check_initiator_node_acl( | |||
| 1501 | struct qla_tgt_sess *sess = qla_tgt_sess; | 1501 | struct qla_tgt_sess *sess = qla_tgt_sess; |
| 1502 | unsigned char port_name[36]; | 1502 | unsigned char port_name[36]; |
| 1503 | unsigned long flags; | 1503 | unsigned long flags; |
| 1504 | int num_tags = (ha->fw_xcb_count) ? ha->fw_xcb_count : | ||
| 1505 | TCM_QLA2XXX_DEFAULT_TAGS; | ||
| 1504 | 1506 | ||
| 1505 | lport = vha->vha_tgt.target_lport_ptr; | 1507 | lport = vha->vha_tgt.target_lport_ptr; |
| 1506 | if (!lport) { | 1508 | if (!lport) { |
| @@ -1518,7 +1520,9 @@ static int tcm_qla2xxx_check_initiator_node_acl( | |||
| 1518 | } | 1520 | } |
| 1519 | se_tpg = &tpg->se_tpg; | 1521 | se_tpg = &tpg->se_tpg; |
| 1520 | 1522 | ||
| 1521 | se_sess = transport_init_session(TARGET_PROT_NORMAL); | 1523 | se_sess = transport_init_session_tags(num_tags, |
| 1524 | sizeof(struct qla_tgt_cmd), | ||
| 1525 | TARGET_PROT_NORMAL); | ||
| 1522 | if (IS_ERR(se_sess)) { | 1526 | if (IS_ERR(se_sess)) { |
| 1523 | pr_err("Unable to initialize struct se_session\n"); | 1527 | pr_err("Unable to initialize struct se_session\n"); |
| 1524 | return PTR_ERR(se_sess); | 1528 | return PTR_ERR(se_sess); |
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h index 33aaac8c7d59..10c002145648 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h | |||
| @@ -4,6 +4,11 @@ | |||
| 4 | #define TCM_QLA2XXX_VERSION "v0.1" | 4 | #define TCM_QLA2XXX_VERSION "v0.1" |
| 5 | /* length of ASCII WWPNs including pad */ | 5 | /* length of ASCII WWPNs including pad */ |
| 6 | #define TCM_QLA2XXX_NAMELEN 32 | 6 | #define TCM_QLA2XXX_NAMELEN 32 |
| 7 | /* | ||
| 8 | * Number of pre-allocated per-session tags, based upon the worst-case | ||
| 9 | * per port number of iocbs | ||
| 10 | */ | ||
| 11 | #define TCM_QLA2XXX_DEFAULT_TAGS 2088 | ||
| 7 | 12 | ||
| 8 | #include "qla_target.h" | 13 | #include "qla_target.h" |
| 9 | 14 | ||
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 99fdb9403944..89ee5929eb6d 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/virtio_config.h> | 23 | #include <linux/virtio_config.h> |
| 24 | #include <linux/virtio_scsi.h> | 24 | #include <linux/virtio_scsi.h> |
| 25 | #include <linux/cpu.h> | 25 | #include <linux/cpu.h> |
| 26 | #include <linux/blkdev.h> | ||
| 26 | #include <scsi/scsi_host.h> | 27 | #include <scsi/scsi_host.h> |
| 27 | #include <scsi/scsi_device.h> | 28 | #include <scsi/scsi_device.h> |
| 28 | #include <scsi/scsi_cmnd.h> | 29 | #include <scsi/scsi_cmnd.h> |
| @@ -37,6 +38,7 @@ struct virtio_scsi_cmd { | |||
| 37 | struct completion *comp; | 38 | struct completion *comp; |
| 38 | union { | 39 | union { |
| 39 | struct virtio_scsi_cmd_req cmd; | 40 | struct virtio_scsi_cmd_req cmd; |
| 41 | struct virtio_scsi_cmd_req_pi cmd_pi; | ||
| 40 | struct virtio_scsi_ctrl_tmf_req tmf; | 42 | struct virtio_scsi_ctrl_tmf_req tmf; |
| 41 | struct virtio_scsi_ctrl_an_req an; | 43 | struct virtio_scsi_ctrl_an_req an; |
| 42 | } req; | 44 | } req; |
| @@ -399,7 +401,7 @@ static int virtscsi_add_cmd(struct virtqueue *vq, | |||
| 399 | size_t req_size, size_t resp_size) | 401 | size_t req_size, size_t resp_size) |
| 400 | { | 402 | { |
| 401 | struct scsi_cmnd *sc = cmd->sc; | 403 | struct scsi_cmnd *sc = cmd->sc; |
| 402 | struct scatterlist *sgs[4], req, resp; | 404 | struct scatterlist *sgs[6], req, resp; |
| 403 | struct sg_table *out, *in; | 405 | struct sg_table *out, *in; |
| 404 | unsigned out_num = 0, in_num = 0; | 406 | unsigned out_num = 0, in_num = 0; |
| 405 | 407 | ||
| @@ -417,16 +419,24 @@ static int virtscsi_add_cmd(struct virtqueue *vq, | |||
| 417 | sgs[out_num++] = &req; | 419 | sgs[out_num++] = &req; |
| 418 | 420 | ||
| 419 | /* Data-out buffer. */ | 421 | /* Data-out buffer. */ |
| 420 | if (out) | 422 | if (out) { |
| 423 | /* Place WRITE protection SGLs before Data OUT payload */ | ||
| 424 | if (scsi_prot_sg_count(sc)) | ||
| 425 | sgs[out_num++] = scsi_prot_sglist(sc); | ||
| 421 | sgs[out_num++] = out->sgl; | 426 | sgs[out_num++] = out->sgl; |
| 427 | } | ||
| 422 | 428 | ||
| 423 | /* Response header. */ | 429 | /* Response header. */ |
| 424 | sg_init_one(&resp, &cmd->resp, resp_size); | 430 | sg_init_one(&resp, &cmd->resp, resp_size); |
| 425 | sgs[out_num + in_num++] = &resp; | 431 | sgs[out_num + in_num++] = &resp; |
| 426 | 432 | ||
| 427 | /* Data-in buffer */ | 433 | /* Data-in buffer */ |
| 428 | if (in) | 434 | if (in) { |
| 435 | /* Place READ protection SGLs before Data IN payload */ | ||
| 436 | if (scsi_prot_sg_count(sc)) | ||
| 437 | sgs[out_num + in_num++] = scsi_prot_sglist(sc); | ||
| 429 | sgs[out_num + in_num++] = in->sgl; | 438 | sgs[out_num + in_num++] = in->sgl; |
| 439 | } | ||
| 430 | 440 | ||
| 431 | return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_ATOMIC); | 441 | return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_ATOMIC); |
| 432 | } | 442 | } |
| @@ -451,12 +461,45 @@ static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq, | |||
| 451 | return err; | 461 | return err; |
| 452 | } | 462 | } |
| 453 | 463 | ||
| 464 | static void virtio_scsi_init_hdr(struct virtio_scsi_cmd_req *cmd, | ||
| 465 | struct scsi_cmnd *sc) | ||
| 466 | { | ||
| 467 | cmd->lun[0] = 1; | ||
| 468 | cmd->lun[1] = sc->device->id; | ||
| 469 | cmd->lun[2] = (sc->device->lun >> 8) | 0x40; | ||
| 470 | cmd->lun[3] = sc->device->lun & 0xff; | ||
| 471 | cmd->tag = (unsigned long)sc; | ||
| 472 | cmd->task_attr = VIRTIO_SCSI_S_SIMPLE; | ||
| 473 | cmd->prio = 0; | ||
| 474 | cmd->crn = 0; | ||
| 475 | } | ||
| 476 | |||
| 477 | static void virtio_scsi_init_hdr_pi(struct virtio_scsi_cmd_req_pi *cmd_pi, | ||
| 478 | struct scsi_cmnd *sc) | ||
| 479 | { | ||
| 480 | struct request *rq = sc->request; | ||
| 481 | struct blk_integrity *bi; | ||
| 482 | |||
| 483 | virtio_scsi_init_hdr((struct virtio_scsi_cmd_req *)cmd_pi, sc); | ||
| 484 | |||
| 485 | if (!rq || !scsi_prot_sg_count(sc)) | ||
| 486 | return; | ||
| 487 | |||
| 488 | bi = blk_get_integrity(rq->rq_disk); | ||
| 489 | |||
| 490 | if (sc->sc_data_direction == DMA_TO_DEVICE) | ||
| 491 | cmd_pi->pi_bytesout = blk_rq_sectors(rq) * bi->tuple_size; | ||
| 492 | else if (sc->sc_data_direction == DMA_FROM_DEVICE) | ||
| 493 | cmd_pi->pi_bytesin = blk_rq_sectors(rq) * bi->tuple_size; | ||
| 494 | } | ||
| 495 | |||
| 454 | static int virtscsi_queuecommand(struct virtio_scsi *vscsi, | 496 | static int virtscsi_queuecommand(struct virtio_scsi *vscsi, |
| 455 | struct virtio_scsi_vq *req_vq, | 497 | struct virtio_scsi_vq *req_vq, |
| 456 | struct scsi_cmnd *sc) | 498 | struct scsi_cmnd *sc) |
| 457 | { | 499 | { |
| 458 | struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); | 500 | struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); |
| 459 | struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc); | 501 | struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc); |
| 502 | int req_size; | ||
| 460 | 503 | ||
| 461 | BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize); | 504 | BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize); |
| 462 | 505 | ||
| @@ -468,22 +511,20 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi, | |||
| 468 | 511 | ||
| 469 | memset(cmd, 0, sizeof(*cmd)); | 512 | memset(cmd, 0, sizeof(*cmd)); |
| 470 | cmd->sc = sc; | 513 | cmd->sc = sc; |
| 471 | cmd->req.cmd = (struct virtio_scsi_cmd_req){ | ||
| 472 | .lun[0] = 1, | ||
| 473 | .lun[1] = sc->device->id, | ||
| 474 | .lun[2] = (sc->device->lun >> 8) | 0x40, | ||
| 475 | .lun[3] = sc->device->lun & 0xff, | ||
| 476 | .tag = (unsigned long)sc, | ||
| 477 | .task_attr = VIRTIO_SCSI_S_SIMPLE, | ||
| 478 | .prio = 0, | ||
| 479 | .crn = 0, | ||
| 480 | }; | ||
| 481 | 514 | ||
| 482 | BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE); | 515 | BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE); |
| 483 | memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len); | ||
| 484 | 516 | ||
| 485 | if (virtscsi_kick_cmd(req_vq, cmd, | 517 | if (virtio_has_feature(vscsi->vdev, VIRTIO_SCSI_F_T10_PI)) { |
| 486 | sizeof cmd->req.cmd, sizeof cmd->resp.cmd) != 0) | 518 | virtio_scsi_init_hdr_pi(&cmd->req.cmd_pi, sc); |
| 519 | memcpy(cmd->req.cmd_pi.cdb, sc->cmnd, sc->cmd_len); | ||
| 520 | req_size = sizeof(cmd->req.cmd_pi); | ||
| 521 | } else { | ||
| 522 | virtio_scsi_init_hdr(&cmd->req.cmd, sc); | ||
| 523 | memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len); | ||
| 524 | req_size = sizeof(cmd->req.cmd); | ||
| 525 | } | ||
| 526 | |||
| 527 | if (virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)) != 0) | ||
| 487 | return SCSI_MLQUEUE_HOST_BUSY; | 528 | return SCSI_MLQUEUE_HOST_BUSY; |
| 488 | return 0; | 529 | return 0; |
| 489 | } | 530 | } |
| @@ -820,7 +861,7 @@ static int virtscsi_probe(struct virtio_device *vdev) | |||
| 820 | { | 861 | { |
| 821 | struct Scsi_Host *shost; | 862 | struct Scsi_Host *shost; |
| 822 | struct virtio_scsi *vscsi; | 863 | struct virtio_scsi *vscsi; |
| 823 | int err; | 864 | int err, host_prot; |
| 824 | u32 sg_elems, num_targets; | 865 | u32 sg_elems, num_targets; |
| 825 | u32 cmd_per_lun; | 866 | u32 cmd_per_lun; |
| 826 | u32 num_queues; | 867 | u32 num_queues; |
| @@ -870,6 +911,16 @@ static int virtscsi_probe(struct virtio_device *vdev) | |||
| 870 | shost->max_id = num_targets; | 911 | shost->max_id = num_targets; |
| 871 | shost->max_channel = 0; | 912 | shost->max_channel = 0; |
| 872 | shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE; | 913 | shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE; |
| 914 | |||
| 915 | if (virtio_has_feature(vdev, VIRTIO_SCSI_F_T10_PI)) { | ||
| 916 | host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION | | ||
| 917 | SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION | | ||
| 918 | SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION; | ||
| 919 | |||
| 920 | scsi_host_set_prot(shost, host_prot); | ||
| 921 | scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); | ||
| 922 | } | ||
| 923 | |||
| 873 | err = scsi_add_host(shost, &vdev->dev); | 924 | err = scsi_add_host(shost, &vdev->dev); |
| 874 | if (err) | 925 | if (err) |
| 875 | goto scsi_add_host_failed; | 926 | goto scsi_add_host_failed; |
| @@ -939,6 +990,7 @@ static struct virtio_device_id id_table[] = { | |||
| 939 | static unsigned int features[] = { | 990 | static unsigned int features[] = { |
| 940 | VIRTIO_SCSI_F_HOTPLUG, | 991 | VIRTIO_SCSI_F_HOTPLUG, |
| 941 | VIRTIO_SCSI_F_CHANGE, | 992 | VIRTIO_SCSI_F_CHANGE, |
| 993 | VIRTIO_SCSI_F_T10_PI, | ||
| 942 | }; | 994 | }; |
| 943 | 995 | ||
| 944 | static struct virtio_driver virtio_scsi_driver = { | 996 | static struct virtio_driver virtio_scsi_driver = { |
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 9189bc0a87ae..5663f4d19d02 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
| @@ -300,7 +300,7 @@ bool iscsit_check_np_match( | |||
| 300 | port = ntohs(sock_in->sin_port); | 300 | port = ntohs(sock_in->sin_port); |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | if ((ip_match == true) && (np->np_port == port) && | 303 | if (ip_match && (np->np_port == port) && |
| 304 | (np->np_network_transport == network_transport)) | 304 | (np->np_network_transport == network_transport)) |
| 305 | return true; | 305 | return true; |
| 306 | 306 | ||
| @@ -325,7 +325,7 @@ static struct iscsi_np *iscsit_get_np( | |||
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | match = iscsit_check_np_match(sockaddr, np, network_transport); | 327 | match = iscsit_check_np_match(sockaddr, np, network_transport); |
| 328 | if (match == true) { | 328 | if (match) { |
| 329 | /* | 329 | /* |
| 330 | * Increment the np_exports reference count now to | 330 | * Increment the np_exports reference count now to |
| 331 | * prevent iscsit_del_np() below from being called | 331 | * 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, | |||
| 1121 | /* | 1121 | /* |
| 1122 | * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. | 1122 | * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. |
| 1123 | */ | 1123 | */ |
| 1124 | if (dump_payload == true) | 1124 | if (dump_payload) |
| 1125 | goto after_immediate_data; | 1125 | goto after_immediate_data; |
| 1126 | 1126 | ||
| 1127 | immed_ret = iscsit_handle_immediate_data(cmd, hdr, | 1127 | immed_ret = iscsit_handle_immediate_data(cmd, hdr, |
| @@ -3390,7 +3390,9 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np) | |||
| 3390 | 3390 | ||
| 3391 | #define SENDTARGETS_BUF_LIMIT 32768U | 3391 | #define SENDTARGETS_BUF_LIMIT 32768U |
| 3392 | 3392 | ||
| 3393 | static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) | 3393 | static int |
| 3394 | iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, | ||
| 3395 | enum iscsit_transport_type network_transport) | ||
| 3394 | { | 3396 | { |
| 3395 | char *payload = NULL; | 3397 | char *payload = NULL; |
| 3396 | struct iscsi_conn *conn = cmd->conn; | 3398 | struct iscsi_conn *conn = cmd->conn; |
| @@ -3467,6 +3469,9 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) | |||
| 3467 | struct iscsi_np *np = tpg_np->tpg_np; | 3469 | struct iscsi_np *np = tpg_np->tpg_np; |
| 3468 | bool inaddr_any = iscsit_check_inaddr_any(np); | 3470 | bool inaddr_any = iscsit_check_inaddr_any(np); |
| 3469 | 3471 | ||
| 3472 | if (np->np_network_transport != network_transport) | ||
| 3473 | continue; | ||
| 3474 | |||
| 3470 | if (!target_name_printed) { | 3475 | if (!target_name_printed) { |
| 3471 | len = sprintf(buf, "TargetName=%s", | 3476 | len = sprintf(buf, "TargetName=%s", |
| 3472 | tiqn->tiqn); | 3477 | tiqn->tiqn); |
| @@ -3485,10 +3490,8 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) | |||
| 3485 | 3490 | ||
| 3486 | len = sprintf(buf, "TargetAddress=" | 3491 | len = sprintf(buf, "TargetAddress=" |
| 3487 | "%s:%hu,%hu", | 3492 | "%s:%hu,%hu", |
| 3488 | (inaddr_any == false) ? | 3493 | inaddr_any ? conn->local_ip : np->np_ip, |
| 3489 | np->np_ip : conn->local_ip, | 3494 | inaddr_any ? conn->local_port : np->np_port, |
| 3490 | (inaddr_any == false) ? | ||
| 3491 | np->np_port : conn->local_port, | ||
| 3492 | tpg->tpgt); | 3495 | tpg->tpgt); |
| 3493 | len += 1; | 3496 | len += 1; |
| 3494 | 3497 | ||
| @@ -3520,11 +3523,12 @@ eob: | |||
| 3520 | 3523 | ||
| 3521 | int | 3524 | int |
| 3522 | iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, | 3525 | iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, |
| 3523 | struct iscsi_text_rsp *hdr) | 3526 | struct iscsi_text_rsp *hdr, |
| 3527 | enum iscsit_transport_type network_transport) | ||
| 3524 | { | 3528 | { |
| 3525 | int text_length, padding; | 3529 | int text_length, padding; |
| 3526 | 3530 | ||
| 3527 | text_length = iscsit_build_sendtargets_response(cmd); | 3531 | text_length = iscsit_build_sendtargets_response(cmd, network_transport); |
| 3528 | if (text_length < 0) | 3532 | if (text_length < 0) |
| 3529 | return text_length; | 3533 | return text_length; |
| 3530 | 3534 | ||
| @@ -3562,7 +3566,7 @@ static int iscsit_send_text_rsp( | |||
| 3562 | u32 tx_size = 0; | 3566 | u32 tx_size = 0; |
| 3563 | int text_length, iov_count = 0, rc; | 3567 | int text_length, iov_count = 0, rc; |
| 3564 | 3568 | ||
| 3565 | rc = iscsit_build_text_rsp(cmd, conn, hdr); | 3569 | rc = iscsit_build_text_rsp(cmd, conn, hdr, ISCSI_TCP); |
| 3566 | if (rc < 0) | 3570 | if (rc < 0) |
| 3567 | return rc; | 3571 | return rc; |
| 3568 | 3572 | ||
| @@ -4234,8 +4238,6 @@ int iscsit_close_connection( | |||
| 4234 | if (conn->conn_transport->iscsit_wait_conn) | 4238 | if (conn->conn_transport->iscsit_wait_conn) |
| 4235 | conn->conn_transport->iscsit_wait_conn(conn); | 4239 | conn->conn_transport->iscsit_wait_conn(conn); |
| 4236 | 4240 | ||
| 4237 | iscsit_free_queue_reqs_for_conn(conn); | ||
| 4238 | |||
| 4239 | /* | 4241 | /* |
| 4240 | * During Connection recovery drop unacknowledged out of order | 4242 | * During Connection recovery drop unacknowledged out of order |
| 4241 | * commands for this connection, and prepare the other commands | 4243 | * commands for this connection, and prepare the other commands |
| @@ -4252,6 +4254,7 @@ int iscsit_close_connection( | |||
| 4252 | iscsit_clear_ooo_cmdsns_for_conn(conn); | 4254 | iscsit_clear_ooo_cmdsns_for_conn(conn); |
| 4253 | iscsit_release_commands_from_conn(conn); | 4255 | iscsit_release_commands_from_conn(conn); |
| 4254 | } | 4256 | } |
| 4257 | iscsit_free_queue_reqs_for_conn(conn); | ||
| 4255 | 4258 | ||
| 4256 | /* | 4259 | /* |
| 4257 | * Handle decrementing session or connection usage count if | 4260 | * Handle decrementing session or connection usage count if |
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index de77d9aa22c6..19b842c3e0b3 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c | |||
| @@ -71,6 +71,40 @@ static void chap_gen_challenge( | |||
| 71 | challenge_asciihex); | 71 | challenge_asciihex); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static int chap_check_algorithm(const char *a_str) | ||
| 75 | { | ||
| 76 | char *tmp, *orig, *token; | ||
| 77 | |||
| 78 | tmp = kstrdup(a_str, GFP_KERNEL); | ||
| 79 | if (!tmp) { | ||
| 80 | pr_err("Memory allocation failed for CHAP_A temporary buffer\n"); | ||
| 81 | return CHAP_DIGEST_UNKNOWN; | ||
| 82 | } | ||
| 83 | orig = tmp; | ||
| 84 | |||
| 85 | token = strsep(&tmp, "="); | ||
| 86 | if (!token) | ||
| 87 | goto out; | ||
| 88 | |||
| 89 | if (strcmp(token, "CHAP_A")) { | ||
| 90 | pr_err("Unable to locate CHAP_A key\n"); | ||
| 91 | goto out; | ||
| 92 | } | ||
| 93 | while (token) { | ||
| 94 | token = strsep(&tmp, ","); | ||
| 95 | if (!token) | ||
| 96 | goto out; | ||
| 97 | |||
| 98 | if (!strncmp(token, "5", 1)) { | ||
| 99 | pr_debug("Selected MD5 Algorithm\n"); | ||
| 100 | kfree(orig); | ||
| 101 | return CHAP_DIGEST_MD5; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | out: | ||
| 105 | kfree(orig); | ||
| 106 | return CHAP_DIGEST_UNKNOWN; | ||
| 107 | } | ||
| 74 | 108 | ||
| 75 | static struct iscsi_chap *chap_server_open( | 109 | static struct iscsi_chap *chap_server_open( |
| 76 | struct iscsi_conn *conn, | 110 | struct iscsi_conn *conn, |
| @@ -79,6 +113,7 @@ static struct iscsi_chap *chap_server_open( | |||
| 79 | char *aic_str, | 113 | char *aic_str, |
| 80 | unsigned int *aic_len) | 114 | unsigned int *aic_len) |
| 81 | { | 115 | { |
| 116 | int ret; | ||
| 82 | struct iscsi_chap *chap; | 117 | struct iscsi_chap *chap; |
| 83 | 118 | ||
| 84 | if (!(auth->naf_flags & NAF_USERID_SET) || | 119 | if (!(auth->naf_flags & NAF_USERID_SET) || |
| @@ -93,21 +128,24 @@ static struct iscsi_chap *chap_server_open( | |||
| 93 | return NULL; | 128 | return NULL; |
| 94 | 129 | ||
| 95 | chap = conn->auth_protocol; | 130 | chap = conn->auth_protocol; |
| 96 | /* | 131 | ret = chap_check_algorithm(a_str); |
| 97 | * We only support MD5 MDA presently. | 132 | switch (ret) { |
| 98 | */ | 133 | case CHAP_DIGEST_MD5: |
| 99 | if (strncmp(a_str, "CHAP_A=5", 8)) { | 134 | pr_debug("[server] Got CHAP_A=5\n"); |
| 100 | pr_err("CHAP_A is not MD5.\n"); | 135 | /* |
| 136 | * Send back CHAP_A set to MD5. | ||
| 137 | */ | ||
| 138 | *aic_len = sprintf(aic_str, "CHAP_A=5"); | ||
| 139 | *aic_len += 1; | ||
| 140 | chap->digest_type = CHAP_DIGEST_MD5; | ||
| 141 | pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type); | ||
| 142 | break; | ||
| 143 | case CHAP_DIGEST_UNKNOWN: | ||
| 144 | default: | ||
| 145 | pr_err("Unsupported CHAP_A value\n"); | ||
| 101 | return NULL; | 146 | return NULL; |
| 102 | } | 147 | } |
| 103 | pr_debug("[server] Got CHAP_A=5\n"); | 148 | |
| 104 | /* | ||
| 105 | * Send back CHAP_A set to MD5. | ||
| 106 | */ | ||
| 107 | *aic_len = sprintf(aic_str, "CHAP_A=5"); | ||
| 108 | *aic_len += 1; | ||
| 109 | chap->digest_type = CHAP_DIGEST_MD5; | ||
| 110 | pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type); | ||
| 111 | /* | 149 | /* |
| 112 | * Set Identifier. | 150 | * Set Identifier. |
| 113 | */ | 151 | */ |
| @@ -314,6 +352,16 @@ static int chap_server_compute_md5( | |||
| 314 | goto out; | 352 | goto out; |
| 315 | } | 353 | } |
| 316 | /* | 354 | /* |
| 355 | * During mutual authentication, the CHAP_C generated by the | ||
| 356 | * initiator must not match the original CHAP_C generated by | ||
| 357 | * the target. | ||
| 358 | */ | ||
| 359 | if (!memcmp(challenge_binhex, chap->challenge, CHAP_CHALLENGE_LENGTH)) { | ||
| 360 | pr_err("initiator CHAP_C matches target CHAP_C, failing" | ||
| 361 | " login attempt\n"); | ||
| 362 | goto out; | ||
| 363 | } | ||
| 364 | /* | ||
| 317 | * Generate CHAP_N and CHAP_R for mutual authentication. | 365 | * Generate CHAP_N and CHAP_R for mutual authentication. |
| 318 | */ | 366 | */ |
| 319 | tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); | 367 | tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); |
diff --git a/drivers/target/iscsi/iscsi_target_auth.h b/drivers/target/iscsi/iscsi_target_auth.h index 2f463c09626d..d22f7b96a06c 100644 --- a/drivers/target/iscsi/iscsi_target_auth.h +++ b/drivers/target/iscsi/iscsi_target_auth.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #ifndef _ISCSI_CHAP_H_ | 1 | #ifndef _ISCSI_CHAP_H_ |
| 2 | #define _ISCSI_CHAP_H_ | 2 | #define _ISCSI_CHAP_H_ |
| 3 | 3 | ||
| 4 | #define CHAP_DIGEST_UNKNOWN 0 | ||
| 4 | #define CHAP_DIGEST_MD5 5 | 5 | #define CHAP_DIGEST_MD5 5 |
| 5 | #define CHAP_DIGEST_SHA 6 | 6 | #define CHAP_DIGEST_SHA 6 |
| 6 | 7 | ||
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index d9b1d88e1ad3..fecb69535a15 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
| @@ -1145,7 +1145,7 @@ iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t) | |||
| 1145 | void iscsi_target_login_sess_out(struct iscsi_conn *conn, | 1145 | void iscsi_target_login_sess_out(struct iscsi_conn *conn, |
| 1146 | struct iscsi_np *np, bool zero_tsih, bool new_sess) | 1146 | struct iscsi_np *np, bool zero_tsih, bool new_sess) |
| 1147 | { | 1147 | { |
| 1148 | if (new_sess == false) | 1148 | if (!new_sess) |
| 1149 | goto old_sess_out; | 1149 | goto old_sess_out; |
| 1150 | 1150 | ||
| 1151 | pr_err("iSCSI Login negotiation failed.\n"); | 1151 | pr_err("iSCSI Login negotiation failed.\n"); |
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 75b685960e80..62a095f36bf2 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c | |||
| @@ -404,7 +404,7 @@ static void iscsi_target_sk_data_ready(struct sock *sk) | |||
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | rc = schedule_delayed_work(&conn->login_work, 0); | 406 | rc = schedule_delayed_work(&conn->login_work, 0); |
| 407 | if (rc == false) { | 407 | if (!rc) { |
| 408 | pr_debug("iscsi_target_sk_data_ready, schedule_delayed_work" | 408 | pr_debug("iscsi_target_sk_data_ready, schedule_delayed_work" |
| 409 | " got false\n"); | 409 | " got false\n"); |
| 410 | } | 410 | } |
| @@ -513,7 +513,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work) | |||
| 513 | state = (tpg->tpg_state == TPG_STATE_ACTIVE); | 513 | state = (tpg->tpg_state == TPG_STATE_ACTIVE); |
| 514 | spin_unlock(&tpg->tpg_state_lock); | 514 | spin_unlock(&tpg->tpg_state_lock); |
| 515 | 515 | ||
| 516 | if (state == false) { | 516 | if (!state) { |
| 517 | pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n"); | 517 | pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n"); |
| 518 | iscsi_target_restore_sock_callbacks(conn); | 518 | iscsi_target_restore_sock_callbacks(conn); |
| 519 | iscsi_target_login_drop(conn, login); | 519 | iscsi_target_login_drop(conn, login); |
| @@ -528,7 +528,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work) | |||
| 528 | state = iscsi_target_sk_state_check(sk); | 528 | state = iscsi_target_sk_state_check(sk); |
| 529 | read_unlock_bh(&sk->sk_callback_lock); | 529 | read_unlock_bh(&sk->sk_callback_lock); |
| 530 | 530 | ||
| 531 | if (state == false) { | 531 | if (!state) { |
| 532 | pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n"); | 532 | pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n"); |
| 533 | iscsi_target_restore_sock_callbacks(conn); | 533 | iscsi_target_restore_sock_callbacks(conn); |
| 534 | iscsi_target_login_drop(conn, login); | 534 | iscsi_target_login_drop(conn, login); |
| @@ -773,6 +773,12 @@ static int iscsi_target_handle_csg_zero( | |||
| 773 | } | 773 | } |
| 774 | 774 | ||
| 775 | goto do_auth; | 775 | goto do_auth; |
| 776 | } else if (!payload_length) { | ||
| 777 | pr_err("Initiator sent zero length security payload," | ||
| 778 | " login failed\n"); | ||
| 779 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | ||
| 780 | ISCSI_LOGIN_STATUS_AUTH_FAILED); | ||
| 781 | return -1; | ||
| 776 | } | 782 | } |
| 777 | 783 | ||
| 778 | if (login->first_request) | 784 | if (login->first_request) |
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 4d2e23fc76fd..02f9de26f38a 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c | |||
| @@ -474,10 +474,10 @@ int iscsi_set_keys_to_negotiate( | |||
| 474 | if (!strcmp(param->name, AUTHMETHOD)) { | 474 | if (!strcmp(param->name, AUTHMETHOD)) { |
| 475 | SET_PSTATE_NEGOTIATE(param); | 475 | SET_PSTATE_NEGOTIATE(param); |
| 476 | } else if (!strcmp(param->name, HEADERDIGEST)) { | 476 | } else if (!strcmp(param->name, HEADERDIGEST)) { |
| 477 | if (iser == false) | 477 | if (!iser) |
| 478 | SET_PSTATE_NEGOTIATE(param); | 478 | SET_PSTATE_NEGOTIATE(param); |
| 479 | } else if (!strcmp(param->name, DATADIGEST)) { | 479 | } else if (!strcmp(param->name, DATADIGEST)) { |
| 480 | if (iser == false) | 480 | if (!iser) |
| 481 | SET_PSTATE_NEGOTIATE(param); | 481 | SET_PSTATE_NEGOTIATE(param); |
| 482 | } else if (!strcmp(param->name, MAXCONNECTIONS)) { | 482 | } else if (!strcmp(param->name, MAXCONNECTIONS)) { |
| 483 | SET_PSTATE_NEGOTIATE(param); | 483 | SET_PSTATE_NEGOTIATE(param); |
| @@ -497,7 +497,7 @@ int iscsi_set_keys_to_negotiate( | |||
| 497 | } else if (!strcmp(param->name, IMMEDIATEDATA)) { | 497 | } else if (!strcmp(param->name, IMMEDIATEDATA)) { |
| 498 | SET_PSTATE_NEGOTIATE(param); | 498 | SET_PSTATE_NEGOTIATE(param); |
| 499 | } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { | 499 | } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { |
| 500 | if (iser == false) | 500 | if (!iser) |
| 501 | SET_PSTATE_NEGOTIATE(param); | 501 | SET_PSTATE_NEGOTIATE(param); |
| 502 | } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { | 502 | } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { |
| 503 | continue; | 503 | continue; |
| @@ -528,13 +528,13 @@ int iscsi_set_keys_to_negotiate( | |||
| 528 | } else if (!strcmp(param->name, OFMARKINT)) { | 528 | } else if (!strcmp(param->name, OFMARKINT)) { |
| 529 | SET_PSTATE_NEGOTIATE(param); | 529 | SET_PSTATE_NEGOTIATE(param); |
| 530 | } else if (!strcmp(param->name, RDMAEXTENSIONS)) { | 530 | } else if (!strcmp(param->name, RDMAEXTENSIONS)) { |
| 531 | if (iser == true) | 531 | if (iser) |
| 532 | SET_PSTATE_NEGOTIATE(param); | 532 | SET_PSTATE_NEGOTIATE(param); |
| 533 | } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) { | 533 | } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) { |
| 534 | if (iser == true) | 534 | if (iser) |
| 535 | SET_PSTATE_NEGOTIATE(param); | 535 | SET_PSTATE_NEGOTIATE(param); |
| 536 | } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) { | 536 | } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) { |
| 537 | if (iser == true) | 537 | if (iser) |
| 538 | SET_PSTATE_NEGOTIATE(param); | 538 | SET_PSTATE_NEGOTIATE(param); |
| 539 | } | 539 | } |
| 540 | } | 540 | } |
| @@ -1605,7 +1605,7 @@ int iscsi_decode_text_input( | |||
| 1605 | 1605 | ||
| 1606 | tmpbuf = kzalloc(length + 1, GFP_KERNEL); | 1606 | tmpbuf = kzalloc(length + 1, GFP_KERNEL); |
| 1607 | if (!tmpbuf) { | 1607 | if (!tmpbuf) { |
| 1608 | pr_err("Unable to allocate memory for tmpbuf.\n"); | 1608 | pr_err("Unable to allocate %u + 1 bytes for tmpbuf.\n", length); |
| 1609 | return -1; | 1609 | return -1; |
| 1610 | } | 1610 | } |
| 1611 | 1611 | ||
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 1431e8400d28..c3cb5c15efda 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c | |||
| @@ -189,7 +189,7 @@ static void iscsit_clear_tpg_np_login_thread( | |||
| 189 | iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg, shutdown); | 189 | iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg, shutdown); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | void iscsit_clear_tpg_np_login_threads( | 192 | static void iscsit_clear_tpg_np_login_threads( |
| 193 | struct iscsi_portal_group *tpg, | 193 | struct iscsi_portal_group *tpg, |
| 194 | bool shutdown) | 194 | bool shutdown) |
| 195 | { | 195 | { |
| @@ -276,8 +276,6 @@ int iscsit_tpg_del_portal_group( | |||
| 276 | tpg->tpg_state = TPG_STATE_INACTIVE; | 276 | tpg->tpg_state = TPG_STATE_INACTIVE; |
| 277 | spin_unlock(&tpg->tpg_state_lock); | 277 | spin_unlock(&tpg->tpg_state_lock); |
| 278 | 278 | ||
| 279 | iscsit_clear_tpg_np_login_threads(tpg, true); | ||
| 280 | |||
| 281 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { | 279 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { |
| 282 | pr_err("Unable to delete iSCSI Target Portal Group:" | 280 | pr_err("Unable to delete iSCSI Target Portal Group:" |
| 283 | " %hu while active sessions exist, and force=0\n", | 281 | " %hu while active sessions exist, and force=0\n", |
| @@ -453,7 +451,7 @@ static bool iscsit_tpg_check_network_portal( | |||
| 453 | 451 | ||
| 454 | match = iscsit_check_np_match(sockaddr, np, | 452 | match = iscsit_check_np_match(sockaddr, np, |
| 455 | network_transport); | 453 | network_transport); |
| 456 | if (match == true) | 454 | if (match) |
| 457 | break; | 455 | break; |
| 458 | } | 456 | } |
| 459 | spin_unlock(&tpg->tpg_np_lock); | 457 | spin_unlock(&tpg->tpg_np_lock); |
| @@ -475,7 +473,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( | |||
| 475 | 473 | ||
| 476 | if (!tpg_np_parent) { | 474 | if (!tpg_np_parent) { |
| 477 | if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr, | 475 | if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr, |
| 478 | network_transport) == true) { | 476 | network_transport)) { |
| 479 | pr_err("Network Portal: %s already exists on a" | 477 | pr_err("Network Portal: %s already exists on a" |
| 480 | " different TPG on %s\n", ip_str, | 478 | " different TPG on %s\n", ip_str, |
| 481 | tpg->tpg_tiqn->tiqn); | 479 | tpg->tpg_tiqn->tiqn); |
diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index 0a182f2aa8a2..e7265337bc43 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h | |||
| @@ -8,7 +8,6 @@ extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *, | |||
| 8 | struct iscsi_np *, struct iscsi_tpg_np **); | 8 | struct iscsi_np *, struct iscsi_tpg_np **); |
| 9 | extern int iscsit_get_tpg(struct iscsi_portal_group *); | 9 | extern int iscsit_get_tpg(struct iscsi_portal_group *); |
| 10 | extern void iscsit_put_tpg(struct iscsi_portal_group *); | 10 | extern void iscsit_put_tpg(struct iscsi_portal_group *); |
| 11 | extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *, bool); | ||
| 12 | extern void iscsit_tpg_dump_params(struct iscsi_portal_group *); | 11 | extern void iscsit_tpg_dump_params(struct iscsi_portal_group *); |
| 13 | extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *); | 12 | extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *); |
| 14 | extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *, | 13 | extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *, |
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 73ab75ddaf42..6d2f37578b29 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c | |||
| @@ -179,7 +179,7 @@ static void tcm_loop_submission_work(struct work_struct *work) | |||
| 179 | struct tcm_loop_hba *tl_hba; | 179 | struct tcm_loop_hba *tl_hba; |
| 180 | struct tcm_loop_tpg *tl_tpg; | 180 | struct tcm_loop_tpg *tl_tpg; |
| 181 | struct scatterlist *sgl_bidi = NULL; | 181 | struct scatterlist *sgl_bidi = NULL; |
| 182 | u32 sgl_bidi_count = 0; | 182 | u32 sgl_bidi_count = 0, transfer_length; |
| 183 | int rc; | 183 | int rc; |
| 184 | 184 | ||
| 185 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); | 185 | 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) | |||
| 213 | 213 | ||
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | if (!scsi_prot_sg_count(sc) && scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) | 216 | transfer_length = scsi_transfer_length(sc); |
| 217 | if (!scsi_prot_sg_count(sc) && | ||
| 218 | scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) { | ||
| 217 | se_cmd->prot_pto = true; | 219 | se_cmd->prot_pto = true; |
| 220 | /* | ||
| 221 | * loopback transport doesn't support | ||
| 222 | * WRITE_GENERATE, READ_STRIP protection | ||
| 223 | * information operations, go ahead unprotected. | ||
| 224 | */ | ||
| 225 | transfer_length = scsi_bufflen(sc); | ||
| 226 | } | ||
| 218 | 227 | ||
| 219 | rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd, | 228 | rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd, |
| 220 | &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun, | 229 | &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun, |
| 221 | scsi_bufflen(sc), tcm_loop_sam_attr(sc), | 230 | transfer_length, tcm_loop_sam_attr(sc), |
| 222 | sc->sc_data_direction, 0, | 231 | sc->sc_data_direction, 0, |
| 223 | scsi_sglist(sc), scsi_sg_count(sc), | 232 | scsi_sglist(sc), scsi_sg_count(sc), |
| 224 | sgl_bidi, sgl_bidi_count, | 233 | sgl_bidi, sgl_bidi_count, |
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index e0229592ec55..bd78d9235ac6 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c | |||
| @@ -81,7 +81,7 @@ sbc_emulate_readcapacity(struct se_cmd *cmd) | |||
| 81 | transport_kunmap_data_sg(cmd); | 81 | transport_kunmap_data_sg(cmd); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | target_complete_cmd(cmd, GOOD); | 84 | target_complete_cmd_with_length(cmd, GOOD, 8); |
| 85 | return 0; | 85 | return 0; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| @@ -137,7 +137,7 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd) | |||
| 137 | transport_kunmap_data_sg(cmd); | 137 | transport_kunmap_data_sg(cmd); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | target_complete_cmd(cmd, GOOD); | 140 | target_complete_cmd_with_length(cmd, GOOD, 32); |
| 141 | return 0; | 141 | return 0; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| @@ -176,24 +176,6 @@ static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors) | |||
| 176 | return cmd->se_dev->dev_attrib.block_size * sectors; | 176 | return cmd->se_dev->dev_attrib.block_size * sectors; |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | static int sbc_check_valid_sectors(struct se_cmd *cmd) | ||
| 180 | { | ||
| 181 | struct se_device *dev = cmd->se_dev; | ||
| 182 | unsigned long long end_lba; | ||
| 183 | u32 sectors; | ||
| 184 | |||
| 185 | sectors = cmd->data_length / dev->dev_attrib.block_size; | ||
| 186 | end_lba = dev->transport->get_blocks(dev) + 1; | ||
| 187 | |||
| 188 | if (cmd->t_task_lba + sectors > end_lba) { | ||
| 189 | pr_err("target: lba %llu, sectors %u exceeds end lba %llu\n", | ||
| 190 | cmd->t_task_lba, sectors, end_lba); | ||
| 191 | return -EINVAL; | ||
| 192 | } | ||
| 193 | |||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | static inline u32 transport_get_sectors_6(unsigned char *cdb) | 179 | static inline u32 transport_get_sectors_6(unsigned char *cdb) |
| 198 | { | 180 | { |
| 199 | /* | 181 | /* |
| @@ -665,8 +647,19 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, | |||
| 665 | 647 | ||
| 666 | cmd->prot_type = dev->dev_attrib.pi_prot_type; | 648 | cmd->prot_type = dev->dev_attrib.pi_prot_type; |
| 667 | cmd->prot_length = dev->prot_length * sectors; | 649 | cmd->prot_length = dev->prot_length * sectors; |
| 668 | pr_debug("%s: prot_type=%d, prot_length=%d prot_op=%d prot_checks=%d\n", | 650 | |
| 669 | __func__, cmd->prot_type, cmd->prot_length, | 651 | /** |
| 652 | * In case protection information exists over the wire | ||
| 653 | * we modify command data length to describe pure data. | ||
| 654 | * The actual transfer length is data length + protection | ||
| 655 | * length | ||
| 656 | **/ | ||
| 657 | if (protect) | ||
| 658 | cmd->data_length = sectors * dev->dev_attrib.block_size; | ||
| 659 | |||
| 660 | pr_debug("%s: prot_type=%d, data_length=%d, prot_length=%d " | ||
| 661 | "prot_op=%d prot_checks=%d\n", | ||
| 662 | __func__, cmd->prot_type, cmd->data_length, cmd->prot_length, | ||
| 670 | cmd->prot_op, cmd->prot_checks); | 663 | cmd->prot_op, cmd->prot_checks); |
| 671 | 664 | ||
| 672 | return true; | 665 | return true; |
| @@ -877,15 +870,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
| 877 | break; | 870 | break; |
| 878 | case SYNCHRONIZE_CACHE: | 871 | case SYNCHRONIZE_CACHE: |
| 879 | case SYNCHRONIZE_CACHE_16: | 872 | case SYNCHRONIZE_CACHE_16: |
| 880 | if (!ops->execute_sync_cache) { | ||
| 881 | size = 0; | ||
| 882 | cmd->execute_cmd = sbc_emulate_noop; | ||
| 883 | break; | ||
| 884 | } | ||
| 885 | |||
| 886 | /* | ||
| 887 | * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE | ||
| 888 | */ | ||
| 889 | if (cdb[0] == SYNCHRONIZE_CACHE) { | 873 | if (cdb[0] == SYNCHRONIZE_CACHE) { |
| 890 | sectors = transport_get_sectors_10(cdb); | 874 | sectors = transport_get_sectors_10(cdb); |
| 891 | cmd->t_task_lba = transport_lba_32(cdb); | 875 | cmd->t_task_lba = transport_lba_32(cdb); |
| @@ -893,18 +877,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
| 893 | sectors = transport_get_sectors_16(cdb); | 877 | sectors = transport_get_sectors_16(cdb); |
| 894 | cmd->t_task_lba = transport_lba_64(cdb); | 878 | cmd->t_task_lba = transport_lba_64(cdb); |
| 895 | } | 879 | } |
| 896 | 880 | if (ops->execute_sync_cache) { | |
| 897 | size = sbc_get_size(cmd, sectors); | 881 | cmd->execute_cmd = ops->execute_sync_cache; |
| 898 | 882 | goto check_lba; | |
| 899 | /* | ||
| 900 | * Check to ensure that LBA + Range does not exceed past end of | ||
| 901 | * device for IBLOCK and FILEIO ->do_sync_cache() backend calls | ||
| 902 | */ | ||
| 903 | if (cmd->t_task_lba || sectors) { | ||
| 904 | if (sbc_check_valid_sectors(cmd) < 0) | ||
| 905 | return TCM_ADDRESS_OUT_OF_RANGE; | ||
| 906 | } | 883 | } |
| 907 | cmd->execute_cmd = ops->execute_sync_cache; | 884 | size = 0; |
| 885 | cmd->execute_cmd = sbc_emulate_noop; | ||
| 908 | break; | 886 | break; |
| 909 | case UNMAP: | 887 | case UNMAP: |
| 910 | if (!ops->execute_unmap) | 888 | if (!ops->execute_unmap) |
| @@ -947,8 +925,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
| 947 | break; | 925 | break; |
| 948 | case VERIFY: | 926 | case VERIFY: |
| 949 | size = 0; | 927 | size = 0; |
| 928 | sectors = transport_get_sectors_10(cdb); | ||
| 929 | cmd->t_task_lba = transport_lba_32(cdb); | ||
| 950 | cmd->execute_cmd = sbc_emulate_noop; | 930 | cmd->execute_cmd = sbc_emulate_noop; |
| 951 | break; | 931 | goto check_lba; |
| 952 | case REZERO_UNIT: | 932 | case REZERO_UNIT: |
| 953 | case SEEK_6: | 933 | case SEEK_6: |
| 954 | case SEEK_10: | 934 | case SEEK_10: |
| @@ -988,7 +968,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
| 988 | dev->dev_attrib.hw_max_sectors); | 968 | dev->dev_attrib.hw_max_sectors); |
| 989 | return TCM_INVALID_CDB_FIELD; | 969 | return TCM_INVALID_CDB_FIELD; |
| 990 | } | 970 | } |
| 991 | 971 | check_lba: | |
| 992 | end_lba = dev->transport->get_blocks(dev) + 1; | 972 | end_lba = dev->transport->get_blocks(dev) + 1; |
| 993 | if (cmd->t_task_lba + sectors > end_lba) { | 973 | if (cmd->t_task_lba + sectors > end_lba) { |
| 994 | pr_err("cmd exceeds last lba %llu " | 974 | pr_err("cmd exceeds last lba %llu " |
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 8653666612a8..6cd7222738fc 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c | |||
| @@ -129,15 +129,10 @@ static sense_reason_t | |||
| 129 | spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) | 129 | spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) |
| 130 | { | 130 | { |
| 131 | struct se_device *dev = cmd->se_dev; | 131 | struct se_device *dev = cmd->se_dev; |
| 132 | u16 len = 0; | 132 | u16 len; |
| 133 | 133 | ||
| 134 | if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) { | 134 | if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) { |
| 135 | u32 unit_serial_len; | 135 | len = sprintf(&buf[4], "%s", dev->t10_wwn.unit_serial); |
| 136 | |||
| 137 | unit_serial_len = strlen(dev->t10_wwn.unit_serial); | ||
| 138 | unit_serial_len++; /* For NULL Terminator */ | ||
| 139 | |||
| 140 | len += sprintf(&buf[4], "%s", dev->t10_wwn.unit_serial); | ||
| 141 | len++; /* Extra Byte for NULL Terminator */ | 136 | len++; /* Extra Byte for NULL Terminator */ |
| 142 | buf[3] = len; | 137 | buf[3] = len; |
| 143 | } | 138 | } |
| @@ -721,6 +716,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) | |||
| 721 | unsigned char *buf; | 716 | unsigned char *buf; |
| 722 | sense_reason_t ret; | 717 | sense_reason_t ret; |
| 723 | int p; | 718 | int p; |
| 719 | int len = 0; | ||
| 724 | 720 | ||
| 725 | buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); | 721 | buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); |
| 726 | if (!buf) { | 722 | if (!buf) { |
| @@ -742,6 +738,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) | |||
| 742 | } | 738 | } |
| 743 | 739 | ||
| 744 | ret = spc_emulate_inquiry_std(cmd, buf); | 740 | ret = spc_emulate_inquiry_std(cmd, buf); |
| 741 | len = buf[4] + 5; | ||
| 745 | goto out; | 742 | goto out; |
| 746 | } | 743 | } |
| 747 | 744 | ||
| @@ -749,6 +746,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) | |||
| 749 | if (cdb[2] == evpd_handlers[p].page) { | 746 | if (cdb[2] == evpd_handlers[p].page) { |
| 750 | buf[1] = cdb[2]; | 747 | buf[1] = cdb[2]; |
| 751 | ret = evpd_handlers[p].emulate(cmd, buf); | 748 | ret = evpd_handlers[p].emulate(cmd, buf); |
| 749 | len = get_unaligned_be16(&buf[2]) + 4; | ||
| 752 | goto out; | 750 | goto out; |
| 753 | } | 751 | } |
| 754 | } | 752 | } |
| @@ -765,7 +763,7 @@ out: | |||
| 765 | kfree(buf); | 763 | kfree(buf); |
| 766 | 764 | ||
| 767 | if (!ret) | 765 | if (!ret) |
| 768 | target_complete_cmd(cmd, GOOD); | 766 | target_complete_cmd_with_length(cmd, GOOD, len); |
| 769 | return ret; | 767 | return ret; |
| 770 | } | 768 | } |
| 771 | 769 | ||
| @@ -1103,7 +1101,7 @@ set_length: | |||
| 1103 | transport_kunmap_data_sg(cmd); | 1101 | transport_kunmap_data_sg(cmd); |
| 1104 | } | 1102 | } |
| 1105 | 1103 | ||
| 1106 | target_complete_cmd(cmd, GOOD); | 1104 | target_complete_cmd_with_length(cmd, GOOD, length); |
| 1107 | return 0; | 1105 | return 0; |
| 1108 | } | 1106 | } |
| 1109 | 1107 | ||
| @@ -1279,7 +1277,7 @@ done: | |||
| 1279 | buf[3] = (lun_count & 0xff); | 1277 | buf[3] = (lun_count & 0xff); |
| 1280 | transport_kunmap_data_sg(cmd); | 1278 | transport_kunmap_data_sg(cmd); |
| 1281 | 1279 | ||
| 1282 | target_complete_cmd(cmd, GOOD); | 1280 | target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8); |
| 1283 | return 0; | 1281 | return 0; |
| 1284 | } | 1282 | } |
| 1285 | EXPORT_SYMBOL(spc_emulate_report_luns); | 1283 | EXPORT_SYMBOL(spc_emulate_report_luns); |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 2179feed0d63..7fa62fc93e0b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
| @@ -504,7 +504,7 @@ void transport_deregister_session(struct se_session *se_sess) | |||
| 504 | * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group | 504 | * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group |
| 505 | * removal context. | 505 | * removal context. |
| 506 | */ | 506 | */ |
| 507 | if (se_nacl && comp_nacl == true) | 507 | if (se_nacl && comp_nacl) |
| 508 | target_put_nacl(se_nacl); | 508 | target_put_nacl(se_nacl); |
| 509 | 509 | ||
| 510 | transport_free_session(se_sess); | 510 | transport_free_session(se_sess); |
| @@ -562,7 +562,7 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists, | |||
| 562 | 562 | ||
| 563 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 563 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
| 564 | 564 | ||
| 565 | complete(&cmd->t_transport_stop_comp); | 565 | complete_all(&cmd->t_transport_stop_comp); |
| 566 | return 1; | 566 | return 1; |
| 567 | } | 567 | } |
| 568 | 568 | ||
| @@ -687,7 +687,7 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) | |||
| 687 | if (cmd->transport_state & CMD_T_ABORTED && | 687 | if (cmd->transport_state & CMD_T_ABORTED && |
| 688 | cmd->transport_state & CMD_T_STOP) { | 688 | cmd->transport_state & CMD_T_STOP) { |
| 689 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 689 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
| 690 | complete(&cmd->t_transport_stop_comp); | 690 | complete_all(&cmd->t_transport_stop_comp); |
| 691 | return; | 691 | return; |
| 692 | } else if (!success) { | 692 | } else if (!success) { |
| 693 | INIT_WORK(&cmd->work, target_complete_failure_work); | 693 | INIT_WORK(&cmd->work, target_complete_failure_work); |
| @@ -703,6 +703,23 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) | |||
| 703 | } | 703 | } |
| 704 | EXPORT_SYMBOL(target_complete_cmd); | 704 | EXPORT_SYMBOL(target_complete_cmd); |
| 705 | 705 | ||
| 706 | void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) | ||
| 707 | { | ||
| 708 | if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) { | ||
| 709 | if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { | ||
| 710 | cmd->residual_count += cmd->data_length - length; | ||
| 711 | } else { | ||
| 712 | cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; | ||
| 713 | cmd->residual_count = cmd->data_length - length; | ||
| 714 | } | ||
| 715 | |||
| 716 | cmd->data_length = length; | ||
| 717 | } | ||
| 718 | |||
| 719 | target_complete_cmd(cmd, scsi_status); | ||
| 720 | } | ||
| 721 | EXPORT_SYMBOL(target_complete_cmd_with_length); | ||
| 722 | |||
| 706 | static void target_add_to_state_list(struct se_cmd *cmd) | 723 | static void target_add_to_state_list(struct se_cmd *cmd) |
| 707 | { | 724 | { |
| 708 | struct se_device *dev = cmd->se_dev; | 725 | struct se_device *dev = cmd->se_dev; |
| @@ -1761,7 +1778,7 @@ void target_execute_cmd(struct se_cmd *cmd) | |||
| 1761 | cmd->se_tfo->get_task_tag(cmd)); | 1778 | cmd->se_tfo->get_task_tag(cmd)); |
| 1762 | 1779 | ||
| 1763 | spin_unlock_irq(&cmd->t_state_lock); | 1780 | spin_unlock_irq(&cmd->t_state_lock); |
| 1764 | complete(&cmd->t_transport_stop_comp); | 1781 | complete_all(&cmd->t_transport_stop_comp); |
| 1765 | return; | 1782 | return; |
| 1766 | } | 1783 | } |
| 1767 | 1784 | ||
| @@ -2363,7 +2380,7 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, | |||
| 2363 | * fabric acknowledgement that requires two target_put_sess_cmd() | 2380 | * fabric acknowledgement that requires two target_put_sess_cmd() |
| 2364 | * invocations before se_cmd descriptor release. | 2381 | * invocations before se_cmd descriptor release. |
| 2365 | */ | 2382 | */ |
| 2366 | if (ack_kref == true) { | 2383 | if (ack_kref) { |
| 2367 | kref_get(&se_cmd->cmd_kref); | 2384 | kref_get(&se_cmd->cmd_kref); |
| 2368 | se_cmd->se_cmd_flags |= SCF_ACK_KREF; | 2385 | se_cmd->se_cmd_flags |= SCF_ACK_KREF; |
| 2369 | } | 2386 | } |
| @@ -2407,6 +2424,10 @@ static void target_release_cmd_kref(struct kref *kref) | |||
| 2407 | */ | 2424 | */ |
| 2408 | int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) | 2425 | int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) |
| 2409 | { | 2426 | { |
| 2427 | if (!se_sess) { | ||
| 2428 | se_cmd->se_tfo->release_cmd(se_cmd); | ||
| 2429 | return 1; | ||
| 2430 | } | ||
| 2410 | return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref, | 2431 | return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref, |
| 2411 | &se_sess->sess_cmd_lock); | 2432 | &se_sess->sess_cmd_lock); |
| 2412 | } | 2433 | } |
| @@ -2934,6 +2955,12 @@ static void target_tmr_work(struct work_struct *work) | |||
| 2934 | int transport_generic_handle_tmr( | 2955 | int transport_generic_handle_tmr( |
| 2935 | struct se_cmd *cmd) | 2956 | struct se_cmd *cmd) |
| 2936 | { | 2957 | { |
| 2958 | unsigned long flags; | ||
| 2959 | |||
| 2960 | spin_lock_irqsave(&cmd->t_state_lock, flags); | ||
| 2961 | cmd->transport_state |= CMD_T_ACTIVE; | ||
| 2962 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
| 2963 | |||
| 2937 | INIT_WORK(&cmd->work, target_tmr_work); | 2964 | INIT_WORK(&cmd->work, target_tmr_work); |
| 2938 | queue_work(cmd->se_dev->tmr_wq, &cmd->work); | 2965 | queue_work(cmd->se_dev->tmr_wq, &cmd->work); |
| 2939 | return 0; | 2966 | return 0; |
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 669c536fd959..e9186cdf35e9 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c | |||
| @@ -70,7 +70,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
| 70 | unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn; | 70 | unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn; |
| 71 | int rc; | 71 | int rc; |
| 72 | 72 | ||
| 73 | if (src == true) | 73 | if (src) |
| 74 | dev_wwn = &xop->dst_tid_wwn[0]; | 74 | dev_wwn = &xop->dst_tid_wwn[0]; |
| 75 | else | 75 | else |
| 76 | dev_wwn = &xop->src_tid_wwn[0]; | 76 | 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 | |||
| 88 | if (rc != 0) | 88 | if (rc != 0) |
| 89 | continue; | 89 | continue; |
| 90 | 90 | ||
| 91 | if (src == true) { | 91 | if (src) { |
| 92 | xop->dst_dev = se_dev; | 92 | xop->dst_dev = se_dev; |
| 93 | pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located" | 93 | pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located" |
| 94 | " se_dev\n", xop->dst_dev); | 94 | " 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 | |||
| 166 | return -EINVAL; | 166 | return -EINVAL; |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | if (src == true) { | 169 | if (src) { |
| 170 | memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); | 170 | memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); |
| 171 | /* | 171 | /* |
| 172 | * Determine if the source designator matches the local device | 172 | * 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, | |||
| 236 | /* | 236 | /* |
| 237 | * Assume target descriptors are in source -> destination order.. | 237 | * Assume target descriptors are in source -> destination order.. |
| 238 | */ | 238 | */ |
| 239 | if (src == true) | 239 | if (src) |
| 240 | src = false; | 240 | src = false; |
| 241 | else | 241 | else |
| 242 | src = true; | 242 | src = true; |
| @@ -560,7 +560,7 @@ static int target_xcopy_init_pt_lun( | |||
| 560 | * reservations. The pt_cmd->se_lun pointer will be setup from within | 560 | * reservations. The pt_cmd->se_lun pointer will be setup from within |
| 561 | * target_xcopy_setup_pt_port() | 561 | * target_xcopy_setup_pt_port() |
| 562 | */ | 562 | */ |
| 563 | if (remote_port == false) { | 563 | if (!remote_port) { |
| 564 | pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH; | 564 | pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH; |
| 565 | return 0; | 565 | return 0; |
| 566 | } | 566 | } |
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index f5fd515b2bee..be0c0d08c56a 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c | |||
| @@ -128,6 +128,7 @@ int ft_queue_status(struct se_cmd *se_cmd) | |||
| 128 | struct fc_lport *lport; | 128 | struct fc_lport *lport; |
| 129 | struct fc_exch *ep; | 129 | struct fc_exch *ep; |
| 130 | size_t len; | 130 | size_t len; |
| 131 | int rc; | ||
| 131 | 132 | ||
| 132 | if (cmd->aborted) | 133 | if (cmd->aborted) |
| 133 | return 0; | 134 | return 0; |
| @@ -137,9 +138,10 @@ int ft_queue_status(struct se_cmd *se_cmd) | |||
| 137 | len = sizeof(*fcp) + se_cmd->scsi_sense_length; | 138 | len = sizeof(*fcp) + se_cmd->scsi_sense_length; |
| 138 | fp = fc_frame_alloc(lport, len); | 139 | fp = fc_frame_alloc(lport, len); |
| 139 | if (!fp) { | 140 | if (!fp) { |
| 140 | /* XXX shouldn't just drop it - requeue and retry? */ | 141 | se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; |
| 141 | return 0; | 142 | return -ENOMEM; |
| 142 | } | 143 | } |
| 144 | |||
| 143 | fcp = fc_frame_payload_get(fp, len); | 145 | fcp = fc_frame_payload_get(fp, len); |
| 144 | memset(fcp, 0, len); | 146 | memset(fcp, 0, len); |
| 145 | fcp->resp.fr_status = se_cmd->scsi_status; | 147 | fcp->resp.fr_status = se_cmd->scsi_status; |
| @@ -170,7 +172,18 @@ int ft_queue_status(struct se_cmd *se_cmd) | |||
| 170 | fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP, | 172 | fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP, |
| 171 | FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0); | 173 | FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0); |
| 172 | 174 | ||
| 173 | lport->tt.seq_send(lport, cmd->seq, fp); | 175 | rc = lport->tt.seq_send(lport, cmd->seq, fp); |
| 176 | if (rc) { | ||
| 177 | pr_info_ratelimited("%s: Failed to send response frame %p, " | ||
| 178 | "xid <0x%x>\n", __func__, fp, ep->xid); | ||
| 179 | /* | ||
| 180 | * Generate a TASK_SET_FULL status to notify the initiator | ||
| 181 | * to reduce it's queue_depth after the se_cmd response has | ||
| 182 | * been re-queued by target-core. | ||
| 183 | */ | ||
| 184 | se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; | ||
| 185 | return -ENOMEM; | ||
| 186 | } | ||
| 174 | lport->tt.exch_done(cmd->seq); | 187 | lport->tt.exch_done(cmd->seq); |
| 175 | return 0; | 188 | return 0; |
| 176 | } | 189 | } |
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index e415af32115a..97b486c3dda1 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c | |||
| @@ -82,6 +82,10 @@ int ft_queue_data_in(struct se_cmd *se_cmd) | |||
| 82 | 82 | ||
| 83 | if (cmd->aborted) | 83 | if (cmd->aborted) |
| 84 | return 0; | 84 | return 0; |
| 85 | |||
| 86 | if (se_cmd->scsi_status == SAM_STAT_TASK_SET_FULL) | ||
| 87 | goto queue_status; | ||
| 88 | |||
| 85 | ep = fc_seq_exch(cmd->seq); | 89 | ep = fc_seq_exch(cmd->seq); |
| 86 | lport = ep->lp; | 90 | lport = ep->lp; |
| 87 | cmd->seq = lport->tt.seq_start_next(cmd->seq); | 91 | cmd->seq = lport->tt.seq_start_next(cmd->seq); |
| @@ -178,14 +182,23 @@ int ft_queue_data_in(struct se_cmd *se_cmd) | |||
| 178 | FC_TYPE_FCP, f_ctl, fh_off); | 182 | FC_TYPE_FCP, f_ctl, fh_off); |
| 179 | error = lport->tt.seq_send(lport, seq, fp); | 183 | error = lport->tt.seq_send(lport, seq, fp); |
| 180 | if (error) { | 184 | if (error) { |
| 181 | /* XXX For now, initiator will retry */ | 185 | pr_info_ratelimited("%s: Failed to send frame %p, " |
| 182 | pr_err_ratelimited("%s: Failed to send frame %p, " | ||
| 183 | "xid <0x%x>, remaining %zu, " | 186 | "xid <0x%x>, remaining %zu, " |
| 184 | "lso_max <0x%x>\n", | 187 | "lso_max <0x%x>\n", |
| 185 | __func__, fp, ep->xid, | 188 | __func__, fp, ep->xid, |
| 186 | remaining, lport->lso_max); | 189 | remaining, lport->lso_max); |
| 190 | /* | ||
| 191 | * Go ahead and set TASK_SET_FULL status ignoring the | ||
| 192 | * rest of the DataIN, and immediately attempt to | ||
| 193 | * send the response via ft_queue_status() in order | ||
| 194 | * to notify the initiator that it should reduce it's | ||
| 195 | * per LUN queue_depth. | ||
| 196 | */ | ||
| 197 | se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; | ||
| 198 | break; | ||
| 187 | } | 199 | } |
| 188 | } | 200 | } |
| 201 | queue_status: | ||
| 189 | return ft_queue_status(se_cmd); | 202 | return ft_queue_status(se_cmd); |
| 190 | } | 203 | } |
| 191 | 204 | ||
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index e9c280f55819..4f4ffa4c604e 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c | |||
| @@ -57,7 +57,8 @@ | |||
| 57 | #define TCM_VHOST_MAX_CDB_SIZE 32 | 57 | #define TCM_VHOST_MAX_CDB_SIZE 32 |
| 58 | #define TCM_VHOST_DEFAULT_TAGS 256 | 58 | #define TCM_VHOST_DEFAULT_TAGS 256 |
| 59 | #define TCM_VHOST_PREALLOC_SGLS 2048 | 59 | #define TCM_VHOST_PREALLOC_SGLS 2048 |
| 60 | #define TCM_VHOST_PREALLOC_PAGES 2048 | 60 | #define TCM_VHOST_PREALLOC_UPAGES 2048 |
| 61 | #define TCM_VHOST_PREALLOC_PROT_SGLS 512 | ||
| 61 | 62 | ||
| 62 | struct vhost_scsi_inflight { | 63 | struct vhost_scsi_inflight { |
| 63 | /* Wait for the flush operation to finish */ | 64 | /* Wait for the flush operation to finish */ |
| @@ -79,10 +80,12 @@ struct tcm_vhost_cmd { | |||
| 79 | u64 tvc_tag; | 80 | u64 tvc_tag; |
| 80 | /* The number of scatterlists associated with this cmd */ | 81 | /* The number of scatterlists associated with this cmd */ |
| 81 | u32 tvc_sgl_count; | 82 | u32 tvc_sgl_count; |
| 83 | u32 tvc_prot_sgl_count; | ||
| 82 | /* Saved unpacked SCSI LUN for tcm_vhost_submission_work() */ | 84 | /* Saved unpacked SCSI LUN for tcm_vhost_submission_work() */ |
| 83 | u32 tvc_lun; | 85 | u32 tvc_lun; |
| 84 | /* Pointer to the SGL formatted memory from virtio-scsi */ | 86 | /* Pointer to the SGL formatted memory from virtio-scsi */ |
| 85 | struct scatterlist *tvc_sgl; | 87 | struct scatterlist *tvc_sgl; |
| 88 | struct scatterlist *tvc_prot_sgl; | ||
| 86 | struct page **tvc_upages; | 89 | struct page **tvc_upages; |
| 87 | /* Pointer to response */ | 90 | /* Pointer to response */ |
| 88 | struct virtio_scsi_cmd_resp __user *tvc_resp; | 91 | struct virtio_scsi_cmd_resp __user *tvc_resp; |
| @@ -166,7 +169,8 @@ enum { | |||
| 166 | }; | 169 | }; |
| 167 | 170 | ||
| 168 | enum { | 171 | enum { |
| 169 | VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) | 172 | VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) | |
| 173 | (1ULL << VIRTIO_SCSI_F_T10_PI) | ||
| 170 | }; | 174 | }; |
| 171 | 175 | ||
| 172 | #define VHOST_SCSI_MAX_TARGET 256 | 176 | #define VHOST_SCSI_MAX_TARGET 256 |
| @@ -456,12 +460,16 @@ static void tcm_vhost_release_cmd(struct se_cmd *se_cmd) | |||
| 456 | struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd, | 460 | struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd, |
| 457 | struct tcm_vhost_cmd, tvc_se_cmd); | 461 | struct tcm_vhost_cmd, tvc_se_cmd); |
| 458 | struct se_session *se_sess = se_cmd->se_sess; | 462 | struct se_session *se_sess = se_cmd->se_sess; |
| 463 | int i; | ||
| 459 | 464 | ||
| 460 | if (tv_cmd->tvc_sgl_count) { | 465 | if (tv_cmd->tvc_sgl_count) { |
| 461 | u32 i; | ||
| 462 | for (i = 0; i < tv_cmd->tvc_sgl_count; i++) | 466 | for (i = 0; i < tv_cmd->tvc_sgl_count; i++) |
| 463 | put_page(sg_page(&tv_cmd->tvc_sgl[i])); | 467 | put_page(sg_page(&tv_cmd->tvc_sgl[i])); |
| 464 | } | 468 | } |
| 469 | if (tv_cmd->tvc_prot_sgl_count) { | ||
| 470 | for (i = 0; i < tv_cmd->tvc_prot_sgl_count; i++) | ||
| 471 | put_page(sg_page(&tv_cmd->tvc_prot_sgl[i])); | ||
| 472 | } | ||
| 465 | 473 | ||
| 466 | tcm_vhost_put_inflight(tv_cmd->inflight); | 474 | tcm_vhost_put_inflight(tv_cmd->inflight); |
| 467 | percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); | 475 | 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) | |||
| 713 | } | 721 | } |
| 714 | 722 | ||
| 715 | static struct tcm_vhost_cmd * | 723 | static struct tcm_vhost_cmd * |
| 716 | vhost_scsi_get_tag(struct vhost_virtqueue *vq, | 724 | vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct tcm_vhost_tpg *tpg, |
| 717 | struct tcm_vhost_tpg *tpg, | 725 | unsigned char *cdb, u64 scsi_tag, u16 lun, u8 task_attr, |
| 718 | struct virtio_scsi_cmd_req *v_req, | 726 | u32 exp_data_len, int data_direction) |
| 719 | u32 exp_data_len, | ||
| 720 | int data_direction) | ||
| 721 | { | 727 | { |
| 722 | struct tcm_vhost_cmd *cmd; | 728 | struct tcm_vhost_cmd *cmd; |
| 723 | struct tcm_vhost_nexus *tv_nexus; | 729 | struct tcm_vhost_nexus *tv_nexus; |
| 724 | struct se_session *se_sess; | 730 | struct se_session *se_sess; |
| 725 | struct scatterlist *sg; | 731 | struct scatterlist *sg, *prot_sg; |
| 726 | struct page **pages; | 732 | struct page **pages; |
| 727 | int tag; | 733 | int tag; |
| 728 | 734 | ||
| @@ -741,19 +747,24 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, | |||
| 741 | 747 | ||
| 742 | cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag]; | 748 | cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag]; |
| 743 | sg = cmd->tvc_sgl; | 749 | sg = cmd->tvc_sgl; |
| 750 | prot_sg = cmd->tvc_prot_sgl; | ||
| 744 | pages = cmd->tvc_upages; | 751 | pages = cmd->tvc_upages; |
| 745 | memset(cmd, 0, sizeof(struct tcm_vhost_cmd)); | 752 | memset(cmd, 0, sizeof(struct tcm_vhost_cmd)); |
| 746 | 753 | ||
| 747 | cmd->tvc_sgl = sg; | 754 | cmd->tvc_sgl = sg; |
| 755 | cmd->tvc_prot_sgl = prot_sg; | ||
| 748 | cmd->tvc_upages = pages; | 756 | cmd->tvc_upages = pages; |
| 749 | cmd->tvc_se_cmd.map_tag = tag; | 757 | cmd->tvc_se_cmd.map_tag = tag; |
| 750 | cmd->tvc_tag = v_req->tag; | 758 | cmd->tvc_tag = scsi_tag; |
| 751 | cmd->tvc_task_attr = v_req->task_attr; | 759 | cmd->tvc_lun = lun; |
| 760 | cmd->tvc_task_attr = task_attr; | ||
| 752 | cmd->tvc_exp_data_len = exp_data_len; | 761 | cmd->tvc_exp_data_len = exp_data_len; |
| 753 | cmd->tvc_data_direction = data_direction; | 762 | cmd->tvc_data_direction = data_direction; |
| 754 | cmd->tvc_nexus = tv_nexus; | 763 | cmd->tvc_nexus = tv_nexus; |
| 755 | cmd->inflight = tcm_vhost_get_inflight(vq); | 764 | cmd->inflight = tcm_vhost_get_inflight(vq); |
| 756 | 765 | ||
| 766 | memcpy(cmd->tvc_cdb, cdb, TCM_VHOST_MAX_CDB_SIZE); | ||
| 767 | |||
| 757 | return cmd; | 768 | return cmd; |
| 758 | } | 769 | } |
| 759 | 770 | ||
| @@ -767,35 +778,28 @@ vhost_scsi_map_to_sgl(struct tcm_vhost_cmd *tv_cmd, | |||
| 767 | struct scatterlist *sgl, | 778 | struct scatterlist *sgl, |
| 768 | unsigned int sgl_count, | 779 | unsigned int sgl_count, |
| 769 | struct iovec *iov, | 780 | struct iovec *iov, |
| 770 | int write) | 781 | struct page **pages, |
| 782 | bool write) | ||
| 771 | { | 783 | { |
| 772 | unsigned int npages = 0, pages_nr, offset, nbytes; | 784 | unsigned int npages = 0, pages_nr, offset, nbytes; |
| 773 | struct scatterlist *sg = sgl; | 785 | struct scatterlist *sg = sgl; |
| 774 | void __user *ptr = iov->iov_base; | 786 | void __user *ptr = iov->iov_base; |
| 775 | size_t len = iov->iov_len; | 787 | size_t len = iov->iov_len; |
| 776 | struct page **pages; | ||
| 777 | int ret, i; | 788 | int ret, i; |
| 778 | 789 | ||
| 779 | if (sgl_count > TCM_VHOST_PREALLOC_SGLS) { | ||
| 780 | pr_err("vhost_scsi_map_to_sgl() psgl_count: %u greater than" | ||
| 781 | " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n", | ||
| 782 | sgl_count, TCM_VHOST_PREALLOC_SGLS); | ||
| 783 | return -ENOBUFS; | ||
| 784 | } | ||
| 785 | |||
| 786 | pages_nr = iov_num_pages(iov); | 790 | pages_nr = iov_num_pages(iov); |
| 787 | if (pages_nr > sgl_count) | 791 | if (pages_nr > sgl_count) { |
| 792 | pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" | ||
| 793 | " sgl_count: %u\n", pages_nr, sgl_count); | ||
| 788 | return -ENOBUFS; | 794 | return -ENOBUFS; |
| 789 | 795 | } | |
| 790 | if (pages_nr > TCM_VHOST_PREALLOC_PAGES) { | 796 | if (pages_nr > TCM_VHOST_PREALLOC_UPAGES) { |
| 791 | pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" | 797 | pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" |
| 792 | " preallocated TCM_VHOST_PREALLOC_PAGES: %u\n", | 798 | " preallocated TCM_VHOST_PREALLOC_UPAGES: %u\n", |
| 793 | pages_nr, TCM_VHOST_PREALLOC_PAGES); | 799 | pages_nr, TCM_VHOST_PREALLOC_UPAGES); |
| 794 | return -ENOBUFS; | 800 | return -ENOBUFS; |
| 795 | } | 801 | } |
| 796 | 802 | ||
| 797 | pages = tv_cmd->tvc_upages; | ||
| 798 | |||
| 799 | ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages); | 803 | ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages); |
| 800 | /* No pages were pinned */ | 804 | /* No pages were pinned */ |
| 801 | if (ret < 0) | 805 | if (ret < 0) |
| @@ -825,33 +829,32 @@ out: | |||
| 825 | static int | 829 | static int |
| 826 | vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd, | 830 | vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd, |
| 827 | struct iovec *iov, | 831 | struct iovec *iov, |
| 828 | unsigned int niov, | 832 | int niov, |
| 829 | int write) | 833 | bool write) |
| 830 | { | 834 | { |
| 831 | int ret; | 835 | struct scatterlist *sg = cmd->tvc_sgl; |
| 832 | unsigned int i; | 836 | unsigned int sgl_count = 0; |
| 833 | u32 sgl_count; | 837 | int ret, i; |
| 834 | struct scatterlist *sg; | ||
| 835 | 838 | ||
| 836 | /* | ||
| 837 | * Find out how long sglist needs to be | ||
| 838 | */ | ||
| 839 | sgl_count = 0; | ||
| 840 | for (i = 0; i < niov; i++) | 839 | for (i = 0; i < niov; i++) |
| 841 | sgl_count += iov_num_pages(&iov[i]); | 840 | sgl_count += iov_num_pages(&iov[i]); |
| 842 | 841 | ||
| 843 | /* TODO overflow checking */ | 842 | if (sgl_count > TCM_VHOST_PREALLOC_SGLS) { |
| 843 | pr_err("vhost_scsi_map_iov_to_sgl() sgl_count: %u greater than" | ||
| 844 | " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n", | ||
| 845 | sgl_count, TCM_VHOST_PREALLOC_SGLS); | ||
| 846 | return -ENOBUFS; | ||
| 847 | } | ||
| 844 | 848 | ||
| 845 | sg = cmd->tvc_sgl; | ||
| 846 | pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count); | 849 | pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count); |
| 847 | sg_init_table(sg, sgl_count); | 850 | sg_init_table(sg, sgl_count); |
| 848 | |||
| 849 | cmd->tvc_sgl_count = sgl_count; | 851 | cmd->tvc_sgl_count = sgl_count; |
| 850 | 852 | ||
| 851 | pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count); | 853 | pr_debug("Mapping iovec %p for %u pages\n", &iov[0], sgl_count); |
| 854 | |||
| 852 | for (i = 0; i < niov; i++) { | 855 | for (i = 0; i < niov; i++) { |
| 853 | ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i], | 856 | ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i], |
| 854 | write); | 857 | cmd->tvc_upages, write); |
| 855 | if (ret < 0) { | 858 | if (ret < 0) { |
| 856 | for (i = 0; i < cmd->tvc_sgl_count; i++) | 859 | for (i = 0; i < cmd->tvc_sgl_count; i++) |
| 857 | put_page(sg_page(&cmd->tvc_sgl[i])); | 860 | put_page(sg_page(&cmd->tvc_sgl[i])); |
| @@ -859,31 +862,70 @@ vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd, | |||
| 859 | cmd->tvc_sgl_count = 0; | 862 | cmd->tvc_sgl_count = 0; |
| 860 | return ret; | 863 | return ret; |
| 861 | } | 864 | } |
| 862 | |||
| 863 | sg += ret; | 865 | sg += ret; |
| 864 | sgl_count -= ret; | 866 | sgl_count -= ret; |
| 865 | } | 867 | } |
| 866 | return 0; | 868 | return 0; |
| 867 | } | 869 | } |
| 868 | 870 | ||
| 871 | static int | ||
| 872 | vhost_scsi_map_iov_to_prot(struct tcm_vhost_cmd *cmd, | ||
| 873 | struct iovec *iov, | ||
| 874 | int niov, | ||
| 875 | bool write) | ||
| 876 | { | ||
| 877 | struct scatterlist *prot_sg = cmd->tvc_prot_sgl; | ||
| 878 | unsigned int prot_sgl_count = 0; | ||
| 879 | int ret, i; | ||
| 880 | |||
| 881 | for (i = 0; i < niov; i++) | ||
| 882 | prot_sgl_count += iov_num_pages(&iov[i]); | ||
| 883 | |||
| 884 | if (prot_sgl_count > TCM_VHOST_PREALLOC_PROT_SGLS) { | ||
| 885 | pr_err("vhost_scsi_map_iov_to_prot() sgl_count: %u greater than" | ||
| 886 | " preallocated TCM_VHOST_PREALLOC_PROT_SGLS: %u\n", | ||
| 887 | prot_sgl_count, TCM_VHOST_PREALLOC_PROT_SGLS); | ||
| 888 | return -ENOBUFS; | ||
| 889 | } | ||
| 890 | |||
| 891 | pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__, | ||
| 892 | prot_sg, prot_sgl_count); | ||
| 893 | sg_init_table(prot_sg, prot_sgl_count); | ||
| 894 | cmd->tvc_prot_sgl_count = prot_sgl_count; | ||
| 895 | |||
| 896 | for (i = 0; i < niov; i++) { | ||
| 897 | ret = vhost_scsi_map_to_sgl(cmd, prot_sg, prot_sgl_count, &iov[i], | ||
| 898 | cmd->tvc_upages, write); | ||
| 899 | if (ret < 0) { | ||
| 900 | for (i = 0; i < cmd->tvc_prot_sgl_count; i++) | ||
| 901 | put_page(sg_page(&cmd->tvc_prot_sgl[i])); | ||
| 902 | |||
| 903 | cmd->tvc_prot_sgl_count = 0; | ||
| 904 | return ret; | ||
| 905 | } | ||
| 906 | prot_sg += ret; | ||
| 907 | prot_sgl_count -= ret; | ||
| 908 | } | ||
| 909 | return 0; | ||
| 910 | } | ||
| 911 | |||
| 869 | static void tcm_vhost_submission_work(struct work_struct *work) | 912 | static void tcm_vhost_submission_work(struct work_struct *work) |
| 870 | { | 913 | { |
| 871 | struct tcm_vhost_cmd *cmd = | 914 | struct tcm_vhost_cmd *cmd = |
| 872 | container_of(work, struct tcm_vhost_cmd, work); | 915 | container_of(work, struct tcm_vhost_cmd, work); |
| 873 | struct tcm_vhost_nexus *tv_nexus; | 916 | struct tcm_vhost_nexus *tv_nexus; |
| 874 | struct se_cmd *se_cmd = &cmd->tvc_se_cmd; | 917 | struct se_cmd *se_cmd = &cmd->tvc_se_cmd; |
| 875 | struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL; | 918 | struct scatterlist *sg_ptr, *sg_prot_ptr = NULL; |
| 876 | int rc, sg_no_bidi = 0; | 919 | int rc; |
| 877 | 920 | ||
| 921 | /* FIXME: BIDI operation */ | ||
| 878 | if (cmd->tvc_sgl_count) { | 922 | if (cmd->tvc_sgl_count) { |
| 879 | sg_ptr = cmd->tvc_sgl; | 923 | sg_ptr = cmd->tvc_sgl; |
| 880 | /* FIXME: Fix BIDI operation in tcm_vhost_submission_work() */ | 924 | |
| 881 | #if 0 | 925 | if (cmd->tvc_prot_sgl_count) |
| 882 | if (se_cmd->se_cmd_flags & SCF_BIDI) { | 926 | sg_prot_ptr = cmd->tvc_prot_sgl; |
| 883 | sg_bidi_ptr = NULL; | 927 | else |
| 884 | sg_no_bidi = 0; | 928 | se_cmd->prot_pto = true; |
| 885 | } | ||
| 886 | #endif | ||
| 887 | } else { | 929 | } else { |
| 888 | sg_ptr = NULL; | 930 | sg_ptr = NULL; |
| 889 | } | 931 | } |
| @@ -894,7 +936,7 @@ static void tcm_vhost_submission_work(struct work_struct *work) | |||
| 894 | cmd->tvc_lun, cmd->tvc_exp_data_len, | 936 | cmd->tvc_lun, cmd->tvc_exp_data_len, |
| 895 | cmd->tvc_task_attr, cmd->tvc_data_direction, | 937 | cmd->tvc_task_attr, cmd->tvc_data_direction, |
| 896 | TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count, | 938 | TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count, |
| 897 | sg_bidi_ptr, sg_no_bidi, NULL, 0); | 939 | NULL, 0, sg_prot_ptr, cmd->tvc_prot_sgl_count); |
| 898 | if (rc < 0) { | 940 | if (rc < 0) { |
| 899 | transport_send_check_condition_and_sense(se_cmd, | 941 | transport_send_check_condition_and_sense(se_cmd, |
| 900 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); | 942 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); |
| @@ -926,12 +968,18 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
| 926 | { | 968 | { |
| 927 | struct tcm_vhost_tpg **vs_tpg; | 969 | struct tcm_vhost_tpg **vs_tpg; |
| 928 | struct virtio_scsi_cmd_req v_req; | 970 | struct virtio_scsi_cmd_req v_req; |
| 971 | struct virtio_scsi_cmd_req_pi v_req_pi; | ||
| 929 | struct tcm_vhost_tpg *tpg; | 972 | struct tcm_vhost_tpg *tpg; |
| 930 | struct tcm_vhost_cmd *cmd; | 973 | struct tcm_vhost_cmd *cmd; |
| 931 | u32 exp_data_len, data_first, data_num, data_direction; | 974 | u64 tag; |
| 975 | u32 exp_data_len, data_first, data_num, data_direction, prot_first; | ||
| 932 | unsigned out, in, i; | 976 | unsigned out, in, i; |
| 933 | int head, ret; | 977 | int head, ret, data_niov, prot_niov, prot_bytes; |
| 934 | u8 target; | 978 | size_t req_size; |
| 979 | u16 lun; | ||
| 980 | u8 *target, *lunp, task_attr; | ||
| 981 | bool hdr_pi; | ||
| 982 | void *req, *cdb; | ||
| 935 | 983 | ||
| 936 | mutex_lock(&vq->mutex); | 984 | mutex_lock(&vq->mutex); |
| 937 | /* | 985 | /* |
| @@ -962,7 +1010,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
| 962 | break; | 1010 | break; |
| 963 | } | 1011 | } |
| 964 | 1012 | ||
| 965 | /* FIXME: BIDI operation */ | 1013 | /* FIXME: BIDI operation */ |
| 966 | if (out == 1 && in == 1) { | 1014 | if (out == 1 && in == 1) { |
| 967 | data_direction = DMA_NONE; | 1015 | data_direction = DMA_NONE; |
| 968 | data_first = 0; | 1016 | data_first = 0; |
| @@ -992,29 +1040,38 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
| 992 | break; | 1040 | break; |
| 993 | } | 1041 | } |
| 994 | 1042 | ||
| 995 | if (unlikely(vq->iov[0].iov_len != sizeof(v_req))) { | 1043 | if (vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI)) { |
| 996 | vq_err(vq, "Expecting virtio_scsi_cmd_req, got %zu" | 1044 | req = &v_req_pi; |
| 997 | " bytes\n", vq->iov[0].iov_len); | 1045 | lunp = &v_req_pi.lun[0]; |
| 1046 | target = &v_req_pi.lun[1]; | ||
| 1047 | req_size = sizeof(v_req_pi); | ||
| 1048 | hdr_pi = true; | ||
| 1049 | } else { | ||
| 1050 | req = &v_req; | ||
| 1051 | lunp = &v_req.lun[0]; | ||
| 1052 | target = &v_req.lun[1]; | ||
| 1053 | req_size = sizeof(v_req); | ||
| 1054 | hdr_pi = false; | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | if (unlikely(vq->iov[0].iov_len < req_size)) { | ||
| 1058 | pr_err("Expecting virtio-scsi header: %zu, got %zu\n", | ||
| 1059 | req_size, vq->iov[0].iov_len); | ||
| 998 | break; | 1060 | break; |
| 999 | } | 1061 | } |
| 1000 | pr_debug("Calling __copy_from_user: vq->iov[0].iov_base: %p," | 1062 | ret = memcpy_fromiovecend(req, &vq->iov[0], 0, req_size); |
| 1001 | " len: %zu\n", vq->iov[0].iov_base, sizeof(v_req)); | ||
| 1002 | ret = __copy_from_user(&v_req, vq->iov[0].iov_base, | ||
| 1003 | sizeof(v_req)); | ||
| 1004 | if (unlikely(ret)) { | 1063 | if (unlikely(ret)) { |
| 1005 | vq_err(vq, "Faulted on virtio_scsi_cmd_req\n"); | 1064 | vq_err(vq, "Faulted on virtio_scsi_cmd_req\n"); |
| 1006 | break; | 1065 | break; |
| 1007 | } | 1066 | } |
| 1008 | 1067 | ||
| 1009 | /* virtio-scsi spec requires byte 0 of the lun to be 1 */ | 1068 | /* virtio-scsi spec requires byte 0 of the lun to be 1 */ |
| 1010 | if (unlikely(v_req.lun[0] != 1)) { | 1069 | if (unlikely(*lunp != 1)) { |
| 1011 | vhost_scsi_send_bad_target(vs, vq, head, out); | 1070 | vhost_scsi_send_bad_target(vs, vq, head, out); |
| 1012 | continue; | 1071 | continue; |
| 1013 | } | 1072 | } |
| 1014 | 1073 | ||
| 1015 | /* Extract the tpgt */ | 1074 | tpg = ACCESS_ONCE(vs_tpg[*target]); |
| 1016 | target = v_req.lun[1]; | ||
| 1017 | tpg = ACCESS_ONCE(vs_tpg[target]); | ||
| 1018 | 1075 | ||
| 1019 | /* Target does not exist, fail the request */ | 1076 | /* Target does not exist, fail the request */ |
| 1020 | if (unlikely(!tpg)) { | 1077 | if (unlikely(!tpg)) { |
| @@ -1022,17 +1079,79 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
| 1022 | continue; | 1079 | continue; |
| 1023 | } | 1080 | } |
| 1024 | 1081 | ||
| 1082 | data_niov = data_num; | ||
| 1083 | prot_niov = prot_first = prot_bytes = 0; | ||
| 1084 | /* | ||
| 1085 | * Determine if any protection information iovecs are preceeding | ||
| 1086 | * the actual data payload, and adjust data_first + data_niov | ||
| 1087 | * values accordingly for vhost_scsi_map_iov_to_sgl() below. | ||
| 1088 | * | ||
| 1089 | * Also extract virtio_scsi header bits for vhost_scsi_get_tag() | ||
| 1090 | */ | ||
| 1091 | if (hdr_pi) { | ||
| 1092 | if (v_req_pi.pi_bytesout) { | ||
| 1093 | if (data_direction != DMA_TO_DEVICE) { | ||
| 1094 | vq_err(vq, "Received non zero do_pi_niov" | ||
| 1095 | ", but wrong data_direction\n"); | ||
| 1096 | goto err_cmd; | ||
| 1097 | } | ||
| 1098 | prot_bytes = v_req_pi.pi_bytesout; | ||
| 1099 | } else if (v_req_pi.pi_bytesin) { | ||
| 1100 | if (data_direction != DMA_FROM_DEVICE) { | ||
| 1101 | vq_err(vq, "Received non zero di_pi_niov" | ||
| 1102 | ", but wrong data_direction\n"); | ||
| 1103 | goto err_cmd; | ||
| 1104 | } | ||
| 1105 | prot_bytes = v_req_pi.pi_bytesin; | ||
| 1106 | } | ||
| 1107 | if (prot_bytes) { | ||
| 1108 | int tmp = 0; | ||
| 1109 | |||
| 1110 | for (i = 0; i < data_num; i++) { | ||
| 1111 | tmp += vq->iov[data_first + i].iov_len; | ||
| 1112 | prot_niov++; | ||
| 1113 | if (tmp >= prot_bytes) | ||
| 1114 | break; | ||
| 1115 | } | ||
| 1116 | prot_first = data_first; | ||
| 1117 | data_first += prot_niov; | ||
| 1118 | data_niov = data_num - prot_niov; | ||
| 1119 | } | ||
| 1120 | tag = v_req_pi.tag; | ||
| 1121 | task_attr = v_req_pi.task_attr; | ||
| 1122 | cdb = &v_req_pi.cdb[0]; | ||
| 1123 | lun = ((v_req_pi.lun[2] << 8) | v_req_pi.lun[3]) & 0x3FFF; | ||
| 1124 | } else { | ||
| 1125 | tag = v_req.tag; | ||
| 1126 | task_attr = v_req.task_attr; | ||
| 1127 | cdb = &v_req.cdb[0]; | ||
| 1128 | lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF; | ||
| 1129 | } | ||
| 1025 | exp_data_len = 0; | 1130 | exp_data_len = 0; |
| 1026 | for (i = 0; i < data_num; i++) | 1131 | for (i = 0; i < data_niov; i++) |
| 1027 | exp_data_len += vq->iov[data_first + i].iov_len; | 1132 | exp_data_len += vq->iov[data_first + i].iov_len; |
| 1133 | /* | ||
| 1134 | * Check that the recieved CDB size does not exceeded our | ||
| 1135 | * hardcoded max for vhost-scsi | ||
| 1136 | * | ||
| 1137 | * TODO what if cdb was too small for varlen cdb header? | ||
| 1138 | */ | ||
| 1139 | if (unlikely(scsi_command_size(cdb) > TCM_VHOST_MAX_CDB_SIZE)) { | ||
| 1140 | vq_err(vq, "Received SCSI CDB with command_size: %d that" | ||
| 1141 | " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n", | ||
| 1142 | scsi_command_size(cdb), TCM_VHOST_MAX_CDB_SIZE); | ||
| 1143 | goto err_cmd; | ||
| 1144 | } | ||
| 1028 | 1145 | ||
| 1029 | cmd = vhost_scsi_get_tag(vq, tpg, &v_req, | 1146 | cmd = vhost_scsi_get_tag(vq, tpg, cdb, tag, lun, task_attr, |
| 1030 | exp_data_len, data_direction); | 1147 | exp_data_len + prot_bytes, |
| 1148 | data_direction); | ||
| 1031 | if (IS_ERR(cmd)) { | 1149 | if (IS_ERR(cmd)) { |
| 1032 | vq_err(vq, "vhost_scsi_get_tag failed %ld\n", | 1150 | vq_err(vq, "vhost_scsi_get_tag failed %ld\n", |
| 1033 | PTR_ERR(cmd)); | 1151 | PTR_ERR(cmd)); |
| 1034 | goto err_cmd; | 1152 | goto err_cmd; |
| 1035 | } | 1153 | } |
| 1154 | |||
| 1036 | pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction" | 1155 | pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction" |
| 1037 | ": %d\n", cmd, exp_data_len, data_direction); | 1156 | ": %d\n", cmd, exp_data_len, data_direction); |
| 1038 | 1157 | ||
| @@ -1040,40 +1159,28 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
| 1040 | cmd->tvc_vq = vq; | 1159 | cmd->tvc_vq = vq; |
| 1041 | cmd->tvc_resp = vq->iov[out].iov_base; | 1160 | cmd->tvc_resp = vq->iov[out].iov_base; |
| 1042 | 1161 | ||
| 1043 | /* | ||
| 1044 | * Copy in the recieved CDB descriptor into cmd->tvc_cdb | ||
| 1045 | * that will be used by tcm_vhost_new_cmd_map() and down into | ||
| 1046 | * target_setup_cmd_from_cdb() | ||
| 1047 | */ | ||
| 1048 | memcpy(cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE); | ||
| 1049 | /* | ||
| 1050 | * Check that the recieved CDB size does not exceeded our | ||
| 1051 | * hardcoded max for tcm_vhost | ||
| 1052 | */ | ||
| 1053 | /* TODO what if cdb was too small for varlen cdb header? */ | ||
| 1054 | if (unlikely(scsi_command_size(cmd->tvc_cdb) > | ||
| 1055 | TCM_VHOST_MAX_CDB_SIZE)) { | ||
| 1056 | vq_err(vq, "Received SCSI CDB with command_size: %d that" | ||
| 1057 | " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n", | ||
| 1058 | scsi_command_size(cmd->tvc_cdb), | ||
| 1059 | TCM_VHOST_MAX_CDB_SIZE); | ||
| 1060 | goto err_free; | ||
| 1061 | } | ||
| 1062 | cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF; | ||
| 1063 | |||
| 1064 | pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n", | 1162 | pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n", |
| 1065 | cmd->tvc_cdb[0], cmd->tvc_lun); | 1163 | cmd->tvc_cdb[0], cmd->tvc_lun); |
| 1066 | 1164 | ||
| 1165 | if (prot_niov) { | ||
| 1166 | ret = vhost_scsi_map_iov_to_prot(cmd, | ||
| 1167 | &vq->iov[prot_first], prot_niov, | ||
| 1168 | data_direction == DMA_FROM_DEVICE); | ||
| 1169 | if (unlikely(ret)) { | ||
| 1170 | vq_err(vq, "Failed to map iov to" | ||
| 1171 | " prot_sgl\n"); | ||
| 1172 | goto err_free; | ||
| 1173 | } | ||
| 1174 | } | ||
| 1067 | if (data_direction != DMA_NONE) { | 1175 | if (data_direction != DMA_NONE) { |
| 1068 | ret = vhost_scsi_map_iov_to_sgl(cmd, | 1176 | ret = vhost_scsi_map_iov_to_sgl(cmd, |
| 1069 | &vq->iov[data_first], data_num, | 1177 | &vq->iov[data_first], data_niov, |
| 1070 | data_direction == DMA_FROM_DEVICE); | 1178 | data_direction == DMA_FROM_DEVICE); |
| 1071 | if (unlikely(ret)) { | 1179 | if (unlikely(ret)) { |
| 1072 | vq_err(vq, "Failed to map iov to sgl\n"); | 1180 | vq_err(vq, "Failed to map iov to sgl\n"); |
| 1073 | goto err_free; | 1181 | goto err_free; |
| 1074 | } | 1182 | } |
| 1075 | } | 1183 | } |
| 1076 | |||
| 1077 | /* | 1184 | /* |
| 1078 | * Save the descriptor from vhost_get_vq_desc() to be used to | 1185 | * Save the descriptor from vhost_get_vq_desc() to be used to |
| 1079 | * complete the virtio-scsi request in TCM callback context via | 1186 | * 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, | |||
| 1716 | tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i]; | 1823 | tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i]; |
| 1717 | 1824 | ||
| 1718 | kfree(tv_cmd->tvc_sgl); | 1825 | kfree(tv_cmd->tvc_sgl); |
| 1826 | kfree(tv_cmd->tvc_prot_sgl); | ||
| 1719 | kfree(tv_cmd->tvc_upages); | 1827 | kfree(tv_cmd->tvc_upages); |
| 1720 | } | 1828 | } |
| 1721 | } | 1829 | } |
| @@ -1750,7 +1858,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg, | |||
| 1750 | tv_nexus->tvn_se_sess = transport_init_session_tags( | 1858 | tv_nexus->tvn_se_sess = transport_init_session_tags( |
| 1751 | TCM_VHOST_DEFAULT_TAGS, | 1859 | TCM_VHOST_DEFAULT_TAGS, |
| 1752 | sizeof(struct tcm_vhost_cmd), | 1860 | sizeof(struct tcm_vhost_cmd), |
| 1753 | TARGET_PROT_NORMAL); | 1861 | TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS); |
| 1754 | if (IS_ERR(tv_nexus->tvn_se_sess)) { | 1862 | if (IS_ERR(tv_nexus->tvn_se_sess)) { |
| 1755 | mutex_unlock(&tpg->tv_tpg_mutex); | 1863 | mutex_unlock(&tpg->tv_tpg_mutex); |
| 1756 | kfree(tv_nexus); | 1864 | kfree(tv_nexus); |
| @@ -1769,12 +1877,20 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg, | |||
| 1769 | } | 1877 | } |
| 1770 | 1878 | ||
| 1771 | tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) * | 1879 | tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) * |
| 1772 | TCM_VHOST_PREALLOC_PAGES, GFP_KERNEL); | 1880 | TCM_VHOST_PREALLOC_UPAGES, GFP_KERNEL); |
| 1773 | if (!tv_cmd->tvc_upages) { | 1881 | if (!tv_cmd->tvc_upages) { |
| 1774 | mutex_unlock(&tpg->tv_tpg_mutex); | 1882 | mutex_unlock(&tpg->tv_tpg_mutex); |
| 1775 | pr_err("Unable to allocate tv_cmd->tvc_upages\n"); | 1883 | pr_err("Unable to allocate tv_cmd->tvc_upages\n"); |
| 1776 | goto out; | 1884 | goto out; |
| 1777 | } | 1885 | } |
| 1886 | |||
| 1887 | tv_cmd->tvc_prot_sgl = kzalloc(sizeof(struct scatterlist) * | ||
| 1888 | TCM_VHOST_PREALLOC_PROT_SGLS, GFP_KERNEL); | ||
| 1889 | if (!tv_cmd->tvc_prot_sgl) { | ||
| 1890 | mutex_unlock(&tpg->tv_tpg_mutex); | ||
| 1891 | pr_err("Unable to allocate tv_cmd->tvc_prot_sgl\n"); | ||
| 1892 | goto out; | ||
| 1893 | } | ||
| 1778 | } | 1894 | } |
| 1779 | /* | 1895 | /* |
| 1780 | * Since we are running in 'demo mode' this call with generate a | 1896 | * Since we are running in 'demo mode' this call with generate a |
diff --git a/include/linux/virtio_scsi.h b/include/linux/virtio_scsi.h index 4195b97a3def..de429d1f4357 100644 --- a/include/linux/virtio_scsi.h +++ b/include/linux/virtio_scsi.h | |||
| @@ -35,11 +35,23 @@ struct virtio_scsi_cmd_req { | |||
| 35 | u8 lun[8]; /* Logical Unit Number */ | 35 | u8 lun[8]; /* Logical Unit Number */ |
| 36 | u64 tag; /* Command identifier */ | 36 | u64 tag; /* Command identifier */ |
| 37 | u8 task_attr; /* Task attribute */ | 37 | u8 task_attr; /* Task attribute */ |
| 38 | u8 prio; | 38 | u8 prio; /* SAM command priority field */ |
| 39 | u8 crn; | 39 | u8 crn; |
| 40 | u8 cdb[VIRTIO_SCSI_CDB_SIZE]; | 40 | u8 cdb[VIRTIO_SCSI_CDB_SIZE]; |
| 41 | } __packed; | 41 | } __packed; |
| 42 | 42 | ||
| 43 | /* SCSI command request, followed by protection information */ | ||
| 44 | struct virtio_scsi_cmd_req_pi { | ||
| 45 | u8 lun[8]; /* Logical Unit Number */ | ||
| 46 | u64 tag; /* Command identifier */ | ||
| 47 | u8 task_attr; /* Task attribute */ | ||
| 48 | u8 prio; /* SAM command priority field */ | ||
| 49 | u8 crn; | ||
| 50 | u32 pi_bytesout; /* DataOUT PI Number of bytes */ | ||
| 51 | u32 pi_bytesin; /* DataIN PI Number of bytes */ | ||
| 52 | u8 cdb[VIRTIO_SCSI_CDB_SIZE]; | ||
| 53 | } __packed; | ||
| 54 | |||
| 43 | /* Response, followed by sense data and data-in */ | 55 | /* Response, followed by sense data and data-in */ |
| 44 | struct virtio_scsi_cmd_resp { | 56 | struct virtio_scsi_cmd_resp { |
| 45 | u32 sense_len; /* Sense data length */ | 57 | u32 sense_len; /* Sense data length */ |
| @@ -97,6 +109,7 @@ struct virtio_scsi_config { | |||
| 97 | #define VIRTIO_SCSI_F_INOUT 0 | 109 | #define VIRTIO_SCSI_F_INOUT 0 |
| 98 | #define VIRTIO_SCSI_F_HOTPLUG 1 | 110 | #define VIRTIO_SCSI_F_HOTPLUG 1 |
| 99 | #define VIRTIO_SCSI_F_CHANGE 2 | 111 | #define VIRTIO_SCSI_F_CHANGE 2 |
| 112 | #define VIRTIO_SCSI_F_T10_PI 3 | ||
| 100 | 113 | ||
| 101 | /* Response codes */ | 114 | /* Response codes */ |
| 102 | #define VIRTIO_SCSI_S_OK 0 | 115 | #define VIRTIO_SCSI_S_OK 0 |
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index e016e2ac38df..42ed789ebafc 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
| 8 | #include <linux/timer.h> | 8 | #include <linux/timer.h> |
| 9 | #include <linux/scatterlist.h> | 9 | #include <linux/scatterlist.h> |
| 10 | #include <scsi/scsi_device.h> | ||
| 10 | 11 | ||
| 11 | struct Scsi_Host; | 12 | struct Scsi_Host; |
| 12 | struct scsi_device; | 13 | struct scsi_device; |
| @@ -315,4 +316,20 @@ static inline void set_driver_byte(struct scsi_cmnd *cmd, char status) | |||
| 315 | cmd->result = (cmd->result & 0x00ffffff) | (status << 24); | 316 | cmd->result = (cmd->result & 0x00ffffff) | (status << 24); |
| 316 | } | 317 | } |
| 317 | 318 | ||
| 319 | static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd) | ||
| 320 | { | ||
| 321 | unsigned int xfer_len = blk_rq_bytes(scmd->request); | ||
| 322 | unsigned int prot_op = scsi_get_prot_op(scmd); | ||
| 323 | unsigned int sector_size = scmd->device->sector_size; | ||
| 324 | |||
| 325 | switch (prot_op) { | ||
| 326 | case SCSI_PROT_NORMAL: | ||
| 327 | case SCSI_PROT_WRITE_STRIP: | ||
| 328 | case SCSI_PROT_READ_INSERT: | ||
| 329 | return xfer_len; | ||
| 330 | } | ||
| 331 | |||
| 332 | return xfer_len + (xfer_len >> ilog2(sector_size)) * 8; | ||
| 333 | } | ||
| 334 | |||
| 318 | #endif /* _SCSI_SCSI_CMND_H */ | 335 | #endif /* _SCSI_SCSI_CMND_H */ |
diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h index 33b487b5da92..daef9daa500c 100644 --- a/include/target/iscsi/iscsi_transport.h +++ b/include/target/iscsi/iscsi_transport.h | |||
| @@ -70,7 +70,8 @@ extern void iscsit_build_nopin_rsp(struct iscsi_cmd *, struct iscsi_conn *, | |||
| 70 | extern void iscsit_build_task_mgt_rsp(struct iscsi_cmd *, struct iscsi_conn *, | 70 | extern void iscsit_build_task_mgt_rsp(struct iscsi_cmd *, struct iscsi_conn *, |
| 71 | struct iscsi_tm_rsp *); | 71 | struct iscsi_tm_rsp *); |
| 72 | extern int iscsit_build_text_rsp(struct iscsi_cmd *, struct iscsi_conn *, | 72 | extern int iscsit_build_text_rsp(struct iscsi_cmd *, struct iscsi_conn *, |
| 73 | struct iscsi_text_rsp *); | 73 | struct iscsi_text_rsp *, |
| 74 | enum iscsit_transport_type); | ||
| 74 | extern void iscsit_build_reject(struct iscsi_cmd *, struct iscsi_conn *, | 75 | extern void iscsit_build_reject(struct iscsi_cmd *, struct iscsi_conn *, |
| 75 | struct iscsi_reject *); | 76 | struct iscsi_reject *); |
| 76 | extern int iscsit_build_logout_rsp(struct iscsi_cmd *, struct iscsi_conn *, | 77 | extern int iscsit_build_logout_rsp(struct iscsi_cmd *, struct iscsi_conn *, |
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 3a1c1eea1fff..9adc1bca1178 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h | |||
| @@ -59,6 +59,7 @@ int transport_subsystem_register(struct se_subsystem_api *); | |||
| 59 | void transport_subsystem_release(struct se_subsystem_api *); | 59 | void transport_subsystem_release(struct se_subsystem_api *); |
| 60 | 60 | ||
| 61 | void target_complete_cmd(struct se_cmd *, u8); | 61 | void target_complete_cmd(struct se_cmd *, u8); |
| 62 | void target_complete_cmd_with_length(struct se_cmd *, u8, int); | ||
| 62 | 63 | ||
| 63 | sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size); | 64 | sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size); |
| 64 | sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd); | 65 | sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd); |
