diff --git a/iscsi-scst/kernel/isert-scst/iser.h b/iscsi-scst/kernel/isert-scst/iser.h index 90fa056a2..eeb8040fc 100644 --- a/iscsi-scst/kernel/isert-scst/iser.h +++ b/iscsi-scst/kernel/isert-scst/iser.h @@ -98,7 +98,11 @@ struct isert_wr { struct ib_sge *sge_list; union { struct ib_recv_wr recv_wr; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) struct ib_send_wr send_wr; +#else + struct ib_rdma_wr send_wr; +#endif }; } ____cacheline_aligned; diff --git a/iscsi-scst/kernel/isert-scst/iser_buf.c b/iscsi-scst/kernel/isert-scst/iser_buf.c index daa78c72a..7bd34c9a2 100644 --- a/iscsi-scst/kernel/isert-scst/iser_buf.c +++ b/iscsi-scst/kernel/isert-scst/iser_buf.c @@ -238,9 +238,14 @@ int isert_wr_init(struct isert_wr *wr, buff_offset = -EFAULT; goto out; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) wr->send_wr.wr.rdma.remote_addr = pdu->rem_write_va + buff_offset; wr->send_wr.wr.rdma.rkey = pdu->rem_write_stag; +#else + wr->send_wr.remote_addr = pdu->rem_write_va + buff_offset; + wr->send_wr.rkey = pdu->rem_write_stag; +#endif break; case ISER_WR_RDMA_WRITE: send_wr_op = IB_WR_RDMA_WRITE; @@ -250,9 +255,14 @@ int isert_wr_init(struct isert_wr *wr, buff_offset = -EFAULT; goto out; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) wr->send_wr.wr.rdma.remote_addr = pdu->rem_read_va + buff_offset; wr->send_wr.wr.rdma.rkey = pdu->rem_read_stag; +#else + wr->send_wr.remote_addr = pdu->rem_read_va + buff_offset; + wr->send_wr.rkey = pdu->rem_read_stag; +#endif break; default: BUG(); @@ -278,12 +288,21 @@ int isert_wr_init(struct isert_wr *wr, wr->recv_wr.sg_list = wr->sge_list; wr->recv_wr.num_sge = sg_cnt; } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) wr->send_wr.next = NULL; wr->send_wr.wr_id = _ptr_to_u64(wr); wr->send_wr.sg_list = wr->sge_list; wr->send_wr.num_sge = sg_cnt; wr->send_wr.opcode = send_wr_op; wr->send_wr.send_flags = send_flags; +#else + wr->send_wr.wr.next = NULL; + wr->send_wr.wr.wr_id = _ptr_to_u64(wr); + wr->send_wr.wr.sg_list = wr->sge_list; + wr->send_wr.wr.num_sge = sg_cnt; + wr->send_wr.wr.opcode = send_wr_op; + wr->send_wr.wr.send_flags = send_flags; +#endif } out: diff --git a/iscsi-scst/kernel/isert-scst/iser_pdu.c b/iscsi-scst/kernel/isert-scst/iser_pdu.c index 0c6e81b32..cf30db258 100644 --- a/iscsi-scst/kernel/isert-scst/iser_pdu.c +++ b/iscsi-scst/kernel/isert-scst/iser_pdu.c @@ -214,7 +214,11 @@ out: static inline void isert_link_send_wrs(struct isert_wr *from_wr, struct isert_wr *to_wr) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) from_wr->send_wr.next = &to_wr->send_wr; +#else + from_wr->send_wr.wr.next = &to_wr->send_wr.wr; +#endif } static inline void isert_link_send_pdu_wrs(struct isert_cmnd *from_pdu, @@ -222,7 +226,11 @@ static inline void isert_link_send_pdu_wrs(struct isert_cmnd *from_pdu, int wr_cnt) { isert_link_send_wrs(&from_pdu->wr[wr_cnt - 1], &to_pdu->wr[0]); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) to_pdu->wr[0].send_wr.next = NULL; +#else + to_pdu->wr[0].send_wr.wr.next = NULL; +#endif } int isert_prepare_rdma(struct isert_cmnd *isert_pdu, @@ -281,8 +289,14 @@ int isert_prepare_rdma(struct isert_cmnd *isert_pdu, isert_link_send_wrs(&isert_pdu->wr[i - 1], &isert_pdu->wr[i]); if (op == ISER_WR_RDMA_READ) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) isert_pdu->wr[wr_cnt - 1].send_wr.send_flags = IB_SEND_SIGNALED; isert_pdu->wr[wr_cnt - 1].send_wr.next = NULL; +#else + isert_pdu->wr[wr_cnt - 1].send_wr.wr.send_flags = + IB_SEND_SIGNALED; + isert_pdu->wr[wr_cnt - 1].send_wr.wr.next = NULL; +#endif } out: @@ -574,7 +588,11 @@ int isert_pdu_send(struct isert_connection *isert_conn, #endif wr = &tx_pdu->wr[0]; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) wr->send_wr.num_sge = isert_pdu_prepare_send(isert_conn, tx_pdu); +#else + wr->send_wr.wr.num_sge = isert_pdu_prepare_send(isert_conn, tx_pdu); +#endif err = isert_post_send(isert_conn, wr, 1); if (unlikely(err)) { @@ -595,8 +613,13 @@ int isert_pdu_post_rdma_write(struct isert_connection *isert_conn, TRACE_ENTRY(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) isert_rsp->wr[0].send_wr.num_sge = isert_pdu_prepare_send(isert_conn, isert_rsp); +#else + isert_rsp->wr[0].send_wr.wr.num_sge = isert_pdu_prepare_send(isert_conn, + isert_rsp); +#endif isert_link_send_pdu_wrs(isert_cmd, isert_rsp, wr_cnt); err = isert_post_send(isert_conn, &isert_cmd->wr[0], wr_cnt + 1); if (unlikely(err)) { diff --git a/iscsi-scst/kernel/isert-scst/iser_rdma.c b/iscsi-scst/kernel/isert-scst/iser_rdma.c index 8fd02ab4a..08050a221 100644 --- a/iscsi-scst/kernel/isert-scst/iser_rdma.c +++ b/iscsi-scst/kernel/isert-scst/iser_rdma.c @@ -103,7 +103,11 @@ int isert_post_send(struct isert_connection *isert_conn, struct isert_wr *first_wr, int num_wr) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) struct ib_send_wr *first_ib_wr = &first_wr->send_wr; +#else + struct ib_send_wr *first_ib_wr = &first_wr->send_wr.wr; +#endif struct ib_send_wr *bad_wr; int num_posted; int err; @@ -131,9 +135,19 @@ void isert_post_drain(struct isert_connection *isert_conn) isert_wr_set_fields(&isert_conn->drain_wr, isert_conn, NULL); isert_conn->drain_wr.wr_op = ISER_WR_SEND; - isert_conn->drain_wr.send_wr.wr_id = _ptr_to_u64(&isert_conn->drain_wr); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) + isert_conn->drain_wr.send_wr.wr_id = + _ptr_to_u64(&isert_conn->drain_wr); isert_conn->drain_wr.send_wr.opcode = IB_WR_SEND; - err = ib_post_send(isert_conn->qp, &isert_conn->drain_wr.send_wr, &bad_wr); + err = ib_post_send(isert_conn->qp, + &isert_conn->drain_wr.send_wr, &bad_wr); +#else + isert_conn->drain_wr.send_wr.wr.wr_id = + _ptr_to_u64(&isert_conn->drain_wr); + isert_conn->drain_wr.send_wr.wr.opcode = IB_WR_SEND; + err = ib_post_send(isert_conn->qp, + &isert_conn->drain_wr.send_wr.wr, &bad_wr); +#endif if (unlikely(err)) { pr_err("Failed to post drain wr, err:%d\n", err); /* @@ -601,6 +615,7 @@ static void isert_handle_wc_error(struct ib_wc *wc) struct isert_buf *isert_buf = wr->buf; struct isert_device *isert_dev = wr->isert_dev; struct ib_device *ib_dev = isert_dev->ib_dev; + u32 num_sge; TRACE_ENTRY(); @@ -615,7 +630,12 @@ static void isert_handle_wc_error(struct ib_wc *wc) switch (wr->wr_op) { case ISER_WR_SEND: - if (unlikely(wr->send_wr.num_sge == 0)) /* Drain WR */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) + num_sge = wr->send_wr.num_sge; +#else + num_sge = wr->send_wr.wr.num_sge; +#endif + if (unlikely(num_sge == 0)) /* Drain WR */ isert_sched_conn_drained(isert_conn); else isert_pdu_err(&isert_pdu->iscsi); @@ -1648,9 +1668,12 @@ struct isert_portal *isert_portal_create(void) #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) && \ (!defined(RHEL_MAJOR) || RHEL_MAJOR -0 <= 5) cm_id = rdma_create_id(isert_cm_evt_handler, portal, RDMA_PS_TCP); -#else +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) cm_id = rdma_create_id(isert_cm_evt_handler, portal, RDMA_PS_TCP, IB_QPT_RC); +#else + cm_id = rdma_create_id(&init_net, isert_cm_evt_handler, portal, + RDMA_PS_TCP, IB_QPT_RC); #endif if (unlikely(IS_ERR(cm_id))) { err = PTR_ERR(cm_id); diff --git a/scst/README b/scst/README index aba51c655..1e45fb175 100644 --- a/scst/README +++ b/scst/README @@ -441,6 +441,19 @@ following entries: have different IDs and SNs. For instance, VDISK dev handler uses this ID to generate T10 vendor specific identifier and SN of the devices. + - suspend - globally suspends or releases all SCSI activities on all + devices. Useful for mass management, like adding or deleting LUNs. + Writing to it value v: + + * v > 0 - suspends activities, but waits no more, than v seconds + + * v = 0 - suspends activities, waits indefinitely + + * V < 0 - releases activities. + + Reading from this attribute returns number of previous suspend + requests. + - threads - allows to read and set number of global SCST I/O threads. Those threads used with async. dev handlers, for instance, vdisk BLOCKIO or NULLIO. @@ -1846,34 +1859,25 @@ EXTENDED COPY ~~~~~~~~~~~~~ SCST implements EXTENDED COPY via internal Copy Manager target. This -target has the following specific attributes in its sysfs: +target has the following specific attribute in its sysfs: - allow_not_connected_copy - if not set (default), an initiator can perform copy only between devices it has direct access to via any target/session. If set, any initiator can copy between any devices in the system. - - mgmt - this attribute allows to control data from which devices can -be copied using Copy Manager. By default, devices belonging to dev -handlers with flag auto_cm_assignment_possible set are auto assigned to -the Copy Manager on the registration. Currently, only vdisk has this -flag set, so all other devices (pass-through, user space, etc.) should -be assigned to the Copy Manager manually. - -Mgmt attribute supports the following commands: - - - add [vname|H:C:I:L] - adds device with name vname or H:C:I:L numbers -(pass-through) to the Copy Manager. - - - del [vname|H:C:I:L] - deletes device with name vname or H:C:I:L numbers -(pass-through) from the Copy Manager. - +The Copy Manager has access only to those devices, for which it has LUNs +in /sys/kernel/scst_tgt/targets/copy_manager/copy_manager_tgt/luns/. +Devices from scst_vdisk dev handler added to it automatically upon +registration, but for other devices you need to manually add LUNs there +the same way as for any target driver. You can also delete any device at +any time from the Copy Manager visibility by deleting the corresponding +LUN from the sysfs. It might be useful during ALUA state switching. Internally SCST implements EXTENDED COPY as generation of sets of internal READ(16) and WRITE(16) SCSI commands. Dev handlers don't need any manual actions to use it. - Also SCST provides for dev handlers possibility to remap blocks instead of copy them, if they support this feature. It allows them to perform EXTENDED COPY command much faster by just metadata update of their diff --git a/scst/README_in-tree b/scst/README_in-tree index 91d0b6ca6..669f97f44 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -305,6 +305,19 @@ following entries: have different IDs and SNs. For instance, VDISK dev handler uses this ID to generate T10 vendor specific identifier and SN of the devices. + - suspend - globally suspends or releases all SCSI activities on all + devices. Useful for mass management, like adding or deleting LUNs. + Writing to it value v: + + * v > 0 - suspends activities, but waits no more, than v seconds + + * v = 0 - suspends activities, waits indefinitely + + * V < 0 - releases activities. + + Reading from this attribute returns number of previous suspend + requests. + - threads - allows to read and set number of global SCST I/O threads. Those threads used with async. dev handlers, for instance, vdisk BLOCKIO or NULLIO. @@ -1699,34 +1712,25 @@ EXTENDED COPY ~~~~~~~~~~~~~ SCST implements EXTENDED COPY via internal Copy Manager target. This -target has the following specific attributes in its sysfs: +target has the following specific attribute in its sysfs: - allow_not_connected_copy - if not set (default), an initiator can perform copy only between devices it has direct access to via any target/session. If set, any initiator can copy between any devices in the system. - - mgmt - this attribute allows to control data from which devices can -be copied using Copy Manager. By default, devices belonging to dev -handlers with flag auto_cm_assignment_possible set are auto assigned to -the Copy Manager on the registration. Currently, only vdisk has this -flag set, so all other devices (pass-through, user space, etc.) should -be assigned to the Copy Manager manually. - -Mgmt attribute supports the following commands: - - - add [vname|H:C:I:L] - adds device with name vname or H:C:I:L numbers -(pass-through) to the Copy Manager. - - - del [vname|H:C:I:L] - deletes device with name vname or H:C:I:L numbers -(pass-through) from the Copy Manager. - +The Copy Manager has access only to those devices, for which it has LUNs +in /sys/kernel/scst_tgt/targets/copy_manager/copy_manager_tgt/luns/. +Devices from scst_vdisk dev handler added to it automatically upon +registration, but for other devices you need to manually add LUNs there +the same way as for any target driver. You can also delete any device at +any time from the Copy Manager visibility by deleting the corresponding +LUN from the sysfs. It might be useful during ALUA state switching. Internally SCST implements EXTENDED COPY as generation of sets of internal READ(16) and WRITE(16) SCSI commands. Dev handlers don't need any manual actions to use it. - Also SCST provides for dev handlers possibility to remap blocks instead of copy them, if they support this feature. It allows them to perform EXTENDED COPY command much faster by just metadata update of their diff --git a/scst/src/Makefile b/scst/src/Makefile index 51d83b986..7e1209cc9 100644 --- a/scst/src/Makefile +++ b/scst/src/Makefile @@ -49,12 +49,7 @@ scst-y += scst_mem.o scst-y += scst_debug.o scst-y += scst_pres.o scst-y += scst_no_dlm.o -ifdef CONFIG_DLM scst-y += scst_dlm.o -endif -ifdef CONFIG_DLM_MODULE -scst-y += scst_dlm.o -endif scst-y += scst_tg.o scst-y += scst_event.o scst-y += scst_copy_mgr.o @@ -160,7 +155,8 @@ INSTALL_DIR_H := $(DESTDIR)$(PREFIX)/include/scst enable-Wextra = $(shell uname_r="$$(uname -r)"; if [ "$${uname_r%.el5}" = "$${uname_r}" ]; then echo "$(1)"; fi) EXTRA_CFLAGS += -I$(SCST_INC_DIR) $(call enable-Wextra,-Wextra \ - -Wno-unused-parameter -Wno-missing-field-initializers) + -Wno-unused-parameter -Wno-missing-field-initializers) \ + $(shell [ -n "${CONFIG_SCST_NO_DLM}" ] && echo -DCONFIG_SCST_NO_DLM) #EXTRA_CFLAGS += -DCONFIG_SCST_STRICT_SERIALIZING diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 085bf56a7..0f5bf3bbb 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -1407,6 +1407,7 @@ static int vdisk_init_block_integrity(struct scst_vdisk_dev *virt_dev) struct inode *inode; struct file *fd; struct blk_integrity *bi; + const char *bi_profile_name; TRACE_ENTRY(); @@ -1430,9 +1431,14 @@ static int vdisk_init_block_integrity(struct scst_vdisk_dev *virt_dev) goto out_no_bi; } - TRACE_DBG("BI name %s", bi->name); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) + bi_profile_name = bi->name; +#else + bi_profile_name = bi->profile->name; +#endif + TRACE_DBG("BI name %s", bi_profile_name); - if (!strcmp(bi->name, "T10-DIF-TYPE1-CRC")) { + if (!strcmp(bi_profile_name, "T10-DIF-TYPE1-CRC")) { dev->dev_dif_ip_not_supported = 1; if (virt_dev->dif_type != 1) { PRINT_ERROR("Integrity type mismatch, %d expected, " @@ -1441,7 +1447,7 @@ static int vdisk_init_block_integrity(struct scst_vdisk_dev *virt_dev) res = -EINVAL; goto out_close; } - } else if (!strcmp(bi->name, "T10-DIF-TYPE1-IP")) { + } else if (!strcmp(bi_profile_name, "T10-DIF-TYPE1-IP")) { if (virt_dev->dif_type != 1) { PRINT_ERROR("Integrity type mismatch, %d expected, " "but block device has 1 (dev %s)", @@ -1449,7 +1455,7 @@ static int vdisk_init_block_integrity(struct scst_vdisk_dev *virt_dev) res = -EINVAL; goto out_close; } - } else if (!strcmp(bi->name, "T10-DIF-TYPE3-CRC")) { + } else if (!strcmp(bi_profile_name, "T10-DIF-TYPE3-CRC")) { dev->dev_dif_ip_not_supported = 1; if (virt_dev->dif_type != 3) { PRINT_ERROR("Integrity type mismatch, %d expected, " @@ -1458,7 +1464,7 @@ static int vdisk_init_block_integrity(struct scst_vdisk_dev *virt_dev) res = -EINVAL; goto out_close; } - } else if (!strcmp(bi->name, "T10-DIF-TYPE3-IP")) { + } else if (!strcmp(bi_profile_name, "T10-DIF-TYPE3-IP")) { if (virt_dev->dif_type != 3) { PRINT_ERROR("Integrity type mismatch, %d expected, " "but block device has 3 (dev %s)", @@ -1468,7 +1474,7 @@ static int vdisk_init_block_integrity(struct scst_vdisk_dev *virt_dev) } } else { PRINT_ERROR("Unable to understand integrity name %s" - "(dev %s)", bi->name, dev->virt_name); + "(dev %s)", bi_profile_name, dev->virt_name); res = -EINVAL; goto out_close; } @@ -2790,6 +2796,7 @@ static const struct scst_opcode_descriptor *vdisk_opcode_descriptors_type2[] = { &scst_op_descr_write_verify32, &scst_op_descr_write_same32, SCST_OPCODE_DESCRIPTORS + &scst_op_descr_stpg, /* must be last, see vdisk_get_supported_opcodes()! */ }; static const struct scst_opcode_descriptor *vcdrom_opcode_descriptors[] = { diff --git a/scst/src/scst_copy_mgr.c b/scst/src/scst_copy_mgr.c index c59233ba8..6fcfbfea7 100644 --- a/scst/src/scst_copy_mgr.c +++ b/scst/src/scst_copy_mgr.c @@ -2519,14 +2519,16 @@ static bool scst_cm_is_lun_free(unsigned int lun) } /* scst_mutex supposed to be held and activities suspended */ -static int scst_cm_dev_register(struct scst_device *dev) +static int scst_cm_dev_register(struct scst_device *dev, uint64_t lun) { int res, i; - unsigned int lun; struct scst_acg_dev *acg_dev; + bool add_lun; TRACE_ENTRY(); + TRACE_DBG("dev %s, LUN %ld", dev->virt_name, (unsigned long)lun); + for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) { struct scst_tgt_dev *tgt_dev; struct list_head *head = &scst_cm_sess->sess_tgt_dev_list[i]; @@ -2541,18 +2543,25 @@ static int scst_cm_dev_register(struct scst_device *dev) } } - while (1) { - lun = scst_cm_next_lun++; - if (lun == SCST_MAX_LUN) - continue; - if (scst_cm_is_lun_free(lun)) - break; - }; + if (lun == SCST_MAX_LUN) { + add_lun = true; + while (1) { + lun = scst_cm_next_lun++; + if (lun == SCST_MAX_LUN) + continue; + if (scst_cm_is_lun_free(lun)) + break; + } + } else + add_lun = false; - res = scst_acg_add_lun(scst_cm_tgt->default_acg, - scst_cm_tgt->tgt_luns_kobj, dev, lun, false, false, &acg_dev); - if (res != 0) - goto out_err; + if (add_lun) { + res = scst_acg_add_lun(scst_cm_tgt->default_acg, + scst_cm_tgt->tgt_luns_kobj, dev, lun, SCST_ADD_LUN_CM, + &acg_dev); + if (res != 0) + goto out_err; + } spin_lock_bh(&dev->dev_lock); scst_block_dev(dev); @@ -2578,13 +2587,15 @@ out_err: } /* scst_mutex supposed to be held and activities suspended */ -static void scst_cm_dev_unregister(struct scst_device *dev) +static void scst_cm_dev_unregister(struct scst_device *dev, bool del_lun) { int i; struct scst_cm_desig *des, *t; TRACE_ENTRY(); + TRACE_DBG("dev %s, del_lun %d", dev->virt_name, del_lun); + list_for_each_entry_safe(des, t, &scst_cm_desig_list, cm_desig_list_entry) { if (des->desig_tgt_dev->dev == dev) { TRACE_DBG("Deleting des %p", des); @@ -2593,6 +2604,9 @@ static void scst_cm_dev_unregister(struct scst_device *dev) } } + if (!del_lun) + goto out; + for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) { struct scst_tgt_dev *tgt_dev; struct list_head *head = &scst_cm_sess->sess_tgt_dev_list[i]; @@ -2606,6 +2620,7 @@ static void scst_cm_dev_unregister(struct scst_device *dev) } } +out: TRACE_EXIT(); return; } @@ -2620,7 +2635,7 @@ int scst_cm_on_dev_register(struct scst_device *dev) if (!dev->handler->auto_cm_assignment_possible) goto out; - res = scst_cm_dev_register(dev); + res = scst_cm_dev_register(dev, SCST_MAX_LUN); out: TRACE_EXIT_RES(res); @@ -2632,12 +2647,87 @@ void scst_cm_on_dev_unregister(struct scst_device *dev) { TRACE_ENTRY(); - scst_cm_dev_unregister(dev); + scst_cm_dev_unregister(dev, true); TRACE_EXIT(); return; } +/* scst_mutex supposed to be held and activities suspended */ +int scst_cm_on_add_acg(struct scst_acg *acg) +{ + int res = 0; + + TRACE_ENTRY(); + + if (scst_cm_tgt == NULL) + goto out; + + if (acg->tgt != scst_cm_tgt) + goto out; + + if (acg != scst_cm_tgt->default_acg) { + PRINT_ERROR("Copy Manager does not support security groups"); + res = -EINVAL; + goto out; + } + +out: + TRACE_EXIT_RES(res); + return res; +} + +/* scst_mutex supposed to be held and activities suspended */ +void scst_cm_on_del_acg(struct scst_acg *acg) +{ + /* Nothing to do */ +} + +/* scst_mutex supposed to be held and activities suspended */ +int scst_cm_on_add_lun(struct scst_acg_dev *acg_dev, uint64_t lun, + unsigned int *flags) +{ + int res = 0; + + TRACE_ENTRY(); + + if (acg_dev->acg != scst_cm_tgt->default_acg) + goto out; + + if (acg_dev->acg_dev_rd_only || acg_dev->dev->dev_rd_only) { + PRINT_ERROR("Copy Manager does not support read only devices"); + res = -EINVAL; + goto out; + } + + *flags &= ~SCST_ADD_LUN_GEN_UA; + + res = scst_cm_dev_register(acg_dev->dev, lun); + +out: + TRACE_EXIT_RES(res); + return res; +} + +/* scst_mutex supposed to be held and activities suspended */ +bool scst_cm_on_del_lun(struct scst_acg_dev *acg_dev, bool gen_report_luns_changed) +{ + bool res = gen_report_luns_changed; + + TRACE_ENTRY(); + + if (acg_dev->acg != scst_cm_tgt->default_acg) + goto out; + + scst_cm_dev_unregister(acg_dev->dev, false); + + res = false; + +out: + TRACE_EXIT_RES(res); + return res; +} + /* scst_mutex supposed to be locked */ static bool scst_cm_check_access_acg(const char *initiator_name, const struct scst_device *dev, const struct scst_acg *acg, @@ -3480,148 +3570,8 @@ static struct kobj_attribute scst_cm_allow_not_conn_copy_attr = scst_cm_allow_not_conn_copy_show, scst_cm_allow_not_conn_copy_store); -static ssize_t scst_cm_mgmt_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - static const char help[] = - "Usage: echo \"add H:C:I:L\" >mgmt\n" - " echo \"add VNAME\" >mgmt\n" - " echo \"del H:C:I:L\" >mgmt\n" - " echo \"del VNAME\" >mgmt\n"; - - return sprintf(buf, "%s", help); -} - -static int scst_cm_mgmt(struct scst_sysfs_work_item *work) -{ - int res = 0; - char *pp, *action, *devstr; - unsigned int host, channel, id, lun; - char *buf = work->buf; - bool vdev; - struct scst_device *d, *dev = NULL; - - TRACE_ENTRY(); - - TRACE_DBG("buffer %s", buf); - - pp = buf; - action = scst_get_next_lexem(&pp); - devstr = scst_get_next_lexem(&pp); - if (*devstr == '\0') { - PRINT_ERROR("%s", "Device required"); - res = -EINVAL; - goto out; - } - - if (*scst_get_next_lexem(&pp) != '\0') { - PRINT_ERROR("%s", "Too many parameters"); - res = -EINVAL; - goto out_syntax_err; - } - - if (sscanf(devstr, "%u:%u:%u:%u", &host, &channel, &id, &lun) != 4) { - vdev = true; - TRACE_DBG("Virt dev %s", devstr); - } else { - vdev = false; - TRACE_DBG("Pass-through dev %d:%d:%d:%d", host, channel, id, lun); - } - - res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER); - if (res != 0) - goto out; - - res = mutex_lock_interruptible(&scst_mutex); - if (res != 0) - goto out_resume; - - list_for_each_entry(d, &scst_dev_list, dev_list_entry) { - if (vdev) { - if ((d->scsi_dev == NULL) && - (strcmp(d->virt_name, devstr) == 0)) { - dev = d; - break; - } - } else if (d->scsi_dev != NULL && - d->scsi_dev->host->host_no == host && - d->scsi_dev->channel == channel && - d->scsi_dev->id == id && - d->scsi_dev->lun == lun) { - dev = d; - break; - } - } - if (dev == NULL) { - PRINT_ERROR("Device %s not found", devstr); - res = -EINVAL; - goto out_unlock; - } else - TRACE_DBG("Dev %p (%s) found", dev, dev->virt_name); - - if (strcasecmp("add", action) == 0) - res = scst_cm_dev_register(dev); - else if (strcasecmp("del", action) == 0) - scst_cm_dev_unregister(dev); - else { - PRINT_ERROR("Action %s not understood", action); - res = -EINVAL; - } - -out_unlock: - mutex_unlock(&scst_mutex); - -out_resume: - scst_resume_activity(); - -out: - TRACE_EXIT_RES(res); - return res; - -out_syntax_err: - PRINT_ERROR("Syntax error on \"%s\"", buf); - res = -EINVAL; - goto out; -} - -static ssize_t scst_cm_mgmt_store(struct kobject *kobj, - struct kobj_attribute *attr, const char *buffer, size_t size) -{ - int res; - struct scst_sysfs_work_item *work; - char *i_buf; - - TRACE_ENTRY(); - - i_buf = kasprintf(GFP_KERNEL, "%.*s", (int)size, buffer); - if (i_buf == NULL) { - PRINT_ERROR("Unable to alloc intermediate buffer with size %zd", - size+1); - res = -ENOMEM; - goto out; - } - - res = scst_alloc_sysfs_work(scst_cm_mgmt, false, &work); - if (res != 0) - goto out; - - work->buf = i_buf; - - res = scst_sysfs_queue_wait_work(work); - if (res == 0) - res = size; - -out: - TRACE_EXIT_RES(res); - return res; -} - -static struct kobj_attribute scst_cm_mgmt_attr = - __ATTR(mgmt, S_IRUGO|S_IWUSR, scst_cm_mgmt_show, scst_cm_mgmt_store); - -static const struct attribute *scst_cm_attrs[] = { +static const struct attribute *scst_cm_tgtt_attrs[] = { &scst_cm_allow_not_conn_copy_attr.attr, - &scst_cm_mgmt_attr.attr, NULL, }; @@ -3693,6 +3643,12 @@ static void scst_cm_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd) return; } +static int scst_cm_report_aen(struct scst_aen *aen) +{ + /* Nothing to do */ + return 0; +} + static struct scst_tgt_template scst_cm_tgtt = { .name = SCST_CM_NAME, #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) @@ -3710,9 +3666,10 @@ static struct scst_tgt_template scst_cm_tgtt = { .release = scst_cm_release, .xmit_response = scst_cm_xmit_response, .task_mgmt_fn_done = scst_cm_task_mgmt_fn_done, + .report_aen = scst_cm_report_aen, .get_initiator_port_transport_id = scst_cm_get_initiator_port_transport_id, #ifndef CONFIG_SCST_PROC - .tgtt_attrs = scst_cm_attrs, + .tgtt_attrs = scst_cm_tgtt_attrs, #endif }; diff --git a/scst/src/scst_dlm.c b/scst/src/scst_dlm.c index 0aa1372ea..342941d96 100644 --- a/scst/src/scst_dlm.c +++ b/scst/src/scst_dlm.c @@ -30,6 +30,9 @@ #include "scst_pres.h" #include "scst_dlm.h" +#if (defined(CONFIG_DLM) || defined(CONFIG_DLM_MODULE)) && \ + !defined(CONFIG_SCST_NO_DLM) + static void scst_pr_dlm_cleanup(struct scst_device *dev); static void scst_dlm_pre_bast(void *bastarg, int mode); static void scst_dlm_post_bast(void *bastarg, int mode); @@ -1493,3 +1496,5 @@ const struct scst_cl_ops scst_dlm_cl_ops = { .is_not_rsv_holder = scst_dlm_is_not_rsv_holder, .reserve = scst_dlm_reserve, }; + +#endif diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 8cd269cc7..2a5599948 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4373,8 +4373,8 @@ out: /* The activity supposed to be suspended and scst_mutex held */ int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent, - struct scst_device *dev, uint64_t lun, int read_only, - bool gen_scst_report_luns_changed, struct scst_acg_dev **out_acg_dev) + struct scst_device *dev, uint64_t lun, unsigned int flags, + struct scst_acg_dev **out_acg_dev) { int res; struct scst_acg_dev *acg_dev; @@ -4395,7 +4395,7 @@ int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent, res = -ENOMEM; goto out; } - acg_dev->acg_dev_rd_only = read_only; + acg_dev->acg_dev_rd_only = ((flags & SCST_ADD_LUN_READ_ONLY) != 0); if (dev->dev_dif_mode & SCST_DIF_MODE_DEV_STORE) { /* Devices are allowed to store only CRCs */ acg_dev->acg_dev_dif_guard_format = SCST_DIF_GUARD_FORMAT_CRC; @@ -4410,6 +4410,12 @@ int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent, list_add_tail(&acg_dev->acg_dev_list_entry, &acg->acg_dev_list); list_add_tail(&acg_dev->dev_acg_dev_list_entry, &dev->dev_acg_dev_list); + if (!(flags & SCST_ADD_LUN_CM)) { + res = scst_cm_on_add_lun(acg_dev, lun, &flags); + if (res != 0) + goto out_free; + } + list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) { res = scst_alloc_add_tgt_dev(sess, acg_dev, &tgt_dev); if (res == -EPERM) @@ -4423,14 +4429,14 @@ int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent, res = scst_acg_dev_sysfs_create(acg_dev, parent); if (res != 0) - goto out_free; + goto out_on_del; - if (gen_scst_report_luns_changed) + if (flags & SCST_ADD_LUN_GEN_UA) scst_report_luns_changed(acg); PRINT_INFO("Added device %s to group %s (LUN %lld, " - "rd_only %d) to target %s", dev->virt_name, acg->acg_name, - lun, read_only, acg->tgt ? acg->tgt->tgt_name : "?"); + "flags 0x%x) to target %s", dev->virt_name, acg->acg_name, + lun, flags, acg->tgt ? acg->tgt->tgt_name : "?"); if (out_acg_dev != NULL) *out_acg_dev = acg_dev; @@ -4439,6 +4445,10 @@ out: TRACE_EXIT_RES(res); return res; +out_on_del: + if (!(flags & SCST_ADD_LUN_CM)) + scst_cm_on_del_lun(acg_dev, false); + out_free: list_for_each_entry_safe(tgt_dev, tt, &tmp_tgt_dev_list, extra_tgt_dev_list_entry) { @@ -4450,7 +4460,7 @@ out_free: /* The activity supposed to be suspended and scst_mutex held */ int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun, - bool gen_scst_report_luns_changed) + bool gen_report_luns_changed) { int res = 0; struct scst_acg_dev *acg_dev = NULL, *a; @@ -4470,6 +4480,8 @@ int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun, goto out; } + gen_report_luns_changed = scst_cm_on_del_lun(acg_dev, gen_report_luns_changed); + list_for_each_entry_safe(tgt_dev, tt, &acg_dev->dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { if (tgt_dev->acg_dev == acg_dev) @@ -4478,7 +4490,7 @@ int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun, scst_del_free_acg_dev(acg_dev, true); - if (gen_scst_report_luns_changed) + if (gen_report_luns_changed) scst_report_luns_changed(acg); PRINT_INFO("Removed LUN %lld from group %s (target %s)", @@ -4490,16 +4502,18 @@ out: } /* The activity supposed to be suspended and scst_mutex held */ -struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, - const char *acg_name, bool tgt_acg) +int scst_alloc_add_acg(struct scst_tgt *tgt, const char *acg_name, + bool tgt_acg, struct scst_acg **out_acg) { struct scst_acg *acg; + int res; TRACE_ENTRY(); acg = kzalloc(sizeof(*acg), GFP_KERNEL); if (acg == NULL) { PRINT_ERROR("%s", "Allocation of acg failed"); + res = -ENOMEM; goto out; } @@ -4512,9 +4526,14 @@ struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, acg->acg_name = kstrdup(acg_name, GFP_KERNEL); if (acg->acg_name == NULL) { PRINT_ERROR("%s", "Allocation of acg_name failed"); + res = -ENOMEM; goto out_free; } + res = scst_cm_on_add_acg(acg); + if (res != 0) + goto out_undup; + #ifdef CONFIG_SCST_PROC acg->addr_method = tgt && tgt->tgtt ? tgt->tgtt->preferred_addr_method : SCST_LUN_ADDR_METHOD_PERIPHERAL; @@ -4527,30 +4546,35 @@ struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, acg->addr_method = tgt->tgtt->preferred_addr_method; if (tgt_acg) { - int rc; - TRACE_DBG("Adding acg '%s' to device '%s' acg_list", acg_name, tgt->tgt_name); list_add_tail(&acg->acg_list_entry, &tgt->tgt_acg_list); acg->tgt_acg = 1; - rc = scst_acg_sysfs_create(tgt, acg); - if (rc != 0) + res = scst_acg_sysfs_create(tgt, acg); + if (res != 0) goto out_del; } kobject_get(&tgt->tgt_kobj); #endif + res = 0; + out: - TRACE_EXIT_HRES(acg); - return acg; + *out_acg = acg; + + TRACE_EXIT_RES(res); + return res; #ifndef CONFIG_SCST_PROC out_del: list_del(&acg->acg_list_entry); #endif +out_undup: + kfree(acg->acg_name); + out_free: kfree(acg); acg = NULL; @@ -4573,6 +4597,8 @@ static void scst_del_acg(struct scst_acg *acg) scst_assert_activity_suspended(); lockdep_assert_held(&scst_mutex); + scst_cm_on_del_acg(acg); + list_for_each_entry_safe(acg_dev, acg_dev_tmp, &acg->acg_dev_list, acg_dev_list_entry) scst_del_acg_dev(acg_dev, true); diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 85ab18fe1..b5b3851e9 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -550,8 +550,8 @@ struct scst_tgt *scst_register_target(struct scst_tgt_template *vtt, if (rc < 0) goto out_unlock; - tgt->default_acg = scst_alloc_add_acg(tgt, tgt->tgt_name, false); - if (tgt->default_acg == NULL) + rc = scst_alloc_add_acg(tgt, tgt->tgt_name, false, &tgt->default_acg); + if (rc != 0) goto out_sysfs_del; #endif @@ -1057,6 +1057,11 @@ static void __scst_resume_activity(void) TRACE_ENTRY(); + if (suspend_count == 0) { + PRINT_WARNING("Resume without suspend"); + goto out; + } + suspend_count--; TRACE_MGMT_DBG("suspend_count %d left", suspend_count); if (suspend_count > 0) @@ -1117,6 +1122,11 @@ void scst_resume_activity(void) } EXPORT_SYMBOL_GPL(scst_resume_activity); +int scst_get_suspend_count(void) +{ + return suspend_count; +} + static int scst_register_device(struct scsi_device *scsidp) { int res; @@ -2640,11 +2650,9 @@ static int __init init_scst(void) goto out_sysfs_cleanup; #ifdef CONFIG_SCST_PROC - scst_default_acg = scst_alloc_add_acg(NULL, SCST_DEFAULT_ACG_NAME, false); - if (scst_default_acg == NULL) { - res = -ENOMEM; + res = scst_alloc_add_acg(NULL, SCST_DEFAULT_ACG_NAME, false, &scst_default_acg); + if (res != 0) goto out_destroy_sgv_pool; - } #endif res = scsi_register_interface(&scst_interface); diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index 8ce467d6e..dff5620e1 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -1173,10 +1173,12 @@ void scst_pr_cleanup(struct scst_device *dev) int scst_pr_set_cluster_mode(struct scst_device *dev, bool cluster_mode, const char *cl_dev_id) { - bool cluster_mode_enabled = false; int res = 0; -#if defined(CONFIG_DLM) || defined(CONFIG_DLM_MODULE) +#if defined(CONFIG_DLM) || defined(CONFIG_DLM_MODULE) && \ + !defined(CONFIG_SCST_NO_DLM) + bool cluster_mode_enabled = false; + cluster_mode_enabled = dev->cl_ops == &scst_dlm_cl_ops; if (cluster_mode_enabled == cluster_mode) @@ -1192,11 +1194,12 @@ int scst_pr_set_cluster_mode(struct scst_device *dev, bool cluster_mode, dev->virt_name, cluster_mode, res); dev->cl_ops = &scst_no_dlm_cl_ops; } + +out: #else res = cluster_mode ? -ENOTSUPP : 0; #endif -out: return res; } EXPORT_SYMBOL(scst_pr_set_cluster_mode); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 327504f35..ae1157d36 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -347,8 +347,8 @@ int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev); void scst_free_device(struct scst_device *dev); bool scst_device_is_exported(struct scst_device *dev); -struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, - const char *acg_name, bool tgt_acg); +int scst_alloc_add_acg(struct scst_tgt *tgt, const char *acg_name, + bool tgt_acg, struct scst_acg **out_acg); int scst_del_free_acg(struct scst_acg *acg, bool close_sessions); void scst_get_acg(struct scst_acg *acg); void scst_put_acg(struct scst_acg *acg); @@ -363,11 +363,14 @@ void scst_sess_free_tgt_devs(struct scst_session *sess); struct scst_tgt_dev *scst_lookup_tgt_dev(struct scst_session *sess, u64 lun); void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA); +#define SCST_ADD_LUN_READ_ONLY 1 +#define SCST_ADD_LUN_GEN_UA 2 +#define SCST_ADD_LUN_CM 4 int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent, - struct scst_device *dev, uint64_t lun, int read_only, - bool gen_scst_report_luns_changed, struct scst_acg_dev **out_acg_dev); + struct scst_device *dev, uint64_t lun, unsigned int flags, + struct scst_acg_dev **out_acg_dev); int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun, - bool gen_scst_report_luns_changed); + bool gen_report_luns_changed); int scst_acg_add_acn(struct scst_acg *acg, const char *name); #ifdef CONFIG_SCST_PROC @@ -729,6 +732,8 @@ void scst_ext_unblock_dev(struct scst_device *dev, bool stpg); void __scst_ext_blocking_done(struct scst_device *dev); void scst_ext_blocking_done(struct scst_device *dev); +int scst_get_suspend_count(void); + /* * Increases global SCST ref counters which prevent from entering into suspended * activities stage, so protects from any global management operations. @@ -855,6 +860,13 @@ static inline bool scst_lba1_inside_lba2(int64_t lba1, int scst_cm_on_dev_register(struct scst_device *dev); void scst_cm_on_dev_unregister(struct scst_device *dev); +int scst_cm_on_add_acg(struct scst_acg *acg); +void scst_cm_on_del_acg(struct scst_acg *acg); +int scst_cm_on_add_lun(struct scst_acg_dev *acg_dev, uint64_t lun, + unsigned int *flags); +bool scst_cm_on_del_lun(struct scst_acg_dev *acg_dev, + bool gen_report_luns_changed); + int scst_cm_parse_descriptors(struct scst_cmd *cmd); void scst_cm_free_descriptors(struct scst_cmd *cmd); diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c index 1d4dc3c25..26b99c3fe 100644 --- a/scst/src/scst_proc.c +++ b/scst/src/scst_proc.c @@ -948,8 +948,8 @@ static int scst_proc_group_add(const char *p, unsigned int addr_method) } strlcpy(name, p, len); - acg = scst_alloc_add_acg(NULL, name, false); - if (acg == NULL) { + res = scst_alloc_add_acg(NULL, name, false, &acg); + if (res != 0) { PRINT_ERROR("scst_alloc_add_acg() (name %s) failed", name); goto out_free; } @@ -969,6 +969,7 @@ out_free_acg: out_free: kfree(name); + goto out; out_nomem: res = -ENOMEM; @@ -2069,7 +2070,8 @@ static ssize_t scst_proc_groups_devices_write(struct file *file, } } - rc = scst_acg_add_lun(acg, NULL, dev, virt_lun, read_only, + rc = scst_acg_add_lun(acg, NULL, dev, virt_lun, + read_only ? SCST_ADD_LUN_READ_ONLY : 0, false, NULL); if (rc) { res = rc; diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 9b7336dd8..cc939175e 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -1327,6 +1327,7 @@ static int __scst_process_luns_mgmt_store(char *buffer, case SCST_LUN_ACTION_REPLACE: { bool dev_replaced = false; + unsigned int flags = 0; e = scst_get_next_lexem(&pp); res = kstrtoul(e, 0, &virt_lun); @@ -1414,9 +1415,13 @@ static int __scst_process_luns_mgmt_store(char *buffer, } } + if (read_only) + flags |= SCST_ADD_LUN_READ_ONLY; + if (!dev_replaced) + flags |= SCST_ADD_LUN_GEN_UA; res = scst_acg_add_lun(acg, tgt_kobj ? tgt->tgt_luns_kobj : acg->luns_kobj, - dev, virt_lun, read_only, !dev_replaced, NULL); + dev, virt_lun, flags, NULL); if (res != 0) goto out_unlock; @@ -2174,8 +2179,8 @@ static int scst_process_ini_group_mgmt_store(char *buffer, res = -EINVAL; goto out_unlock; } - acg = scst_alloc_add_acg(tgt, p, true); - if (acg == NULL) + res = scst_alloc_add_acg(tgt, p, true, &acg); + if (res != 0) goto out_unlock; break; case SCST_INI_GROUP_ACTION_DEL: @@ -7056,6 +7061,55 @@ static struct kobj_attribute scst_max_tasklet_cmd_attr = __ATTR(max_tasklet_cmd, S_IRUGO | S_IWUSR, scst_max_tasklet_cmd_show, scst_max_tasklet_cmd_store); +static ssize_t scst_suspend_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int count; + + TRACE_ENTRY(); + + count = sprintf(buf, "%d\n", scst_get_suspend_count()); + + TRACE_EXIT(); + return count; +} + +static ssize_t scst_suspend_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int res; + long val; + + TRACE_ENTRY(); + + res = kstrtol(buf, 0, &val); + if (res != 0) { + PRINT_ERROR("kstrtoul() for %s failed: %d ", buf, res); + goto out; + } + + if (val >= 0) { + PRINT_INFO("SYSFS: suspending activities (timeout %ld)...", val); + res = scst_suspend_activity(val*HZ); + if (res == 0) + PRINT_INFO("sysfs suspending done"); + } else { + PRINT_INFO("SYSFS: resuming activities"); + scst_resume_activity(); + } + + if (res == 0) + res = count; + +out: + TRACE_EXIT_RES(res); + return res; +} + +static struct kobj_attribute scst_suspend_attr = + __ATTR(suspend, S_IRUGO | S_IWUSR, scst_suspend_show, + scst_suspend_store); + #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) static ssize_t scst_main_trace_level_show(struct kobject *kobj, @@ -7281,6 +7335,7 @@ static struct attribute *scst_sysfs_root_default_attrs[] = { &scst_threads_attr.attr, &scst_setup_id_attr.attr, &scst_max_tasklet_cmd_attr.attr, + &scst_suspend_attr.attr, #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) &scst_main_trace_level_attr.attr, #endif diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index a003b16b1..a701a0a72 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -3356,7 +3356,11 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch, struct srpt_send_ioctx *ioctx, scst_data_direction dir) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) struct ib_send_wr wr; +#else + struct ib_rdma_wr wr; +#endif struct ib_send_wr *bad_wr; struct rdma_iu *riu; int i; @@ -3377,6 +3381,7 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch, memset(&wr, 0, sizeof(wr)); for (i = 0; i < n_rdma; ++i, ++riu) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) if (dir == SCST_DATA_READ) { wr.opcode = IB_WR_RDMA_WRITE; wr.wr_id = encode_wr_id(i == n_rdma - 1 ? @@ -3401,6 +3406,32 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch, wr.send_flags = IB_SEND_SIGNALED; ret = ib_post_send(ch->qp, &wr, &bad_wr); +#else + if (dir == SCST_DATA_READ) { + wr.wr.opcode = IB_WR_RDMA_WRITE; + wr.wr.wr_id = encode_wr_id(i == n_rdma - 1 ? + SRPT_RDMA_WRITE_LAST : + SRPT_RDMA_MID, + ioctx->ioctx.index); + } else { + wr.wr.opcode = IB_WR_RDMA_READ; + wr.wr.wr_id = encode_wr_id(i == n_rdma - 1 ? + SRPT_RDMA_READ_LAST : + SRPT_RDMA_MID, + ioctx->ioctx.index); + } + wr.wr.next = NULL; + wr.remote_addr = riu->raddr; + wr.rkey = riu->rkey; + wr.wr.num_sge = riu->sge_cnt; + wr.wr.sg_list = riu->sge; + + /* only get completion event for the last rdma wr */ + if (i == (n_rdma - 1) && dir == SCST_DATA_WRITE) + wr.wr.send_flags = IB_SEND_SIGNALED; + + ret = ib_post_send(ch->qp, &wr.wr, &bad_wr); +#endif if (ret) break; } @@ -3409,6 +3440,7 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch, pr_err("%s: ib_post_send() returned %d for %d/%d\n", __func__, ret, i, n_rdma); if (ret && i > 0) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) wr.num_sge = 0; wr.wr_id = encode_wr_id(SRPT_RDMA_ABORT, ioctx->ioctx.index); wr.send_flags = IB_SEND_SIGNALED; @@ -3420,13 +3452,34 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch, ioctx->ioctx.index); msleep(1000); } +#else + wr.wr.num_sge = 0; + wr.wr.wr_id = encode_wr_id(SRPT_RDMA_ABORT, ioctx->ioctx.index); + wr.wr.send_flags = IB_SEND_SIGNALED; + pr_info("Trying to abort failed RDMA transfer [%d]\n", + ioctx->ioctx.index); + while (ch->state == CH_LIVE && + ib_post_send(ch->qp, &wr.wr, &bad_wr) != 0) { + pr_info("Trying to abort failed RDMA transfer [%d]\n", + ioctx->ioctx.index); + msleep(1000); + } +#endif pr_info("Waiting until RDMA abort finished [%d]\n", ioctx->ioctx.index); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) while (ch->state < CH_DISCONNECTED && !ioctx->rdma_aborted) { pr_info("Waiting until RDMA abort finished [%d]\n", ioctx->ioctx.index); msleep(1000); } +#else + while (ch->state < CH_DISCONNECTED && !ioctx->rdma_aborted) { + pr_info("Waiting until RDMA abort finished [%d]\n", + ioctx->ioctx.index); + msleep(1000); + } +#endif pr_info("%s[%d]: done\n", __func__, __LINE__); } @@ -4480,13 +4533,16 @@ static int __init srpt_init_module(void) if (rdma_cm_port) { struct sockaddr_in addr; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) || \ - defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6 +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0) && \ + (!defined(RHEL_MAJOR) || RHEL_MAJOR -0 < 6) + rdma_cm_id = rdma_create_id(srpt_rdma_cm_handler, NULL, + RDMA_PS_TCP); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) rdma_cm_id = rdma_create_id(srpt_rdma_cm_handler, NULL, RDMA_PS_TCP, IB_QPT_RC); #else - rdma_cm_id = rdma_create_id(srpt_rdma_cm_handler, NULL, - RDMA_PS_TCP); + rdma_cm_id = rdma_create_id(&init_net, srpt_rdma_cm_handler, + NULL, RDMA_PS_TCP, IB_QPT_RC); #endif if (IS_ERR(rdma_cm_id)) { rdma_cm_id = NULL;