diff --git a/.github/workflows/checkpatch_pull.yml b/.github/workflows/checkpatch_pull.yml index c231e64b5..a9ced9892 100644 --- a/.github/workflows/checkpatch_pull.yml +++ b/.github/workflows/checkpatch_pull.yml @@ -30,10 +30,12 @@ jobs: UNKNOWN_COMMIT_ID NO_AUTHOR_SIGN_OFF COMMIT_LOG_USE_LINK + BAD_REPORTED_BY_LINK FILE_PATH_CHANGES SPDX_LICENSE_TAG LINUX_VERSION_CODE CONSTANT_COMPARISON + NEW_TYPEDEFS SPACING ) ignore_str=${ignore[*]} diff --git a/.github/workflows/checkpatch_push.yml b/.github/workflows/checkpatch_push.yml index c5071f46f..28acad5e5 100644 --- a/.github/workflows/checkpatch_push.yml +++ b/.github/workflows/checkpatch_push.yml @@ -35,10 +35,12 @@ jobs: UNKNOWN_COMMIT_ID NO_AUTHOR_SIGN_OFF COMMIT_LOG_USE_LINK + BAD_REPORTED_BY_LINK FILE_PATH_CHANGES SPDX_LICENSE_TAG LINUX_VERSION_CODE CONSTANT_COMPARISON + NEW_TYPEDEFS SPACING ) ignore_str=${ignore[*]} diff --git a/INSTALL.md b/INSTALL.md index ce7c6b272..80c3472e5 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -22,7 +22,7 @@ If the following packages have not yet been installed, install these now: The next step is to build and install SCST. How to do that depends on whether or not your Linux distribution supports a package manager: - make release + make 2release if rpm -q glibc >/dev/null 2>&1; then rm -rf {,scstadmin/}rpmbuilddir make rpm diff --git a/Makefile b/Makefile index 6a5bc2c94..d4374f7e0 100644 --- a/Makefile +++ b/Makefile @@ -146,6 +146,13 @@ help: @echo " usr_install : usr target: install" @echo " usr_uninstall : usr target: uninstall" @echo "" + @echo " scst-rpm : make SCST RPM packages" + @echo " scst-dkms-rpm : make SCST DKMS RPM packages" + @echo " rpm : make both SCST and scstadmin RPM packages" + @echo " rpm-dkms : make both SCST DKMS and scstadmin RPM packages" + @echo "" + @echo " dpkg : make SCST dpkg packages" + @echo "" @echo " 2perf : changes debug state to full performance" @echo " 2release : changes debug state to release" @echo " 2debug : changes debug state to full debug" diff --git a/fcst/Makefile b/fcst/Makefile index 8c82d4a41..497291bb2 100644 --- a/fcst/Makefile +++ b/fcst/Makefile @@ -55,7 +55,9 @@ ifeq ($(INSTALL_MOD_PATH),) export INSTALL_MOD_PATH := $(DESTDIR) endif -INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra +INSTALL_MOD_DIR=extra + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/$(INSTALL_MOD_DIR) SCST_DIR := $(shell echo "$$PWD")/../scst/src @@ -67,6 +69,7 @@ install: all KDIR=$(KDIR) ../scripts/sign-modules $(MAKE) -C $(KDIR) M=$(shell pwd) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install @@ -87,4 +90,4 @@ extraclean: clean release-archive: ../scripts/generate-release-archive fcst "$$(sed -n 's/^#define[[:blank:]]FT_VERSION[[:blank:]]*\"\([^\"]*\)\".*/\1/p' fcst.h)" -.PHONY: all tgt install uninstall clean extraclean release-archive +.PHONY: all install uninstall clean extraclean release-archive diff --git a/iscsi-scst/Makefile b/iscsi-scst/Makefile index 557088e98..f153e3522 100644 --- a/iscsi-scst/Makefile +++ b/iscsi-scst/Makefile @@ -43,7 +43,9 @@ ifeq ($(INSTALL_MOD_PATH),) export INSTALL_MOD_PATH := $(DESTDIR) endif -INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra +INSTALL_MOD_DIR=extra + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/$(INSTALL_MOD_DIR) INFINIBAND_ENABLED = $(shell syms=$$(dirname "$(KDIR)")/modules.symbols; if [ -e "$$syms" ] && grep -wq 'ib_register_client' "$$syms" || grep -q "^CONFIG_INFINIBAND=[my]$$" "$(KDIR)/.config"; then echo true; else echo false; fi) all: progs mods @@ -166,6 +168,7 @@ install: all (cd $(KMOD) && KDIR=$(KDIR) ../../scripts/sign-modules) $(MAKE) -C $(KDIR) M=$(KMOD) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install echo "$@: INFINIBAND_ENABLED = $(INFINIBAND_ENABLED)" @@ -173,6 +176,7 @@ install: all (cd $(ISERTMOD) && KDIR=$(KDIR) ../../../scripts/sign-modules);\ $(MAKE) -C $(KDIR) M=$(ISERTMOD) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install; \ fi diff --git a/iscsi-scst/README b/iscsi-scst/README index 9f67fac38..d086c6ec2 100644 --- a/iscsi-scst/README +++ b/iscsi-scst/README @@ -283,6 +283,10 @@ Each target subdirectory contains the following entries: - tid - TID of this target. + - alias - TargetAlias of this target. If not set, it will default to the + empty string and no TargetAlias will be reported in LOGIN RESPONSE or iSNS + for this target. + The "sessions" subdirectory contains the following attribute: - thread_pid - the process identifiers (PIDs) of the iscsird and iscsiwr @@ -559,6 +563,7 @@ both iSCSI-SCST targets will look like: | | |-- NopInInterval | | |-- QueuedCommands | | |-- RspTimeout +| | |-- alias | | |-- enabled | | |-- ini_groups | | | `-- mgmt diff --git a/iscsi-scst/kernel/conn.c b/iscsi-scst/kernel/conn.c index 031e6c305..487cf655a 100644 --- a/iscsi-scst/kernel/conn.c +++ b/iscsi-scst/kernel/conn.c @@ -741,7 +741,6 @@ int conn_activate(struct iscsi_conn *conn) static int conn_setup_sock(struct iscsi_conn *conn) { - int res = 0; int opt = 1; mm_segment_t oldfs; struct iscsi_session *session = conn->session; @@ -750,12 +749,13 @@ static int conn_setup_sock(struct iscsi_conn *conn) conn->sock = SOCKET_I(file_inode(conn->file)); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0) if (conn->sock->ops->sendpage == NULL) { PRINT_ERROR("Socket for sid %llx doesn't support sendpage()", (unsigned long long)session->sid); - res = -EINVAL; - goto out; + return -EINVAL; } +#endif #if 0 conn->sock->sk->sk_allocation = GFP_NOIO; @@ -768,8 +768,7 @@ static int conn_setup_sock(struct iscsi_conn *conn) KERNEL_SOCKPTR(&opt), sizeof(opt)); set_fs(oldfs); -out: - return res; + return 0; } void iscsi_tcp_conn_free(struct iscsi_conn *conn) diff --git a/iscsi-scst/kernel/isert-scst/iser_global.c b/iscsi-scst/kernel/isert-scst/iser_global.c index 5b8b92b97..c070a66fa 100644 --- a/iscsi-scst/kernel/isert-scst/iser_global.c +++ b/iscsi-scst/kernel/isert-scst/iser_global.c @@ -138,7 +138,7 @@ int isert_global_init(void) spin_lock_init(&isert_glob.portal_lock); init_waitqueue_head(&isert_glob.portal_wq); - isert_glob.conn_wq = alloc_workqueue("isert_conn_wq", WQ_MEM_RECLAIM, 0); + isert_glob.conn_wq = alloc_workqueue("isert_conn_wq", 0, 1); if (!isert_glob.conn_wq) { PRINT_ERROR("Failed to alloc iser conn work queue"); return -ENOMEM; diff --git a/iscsi-scst/kernel/isert-scst/iser_rdma.c b/iscsi-scst/kernel/isert-scst/iser_rdma.c index bad41bfe7..c5e30b167 100644 --- a/iscsi-scst/kernel/isert-scst/iser_rdma.c +++ b/iscsi-scst/kernel/isert-scst/iser_rdma.c @@ -938,8 +938,7 @@ static struct isert_device *isert_device_create(struct ib_device *ib_dev) goto free_isert_dev; } - isert_dev->cq_desc = vmalloc(sizeof(*isert_dev->cq_desc) * - isert_dev->num_cqs); + isert_dev->cq_desc = vmalloc_array(isert_dev->num_cqs, sizeof(*isert_dev->cq_desc)); if (unlikely(isert_dev->cq_desc == NULL)) { PRINT_ERROR("Failed to allocate %zd bytes for iser cq_desc", sizeof(*isert_dev->cq_desc) * isert_dev->num_cqs); @@ -1793,7 +1792,7 @@ struct isert_portal *isert_portal_create(struct sockaddr *sa, size_t addr_len) goto err_alloc; } - portal->reinit_id_wq = alloc_ordered_workqueue("isert_reinit_id_wq", WQ_MEM_RECLAIM); + portal->reinit_id_wq = alloc_ordered_workqueue("isert_reinit_id_wq", 0); if (unlikely(!portal->reinit_id_wq)) { PRINT_ERROR("Unable to allocate reinit workqueue"); err = -ENOMEM; diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index e91a88541..09a233017 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -960,8 +960,7 @@ int istrd(void *arg) spin_lock_bh(&p->rd_lock); while (!kthread_should_stop()) { - wait_event_locked(p->rd_waitQ, test_rd_list(p), lock_bh, - p->rd_lock); + scst_wait_event_interruptible_lock_bh(p->rd_waitQ, test_rd_list(p), p->rd_lock); scst_do_job_rd(p); } spin_unlock_bh(&p->rd_lock); @@ -1096,69 +1095,79 @@ void req_add_to_write_timeout_list(struct iscsi_cmnd *req) static int write_data(struct iscsi_conn *conn) { - struct file *file; - struct kvec *iop; struct socket *sock; - ssize_t (*sock_sendpage)(struct socket *, struct page *, int, size_t, - int); - ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); - struct iscsi_cmnd *write_cmnd = conn->write_cmnd; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0) + ssize_t (*sock_sendpage)(struct socket *sock, struct page *page, + int offset, size_t size, int flags); +#else + struct msghdr msg = {}; + struct bio_vec bvec; +#endif + struct iscsi_cmnd *write_cmnd, *parent_req; struct iscsi_cmnd *ref_cmd; struct page *page; struct scatterlist *sg; - int saved_size, size, sendsize; - int length, offset, idx; - int flags, res, count, sg_size; + size_t saved_size, size, sg_size; + size_t sendsize, length; + int offset, idx, flags, res = 0; bool ref_cmd_to_parent; TRACE_ENTRY(); + write_cmnd = conn->write_cmnd; + parent_req = write_cmnd->parent_req; + iscsi_extracheck_is_wr_thread(conn); if (!write_cmnd->own_sg) { - ref_cmd = write_cmnd->parent_req; + ref_cmd = parent_req; ref_cmd_to_parent = true; } else { ref_cmd = write_cmnd; ref_cmd_to_parent = false; } - req_add_to_write_timeout_list(write_cmnd->parent_req); + req_add_to_write_timeout_list(parent_req); - file = conn->file; - size = conn->write_size; - saved_size = size; - iop = conn->write_iop; - count = conn->write_iop_used; + saved_size = size = conn->write_size; - if (iop) { - while (1) { - loff_t off = 0; - int rest; + if (conn->write_iop) { + struct file *file = conn->file; + struct kvec *iop = conn->write_iop; + int count = conn->write_iop_used; + loff_t off; + + sBUG_ON(count > ARRAY_SIZE(conn->write_iov)); + + while (true) { + off = 0; - sBUG_ON(count > ARRAY_SIZE(conn->write_iov)); -retry: res = scst_writev(file, iop, count, &off); TRACE_WRITE("sid %#Lx, cid %u, res %d, iov_len %zd", (unsigned long long)conn->session->sid, conn->cid, res, iop->iov_len); + if (unlikely(res <= 0)) { + if (res == -EINTR) + continue; + if (res == -EAGAIN) { conn->write_iop = iop; conn->write_iop_used = count; goto out_iov; - } else if (res == -EINTR) - goto retry; + } + goto out_err; } - rest = res; size -= res; - while ((typeof(rest))iop->iov_len <= rest && rest) { - rest -= iop->iov_len; + + while ((typeof(res))iop->iov_len <= res && res) { + res -= iop->iov_len; iop++; count--; } + if (count == 0) { conn->write_iop = NULL; conn->write_iop_used = 0; @@ -1168,8 +1177,8 @@ static int write_data(struct iscsi_conn *conn) } sBUG_ON(iop > conn->write_iov + ARRAY_SIZE(conn->write_iov)); - iop->iov_base += rest; - iop->iov_len -= rest; + iop->iov_base += res; + iop->iov_len -= res; } } @@ -1181,15 +1190,19 @@ static int write_data(struct iscsi_conn *conn) } sock = conn->sock; + flags = MSG_DONTWAIT; - if (write_cmnd->parent_req->scst_cmd && - write_cmnd->parent_req->scst_state != ISCSI_CMD_STATE_AEN && - scst_cmd_get_dh_data_buff_alloced(write_cmnd->parent_req->scst_cmd)) - sock_sendpage = sock_no_sendpage; - else + if (sg != write_cmnd->rsp_sg && + (!parent_req->scst_cmd || parent_req->scst_state == ISCSI_CMD_STATE_AEN || + !scst_cmd_get_dh_data_buff_alloced(parent_req->scst_cmd))) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0) + flags |= MSG_SPLICE_PAGES; +#else sock_sendpage = sock->ops->sendpage; + else + sock_sendpage = sock_no_sendpage; +#endif - flags = MSG_DONTWAIT; sg_size = size; if (sg != write_cmnd->rsp_sg) { @@ -1202,8 +1215,8 @@ static int write_data(struct iscsi_conn *conn) offset = conn->write_offset + sg[0].offset; idx = offset >> PAGE_SHIFT; offset &= ~PAGE_MASK; - length = min(size, (int)PAGE_SIZE - offset); - TRACE_WRITE("write_offset %d, sg_size %d, idx %d, offset %d, length %d", + length = min_t(size_t, size, PAGE_SIZE - offset); + TRACE_WRITE("write_offset %d, sg_size %lu, idx %d, offset %d, length %lu", conn->write_offset, sg_size, idx, offset, length); } else { /* @@ -1218,93 +1231,73 @@ static int write_data(struct iscsi_conn *conn) } length = sg[idx].length - offset; offset += sg[idx].offset; - sock_sendpage = sock_no_sendpage; - TRACE_WRITE("rsp_sg: write_offset %d, sg_size %d, idx %d, " - "offset %d, length %d", conn->write_offset, sg_size, - idx, offset, length); + TRACE_WRITE("rsp_sg: write_offset %d, sg_size %lu, idx %d, offset %d, length %lu", + conn->write_offset, sg_size, idx, offset, length); } page = sg_page(&sg[idx]); - while (1) { - sendpage = sock_sendpage; - - sendsize = min(size, length); - if (size <= sendsize) { -retry2: - res = sendpage(sock, page, offset, size, flags); - TRACE_WRITE("Final %s sid %#Lx, cid %u, res %d (page index %lu, offset %u, size %u, cmd %p, page %p)", - (sendpage != sock_no_sendpage) ? - "sendpage" : "sock_no_sendpage", - (unsigned long long)conn->session->sid, - conn->cid, res, page->index, - offset, size, write_cmnd, page); + while (true) { + sendsize = min_t(size_t, size, length); + + if (sendsize == size) + flags &= ~MSG_MORE; + else + flags |= MSG_MORE; + + while (sendsize) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0) + res = sock_sendpage(sock, page, offset, sendsize, flags); +#else + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_flags = flags; + + bvec_set_page(&bvec, page, sendsize, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, sendsize); + res = sock_sendmsg(sock, &msg); +#endif + TRACE_WRITE( + "sid %#Lx cid %u: res %d (page[%p] index %lu, offset %u, sendsize %lu, size %lu, cmd %p)", + (unsigned long long)conn->session->sid, conn->cid, + res, page, page->index, offset, sendsize, size, + write_cmnd); + if (unlikely(res <= 0)) { if (res == -EINTR) - goto retry2; - else - goto out_res; - } + continue; + + if (res == -EAGAIN) { + conn->write_offset += sg_size - size; + goto out_iov; + } - if (res == size) { - conn->write_size = 0; - res = saved_size; - goto out; + goto out_err; } offset += res; + sendsize -= res; size -= res; - goto retry2; - } - -retry1: - res = sendpage(sock, page, offset, sendsize, flags | MSG_MORE); - TRACE_WRITE("%s sid %#Lx, cid %u, res %d (page index %lu, offset %u, sendsize %u, size %u, cmd %p, page %p)", - (sendpage != sock_no_sendpage) ? "sendpage" : - "sock_no_sendpage", - (unsigned long long)conn->session->sid, conn->cid, - res, page->index, offset, sendsize, size, - write_cmnd, page); - if (unlikely(res <= 0)) { - if (res == -EINTR) - goto retry1; - else - goto out_res; } - size -= res; + if (size == 0) + goto out_iov; - if (res == sendsize) { - idx++; - EXTRACHECKS_BUG_ON(idx >= ref_cmd->sg_cnt); - page = sg_page(&sg[idx]); - length = sg[idx].length; - offset = sg[idx].offset; - } else { - offset += res; - sendsize -= res; - goto retry1; - } + idx++; + EXTRACHECKS_BUG_ON(idx >= ref_cmd->sg_cnt); + page = sg_page(&sg[idx]); + length = sg[idx].length; + offset = sg[idx].offset; } -out_off: - conn->write_offset += sg_size - size; - out_iov: conn->write_size = size; - if ((saved_size == size) && res == -EAGAIN) - goto out; - res = saved_size - size; + if (res != -EAGAIN || saved_size != size) + res = saved_size - size; out: TRACE_EXIT_RES(res); return res; -out_res: - if (res == -EAGAIN) - goto out_off; - /* else go through */ - out_err: #ifndef CONFIG_SCST_DEBUG if (!conn->closing) { @@ -1613,8 +1606,7 @@ int istwr(void *arg) spin_lock_bh(&p->wr_lock); while (!kthread_should_stop()) { - wait_event_locked(p->wr_waitQ, test_wr_list(p), lock_bh, - p->wr_lock); + scst_wait_event_interruptible_lock_bh(p->wr_waitQ, test_wr_list(p), p->wr_lock); scst_do_job_wr(p); } spin_unlock_bh(&p->wr_lock); diff --git a/iscsi-scst/kernel/target.c b/iscsi-scst/kernel/target.c index 8840d349d..a74ef486d 100644 --- a/iscsi-scst/kernel/target.c +++ b/iscsi-scst/kernel/target.c @@ -89,7 +89,7 @@ static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid, target->tid = info->tid = tid; - strlcpy(target->name, name, sizeof(target->name)); + strscpy(target->name, name, sizeof(target->name)); mutex_init(&target->target_mutex); INIT_LIST_HEAD(&target->session_list); diff --git a/iscsi-scst/usr/config.c b/iscsi-scst/usr/config.c index e90a05baa..35fb16b5f 100644 --- a/iscsi-scst/usr/config.c +++ b/iscsi-scst/usr/config.c @@ -265,6 +265,32 @@ char *config_sep_string(char **pp) return p; } +/* + * Strip leading and trailing whitespace. + * + * Modifies the contents of the parameter string. + */ +char *config_strip_string(char *s) +{ + size_t size; + char *end; + + size = strlen(s); + + if (!size) + return s; + + end = s + size - 1; + while (end >= s && isspace(*end)) + end--; + *(end + 1) = '\0'; + + while (*s && isspace(*s)) + s++; + + return s; +} + static char *config_gets(char *buf, int size, const char *data, int *offset) { int offs = *offset, i = 0; diff --git a/iscsi-scst/usr/ctldev.c b/iscsi-scst/usr/ctldev.c index 70258cc46..49efe5677 100644 --- a/iscsi-scst/usr/ctldev.c +++ b/iscsi-scst/usr/ctldev.c @@ -78,7 +78,12 @@ int kernel_target_create(struct target *target, u32 *tid, u32 cookie) info.tid = (tid != NULL) ? *tid : 0; info.cookie = cookie; - info.attrs_num = 2; + /* + * ISCSI_PER_PORTAL_ACL_ATTR_NAME + * ISCSI_TARGET_REDIRECTION_ATTR_NAME + * ISCSI_TARGET_ALIAS_ATTR_NAME + */ + info.attrs_num = 3; for (j = 0; j < session_key_last; j++) { if (session_keys[j].show_in_sysfs) @@ -117,6 +122,11 @@ int kernel_target_create(struct target *target, u32 *tid, u32 cookie) sizeof(ISCSI_TARGET_REDIRECTION_ATTR_NAME)); i++; + kern_attrs[i].mode = 0644; + strlcpy(kern_attrs[i].name, ISCSI_TARGET_ALIAS_ATTR_NAME, + sizeof(ISCSI_TARGET_ALIAS_ATTR_NAME)); + i++; + for (j = 0; j < session_key_last; j++) { if (!session_keys[j].show_in_sysfs) continue; diff --git a/iscsi-scst/usr/event.c b/iscsi-scst/usr/event.c index 61cb13205..e08cd4b0c 100644 --- a/iscsi-scst/usr/event.c +++ b/iscsi-scst/usr/event.c @@ -611,6 +611,17 @@ static int handle_e_get_attr_value(int fd, const struct iscsi_kern_event *event) add_key_mark(res_str, sizeof(res_str), 0); } else *res_str = '\0'; + } else if (strcasecmp(ISCSI_TARGET_ALIAS_ATTR_NAME, pp) == 0) { + if (target == NULL) { + log_error("Target expected for attr %s", pp); + res = -EINVAL; + goto out_free; + } + if (target->alias) { + snprintf(res_str, sizeof(res_str), "%s\n", target->alias); + add_key_mark(res_str, sizeof(res_str), 0); + } else + *res_str = '\0'; } else if (strcasecmp(ISCSI_ISNS_SERVER_ATTR_NAME, pp) == 0) { if (target != NULL) { log_error("Not NULL target %s for global attribute %s", @@ -955,6 +966,48 @@ static int handle_e_set_attr_value(int fd, const struct iscsi_kern_event *event) res = handle_target_redirect(target, p); if (res != 0) goto out_free; + } else if (strcasecmp(ISCSI_TARGET_ALIAS_ATTR_NAME, pp) == 0) { + bool alias_changed = false; + + if (target == NULL) { + log_error("Target expected for attr %s", pp); + res = -EINVAL; + goto out_free; + } + p = config_strip_string(p); + if (*p == '\0') { + if (target->alias) { + free(target->alias); + target->alias = NULL; + alias_changed = true; + } + } else { + char *newval = strdup(p); + + if (newval == NULL) { + log_error("Unable to duplicate alias name %s", p); + res = -ENOMEM; + goto out_free; + } + if (target->alias) + free(target->alias); + target->alias = newval; + alias_changed = true; + } + /* If we previously registered an alias and we need to update it */ + if (alias_changed && target->isns_registered) { + if (target->alias) { + isns_target_register(target->name); + } else { + /* + * We have cleared a previously set alias. + * Work-around to make change visible in + * open-isns server. + */ + isns_target_deregister(target->name); + isns_target_register(target->name); + } + } } else if (strcasecmp(ISCSI_ISNS_SERVER_ATTR_NAME, pp) == 0) { if (target != NULL) { log_error("Not NULL target %s for global attribute %s", diff --git a/iscsi-scst/usr/iscsid.c b/iscsi-scst/usr/iscsid.c index 773fa5083..1ef94ce3c 100644 --- a/iscsi-scst/usr/iscsid.c +++ b/iscsi-scst/usr/iscsid.c @@ -921,6 +921,8 @@ static void login_start(struct connection *conn) return; } } + if (target->alias) + text_key_add(conn, "TargetAlias", target->alias); log_debug(1, "target %s, sessions_count %d", target_name, target->sessions_count); } diff --git a/iscsi-scst/usr/iscsid.h b/iscsi-scst/usr/iscsid.h index 4155d2ac7..69146bd2b 100644 --- a/iscsi-scst/usr/iscsid.h +++ b/iscsi-scst/usr/iscsid.h @@ -198,6 +198,7 @@ struct target { unsigned int tgt_enabled:1; unsigned int per_portal_acl:1; + unsigned int isns_registered:1; unsigned int target_params[target_key_last]; unsigned int session_params[session_key_last]; @@ -353,6 +354,7 @@ extern int nl_open(void); /* config.c */ extern char *config_sep_string(char **pp); +extern char *config_strip_string(char *s); extern int config_parse_main(const char *data, u32 cookie); extern int config_load(const char *config_name); extern int config_target_create(u32 *tid, char *name); diff --git a/iscsi-scst/usr/isns.c b/iscsi-scst/usr/isns.c index 75ffa8a88..323e00c53 100644 --- a/iscsi-scst/usr/isns.c +++ b/iscsi-scst/usr/isns.c @@ -482,7 +482,7 @@ int isns_target_register(char *name) uint32_t port = htonl(server_port); uint32_t node = htonl(ISNS_NODE_TARGET); uint32_t type = htonl(2); - struct target *target; + struct target *target, *alias_target; int err, initial = list_length_is_one(&targets_list); int max_buf; @@ -499,6 +499,7 @@ int isns_target_register(char *name) tlv = (struct isns_tlv *)hdr->pdu; max_buf = sizeof(buf) - offsetof(struct isns_hdr, pdu); + alias_target = target_find_by_name(name); if (strlen(isns_entity_target_name) < 1) { target = list_entry(targets_list.q_forw, struct target, tlist); err = isns_tlv_set(&tlv, max_buf - length, ISNS_ATTR_ISCSI_NAME, @@ -566,6 +567,14 @@ int isns_target_register(char *name) goto out; length += err; + if (alias_target && alias_target->alias) { + err = isns_tlv_set(&tlv, max_buf - length, ISNS_ATTR_ISCSI_ALIAS, + strlen(alias_target->alias) + 1, alias_target->alias); + if (err < 0) + goto out; + length += err; + } + err = isns_tlv_set(&tlv, max_buf - length, ISNS_ATTR_ISCSI_NODE_TYPE, sizeof(node), &node); if (err < 0) @@ -579,6 +588,8 @@ int isns_target_register(char *name) err = write(isns_fd, buf, length + sizeof(struct isns_hdr)); if (err < 0) log_error("%s %d: %s", __func__, __LINE__, strerror(errno)); + else if (alias_target) + alias_target->isns_registered = 1; if (scn_listen_port) isns_scn_register(); @@ -662,6 +673,9 @@ int isns_target_deregister(char *name) if (err < 0) log_error("%s %d: %s", __func__, __LINE__, strerror(errno)); + if (target) + target->isns_registered = 0; + out: return err; } diff --git a/iscsi-scst/usr/param.h b/iscsi-scst/usr/param.h index 994232c86..6a1d8b751 100644 --- a/iscsi-scst/usr/param.h +++ b/iscsi-scst/usr/param.h @@ -25,6 +25,7 @@ #define ISCSI_TARGET_REDIRECTION_ATTR_NAME "redirect" #define ISCSI_TARGET_REDIRECTION_VALUE_TEMP "temp" #define ISCSI_TARGET_REDIRECTION_VALUE_PERM "perm" +#define ISCSI_TARGET_ALIAS_ATTR_NAME "alias" struct iscsi_key; diff --git a/nightly/conf/nightly.conf b/nightly/conf/nightly.conf index dec343700..1f596da5f 100644 --- a/nightly/conf/nightly.conf +++ b/nightly/conf/nightly.conf @@ -3,37 +3,39 @@ ABT_DETAILS="x86_64" ABT_JOBS=5 ABT_KERNELS=" \ -6.3 \ -6.2.13-nc \ -6.1.26-nc \ +6.5.4 \ +6.4.16-nc \ +6.3.13-nc \ +6.2.16-nc \ +6.1.54-nc \ 6.0.19-nc \ 5.19.17-nc \ 5.18.19-nc \ 5.17.15-nc \ 5.16.20-nc \ -5.15.109-nc \ +5.15.132-nc \ 5.14.21-nc \ 5.13.19-nc \ 5.12.19-nc \ 5.11.22-nc \ -5.10.179-nc \ +5.10.195-nc \ 5.9.16-nc \ 5.8.18-nc \ 5.7.19-nc \ 5.6.19-nc \ 5.5.19-nc \ -5.4.242-nc \ +5.4.256-nc \ 5.3.18-nc \ 5.2.21-nc \ 5.1.21-nc \ 5.0.21-nc \ 4.20.17-nc \ -4.19.282-nc \ +4.19.294-nc \ 4.18.20-nc \ 4.17.19-nc \ 4.16.18-nc \ 4.15.18-nc \ -4.14.314-nc \ +4.14.325-nc \ 4.13.16-nc \ 4.12.14-nc \ 4.11.12-nc \ @@ -58,8 +60,10 @@ ABT_KERNELS=" \ 3.12.74-nc \ 3.11.10-nc \ 3.10.108-nc \ +5.14.0-284.30.1.el9_2^AlmaLinux^9.2-nc \ 5.14.0-162.23.1.el9_1^AlmaLinux^9.1-nc \ 5.14.0-70.30.1.el9_0^AlmaLinux^9.0-nc \ +4.18.0-477.21.1.el8_8^AlmaLinux^8.8-nc \ 4.18.0-425.19.2.el8_7^AlmaLinux^8.7-nc \ 4.18.0-372.32.1.el8_6^AlmaLinux^8.6-nc \ 4.18.0-348.2.1.el8_5^CentOS^8.5.2111-nc \ @@ -68,20 +72,20 @@ ABT_KERNELS=" \ 4.18.0-193.28.1.el8_2^CentOS^8.2.2004-nc \ 4.18.0-147.8.1.el8_1^CentOS^8.1.1911-nc \ 4.18.0-80.11.2.el8_0^CentOS^8.0.1905-nc \ -3.10.0-1160.88.1.el7^CentOS^7.9.2009-nc \ -3.10.0-1127.19.1.el7^CentOS^7.8.2003-nc \ -3.10.0-1062.18.1.el7^CentOS^7.7.1908-nc \ -3.10.0-957.27.2.el7^CentOS^7.6.1810-nc \ -3.10.0-862.14.4.el7^CentOS^7.5.1804-nc \ -5.15.0-8.91.4.1.el9uek^UEK^9-nc \ -5.15.0-8.91.4.1.el8uek^UEK^8-nc \ -5.4.17-2136.318.7.1.el8uek^UEK^8-nc \ -5.4.17-2102.206.1.el8uek^UEK^8-nc \ -5.4.17-2036.104.5.el8uek^UEK^8-nc \ -5.4.17-2011.7.4.el8uek^UEK^8-nc \ -5.4.17-2136.318.7.1.el7uek^UEK^7-nc \ -5.4.17-2102.206.1.el7uek^UEK^7-nc \ -5.4.17-2036.104.5.el7uek^UEK^7-nc \ -5.4.17-2011.7.4.el7uek^UEK^7-nc \ -4.1.12-124.48.6.el6uek^UEK^6-nc \ +3.10.0-1160.95.1.el7^CentOS^7.9.2009-nc \ +3.10.0-1127.19.1.el7^CentOS^7.8.2003-nc \ +3.10.0-1062.18.1.el7^CentOS^7.7.1908-nc \ +3.10.0-957.27.2.el7^CentOS^7.6.1810-nc \ +3.10.0-862.14.4.el7^CentOS^7.5.1804-nc \ +5.15.0-105.125.6.2.1.el9uek^UEK^9-nc \ +5.15.0-105.125.6.2.1.el8uek^UEK^8-nc \ +5.4.17-2136.323.8.1.el8uek^UEK^8-nc \ +5.4.17-2102.206.1.el8uek^UEK^8-nc \ +5.4.17-2036.104.5.el8uek^UEK^8-nc \ +5.4.17-2011.7.4.el8uek^UEK^8-nc \ +5.4.17-2136.323.8.1.el7uek^UEK^7-nc \ +5.4.17-2102.206.1.el7uek^UEK^7-nc \ +5.4.17-2036.104.5.el7uek^UEK^7-nc \ +5.4.17-2011.7.4.el7uek^UEK^7-nc \ +4.1.12-124.48.6.el6uek^UEK^6-nc \ " diff --git a/qla2x00t-32gbit/Makefile b/qla2x00t-32gbit/Makefile index ddcaafc56..48dad4ff1 100644 --- a/qla2x00t-32gbit/Makefile +++ b/qla2x00t-32gbit/Makefile @@ -45,7 +45,9 @@ ifeq ($(INSTALL_MOD_PATH),) export INSTALL_MOD_PATH := $(DESTDIR) endif -INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra +INSTALL_MOD_DIR=extra + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/$(INSTALL_MOD_DIR) all: $(MAKE) -C $(KDIR) M=$(shell pwd) \ @@ -56,6 +58,7 @@ install: all KDIR=$(KDIR) ../scripts/sign-modules $(MAKE) -C $(KDIR) M=$(shell pwd) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install @@ -71,7 +74,7 @@ clean: extraclean: clean rm -f *.orig *.rej -.PHONY: all tgt install uninstall clean extraclean +.PHONY: all install uninstall clean extraclean endif diff --git a/qla2x00t-32gbit/qla2x00-target/Makefile b/qla2x00t-32gbit/qla2x00-target/Makefile index 886494dc5..4de10dc7a 100644 --- a/qla2x00t-32gbit/qla2x00-target/Makefile +++ b/qla2x00t-32gbit/qla2x00-target/Makefile @@ -62,7 +62,9 @@ ifndef PREFIX PREFIX=/usr/local endif -INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra +INSTALL_MOD_DIR=extra + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/$(INSTALL_MOD_DIR) SCST_DIR := $(shell echo "$$PWD/../../scst/src") @@ -77,6 +79,7 @@ endif KDIR=$(KDIR) ../../scripts/sign-modules $(MAKE) -C $(KDIR) M=$(shell pwd) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install @@ -102,4 +105,4 @@ endif extraclean: clean rm -f *.orig *.rej -.PHONY: all tgt install uninstall clean extraclean qla2xxx_scst +.PHONY: all install uninstall clean extraclean qla2xxx_scst diff --git a/qla2x00t-32gbit/qla_attr.c b/qla2x00t-32gbit/qla_attr.c index 16b6b5cc3..c35bdddfe 100644 --- a/qla2x00t-32gbit/qla_attr.c +++ b/qla2x00t-32gbit/qla_attr.c @@ -2821,6 +2821,7 @@ static void qla2x00_terminate_rport_io(struct fc_rport *rport) { fc_port_t *fcport = *(fc_port_t **)rport->dd_data; + scsi_qla_host_t *vha; if (!fcport) return; @@ -2830,9 +2831,12 @@ qla2x00_terminate_rport_io(struct fc_rport *rport) if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags)) return; + vha = fcport->vha; if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) { qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16); + qla2x00_eh_wait_for_pending_commands(fcport->vha, fcport->d_id.b24, + 0, WAIT_TARGET); return; } /* @@ -2857,6 +2861,15 @@ qla2x00_terminate_rport_io(struct fc_rport *rport) qla2x00_port_logout(fcport->vha, fcport); } } + + /* check for any straggling io left behind */ + if (qla2x00_eh_wait_for_pending_commands(fcport->vha, fcport->d_id.b24, 0, WAIT_TARGET)) { + ql_log(ql_log_warn, vha, 0x300b, + "IO not return. Resetting. \n"); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + qla2x00_wait_for_chip_reset(vha); + } } static int @@ -3151,8 +3164,6 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) vha->flags.difdix_supported = 1; ql_dbg(ql_dbg_user, vha, 0x7082, "Registered for DIF/DIX type 1 and 3 protection.\n"); - if (ql2xenabledif == 1) - prot = SHOST_DIX_TYPE0_PROTECTION; scsi_host_set_prot(vha->host, prot | SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION diff --git a/qla2x00t-32gbit/qla_bsg.c b/qla2x00t-32gbit/qla_bsg.c index 8e0f44caa..cc8c98d16 100644 --- a/qla2x00t-32gbit/qla_bsg.c +++ b/qla2x00t-32gbit/qla_bsg.c @@ -286,6 +286,10 @@ qla2x00_process_els(BSG_JOB_TYPE *bsg_job) if (bsg_request->msgcode == FC_BSG_RPT_ELS) { rport = fc_bsg_to_rport(bsg_job); + if (!rport) { + rval = -ENOMEM; + goto done; + } fcport = *(fc_port_t **) rport->dd_data; host = rport_to_shost(rport); vha = shost_priv(host); @@ -2996,6 +3000,8 @@ qla24xx_bsg_request(BSG_JOB_TYPE *bsg_job) if (bsg_request->msgcode == FC_BSG_RPT_ELS) { rport = fc_bsg_to_rport(bsg_job); + if (!rport) + return ret; host = rport_to_shost(rport); vha = shost_priv(host); } else { diff --git a/qla2x00t-32gbit/qla_dbg.c b/qla2x00t-32gbit/qla_dbg.c index d9f9dda15..9de6e3a3b 100644 --- a/qla2x00t-32gbit/qla_dbg.c +++ b/qla2x00t-32gbit/qla_dbg.c @@ -12,13 +12,12 @@ * ---------------------------------------------------------------------- * | Module Init and Probe | 0x0199 | | * | Mailbox commands | 0x1206 | 0x11a5-0x11ff | - * | Device Discovery | 0x2134 | 0x210e-0x2115 | - * | | | 0x211c-0x2128 | - * | | | 0x212c-0x2134 | + * | Device Discovery | 0x2134 | 0x2112-0x2115 | + * | | | 0x2127-0x2128 | * | Queue Command and IO tracing | 0x3074 | 0x300b | * | | | 0x3027-0x3028 | * | | | 0x303d-0x3041 | - * | | | 0x302d,0x3033 | + * | | | 0x302e,0x3033 | * | | | 0x3036,0x3038 | * | | | 0x303a | * | DPC Thread | 0x4023 | 0x4002,0x4013 | diff --git a/qla2x00t-32gbit/qla_dbg.h b/qla2x00t-32gbit/qla_dbg.h index 4ea3463a3..ecdc747dd 100644 --- a/qla2x00t-32gbit/qla_dbg.h +++ b/qla2x00t-32gbit/qla_dbg.h @@ -368,6 +368,7 @@ ql_log_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...); #define ql_dbg_tgt_tmr 0x00001000 /* Target mode task management */ #define ql_dbg_tgt_dif 0x00000800 /* Target mode dif */ #define ql_dbg_edif 0x00000400 /* edif and purex debug */ +#define ql_dbg_unsol 0x00000100 /* Unsolicited path debug */ extern int qla27xx_dump_mpi_ram(struct qla_hw_data *, uint32_t, uint32_t *, uint32_t, void **); diff --git a/qla2x00t-32gbit/qla_def.h b/qla2x00t-32gbit/qla_def.h index e25f8ea2b..f009d2cfa 100644 --- a/qla2x00t-32gbit/qla_def.h +++ b/qla2x00t-32gbit/qla_def.h @@ -6,6 +6,9 @@ #ifndef __QLA_DEF_H #define __QLA_DEF_H +#ifndef INSIDE_KERNEL_TREE +#include +#endif #include #include #include @@ -22,7 +25,9 @@ #include #include #include +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) #include +#endif #include #include #include @@ -384,6 +389,14 @@ struct name_list_extended { u8 sent; }; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) +struct qla_nvme_fc_rjt { + struct fcnvme_ls_rjt *c; + dma_addr_t cdma; + u16 size; +}; +#endif + struct els_reject { struct fc_els_ls_rjt *c; dma_addr_t cdma; @@ -503,6 +516,16 @@ static inline be_id_t port_id_to_be_id(port_id_t port_id) return res; } +struct tmf_arg { + struct list_head tmf_elem; + struct qla_qpair *qpair; + struct fc_port *fcport; + struct scsi_qla_host *vha; + u64 lun; + u32 flags; + uint8_t modifier; +}; + struct els_logo_payload { uint8_t opcode; uint8_t rsvd[3]; @@ -531,6 +554,22 @@ struct ct_arg { port_id_t id; }; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) +struct qla_nvme_lsrjt_pt_arg { + struct fc_port *fcport; + u8 opcode; + u8 vp_idx; + u8 reason; + u8 explanation; + __le16 nport_handle; + u16 control_flags; + __le16 ox_id; + __le32 xchg_address; + u32 tx_byte_count, rx_byte_count; + dma_addr_t tx_addr, rx_addr; +}; +#endif + /* * SRB extensions. */ @@ -582,6 +621,10 @@ struct srb_iocb { uint32_t data; struct completion comp; __le16 comp_status; + + uint8_t modifier; + uint8_t vp_index; + uint16_t loop_id; } tmf; struct { #define SRB_FXDISC_REQ_DMA_VALID BIT_0 @@ -635,13 +678,16 @@ struct srb_iocb { void *desc; /* These are only used with ls4 requests */ - int cmd_len; - int rsp_len; + __le32 cmd_len; + __le32 rsp_len; dma_addr_t cmd_dma; dma_addr_t rsp_dma; enum nvmefc_fcp_datadir dir; uint32_t dl; uint32_t timeout_sec; + __le32 exchange_address; + __le16 nport_handle; + __le16 ox_id; struct list_head entry; } nvme; struct { @@ -685,6 +731,7 @@ struct srb_iocb { #define SRB_SA_UPDATE 25 #define SRB_ELS_CMD_HST_NOLOGIN 26 #define SRB_SA_REPLACE 27 +#define SRB_MARKER 28 struct qla_els_pt_arg { u8 els_opcode; @@ -731,10 +778,13 @@ typedef struct srb { struct iocb_resource iores; struct kref cmd_kref; /* need to migrate ref_count over to this */ void *priv; - wait_queue_head_t nvme_ls_waitq; struct fc_port *fcport; struct scsi_qla_host *vha; unsigned int start_timer:1; + unsigned int abort:1; + unsigned int aborted:1; + unsigned int completed:1; + unsigned int unsol_rsp:1; uint32_t handle; uint16_t flags; @@ -2574,6 +2624,7 @@ enum rscn_addr_format { typedef struct fc_port { struct list_head list; struct scsi_qla_host *vha; + struct list_head unsol_ctx_head; unsigned int conf_compl_supported:1; unsigned int deleted:2; @@ -2594,7 +2645,6 @@ typedef struct fc_port { unsigned int do_prli_nvme:1; uint8_t nvme_flag; - uint8_t node_name[WWN_SIZE]; uint8_t port_name[WWN_SIZE]; port_id_t d_id; @@ -3204,12 +3254,12 @@ struct ct_sns_gpnft_rsp { uint8_t vendor_unique; }; /* Assume the largest number of targets for the union */ - struct ct_sns_gpn_ft_data { + DECLARE_FLEX_ARRAY(struct ct_sns_gpn_ft_data { u8 control_byte; u8 port_id[3]; u32 reserved; u8 port_name[8]; - } entries[1]; + }, entries); }; /* CT command response */ @@ -3776,6 +3826,16 @@ struct qla_fw_resources { u16 pad; }; +struct qla_fw_res { + u16 iocb_total; + u16 iocb_limit; + atomic_t iocb_used; + + u16 exch_total; + u16 exch_limit; + atomic_t exch_used; +}; + #define QLA_IOCB_PCT_LIMIT 95 struct qla_buf_pool { @@ -3821,6 +3881,12 @@ struct qla_qpair { uint16_t id; /* qp number used with FW */ uint16_t vp_idx; /* vport ID */ + + uint16_t dsd_inuse; + uint16_t dsd_avail; + struct list_head dsd_list; +#define NUM_DSD_CHAIN 4096 + mempool_t *srb_mempool; struct pci_dev *pdev; @@ -3843,6 +3909,7 @@ struct qla_qpair { uint64_t retry_term_jiff; struct qla_tgt_counters tgt_counters; uint16_t cpuid; + bool cpu_mapped; struct qla_fw_resources fwres ____cacheline_aligned; struct qla_buf_pool buf_pool; u32 cmd_cnt; @@ -4417,7 +4484,6 @@ struct qla_hw_data { uint8_t aen_mbx_count; atomic_t num_pend_mbx_stage1; atomic_t num_pend_mbx_stage2; - atomic_t num_pend_mbx_stage3; uint16_t frame_payload_size; uint32_t login_retry_count; @@ -4492,7 +4558,6 @@ struct qla_hw_data { /* n2n */ struct fc_els_flogi plogi_els_payld; -#define LOGIN_TEMPLATE_SIZE (sizeof(struct fc_els_flogi) - 4) void *swl; @@ -4687,6 +4752,8 @@ struct qla_hw_data { uint32_t flt_region_aux_img_status_sec; }; uint8_t active_image; + uint8_t active_tmf; +#define MAX_ACTIVE_TMF 8 /* Needed for BEACON */ uint16_t beacon_blink_led; @@ -4701,6 +4768,8 @@ struct qla_hw_data { struct qla_msix_entry *msix_entries; + struct list_head tmf_pending; + struct list_head tmf_active; struct list_head vp_list; /* list of VP */ unsigned long vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) / sizeof(unsigned long)]; @@ -4744,11 +4813,6 @@ struct qla_hw_data { struct fw_blob *hablob; struct qla82xx_legacy_intr_set nx_legacy_intr; - uint16_t gbl_dsd_inuse; - uint16_t gbl_dsd_avail; - struct list_head gbl_dsd_list; -#define NUM_DSD_CHAIN 4096 - uint8_t fw_type; uint32_t file_prd_off; /* File firmware product offset */ @@ -4830,6 +4894,10 @@ struct qla_hw_data { struct els_reject elsrej; u8 edif_post_stop_cnt_down; struct qla_vp_map *vp_map; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) + struct qla_nvme_fc_rjt lsrjt; +#endif + struct qla_fw_res fwres ____cacheline_aligned; }; #define RX_ELS_SIZE (roundup(sizeof(struct enode) + ELS_MAX_PAYLOAD, SMP_CACHE_BYTES)) @@ -4862,6 +4930,7 @@ struct active_regions { * is variable) starting at "iocb". */ struct purex_item { + void *purls_context; struct list_head list; struct scsi_qla_host *vha; void (*process_item)(struct scsi_qla_host *vha, @@ -5545,4 +5614,8 @@ struct ql_vnd_tgt_stats_resp { _fp->disc_state, _fp->scan_state, _fp->loop_id, _fp->deleted, \ _fp->flags +#define TMF_NOT_READY(_fcport) \ + (!_fcport || IS_SESSION_DELETED(_fcport) || atomic_read(&_fcport->state) != FCS_ONLINE || \ + !_fcport->vha->hw->flags.fw_started) + #endif diff --git a/qla2x00t-32gbit/qla_dfs.c b/qla2x00t-32gbit/qla_dfs.c index 6fd6f48a6..e0b55d23c 100644 --- a/qla2x00t-32gbit/qla_dfs.c +++ b/qla2x00t-32gbit/qla_dfs.c @@ -120,7 +120,7 @@ qla2x00_dfs_create_rport(scsi_qla_host_t *vha, struct fc_port *fp) sprintf(wwn, "pn-%016llx", wwn_to_u64(fp->port_name)); fp->dfs_rport_dir = debugfs_create_dir(wwn, vha->dfs_rport_root); - if (!fp->dfs_rport_dir) + if (IS_ERR(fp->dfs_rport_dir)) return; if (NVME_TARGET(vha->hw, fp)) debugfs_create_file("dev_loss_tmo", 0600, fp->dfs_rport_dir, @@ -280,6 +280,16 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused) seq_printf(s, "estimate exchange used[%d] high water limit [%d] n", exch_used, ha->base_qpair->fwres.exch_limit); + + if (ql2xenforce_iocb_limit == 2) { + iocbs_used = atomic_read(&ha->fwres.iocb_used); + exch_used = atomic_read(&ha->fwres.exch_used); + seq_printf(s, " estimate iocb2 used [%d] high water limit [%d]\n", + iocbs_used, ha->fwres.iocb_limit); + + seq_printf(s, " estimate exchange2 used[%d] high water limit [%d] \n", + exch_used, ha->fwres.exch_limit); + } } return 0; @@ -702,14 +712,14 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha) if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha)) { ha->tgt.dfs_naqp = debugfs_create_file("naqp", 0400, ha->dfs_dir, vha, &dfs_naqp_ops); - if (!ha->tgt.dfs_naqp) { + if (IS_ERR(ha->tgt.dfs_naqp)) { ql_log(ql_log_warn, vha, 0xd011, "Unable to create debugFS naqp node.\n"); goto out; } } vha->dfs_rport_root = debugfs_create_dir("rports", ha->dfs_dir); - if (!vha->dfs_rport_root) { + if (IS_ERR(vha->dfs_rport_root)) { ql_log(ql_log_warn, vha, 0xd012, "Unable to create debugFS rports node.\n"); goto out; diff --git a/qla2x00t-32gbit/qla_edif.c b/qla2x00t-32gbit/qla_edif.c index 9e0fd61c0..96b45f630 100644 --- a/qla2x00t-32gbit/qla_edif.c +++ b/qla2x00t-32gbit/qla_edif.c @@ -2362,8 +2362,8 @@ qla24xx_issue_sa_replace_iocb(scsi_qla_host_t *vha, struct qla_work_evt *e) if (!sa_ctl) { ql_dbg(ql_dbg_edif, vha, 0x70e6, "sa_ctl allocation failed\n"); - rval = -ENOMEM; - goto done; + rval = -ENOMEM; + return rval; } fcport = sa_ctl->fcport; diff --git a/qla2x00t-32gbit/qla_gbl.h b/qla2x00t-32gbit/qla_gbl.h index 82701c436..ea684de65 100644 --- a/qla2x00t-32gbit/qla_gbl.h +++ b/qla2x00t-32gbit/qla_gbl.h @@ -48,8 +48,6 @@ extern int qla24xx_els_dcmd2_iocb(scsi_qla_host_t *, int, fc_port_t *, bool); extern void qla2x00_els_dcmd2_free(scsi_qla_host_t *vha, struct els_plogi *els_plogi); -extern void qla2x00_update_fcports(scsi_qla_host_t *); - extern int qla2x00_abort_isp(scsi_qla_host_t *); extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *); extern void qla2x00_quiesce_io(scsi_qla_host_t *); @@ -69,7 +67,7 @@ extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *); extern int qla2x00_async_prlo(struct scsi_qla_host *, fc_port_t *); extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *, uint16_t *); -extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t); +extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint64_t, uint32_t); struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *, enum qla_work_type); extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *); @@ -143,6 +141,7 @@ void qla_edif_sess_down(struct scsi_qla_host *vha, struct fc_port *sess); void qla_edif_clear_appdata(struct scsi_qla_host *vha, struct fc_port *fcport); const char *sc_to_str(uint16_t cmd); +void qla_adjust_iocb_limit(scsi_qla_host_t *vha); /* * Global Data in qla_os.c source file. @@ -211,8 +210,6 @@ extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *, uint16_t *); -extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *, - fc_port_t *, uint16_t *); extern int qla2x00_set_exlogins_buffer(struct scsi_qla_host *); extern void qla2x00_free_exlogin_buffer(struct qla_hw_data *); extern int qla2x00_set_exchoffld_buffer(struct scsi_qla_host *); @@ -222,7 +219,6 @@ extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *); extern struct scsi_qla_host *qla2x00_create_host(const struct scsi_host_template *, struct qla_hw_data *); -extern void qla2x00_free_host(struct scsi_qla_host *); extern void qla2x00_relogin(struct scsi_qla_host *); extern void qla2x00_do_work(struct scsi_qla_host *); extern void qla2x00_free_fcports(struct scsi_qla_host *); @@ -244,13 +240,10 @@ extern int __qla83xx_clear_drv_presence(scsi_qla_host_t *vha); extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32); extern void qla2x00_disable_board_on_pci_error(struct work_struct *); -extern void qla_eeh_work(struct work_struct *); extern void qla2x00_sp_compl(srb_t *sp, int); extern void qla2xxx_qpair_sp_free_dma(srb_t *sp); extern void qla2xxx_qpair_sp_compl(srb_t *sp, int); extern void qla24xx_sched_upd_fcport(fc_port_t *); -void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *, - uint16_t *); int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *); int qla24xx_post_relogin_work(struct scsi_qla_host *vha); void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *); @@ -616,7 +609,13 @@ qla2xxx_msix_rsp_q_hs(int irq, void *dev_id); fc_port_t *qla2x00_find_fcport_by_loopid(scsi_qla_host_t *, uint16_t); fc_port_t *qla2x00_find_fcport_by_wwpn(scsi_qla_host_t *, u8 *, u8); fc_port_t *qla2x00_find_fcport_by_nportid(scsi_qla_host_t *, port_id_t *, u8); -void __qla_consume_iocb(struct scsi_qla_host *vha, void **pkt, struct rsp_que **rsp); +void qla24xx_queue_purex_item(scsi_qla_host_t *, struct purex_item *, + void (*process_item)(struct scsi_qla_host *, + struct purex_item *)); +void __qla_consume_iocb(struct scsi_qla_host *, void **, struct rsp_que **); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) +void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp); +#endif /* * Global Function Prototypes in qla_sup.c source file. @@ -679,8 +678,11 @@ extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t); extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *); extern int qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *); extern int qla2x00_mailbox_passthru(BSG_JOB_TYPE *bsg_job); -int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha, void **pkt, - struct rsp_que **rsp, u8 *buf, u32 buf_len); +int qla2x00_sys_ld_info(struct bsg_job *bsg_job); +int __qla_copy_purex_to_buffer(struct scsi_qla_host *, void **, + struct rsp_que **, u8 *, u32); +struct purex_item *qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, + void **pkt, struct rsp_que **rsp, bool is_purls, bool byte_order); int qla_mailbox_passthru(scsi_qla_host_t *vha, uint16_t *mbx_in, uint16_t *mbx_out); @@ -734,7 +736,6 @@ int qla24xx_post_gpsc_work(struct scsi_qla_host *, fc_port_t *); int qla24xx_async_gpsc(scsi_qla_host_t *, fc_port_t *); void qla24xx_handle_gpsc_event(scsi_qla_host_t *, struct event_arg *); int qla2x00_mgmt_svr_login(scsi_qla_host_t *); -void qla24xx_handle_gffid_event(scsi_qla_host_t *vha, struct event_arg *ea); int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport, bool); int qla24xx_async_gpnft(scsi_qla_host_t *, u8, srb_t *); void qla24xx_async_gpnft_done(scsi_qla_host_t *, srb_t *); @@ -864,7 +865,6 @@ extern void qla2x00_start_iocbs(struct scsi_qla_host *, struct req_que *); /* Interrupt related */ extern irqreturn_t qla82xx_intr_handler(int, void *); -extern irqreturn_t qla82xx_msi_handler(int, void *); extern irqreturn_t qla82xx_msix_default(int, void *); extern irqreturn_t qla82xx_msix_rsp_q(int, void *); extern void qla82xx_enable_intrs(struct qla_hw_data *); diff --git a/qla2x00t-32gbit/qla_gs.c b/qla2x00t-32gbit/qla_gs.c index 4738f8935..1cf9d200d 100644 --- a/qla2x00t-32gbit/qla_gs.c +++ b/qla2x00t-32gbit/qla_gs.c @@ -3776,8 +3776,8 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) sp->u.iocb_cmd.u.ctarg.req_size = GPN_FT_REQ_SIZE; rspsz = sizeof(struct ct_sns_gpnft_rsp) + - ((vha->hw->max_fibre_devices - 1) * - sizeof(struct ct_sns_gpn_ft_data)); + vha->hw->max_fibre_devices * + sizeof(struct ct_sns_gpn_ft_data); sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev, rspsz, diff --git a/qla2x00t-32gbit/qla_init.c b/qla2x00t-32gbit/qla_init.c index 8dc879c01..68d9d220c 100644 --- a/qla2x00t-32gbit/qla_init.c +++ b/qla2x00t-32gbit/qla_init.c @@ -508,6 +508,7 @@ static void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) { struct fc_port *fcport = ea->fcport; + unsigned long flags; ql_dbg(ql_dbg_disc, vha, 0x20d2, "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n", @@ -522,9 +523,15 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) ql_dbg(ql_dbg_disc, vha, 0x2066, "%s %8phC: adisc fail: post delete\n", __func__, ea->fcport->port_name); + + spin_lock_irqsave(&vha->work_lock, flags); /* deleted = 0 & logout_on_delete = force fw cleanup */ - fcport->deleted = 0; + if (fcport->deleted == QLA_SESS_DELETED) + fcport->deleted = 0; + fcport->logout_on_delete = 1; + spin_unlock_irqrestore(&vha->work_lock, flags); + qlt_schedule_sess_for_deletion(ea->fcport); return; } @@ -1134,7 +1141,7 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) u16 *mb; if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) - return rval; + goto done; ql_dbg(ql_dbg_disc, vha, 0x20d9, "Async-gnlist WWPN %8phC \n", fcport->port_name); @@ -1188,8 +1195,9 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) done_free_sp: /* ref: INIT */ kref_put(&sp->cmd_kref, qla2x00_sp_release); + fcport->flags &= ~(FCF_ASYNC_SENT); done: - fcport->flags &= ~(FCF_ASYNC_ACTIVE | FCF_ASYNC_SENT); + fcport->flags &= ~(FCF_ASYNC_ACTIVE); return rval; } @@ -1446,7 +1454,6 @@ void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); ea->fcport->login_gen++; - ea->fcport->deleted = 0; ea->fcport->logout_on_delete = 1; if (!ea->fcport->login_succ && !IS_SW_RESV_ADDR(ea->fcport->d_id)) { @@ -1996,7 +2003,11 @@ qla2x00_tmf_iocb_timeout(void *data) int rc, h; unsigned long flags; - rc = qla24xx_async_abort_cmd(sp, false); + if (sp->type == SRB_MARKER) + rc = QLA_FUNCTION_FAILED; + else + rc = qla24xx_async_abort_cmd(sp, false); + if (rc) { spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) { @@ -2013,24 +2024,154 @@ qla2x00_tmf_iocb_timeout(void *data) } } +static void qla_marker_sp_done(srb_t *sp, int res) +{ + struct srb_iocb *tmf = &sp->u.iocb_cmd; + + if (res != QLA_SUCCESS) + ql_dbg(ql_dbg_taskm, sp->vha, 0x8004, + "Async-marker fail hdl=%x portid=%06x ctrl=%x lun=%lld qp=%d.\n", + sp->handle, sp->fcport->d_id.b24, sp->u.iocb_cmd.u.tmf.flags, + sp->u.iocb_cmd.u.tmf.lun, sp->qpair->id); + + sp->u.iocb_cmd.u.tmf.data = res; + complete(&tmf->u.tmf.comp); +} + +#define START_SP_W_RETRIES(_sp, _rval, _chip_gen, _login_gen) \ +{\ + int cnt = 5; \ + do { \ + if (_chip_gen != sp->vha->hw->chip_reset || _login_gen != sp->fcport->login_gen) {\ + _rval = EINVAL; \ + break; \ + } \ + _rval = qla2x00_start_sp(_sp); \ + if (_rval == EAGAIN) \ + msleep(1); \ + else \ + break; \ + cnt--; \ + } while (cnt); \ +} + +/** + * qla26xx_marker: send marker IOCB and wait for the completion of it. + * @arg: pointer to argument list. + * It is assume caller will provide an fcport pointer and modifier + */ +static int +qla26xx_marker(struct tmf_arg *arg) +{ + struct scsi_qla_host *vha = arg->vha; + struct srb_iocb *tm_iocb; + srb_t *sp; + int rval = QLA_FUNCTION_FAILED; + fc_port_t *fcport = arg->fcport; + u32 chip_gen, login_gen; + + if (TMF_NOT_READY(arg->fcport)) { + ql_dbg(ql_dbg_taskm, vha, 0x8039, + "FC port not ready for marker loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n", + fcport->loop_id, fcport->d_id.b24, + arg->modifier, arg->lun, arg->qpair->id); + return QLA_SUSPENDED; + } + + chip_gen = vha->hw->chip_reset; + login_gen = fcport->login_gen; + + /* ref: INIT */ + sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL); + if (!sp) + goto done; + + sp->type = SRB_MARKER; + sp->name = "marker"; + qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha), qla_marker_sp_done); + sp->u.iocb_cmd.timeout = qla2x00_tmf_iocb_timeout; + + tm_iocb = &sp->u.iocb_cmd; + init_completion(&tm_iocb->u.tmf.comp); + tm_iocb->u.tmf.modifier = arg->modifier; + tm_iocb->u.tmf.lun = arg->lun; + tm_iocb->u.tmf.loop_id = fcport->loop_id; + tm_iocb->u.tmf.vp_index = vha->vp_idx; + + START_SP_W_RETRIES(sp, rval, chip_gen, login_gen); + + ql_dbg(ql_dbg_taskm, vha, 0x8006, + "Async-marker hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n", + sp->handle, fcport->loop_id, fcport->d_id.b24, + arg->modifier, arg->lun, sp->qpair->id, rval); + + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x8031, + "Marker IOCB send failure (%x).\n", rval); + goto done_free_sp; + } + + wait_for_completion(&tm_iocb->u.tmf.comp); + rval = tm_iocb->u.tmf.data; + + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x8019, + "Marker failed hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n", + sp->handle, fcport->loop_id, fcport->d_id.b24, + arg->modifier, arg->lun, sp->qpair->id, rval); + } + +done_free_sp: + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); +done: + return rval; +} + static void qla2x00_tmf_sp_done(srb_t *sp, int res) { struct srb_iocb *tmf = &sp->u.iocb_cmd; + if (res) + tmf->u.tmf.data = res; complete(&tmf->u.tmf.comp); } -int -qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, - uint32_t tag) +static int qla_tmf_wait(struct tmf_arg *arg) { - struct scsi_qla_host *vha = fcport->vha; + /* there are only 2 types of error handling that reaches here, lun or target reset */ + if (arg->flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET | TCF_CLEAR_TASK_SET)) + return qla2x00_eh_wait_for_pending_commands(arg->vha, + arg->fcport->d_id.b24, arg->lun, WAIT_LUN); + else + return qla2x00_eh_wait_for_pending_commands(arg->vha, + arg->fcport->d_id.b24, arg->lun, WAIT_TARGET); +} + +static int +__qla2x00_async_tm_cmd(struct tmf_arg *arg) +{ + struct scsi_qla_host *vha = arg->vha; struct srb_iocb *tm_iocb; srb_t *sp; int rval = QLA_FUNCTION_FAILED; + fc_port_t *fcport = arg->fcport; + u32 chip_gen, login_gen; + u64 jif; + + if (TMF_NOT_READY(arg->fcport)) { + ql_dbg(ql_dbg_taskm, vha, 0x8032, + "FC port not ready for TM command loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n", + fcport->loop_id, fcport->d_id.b24, + arg->modifier, arg->lun, arg->qpair->id); + return QLA_SUSPENDED; + } + + chip_gen = vha->hw->chip_reset; + login_gen = fcport->login_gen; /* ref: INIT */ - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); + sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL); if (!sp) goto done; @@ -2043,15 +2184,16 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, tm_iocb = &sp->u.iocb_cmd; init_completion(&tm_iocb->u.tmf.comp); - tm_iocb->u.tmf.flags = flags; - tm_iocb->u.tmf.lun = lun; + tm_iocb->u.tmf.flags = arg->flags; + tm_iocb->u.tmf.lun = arg->lun; + + START_SP_W_RETRIES(sp, rval, chip_gen, login_gen); ql_dbg(ql_dbg_taskm, vha, 0x802f, - "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n", - sp->handle, fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); + "Async-tmf hdl=%x loop-id=%x portid=%06x ctrl=%x lun=%lld qp=%d rval=%x.\n", + sp->handle, fcport->loop_id, fcport->d_id.b24, + arg->flags, arg->lun, sp->qpair->id, rval); - rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) goto done_free_sp; wait_for_completion(&tm_iocb->u.tmf.comp); @@ -2064,14 +2206,25 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, } if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) { - flags = tm_iocb->u.tmf.flags; - lun = (uint16_t)tm_iocb->u.tmf.lun; + jif = jiffies; + if (qla_tmf_wait(arg)) { + ql_log(ql_log_info, vha, 0x803e, + "Waited %u ms Nexus=%ld:%06x:%llu.\n", + jiffies_to_msecs(jiffies - jif), vha->host_no, + fcport->d_id.b24, arg->lun); + } - /* Issue Marker IOCB */ - qla2x00_marker(vha, vha->hw->base_qpair, - fcport->loop_id, lun, - flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID); + if (chip_gen == vha->hw->chip_reset && login_gen == fcport->login_gen) { + rval = qla26xx_marker(arg); + } else { + ql_log(ql_log_info, vha, 0x803e, + "Skip Marker due to disruption. Nexus=%ld:%06x:%llu.\n", + vha->host_no, fcport->d_id.b24, arg->lun); + rval = QLA_FUNCTION_FAILED; + } } + if (tm_iocb->u.tmf.data) + rval = tm_iocb->u.tmf.data; done_free_sp: /* ref: INIT */ @@ -2080,6 +2233,103 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, return rval; } +static void qla_put_tmf(struct tmf_arg *arg) +{ + struct scsi_qla_host *vha = arg->vha; + struct qla_hw_data *ha = vha->hw; + unsigned long flags; + + spin_lock_irqsave(&ha->tgt.sess_lock, flags); + ha->active_tmf--; + list_del(&arg->tmf_elem); + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); +} + +static +int qla_get_tmf(struct tmf_arg *arg) +{ + struct scsi_qla_host *vha = arg->vha; + struct qla_hw_data *ha = vha->hw; + unsigned long flags; + fc_port_t *fcport = arg->fcport; + int rc = 0; + struct tmf_arg *t; + + spin_lock_irqsave(&ha->tgt.sess_lock, flags); + list_for_each_entry(t, &ha->tmf_active, tmf_elem) { + if (t->fcport == arg->fcport && t->lun == arg->lun) { + /* reject duplicate TMF */ + ql_log(ql_log_warn, vha, 0x802c, + "found duplicate TMF. Nexus=%ld:%06x:%llu.\n", + vha->host_no, fcport->d_id.b24, arg->lun); + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + return -EINVAL; + } + } + + list_add_tail(&arg->tmf_elem, &ha->tmf_pending); + while (ha->active_tmf >= MAX_ACTIVE_TMF) { + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + + msleep(1); + + spin_lock_irqsave(&ha->tgt.sess_lock, flags); + if (TMF_NOT_READY(fcport)) { + ql_log(ql_log_warn, vha, 0x802c, + "Unable to acquire TM resource due to disruption.\n"); + rc = EIO; + break; + } + if (ha->active_tmf < MAX_ACTIVE_TMF && + list_is_first(&arg->tmf_elem, &ha->tmf_pending)) + break; + } + + list_del(&arg->tmf_elem); + + if (!rc) { + ha->active_tmf++; + list_add_tail(&arg->tmf_elem, &ha->tmf_active); + } + + spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + + return rc; +} + +int +qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun, + uint32_t tag) +{ + struct scsi_qla_host *vha = fcport->vha; + struct tmf_arg a; + int rval = QLA_SUCCESS; + + if (TMF_NOT_READY(fcport)) + return QLA_SUSPENDED; + + a.vha = fcport->vha; + a.fcport = fcport; + a.lun = lun; + a.flags = flags; + INIT_LIST_HEAD(&a.tmf_elem); + + if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) { + a.modifier = MK_SYNC_ID_LUN; + } else { + a.modifier = MK_SYNC_ID; + } + + if (qla_get_tmf(&a)) + return QLA_FUNCTION_FAILED; + + a.qpair = vha->hw->base_qpair; + rval = __qla2x00_async_tm_cmd(&a); + + qla_put_tmf(&a); + return rval; +} + int qla24xx_async_abort_command(srb_t *sp) { @@ -3935,39 +4185,61 @@ qla24xx_detect_sfp(scsi_qla_host_t *vha) return ha->flags.lr_detected; } -void qla_init_iocb_limit(scsi_qla_host_t *vha) +static void __qla_adjust_iocb_limit(struct qla_qpair *qpair) { - u16 i, num_qps; - u32 limit; - struct qla_hw_data *ha = vha->hw; + u8 num_qps; + u16 limit; + struct qla_hw_data *ha = qpair->vha->hw; num_qps = ha->num_qpairs + 1; limit = (ha->orig_fw_iocb_count * QLA_IOCB_PCT_LIMIT) / 100; - ha->base_qpair->fwres.iocbs_total = ha->orig_fw_iocb_count; - ha->base_qpair->fwres.iocbs_limit = limit; - ha->base_qpair->fwres.iocbs_qp_limit = limit / num_qps; - ha->base_qpair->fwres.iocbs_used = 0; + qpair->fwres.iocbs_total = ha->orig_fw_iocb_count; + qpair->fwres.iocbs_limit = limit; + qpair->fwres.iocbs_qp_limit = limit / num_qps; + + qpair->fwres.exch_total = ha->orig_fw_xcb_count; + qpair->fwres.exch_limit = (ha->orig_fw_xcb_count * + QLA_IOCB_PCT_LIMIT) / 100; +} + +void qla_init_iocb_limit(scsi_qla_host_t *vha) +{ + u8 i; + struct qla_hw_data *ha = vha->hw; - ha->base_qpair->fwres.exch_total = ha->orig_fw_xcb_count; - ha->base_qpair->fwres.exch_limit = (ha->orig_fw_xcb_count * - QLA_IOCB_PCT_LIMIT) / 100; + __qla_adjust_iocb_limit(ha->base_qpair); + ha->base_qpair->fwres.iocbs_used = 0; ha->base_qpair->fwres.exch_used = 0; for (i = 0; i < ha->max_qpairs; i++) { if (ha->queue_pair_map[i]) { - ha->queue_pair_map[i]->fwres.iocbs_total = - ha->orig_fw_iocb_count; - ha->queue_pair_map[i]->fwres.iocbs_limit = limit; - ha->queue_pair_map[i]->fwres.iocbs_qp_limit = - limit / num_qps; + __qla_adjust_iocb_limit(ha->queue_pair_map[i]); ha->queue_pair_map[i]->fwres.iocbs_used = 0; - ha->queue_pair_map[i]->fwres.exch_total = ha->orig_fw_xcb_count; - ha->queue_pair_map[i]->fwres.exch_limit = - (ha->orig_fw_xcb_count * QLA_IOCB_PCT_LIMIT) / 100; ha->queue_pair_map[i]->fwres.exch_used = 0; } } + + ha->fwres.iocb_total = ha->orig_fw_iocb_count; + ha->fwres.iocb_limit = (ha->orig_fw_iocb_count * QLA_IOCB_PCT_LIMIT) / 100; + ha->fwres.exch_total = ha->orig_fw_xcb_count; + ha->fwres.exch_limit = (ha->orig_fw_xcb_count * QLA_IOCB_PCT_LIMIT) / 100; + + atomic_set(&ha->fwres.iocb_used, 0); + atomic_set(&ha->fwres.exch_used, 0); +} + +void qla_adjust_iocb_limit(scsi_qla_host_t *vha) +{ + u8 i; + struct qla_hw_data *ha = vha->hw; + + __qla_adjust_iocb_limit(ha->base_qpair); + + for (i = 0; i < ha->max_qpairs; i++) { + if (ha->queue_pair_map[i]) + __qla_adjust_iocb_limit(ha->queue_pair_map[i]); + } } /** @@ -4565,15 +4837,16 @@ qla2x00_init_rings(scsi_qla_host_t *vha) if (ha->flags.edif_enabled) mid_init_cb->init_cb.frame_payload_size = cpu_to_le16(ELS_MAX_PAYLOAD); + QLA_FW_STARTED(ha); rval = qla2x00_init_firmware(vha, ha->init_cb_size); next_check: if (rval) { + QLA_FW_STOPPED(ha); ql_log(ql_log_fatal, vha, 0x00d2, "Init Firmware **** FAILED ****.\n"); } else { ql_dbg(ql_dbg_init, vha, 0x00d3, "Init Firmware -- success.\n"); - QLA_FW_STARTED(ha); vha->u_ql2xexchoffld = vha->u_ql2xiniexchg = 0; } @@ -4864,7 +5137,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, if (use_tbl && ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) - strlcpy(ha->model_desc, + strscpy(ha->model_desc, qla2x00_model_name[index * 2 + 1], sizeof(ha->model_desc)); } else { @@ -4872,14 +5145,14 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, if (use_tbl && ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) { - strlcpy(ha->model_number, + strscpy(ha->model_number, qla2x00_model_name[index * 2], sizeof(ha->model_number)); - strlcpy(ha->model_desc, + strscpy(ha->model_desc, qla2x00_model_name[index * 2 + 1], sizeof(ha->model_desc)); } else { - strlcpy(ha->model_number, def, + strscpy(ha->model_number, def, sizeof(ha->model_number)); } } @@ -5294,6 +5567,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) INIT_WORK(&fcport->reg_work, qla_register_fcport_fn); INIT_LIST_HEAD(&fcport->gnl_entry); INIT_LIST_HEAD(&fcport->list); + INIT_LIST_HEAD(&fcport->unsol_ctx_head); INIT_LIST_HEAD(&fcport->sess_cmd_list); spin_lock_init(&fcport->sess_cmd_lock); @@ -5877,6 +6151,8 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) void qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) { + unsigned long flags; + if (IS_SW_RESV_ADDR(fcport->d_id)) return; @@ -5886,7 +6162,11 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla2x00_set_fcport_disc_state(fcport, DSC_UPD_FCPORT); fcport->login_retry = vha->hw->login_retry_count; fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); + + spin_lock_irqsave(&vha->work_lock, flags); fcport->deleted = 0; + spin_unlock_irqrestore(&vha->work_lock, flags); + if (vha->hw->current_topology == ISP_CFG_NL) fcport->logout_on_delete = 0; else @@ -6007,7 +6287,6 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) fc_port_t *fcport; uint16_t mb[MAILBOX_REGISTER_COUNT]; uint16_t loop_id; - LIST_HEAD(new_fcports); struct qla_hw_data *ha = vha->hw; int discovery_gen; @@ -7125,14 +7404,15 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) } /* purge MBox commands */ - if (atomic_read(&ha->num_pend_mbx_stage3)) { + spin_lock_irqsave(&ha->hardware_lock, flags); + if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags)) { clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); complete(&ha->mbx_intr_comp); } + spin_unlock_irqrestore(&ha->hardware_lock, flags); i = 0; - while (atomic_read(&ha->num_pend_mbx_stage3) || - atomic_read(&ha->num_pend_mbx_stage2) || + while (atomic_read(&ha->num_pend_mbx_stage2) || atomic_read(&ha->num_pend_mbx_stage1)) { msleep(20); i++; @@ -8222,7 +8502,7 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, ql_dbg(ql_dbg_init, vha, 0x0163, "-> fwdt%u template allocate template %#x words...\n", j, risc_size); - fwdt->template = vmalloc(risc_size * sizeof(*dcode)); + fwdt->template = vmalloc_array(risc_size, sizeof(*dcode)); if (!fwdt->template) { ql_log(ql_log_warn, vha, 0x0164, "-> fwdt%u failed allocate template.\n", j); @@ -8477,7 +8757,7 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr) ql_dbg(ql_dbg_init, vha, 0x0173, "-> fwdt%u template allocate template %#x words...\n", j, risc_size); - fwdt->template = vmalloc(risc_size * sizeof(*dcode)); + fwdt->template = vmalloc_array(risc_size, sizeof(*dcode)); if (!fwdt->template) { ql_log(ql_log_warn, vha, 0x0174, "-> fwdt%u failed allocate template.\n", j); @@ -9378,6 +9658,7 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, qpair->vp_idx = vp_idx; qpair->fw_started = ha->flags.fw_started; INIT_LIST_HEAD(&qpair->hints_list); + INIT_LIST_HEAD(&qpair->dsd_list); qpair->chip_reset = ha->base_qpair->chip_reset; qpair->enable_class_2 = ha->base_qpair->enable_class_2; qpair->enable_explicit_conf = @@ -9428,12 +9709,9 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, qpair->req = ha->req_q_map[req_id]; qpair->rsp->req = qpair->req; qpair->rsp->qpair = qpair; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) && \ - (!defined(RHEL_RELEASE_CODE) || \ - RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(7, 5)) - /* init qpair to this cpu. Will adjust at run time. */ - qla_cpu_update(qpair, raw_smp_processor_id()); -#endif + + if (!qpair->cpu_mapped) + qla_cpu_update(qpair, raw_smp_processor_id()); if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) @@ -9509,6 +9787,19 @@ int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair) if (ret != QLA_SUCCESS) goto fail; + if (!list_empty(&qpair->dsd_list)) { + struct dsd_dma *dsd_ptr, *tdsd_ptr; + + /* clean up allocated prev pool */ + list_for_each_entry_safe(dsd_ptr, tdsd_ptr, + &qpair->dsd_list, list) { + dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr, + dsd_ptr->dsd_list_dma); + list_del(&dsd_ptr->list); + kfree(dsd_ptr); + } + } + mutex_lock(&ha->mq_lock); ha->queue_pair_map[qpair->id] = NULL; clear_bit(qpair->id, ha->qpair_qid_map); diff --git a/qla2x00t-32gbit/qla_inline.h b/qla2x00t-32gbit/qla_inline.h index c3f1b3b7f..874618471 100644 --- a/qla2x00t-32gbit/qla_inline.h +++ b/qla2x00t-32gbit/qla_inline.h @@ -117,11 +117,13 @@ qla2x00_set_fcport_disc_state(fc_port_t *fcport, int state) { int old_val; uint8_t shiftbits, mask; + uint8_t port_dstate_str_sz; /* This will have to change when the max no. of states > 16 */ shiftbits = 4; mask = (1 << shiftbits) - 1; + port_dstate_str_sz = sizeof(port_dstate_str) / sizeof(char *); fcport->disc_state = state; while (1) { old_val = atomic_read(&fcport->shadow_disc_state); @@ -129,7 +131,8 @@ qla2x00_set_fcport_disc_state(fc_port_t *fcport, int state) old_val, (old_val << shiftbits) | state)) { ql_dbg(ql_dbg_disc, fcport->vha, 0x2134, "FCPort %8phC disc_state transition: %s to %s - portid=%06x.\n", - fcport->port_name, port_dstate_str[old_val & mask], + fcport->port_name, (old_val & mask) < port_dstate_str_sz ? + port_dstate_str[old_val & mask] : "Unknown", port_dstate_str[state], fcport->d_id.b24); return; } @@ -391,6 +394,7 @@ enum { RESOURCE_IOCB = BIT_0, RESOURCE_EXCH = BIT_1, /* exchange */ RESOURCE_FORCE = BIT_2, + RESOURCE_HA = BIT_3, }; static inline int @@ -398,7 +402,7 @@ qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores) { u16 iocbs_used, i; u16 exch_used; - struct qla_hw_data *ha = qp->vha->hw; + struct qla_hw_data *ha = qp->hw; if (!ql2xenforce_iocb_limit) { iores->res_type = RESOURCE_NONE; @@ -433,15 +437,69 @@ qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores) return -ENOSPC; } } + + if (ql2xenforce_iocb_limit == 2) { + if ((iores->iocb_cnt + atomic_read(&ha->fwres.iocb_used)) >= + ha->fwres.iocb_limit) { + iores->res_type = RESOURCE_NONE; + return -ENOSPC; + } + + if (iores->res_type & RESOURCE_EXCH) { + if ((iores->exch_cnt + atomic_read(&ha->fwres.exch_used)) >= + ha->fwres.exch_limit) { + iores->res_type = RESOURCE_NONE; + return -ENOSPC; + } + } + } + force: qp->fwres.iocbs_used += iores->iocb_cnt; qp->fwres.exch_used += iores->exch_cnt; + if (ql2xenforce_iocb_limit == 2) { + atomic_add(iores->iocb_cnt, &ha->fwres.iocb_used); + atomic_add(iores->exch_cnt, &ha->fwres.exch_used); + iores->res_type |= RESOURCE_HA; + } return 0; } +/* + * decrement to zero. This routine will not decrement below zero + * @v: pointer of type atomic_t + * @amount: amount to decrement from v + */ +static void qla_atomic_dtz(atomic_t *v, int amount) +{ + int c, old, dec; + + c = atomic_read(v); + for (;;) { + dec = c - amount; + if (unlikely(dec < 0)) + dec = 0; + + old = atomic_cmpxchg((v), c, dec); + if (likely(old == c)) + break; + c = old; + } +} + static inline void qla_put_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores) { + struct qla_hw_data *ha = qp->hw; + + if (iores->res_type & RESOURCE_HA) { + if (iores->res_type & RESOURCE_IOCB) + qla_atomic_dtz(&ha->fwres.iocb_used, iores->iocb_cnt); + + if (iores->res_type & RESOURCE_EXCH) + qla_atomic_dtz(&ha->fwres.exch_used, iores->exch_cnt); + } + if (iores->res_type & RESOURCE_IOCB) { if (qp->fwres.iocbs_used >= iores->iocb_cnt) { qp->fwres.iocbs_used -= iores->iocb_cnt; @@ -527,7 +585,7 @@ fcport_is_bigger(fc_port_t *fcport) static inline struct qla_qpair * qla_mapq_nvme_select_qpair(struct qla_hw_data *ha, struct qla_qpair *qpair) { - int cpuid = smp_processor_id(); + int cpuid = raw_smp_processor_id(); if (qpair->cpuid != cpuid && ha->qp_cpu_map[cpuid]) { @@ -550,11 +608,14 @@ qla_mapq_init_qp_cpu_map(struct qla_hw_data *ha, if (!ha->qp_cpu_map) return; mask = pci_irq_get_affinity(ha->pdev, msix->vector_base0); + if (!mask) + return; qpair->cpuid = cpumask_first(mask); for_each_cpu(cpu, mask) { ha->qp_cpu_map[cpu] = qpair; } msix->cpuid = qpair->cpuid; + qpair->cpu_mapped = true; #endif } diff --git a/qla2x00t-32gbit/qla_iocb.c b/qla2x00t-32gbit/qla_iocb.c index b007ba435..e045f39cb 100644 --- a/qla2x00t-32gbit/qla_iocb.c +++ b/qla2x00t-32gbit/qla_iocb.c @@ -11,6 +11,7 @@ #include +static int qla_start_scsi_type6(srb_t *sp); /** * qla2x00_get_cmd_direction() - Determine control_flag data direction. * @sp: SCSI command @@ -528,21 +529,25 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair, return (QLA_FUNCTION_FAILED); } + mrk24 = (struct mrk_entry_24xx *)mrk; + mrk->entry_type = MARKER_TYPE; mrk->modifier = type; if (type != MK_SYNC_ALL) { if (IS_FWI2_CAPABLE(ha)) { - mrk24 = (struct mrk_entry_24xx *) mrk; mrk24->nport_handle = cpu_to_le16(loop_id); int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun); host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun)); mrk24->vp_index = vha->vp_idx; - mrk24->handle = make_handle(req->id, mrk24->handle); } else { SET_TARGET_ID(ha, mrk->target, loop_id); mrk->lun = cpu_to_le16((uint16_t)lun); } } + + if (IS_FWI2_CAPABLE(ha)) + mrk24->handle = QLA_SKIP_HANDLE; + wmb(); qla2x00_start_iocbs(vha, req); @@ -592,8 +597,6 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, uint16_t tot_dsds) { struct dsd64 *cur_dsd = NULL, *next_dsd; - scsi_qla_host_t *vha; - struct qla_hw_data *ha; struct scsi_cmnd *cmd; struct scatterlist *cur_seg; uint8_t avail_dsds; @@ -609,14 +612,12 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, put_unaligned_le32(COMMAND_TYPE_6, &cmd_pkt->entry_type); /* No data transfer */ - if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { + if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE || + tot_dsds == 0) { cmd_pkt->byte_count = cpu_to_le32(0); return 0; } - vha = sp->vha; - ha = vha->hw; - /* Set transfer direction */ if (cmd->sc_data_direction == DMA_TO_DEVICE) { cmd_pkt->control_flags = cpu_to_le16(CF_WRITE_DATA); @@ -637,14 +638,13 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, tot_dsds -= avail_dsds; dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE; - dsd_ptr = list_first_entry(&ha->gbl_dsd_list, - struct dsd_dma, list); + dsd_ptr = list_first_entry(&qpair->dsd_list, struct dsd_dma, list); next_dsd = dsd_ptr->dsd_addr; list_del(&dsd_ptr->list); - ha->gbl_dsd_avail--; + qpair->dsd_avail--; list_add_tail(&dsd_ptr->list, &ctx->dsd_list); ctx->dsd_use_cnt++; - ha->gbl_dsd_inuse++; + qpair->dsd_inuse++; if (first_iocb) { first_iocb = 0; @@ -1733,6 +1733,8 @@ qla24xx_dif_start_scsi(srb_t *sp) if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) { if (cmd->cmd_len <= 16) return qla24xx_start_scsi(sp); + else + return qla_start_scsi_type6(sp); } /* Setup device pointers. */ @@ -2112,6 +2114,8 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) { if (cmd->cmd_len <= 16) return qla2xxx_start_scsi_mq(sp); + else + return qla_start_scsi_type6(sp); } spin_lock_irqsave(&qpair->qp_lock, flags); @@ -2557,7 +2561,7 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) scsi_qla_host_t *vha = fcport->vha; struct qla_hw_data *ha = vha->hw; struct srb_iocb *iocb = &sp->u.iocb_cmd; - struct req_que *req = vha->req; + struct req_que *req = sp->qpair->req; flags = iocb->u.tmf.flags; lun = iocb->u.tmf.lun; @@ -2573,7 +2577,8 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) tsk->port_id[2] = fcport->d_id.b.domain; tsk->vp_index = fcport->vha->vp_idx; - if (flags == TCF_LUN_RESET) { + if (flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET| + TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) { int_to_scsilun(lun, &tsk->lun); host_to_fcp_swap((uint8_t *)&tsk->lun, sizeof(tsk->lun)); @@ -3083,7 +3088,8 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, memset(ptr, 0, sizeof(struct els_plogi_payload)); memset(resp_ptr, 0, sizeof(struct els_plogi_payload)); memcpy(elsio->u.els_plogi.els_plogi_pyld->data, - &ha->plogi_els_payld.fl_csp, LOGIN_TEMPLATE_SIZE); + (void *)&ha->plogi_els_payld + offsetof(struct fc_els_flogi, fl_csp), + sizeof(ha->plogi_els_payld) - offsetof(struct fc_els_flogi, fl_csp)); elsio->u.els_plogi.els_cmd = els_opcode; elsio->u.els_plogi.els_plogi_pyld->opcode = els_opcode; @@ -3377,6 +3383,7 @@ qla82xx_start_scsi(srb_t *sp) struct qla_hw_data *ha = vha->hw; struct req_que *req = NULL; struct rsp_que *rsp = NULL; + struct qla_qpair *qpair = sp->qpair; /* Setup device pointers. */ reg = &ha->iobase->isp82; @@ -3425,18 +3432,18 @@ qla82xx_start_scsi(srb_t *sp) uint16_t i; more_dsd_lists = qla24xx_calc_dsd_lists(tot_dsds); - if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN) { + if ((more_dsd_lists + qpair->dsd_inuse) >= NUM_DSD_CHAIN) { ql_dbg(ql_dbg_io, vha, 0x300d, "Num of DSD list %d is than %d for cmd=%p.\n", - more_dsd_lists + ha->gbl_dsd_inuse, NUM_DSD_CHAIN, + more_dsd_lists + qpair->dsd_inuse, NUM_DSD_CHAIN, cmd); goto queuing_error; } - if (more_dsd_lists <= ha->gbl_dsd_avail) + if (more_dsd_lists <= qpair->dsd_avail) goto sufficient_dsds; else - more_dsd_lists -= ha->gbl_dsd_avail; + more_dsd_lists -= qpair->dsd_avail; for (i = 0; i < more_dsd_lists; i++) { dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); @@ -3456,8 +3463,8 @@ qla82xx_start_scsi(srb_t *sp) "for cmd=%p.\n", cmd); goto queuing_error; } - list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list); - ha->gbl_dsd_avail++; + list_add_tail(&dsd_ptr->list, &qpair->dsd_list); + qpair->dsd_avail++; } sufficient_dsds: @@ -3776,21 +3783,29 @@ qla_nvme_ls(srb_t *sp, struct pt_ls4_request *cmd_pkt) nvme = &sp->u.iocb_cmd; cmd_pkt->entry_type = PT_LS4_REQUEST; cmd_pkt->entry_count = 1; - cmd_pkt->control_flags = cpu_to_le16(CF_LS4_ORIGINATOR << CF_LS4_SHIFT); cmd_pkt->timeout = cpu_to_le16(nvme->u.nvme.timeout_sec); - cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); cmd_pkt->vp_index = sp->fcport->vha->vp_idx; + if (sp->unsol_rsp) { + cmd_pkt->control_flags = + cpu_to_le16(CF_LS4_RESPONDER << CF_LS4_SHIFT); + cmd_pkt->nport_handle = nvme->u.nvme.nport_handle; + cmd_pkt->exchange_address = nvme->u.nvme.exchange_address; + } else { + cmd_pkt->control_flags = + cpu_to_le16(CF_LS4_ORIGINATOR << CF_LS4_SHIFT); + cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); + cmd_pkt->rx_dseg_count = cpu_to_le16(1); + cmd_pkt->rx_byte_count = nvme->u.nvme.rsp_len; + cmd_pkt->dsd[1].length = nvme->u.nvme.rsp_len; + put_unaligned_le64(nvme->u.nvme.rsp_dma, &cmd_pkt->dsd[1].address); + } + cmd_pkt->tx_dseg_count = cpu_to_le16(1); - cmd_pkt->tx_byte_count = cpu_to_le32(nvme->u.nvme.cmd_len); - cmd_pkt->dsd[0].length = cpu_to_le32(nvme->u.nvme.cmd_len); + cmd_pkt->tx_byte_count = nvme->u.nvme.cmd_len; + cmd_pkt->dsd[0].length = nvme->u.nvme.cmd_len; put_unaligned_le64(nvme->u.nvme.cmd_dma, &cmd_pkt->dsd[0].address); - - cmd_pkt->rx_dseg_count = cpu_to_le16(1); - cmd_pkt->rx_byte_count = cpu_to_le32(nvme->u.nvme.rsp_len); - cmd_pkt->dsd[1].length = cpu_to_le32(nvme->u.nvme.rsp_len); - put_unaligned_le64(nvme->u.nvme.rsp_dma, &cmd_pkt->dsd[1].address); } static void @@ -3868,9 +3883,9 @@ static int qla_get_iocbs_resource(struct srb *sp) case SRB_NACK_LOGO: case SRB_LOGOUT_CMD: case SRB_CTRL_VP: - push_it_through = true; - fallthrough; + case SRB_MARKER: default: + push_it_through = true; get_exch = false; } @@ -3886,6 +3901,20 @@ static int qla_get_iocbs_resource(struct srb *sp) return qla_get_fw_resources(sp->qpair, &sp->iores); } +static void +qla_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk) +{ + mrk->entry_type = MARKER_TYPE; + mrk->modifier = sp->u.iocb_cmd.u.tmf.modifier; + mrk->handle = make_handle(sp->qpair->req->id, sp->handle); + if (sp->u.iocb_cmd.u.tmf.modifier != MK_SYNC_ALL) { + mrk->nport_handle = cpu_to_le16(sp->u.iocb_cmd.u.tmf.loop_id); + int_to_scsilun(sp->u.iocb_cmd.u.tmf.lun, (struct scsi_lun *)&mrk->lun); + host_to_fcp_swap(mrk->lun, sizeof(mrk->lun)); + mrk->vp_index = sp->u.iocb_cmd.u.tmf.vp_index; + } +} + int qla2x00_start_sp(srb_t *sp) { @@ -3908,7 +3937,7 @@ qla2x00_start_sp(srb_t *sp) pkt = __qla2x00_alloc_iocbs(sp->qpair, sp); if (!pkt) { - rval = EAGAIN; + rval = -EAGAIN; ql_log(ql_log_warn, vha, 0x700c, "qla2x00_alloc_iocbs failed.\n"); goto done; @@ -3989,6 +4018,9 @@ qla2x00_start_sp(srb_t *sp) case SRB_SA_REPLACE: qla24xx_sa_replace_iocb(sp, pkt); break; + case SRB_MARKER: + qla_marker_iocb(sp, pkt); + break; default: break; } @@ -4190,3 +4222,267 @@ qla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds) return rval; } + +/** + * qla_start_scsi_type6() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * + * Returns non-zero if a failure occurred, else zero. + */ +static int +qla_start_scsi_type6(srb_t *sp) +{ + int nseg; + unsigned long flags; + uint32_t *clr_ptr; + uint32_t handle; + struct cmd_type_6 *cmd_pkt; + uint16_t cnt; + uint16_t req_cnt; + uint16_t tot_dsds; + struct req_que *req = NULL; + struct rsp_que *rsp; + struct scsi_cmnd *cmd = GET_CMD_SP(sp); + struct scsi_qla_host *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qpair = sp->qpair; + uint16_t more_dsd_lists = 0; + struct dsd_dma *dsd_ptr; + uint16_t i; + __be32 *fcp_dl; + uint8_t additional_cdb_len; + struct ct6_dsd *ctx; + + /* Acquire qpair specific lock */ + spin_lock_irqsave(&qpair->qp_lock, flags); + + /* Setup qpair pointers */ + req = qpair->req; + rsp = qpair->rsp; + + /* So we know we haven't pci_map'ed anything yet */ + tot_dsds = 0; + + /* Send marker if required */ + if (vha->marker_needed != 0) { + if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { + spin_unlock_irqrestore(&qpair->qp_lock, flags); + return QLA_FUNCTION_FAILED; + } + vha->marker_needed = 0; + } + + handle = qla2xxx_get_next_handle(req); + if (handle == 0) + goto queuing_error; + + /* Map the sg table so we have an accurate count of sg entries needed */ + if (scsi_sg_count(cmd)) { + nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), + scsi_sg_count(cmd), cmd->sc_data_direction); + if (unlikely(!nseg)) + goto queuing_error; + } else { + nseg = 0; + } + + tot_dsds = nseg; + + /* eventhough driver only need 1 T6 IOCB, FW still convert DSD to Continueation IOCB */ + req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); + + sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; + sp->iores.exch_cnt = 1; + sp->iores.iocb_cnt = req_cnt; + + if (qla_get_fw_resources(sp->qpair, &sp->iores)) + goto queuing_error; + + more_dsd_lists = qla24xx_calc_dsd_lists(tot_dsds); + if ((more_dsd_lists + qpair->dsd_inuse) >= NUM_DSD_CHAIN) { + ql_dbg(ql_dbg_io, vha, 0x3028, + "Num of DSD list %d is than %d for cmd=%p.\n", + more_dsd_lists + qpair->dsd_inuse, NUM_DSD_CHAIN, cmd); + goto queuing_error; + } + + if (more_dsd_lists <= qpair->dsd_avail) + goto sufficient_dsds; + else + more_dsd_lists -= qpair->dsd_avail; + + for (i = 0; i < more_dsd_lists; i++) { + dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); + if (!dsd_ptr) { + ql_log(ql_log_fatal, vha, 0x3029, + "Failed to allocate memory for dsd_dma for cmd=%p.\n", cmd); + goto queuing_error; + } + INIT_LIST_HEAD(&dsd_ptr->list); + + dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool, + GFP_ATOMIC, &dsd_ptr->dsd_list_dma); + if (!dsd_ptr->dsd_addr) { + kfree(dsd_ptr); + ql_log(ql_log_fatal, vha, 0x302a, + "Failed to allocate memory for dsd_addr for cmd=%p.\n", cmd); + goto queuing_error; + } + list_add_tail(&dsd_ptr->list, &qpair->dsd_list); + qpair->dsd_avail++; + } + +sufficient_dsds: + req_cnt = 1; + + if (req->cnt < (req_cnt + 2)) { + if (IS_SHADOW_REG_CAPABLE(ha)) { + cnt = *req->out_ptr; + } else { + cnt = (uint16_t)rd_reg_dword_relaxed(req->req_q_out); + if (qla2x00_check_reg16_for_disconnect(vha, cnt)) + goto queuing_error; + } + + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - (req->ring_index - cnt); + if (req->cnt < (req_cnt + 2)) + goto queuing_error; + } + + ctx = &sp->u.scmd.ct6_ctx; + + memset(ctx, 0, sizeof(struct ct6_dsd)); + ctx->fcp_cmnd = dma_pool_zalloc(ha->fcp_cmnd_dma_pool, + GFP_ATOMIC, &ctx->fcp_cmnd_dma); + if (!ctx->fcp_cmnd) { + ql_log(ql_log_fatal, vha, 0x3031, + "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd); + goto queuing_error; + } + + /* Initialize the DSD list and dma handle */ + INIT_LIST_HEAD(&ctx->dsd_list); + ctx->dsd_use_cnt = 0; + + if (cmd->cmd_len > 16) { + additional_cdb_len = cmd->cmd_len - 16; + if (cmd->cmd_len % 4 || + cmd->cmd_len > QLA_CDB_BUF_SIZE) { + /* + * SCSI command bigger than 16 bytes must be + * multiple of 4 or too big. + */ + ql_log(ql_log_warn, vha, 0x3033, + "scsi cmd len %d not multiple of 4 for cmd=%p.\n", + cmd->cmd_len, cmd); + goto queuing_error_fcp_cmnd; + } + ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4; + } else { + additional_cdb_len = 0; + ctx->fcp_cmnd_len = 12 + 16 + 4; + } + + /* Build command packet. */ + req->current_outstanding_cmd = handle; + req->outstanding_cmds[handle] = sp; + sp->handle = handle; + cmd->host_scribble = (unsigned char *)(unsigned long)handle; + req->cnt -= req_cnt; + + cmd_pkt = (struct cmd_type_6 *)req->ring_ptr; + cmd_pkt->handle = make_handle(req->id, handle); + + /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ + clr_ptr = (uint32_t *)cmd_pkt + 2; + memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); + cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + + /* Set NPORT-ID and LUN number */ + cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); + cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; + cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; + cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; + cmd_pkt->vp_index = sp->vha->vp_idx; + + /* Build IOCB segments */ + qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds); + + int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); + host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); + + /* build FCP_CMND IU */ + int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun); + ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; + + if (cmd->sc_data_direction == DMA_TO_DEVICE) + ctx->fcp_cmnd->additional_cdb_len |= 1; + else if (cmd->sc_data_direction == DMA_FROM_DEVICE) + ctx->fcp_cmnd->additional_cdb_len |= 2; + + /* Populate the FCP_PRIO. */ + if (ha->flags.fcp_prio_enabled) + ctx->fcp_cmnd->task_attribute |= + sp->fcport->fcp_prio << 3; + + memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); + + fcp_dl = (__be32 *)(ctx->fcp_cmnd->cdb + 16 + + additional_cdb_len); + *fcp_dl = htonl((uint32_t)scsi_bufflen(cmd)); + + cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len); + put_unaligned_le64(ctx->fcp_cmnd_dma, + &cmd_pkt->fcp_cmnd_dseg_address); + + sp->flags |= SRB_FCP_CMND_DMA_VALID; + cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); + /* Set total data segment count. */ + cmd_pkt->entry_count = (uint8_t)req_cnt; + + wmb(); + /* Adjust ring index. */ + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; + } else { + req->ring_ptr++; + } + + sp->qpair->cmd_cnt++; + sp->flags |= SRB_DMA_VALID; + + /* Set chip new ring index. */ + wrt_reg_dword(req->req_q_in, req->ring_index); + + /* Manage unprocessed RIO/ZIO commands in response queue. */ + if (vha->flags.process_response_queue && + rsp->ring_ptr->signature != RESPONSE_PROCESSED) + qla24xx_process_response_queue(vha, rsp); + + spin_unlock_irqrestore(&qpair->qp_lock, flags); + + return QLA_SUCCESS; + +queuing_error_fcp_cmnd: + dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma); + +queuing_error: + if (tot_dsds) + scsi_dma_unmap(cmd); + + qla_put_fw_resources(sp->qpair, &sp->iores); + + if (sp->u.scmd.crc_ctx) { + mempool_free(sp->u.scmd.crc_ctx, ha->ctx_mempool); + sp->u.scmd.crc_ctx = NULL; + } + + spin_unlock_irqrestore(&qpair->qp_lock, flags); + + return QLA_FUNCTION_FAILED; +} diff --git a/qla2x00t-32gbit/qla_isr.c b/qla2x00t-32gbit/qla_isr.c index 9a57920f2..a6209b2f2 100644 --- a/qla2x00t-32gbit/qla_isr.c +++ b/qla2x00t-32gbit/qla_isr.c @@ -68,6 +68,22 @@ const char *const port_state_str[] = { [FCS_ONLINE] = "ONLINE" }; +#define SFP_DISABLE_LASER_INITIATED 0x15 /* Sub code of 8070 AEN */ +#define SFP_ENABLE_LASER_INITIATED 0x16 /* Sub code of 8070 AEN */ + +static inline void display_Laser_info(scsi_qla_host_t *vha, + u16 mb1, u16 mb2, u16 mb3) { + + if (mb1 == SFP_DISABLE_LASER_INITIATED) + ql_log(ql_log_warn, vha, 0xf0a2, + "SFP temperature (%d C) reached/exceeded the threshold (%d C). Laser is disabled.\n", + mb3, mb2); + if (mb1 == SFP_ENABLE_LASER_INITIATED) + ql_log(ql_log_warn, vha, 0xf0a3, + "SFP temperature (%d C) reached normal operating level. Laser is enabled.\n", + mb3); +} + static void qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt) { @@ -835,6 +851,135 @@ qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb) } } +/** + * qla27xx_copy_multiple_pkt() - Copy over purex/purls packets that can + * span over multiple IOCBs. + * @vha: SCSI driver HA context + * @pkt: ELS packet + * @rsp: Response queue + * @is_purls: True, for Unsolicited Received FC-NVMe LS rsp IOCB + * false, for Unsolicited Received ELS IOCB + * @byte_order: True, to change the byte ordering of iocb payload + */ +struct purex_item * +qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt, + struct rsp_que **rsp, bool is_purls, + bool byte_order) +{ + struct purex_entry_24xx *purex = NULL; + struct pt_ls4_rx_unsol *purls = NULL; + struct rsp_que *rsp_q = *rsp; + sts_cont_entry_t *new_pkt; + uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0; + uint16_t buffer_copy_offset = 0, payload_size = 0; + uint16_t entry_count, entry_count_remaining; + struct purex_item *item; + void *iocb_pkt = NULL; + + if (is_purls) { + purls = *pkt; + total_bytes = (le16_to_cpu(purls->frame_size) & 0x0FFF) - + PURX_ELS_HEADER_SIZE; + entry_count = entry_count_remaining = purls->entry_count; + payload_size = sizeof(purls->payload); + } else { + purex = *pkt; + total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) - + PURX_ELS_HEADER_SIZE; + entry_count = entry_count_remaining = purex->entry_count; + payload_size = sizeof(purex->els_frame_payload); + } + + pending_bytes = total_bytes; + no_bytes = (pending_bytes > payload_size) ? payload_size : + pending_bytes; + ql_dbg(ql_dbg_async, vha, 0x509a, + "%s LS, frame_size 0x%x, entry count %d\n", + (is_purls ? "PURLS" : "FPIN"), total_bytes, entry_count); + + item = qla24xx_alloc_purex_item(vha, total_bytes); + if (!item) + return item; + + iocb_pkt = &item->iocb; + + if (is_purls) + memcpy(iocb_pkt, &purls->payload[0], no_bytes); + else + memcpy(iocb_pkt, &purex->els_frame_payload[0], no_bytes); + buffer_copy_offset += no_bytes; + pending_bytes -= no_bytes; + --entry_count_remaining; + + if (is_purls) + ((response_t *)purls)->signature = RESPONSE_PROCESSED; + else + ((response_t *)purex)->signature = RESPONSE_PROCESSED; + wmb(); + + do { + while ((total_bytes > 0) && (entry_count_remaining > 0)) { + if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) { + ql_dbg(ql_dbg_async, vha, 0x5084, + "Ran out of IOCBs, partial data 0x%x\n", + buffer_copy_offset); + cpu_relax(); + continue; + } + + new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr; + *pkt = new_pkt; + + if (new_pkt->entry_type != STATUS_CONT_TYPE) { + ql_log(ql_log_warn, vha, 0x507a, + "Unexpected IOCB type, partial data 0x%x\n", + buffer_copy_offset); + break; + } + + rsp_q->ring_index++; + if (rsp_q->ring_index == rsp_q->length) { + rsp_q->ring_index = 0; + rsp_q->ring_ptr = rsp_q->ring; + } else { + rsp_q->ring_ptr++; + } + no_bytes = (pending_bytes > sizeof(new_pkt->data)) ? + sizeof(new_pkt->data) : pending_bytes; + if ((buffer_copy_offset + no_bytes) <= total_bytes) { + memcpy(((uint8_t *)iocb_pkt + buffer_copy_offset), + new_pkt->data, no_bytes); + buffer_copy_offset += no_bytes; + pending_bytes -= no_bytes; + --entry_count_remaining; + } else { + ql_log(ql_log_warn, vha, 0x5044, + "Attempt to copy more that we got, optimizing..%x\n", + buffer_copy_offset); + memcpy(((uint8_t *)iocb_pkt + buffer_copy_offset), + new_pkt->data, + total_bytes - buffer_copy_offset); + } + + ((response_t *)new_pkt)->signature = RESPONSE_PROCESSED; + wmb(); + } + + if (pending_bytes != 0 || entry_count_remaining != 0) { + ql_log(ql_log_fatal, vha, 0x508b, + "Dropping partial FPIN, underrun bytes = 0x%x, entry cnts 0x%x\n", + total_bytes, entry_count_remaining); + qla24xx_free_purex_item(item); + return NULL; + } + } while (entry_count_remaining > 0); + + if (byte_order) + host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes); + + return item; +} + int qla2x00_is_a_vp_did(scsi_qla_host_t *vha, uint32_t rscn_entry) { @@ -970,7 +1115,7 @@ qla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size) return item; } -static void +void qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt, void (*process_item)(struct scsi_qla_host *vha, struct purex_item *pkt)) @@ -1133,8 +1278,12 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) unsigned long flags; fc_port_t *fcport = NULL; - if (!vha->hw->flags.fw_started) + if (!vha->hw->flags.fw_started) { + ql_log(ql_log_warn, vha, 0x50ff, + "Dropping AEN - %04x %04x %04x %04x.\n", + mb[0], mb[1], mb[2], mb[3]); return; + } /* Setup to process RIO completion. */ handle_cnt = 0; @@ -1806,6 +1955,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) break; case MBA_TEMPERATURE_ALERT: + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) + display_Laser_info(vha, mb[1], mb[2], mb[3]); ql_dbg(ql_dbg_async, vha, 0x505e, "TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]); break; @@ -1874,9 +2025,9 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha, } } -srb_t * -qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, - struct req_que *req, void *iocb) +static srb_t * +qla_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, + struct req_que *req, void *iocb, u16 *ret_index) { struct qla_hw_data *ha = vha->hw; sts_entry_t *pkt = iocb; @@ -1911,12 +2062,25 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, return NULL; } - req->outstanding_cmds[index] = NULL; - + *ret_index = index; qla_put_fw_resources(sp->qpair, &sp->iores); return sp; } +srb_t * +qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, + struct req_que *req, void *iocb) +{ + uint16_t index; + srb_t *sp; + + sp = qla_get_sp_from_handle(vha, func, req, iocb, &index); + if (sp) + req->outstanding_cmds[index] = NULL; + + return sp; +} + static void qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, struct mbx_entry *mbx) @@ -2538,7 +2702,6 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) case CS_PORT_BUSY: case CS_INCOMPLETE: case CS_PORT_UNAVAILABLE: - case CS_TIMEOUT: case CS_RESET: if (atomic_read(&fcport->state) == FCS_ONLINE) { ql_dbg(ql_dbg_disc, fcport->vha, 0x3021, @@ -3260,13 +3423,13 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) return; } - req->outstanding_cmds[handle] = NULL; cp = GET_CMD_SP(sp); if (cp == NULL) { ql_dbg(ql_dbg_io, vha, 0x3018, "Command already returned (0x%x/%p).\n", sts->handle, sp); + req->outstanding_cmds[handle] = NULL; return; } @@ -3537,6 +3700,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (rsp->status_srb == NULL) sp->done(sp, res); + + /* for io's, clearing of outstanding_cmds[handle] means scsi_done was called */ + req->outstanding_cmds[handle] = NULL; } /** @@ -3613,6 +3779,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) uint16_t que = MSW(pkt->handle); struct req_que *req = NULL; int res = DID_ERROR << 16; + u16 index; ql_dbg(ql_dbg_async, vha, 0x502a, "iocb type %xh with error status %xh, handle %xh, rspq id %d\n", @@ -3631,7 +3798,6 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) switch (pkt->entry_type) { case NOTIFY_ACK_TYPE: - case STATUS_TYPE: case STATUS_CONT_TYPE: case LOGINOUT_PORT_IOCB_TYPE: case CT_IOCB_TYPE: @@ -3651,6 +3817,14 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) case CTIO_TYPE7: case CTIO_CRC2: return 1; + case STATUS_TYPE: + sp = qla_get_sp_from_handle(vha, func, req, pkt, &index); + if (sp) { + sp->done(sp, res); + req->outstanding_cmds[index] = NULL; + return 0; + } + break; } fatal: ql_log(ql_log_warn, vha, 0x5030, @@ -3773,6 +3947,28 @@ static int qla_chk_cont_iocb_avail(struct scsi_qla_host *vha, return rc; } +static void qla_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, + struct mrk_entry_24xx *pkt) +{ + const char func[] = "MRK-IOCB"; + srb_t *sp; + int res = QLA_SUCCESS; + + if (!IS_FWI2_CAPABLE(vha->hw)) + return; + + sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); + if (!sp) + return; + + if (pkt->entry_status) { + ql_dbg(ql_dbg_taskm, vha, 0x8025, "marker failure.\n"); + res = QLA_COMMAND_ERROR; + } + sp->u.iocb_cmd.u.tmf.data = res; + sp->done(sp, res); +} + /** * qla24xx_process_response_queue() - Process response queue entries. * @vha: SCSI driver HA context @@ -3785,20 +3981,20 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, struct qla_hw_data *ha = vha->hw; struct purex_entry_24xx *purex_entry; struct purex_item *pure_item; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) + struct pt_ls4_rx_unsol *p; +#endif u16 rsp_in = 0, cur_ring_index; int is_shadow_hba; if (!ha->flags.fw_started) return; - if (rsp->qpair->cpuid != raw_smp_processor_id() || - !rsp->qpair->rcv_intr) { + if (rsp->qpair->cpuid != raw_smp_processor_id() || !rsp->qpair->rcv_intr) { rsp->qpair->rcv_intr = 1; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) && \ - (!defined(RHEL_RELEASE_CODE) || \ - RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(7, 5)) - qla_cpu_update(rsp->qpair, raw_smp_processor_id()); -#endif + + if (!rsp->qpair->cpu_mapped) + qla_cpu_update(rsp->qpair, raw_smp_processor_id()); } #define __update_rsp_in(_is_shadow_hba, _rsp, _rsp_in) \ @@ -3892,9 +4088,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, (struct nack_to_isp *)pkt); break; case MARKER_TYPE: - /* Do nothing in this case, this check is to prevent it - * from falling into default case - */ + qla_marker_iocb_entry(vha, rsp->req, (struct mrk_entry_24xx *)pkt); break; case ABORT_IOCB_TYPE: qla24xx_abort_iocb_entry(vha, rsp->req, @@ -3962,7 +4156,21 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, qla28xx_sa_update_iocb_entry(vha, rsp->req, (struct sa_update_28xx *)pkt); break; - +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) + case PT_LS4_UNSOL: + p = (void *)pkt; + if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt, rsp_in)) { + rsp->ring_ptr = (response_t *)pkt; + rsp->ring_index = cur_ring_index; + + ql_dbg(ql_dbg_init, vha, 0x2124, + "Defer processing UNSOL LS req opcode %#x...\n", + p->payload[0]); + return; + } + qla2xxx_process_purls_iocb((void **)&pkt, &rsp); + break; +#endif default: /* Type Not Supported. */ ql_dbg(ql_dbg_async, vha, 0x5042, @@ -4287,7 +4495,7 @@ qla2xxx_msix_rsp_q(int irq, void *dev_id) } ha = qpair->hw; - queue_work_on(smp_processor_id(), ha->wq, &qpair->q_work); + queue_work(ha->wq, &qpair->q_work); return IRQ_HANDLED; } @@ -4313,7 +4521,7 @@ qla2xxx_msix_rsp_q_hs(int irq, void *dev_id) wrt_reg_dword(®->hccr, HCCRX_CLR_RISC_INT); spin_unlock_irqrestore(&ha->hardware_lock, flags); - queue_work_on(smp_processor_id(), ha->wq, &qpair->q_work); + queue_work(ha->wq, &qpair->q_work); return IRQ_HANDLED; } diff --git a/qla2x00t-32gbit/qla_mbx.c b/qla2x00t-32gbit/qla_mbx.c index 254fd4c64..21ec32b4f 100644 --- a/qla2x00t-32gbit/qla_mbx.c +++ b/qla2x00t-32gbit/qla_mbx.c @@ -273,7 +273,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) spin_unlock_irqrestore(&ha->hardware_lock, flags); wait_time = jiffies; - atomic_inc(&ha->num_pend_mbx_stage3); if (!wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ)) { ql_dbg(ql_dbg_mbx, vha, 0x117a, @@ -290,7 +289,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) spin_unlock_irqrestore(&ha->hardware_lock, flags); atomic_dec(&ha->num_pend_mbx_stage2); - atomic_dec(&ha->num_pend_mbx_stage3); rval = QLA_ABORTED; goto premature_exit; } @@ -302,11 +300,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) ha->flags.mbox_busy = 0; spin_unlock_irqrestore(&ha->hardware_lock, flags); atomic_dec(&ha->num_pend_mbx_stage2); - atomic_dec(&ha->num_pend_mbx_stage3); rval = QLA_ABORTED; goto premature_exit; } - atomic_dec(&ha->num_pend_mbx_stage3); if (time_after(jiffies, wait_time + 5 * HZ)) ql_log(ql_log_warn, vha, 0x1015, "cmd=0x%x, waited %d msecs\n", @@ -2213,6 +2209,9 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1054, "Entered %s.\n", __func__); + if (!ha->flags.fw_started) + return QLA_FUNCTION_FAILED; + mcp->mb[0] = MBC_GET_FIRMWARE_STATE; mcp->out_mb = MBX_0; if (IS_FWI2_CAPABLE(vha->hw)) diff --git a/qla2x00t-32gbit/qla_mr.c b/qla2x00t-32gbit/qla_mr.c index 84c129f40..ba12fdc84 100644 --- a/qla2x00t-32gbit/qla_mr.c +++ b/qla2x00t-32gbit/qla_mr.c @@ -691,7 +691,7 @@ qlafx00_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len) struct qla_hw_data *ha = vha->hw; if (pci_is_pcie(ha->pdev)) - strlcpy(str, "PCIe iSA", str_len); + strscpy(str, "PCIe iSA", str_len); return str; } @@ -1860,21 +1860,21 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type) phost_info = &preg_hsi->hsi; memset(preg_hsi, 0, sizeof(struct register_host_info)); phost_info->os_type = OS_TYPE_LINUX; - strlcpy(phost_info->sysname, p_sysid->sysname, + strscpy(phost_info->sysname, p_sysid->sysname, sizeof(phost_info->sysname)); - strlcpy(phost_info->nodename, p_sysid->nodename, + strscpy(phost_info->nodename, p_sysid->nodename, sizeof(phost_info->nodename)); if (!strcmp(phost_info->nodename, "(none)")) ha->mr.host_info_resend = true; - strlcpy(phost_info->release, p_sysid->release, + strscpy(phost_info->release, p_sysid->release, sizeof(phost_info->release)); - strlcpy(phost_info->version, p_sysid->version, + strscpy(phost_info->version, p_sysid->version, sizeof(phost_info->version)); - strlcpy(phost_info->machine, p_sysid->machine, + strscpy(phost_info->machine, p_sysid->machine, sizeof(phost_info->machine)); - strlcpy(phost_info->domainname, p_sysid->domainname, + strscpy(phost_info->domainname, p_sysid->domainname, sizeof(phost_info->domainname)); - strlcpy(phost_info->hostdriver, QLA2XXX_VERSION, + strscpy(phost_info->hostdriver, QLA2XXX_VERSION, sizeof(phost_info->hostdriver)); preg_hsi->utc = (uint64_t)ktime_get_real_seconds(); ql_dbg(ql_dbg_init, vha, 0x0149, @@ -1919,9 +1919,9 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type) if (fx_type == FXDISC_GET_CONFIG_INFO) { struct config_info_data *pinfo = (struct config_info_data *) fdisc->u.fxiocb.rsp_addr; - strlcpy(vha->hw->model_number, pinfo->model_num, + strscpy(vha->hw->model_number, pinfo->model_num, ARRAY_SIZE(vha->hw->model_number)); - strlcpy(vha->hw->model_desc, pinfo->model_description, + strscpy(vha->hw->model_desc, pinfo->model_description, ARRAY_SIZE(vha->hw->model_desc)); memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name, sizeof(vha->hw->mr.symbolic_name)); diff --git a/qla2x00t-32gbit/qla_nvme.c b/qla2x00t-32gbit/qla_nvme.c index de6948680..e0a9a4f65 100644 --- a/qla2x00t-32gbit/qla_nvme.c +++ b/qla2x00t-32gbit/qla_nvme.c @@ -17,6 +17,28 @@ #include static struct nvme_fc_port_template qla_nvme_fc_transport; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) +static int qla_nvme_ls_reject_iocb(struct scsi_qla_host *vha, + struct qla_qpair *qp, + struct qla_nvme_lsrjt_pt_arg *a, + bool is_xchg_terminate); + +struct qla_nvme_unsol_ctx { + struct list_head elem; + struct scsi_qla_host *vha; + struct fc_port *fcport; + struct srb *sp; + struct nvmefc_ls_rsp lsrsp; + struct nvmefc_ls_rsp *fd_rsp; + struct work_struct lsrsp_work; + struct work_struct abort_work; + __le32 exchange_address; + __le16 nport_handle; + __le16 ox_id; + int comp_status; + spinlock_t cmd_lock; +}; +#endif int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) { @@ -147,6 +169,7 @@ static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport, "Failed to allocate qpair\n"); return -EINVAL; } + qla_adjust_iocb_limit(vha); } *handle = qpair; @@ -230,6 +253,57 @@ static void qla_nvme_sp_ls_done(srb_t *sp, int res) schedule_work(&priv->ls_work); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) +static void qla_nvme_release_lsrsp_cmd_kref(struct kref *kref) +{ + struct srb *sp = container_of(kref, struct srb, cmd_kref); + struct qla_nvme_unsol_ctx *uctx = sp->priv; + struct nvmefc_ls_rsp *fd_rsp; + unsigned long flags; + + if (!uctx) { + qla2x00_rel_sp(sp); + return; + } + + spin_lock_irqsave(&uctx->cmd_lock, flags); + uctx->sp = NULL; + sp->priv = NULL; + spin_unlock_irqrestore(&uctx->cmd_lock, flags); + + fd_rsp = uctx->fd_rsp; + + list_del(&uctx->elem); + + fd_rsp->done(fd_rsp); + kfree(uctx); + qla2x00_rel_sp(sp); +} + +static void qla_nvme_lsrsp_complete(struct work_struct *work) +{ + struct qla_nvme_unsol_ctx *uctx = + container_of(work, struct qla_nvme_unsol_ctx, lsrsp_work); + + kref_put(&uctx->sp->cmd_kref, qla_nvme_release_lsrsp_cmd_kref); +} + +static void qla_nvme_sp_lsrsp_done(srb_t *sp, int res) +{ + struct qla_nvme_unsol_ctx *uctx = sp->priv; + + if (WARN_ON_ONCE(kref_read(&sp->cmd_kref) == 0)) + return; + + if (res) + res = -EINVAL; + + uctx->comp_status = res; + INIT_WORK(&uctx->lsrsp_work, qla_nvme_lsrsp_complete); + schedule_work(&uctx->lsrsp_work); +} +#endif + /* it assumed that QPair lock is held. */ static void qla_nvme_sp_done(srb_t *sp, int res) { @@ -302,6 +376,94 @@ static void qla_nvme_abort_work(struct work_struct *work) kref_put(&sp->cmd_kref, sp->put_fn); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) +static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport, + struct nvme_fc_remote_port *rport, + struct nvmefc_ls_rsp *fd_resp) +{ + struct qla_nvme_unsol_ctx *uctx = container_of(fd_resp, + struct qla_nvme_unsol_ctx, lsrsp); + struct qla_nvme_rport *qla_rport = rport->private; + fc_port_t *fcport = qla_rport->fcport; + struct scsi_qla_host *vha = uctx->vha; + struct qla_hw_data *ha = vha->hw; + struct qla_nvme_lsrjt_pt_arg a; + struct srb_iocb *nvme; + srb_t *sp; + int rval = QLA_FUNCTION_FAILED; + uint8_t cnt = 0; + + if (!fcport || fcport->deleted) + goto out; + + if (!ha->flags.fw_started) + goto out; + + /* Alloc SRB structure */ + sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); + if (!sp) + goto out; + + sp->type = SRB_NVME_LS; + sp->name = "nvme_ls"; + sp->done = qla_nvme_sp_lsrsp_done; + sp->put_fn = qla_nvme_release_lsrsp_cmd_kref; + sp->priv = (void *)uctx; + sp->unsol_rsp = 1; + uctx->sp = sp; + spin_lock_init(&uctx->cmd_lock); + nvme = &sp->u.iocb_cmd; + uctx->fd_rsp = fd_resp; + nvme->u.nvme.desc = fd_resp; + nvme->u.nvme.dir = 0; + nvme->u.nvme.dl = 0; + nvme->u.nvme.timeout_sec = 0; + nvme->u.nvme.cmd_dma = fd_resp->rspdma; + nvme->u.nvme.cmd_len = cpu_to_le32(fd_resp->rsplen); + nvme->u.nvme.rsp_len = 0; + nvme->u.nvme.rsp_dma = 0; + nvme->u.nvme.exchange_address = uctx->exchange_address; + nvme->u.nvme.nport_handle = uctx->nport_handle; + nvme->u.nvme.ox_id = uctx->ox_id; + dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma, + fd_resp->rsplen, DMA_TO_DEVICE); + + ql_dbg(ql_dbg_unsol, vha, 0x2122, + "Unsol lsreq portid=%06x %8phC exchange_address 0x%x ox_id 0x%x hdl 0x%x\n", + fcport->d_id.b24, fcport->port_name, uctx->exchange_address, + uctx->ox_id, uctx->nport_handle); +retry: + rval = qla2x00_start_sp(sp); + switch (rval) { + case QLA_SUCCESS: + break; + case EAGAIN: + msleep(PURLS_MSLEEP_INTERVAL); + cnt++; + if (cnt < PURLS_RETRY_COUNT) + goto retry; + + fallthrough; + default: + ql_dbg(ql_log_warn, vha, 0x2123, + "Failed to xmit Unsol ls response = %d\n", rval); + rval = -EIO; + qla2x00_rel_sp(sp); + goto out; + } + + return 0; +out: + memset((void *)&a, 0, sizeof(a)); + a.vp_idx = vha->vp_idx; + a.nport_handle = uctx->nport_handle; + a.xchg_address = uctx->exchange_address; + qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true); + kfree(uctx); + return rval; +} +#endif + static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport, struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) { @@ -363,8 +525,8 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, nvme->u.nvme.desc = fd; nvme->u.nvme.dir = 0; nvme->u.nvme.dl = 0; - nvme->u.nvme.cmd_len = fd->rqstlen; - nvme->u.nvme.rsp_len = fd->rsplen; + nvme->u.nvme.cmd_len = cpu_to_le32(fd->rqstlen); + nvme->u.nvme.rsp_len = cpu_to_le32(fd->rsplen); nvme->u.nvme.rsp_dma = fd->rspdma; nvme->u.nvme.timeout_sec = fd->timeout; nvme->u.nvme.cmd_dma = fd->rqstdma; @@ -375,7 +537,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x700e, "qla2x00_start_sp failed = %d\n", rval); - wake_up(&sp->nvme_ls_waitq); sp->priv = NULL; priv->sp = NULL; qla2x00_rel_sp(sp); @@ -667,7 +828,6 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, if (!sp) return -EBUSY; - init_waitqueue_head(&sp->nvme_ls_waitq); kref_init(&sp->cmd_kref); spin_lock_init(&priv->cmd_lock); sp->priv = priv; @@ -684,9 +844,8 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, rval = qla2x00_start_nvme_mq(sp); if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x212d, + ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x212d, "qla2x00_start_nvme_mq failed = %d\n", rval); - wake_up(&sp->nvme_ls_waitq); sp->priv = NULL; priv->sp = NULL; qla2xxx_rel_qpair_sp(sp->qpair, sp); @@ -743,6 +902,9 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = { .ls_abort = qla_nvme_ls_abort, .fcp_io = qla_nvme_post_cmd, .fcp_abort = qla_nvme_fcp_abort, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) + .xmt_ls_rsp = qla_nvme_xmt_ls_rsp, +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) .map_queues = qla_nvme_map_queues, #endif @@ -870,6 +1032,252 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha) return ret; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) +static void qla_nvme_fc_format_rjt(void *buf, u8 ls_cmd, u8 reason, + u8 explanation, u8 vendor) +{ + struct fcnvme_ls_rjt *rjt = buf; + + rjt->w0.ls_cmd = FCNVME_LSDESC_RQST; + rjt->desc_list_len = fcnvme_lsdesc_len(sizeof(struct fcnvme_ls_rjt)); + rjt->rqst.desc_tag = cpu_to_be32(FCNVME_LSDESC_RQST); + rjt->rqst.desc_len = + fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rqst)); + rjt->rqst.w0.ls_cmd = ls_cmd; + rjt->rjt.desc_tag = cpu_to_be32(FCNVME_LSDESC_RJT); + rjt->rjt.desc_len = fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rjt)); + rjt->rjt.reason_code = reason; + rjt->rjt.reason_explanation = explanation; + rjt->rjt.vendor = vendor; +} + +static void qla_nvme_lsrjt_pt_iocb(struct scsi_qla_host *vha, + struct pt_ls4_request *lsrjt_iocb, + struct qla_nvme_lsrjt_pt_arg *a) +{ + lsrjt_iocb->entry_type = PT_LS4_REQUEST; + lsrjt_iocb->entry_count = 1; + lsrjt_iocb->sys_define = 0; + lsrjt_iocb->entry_status = 0; + lsrjt_iocb->handle = QLA_SKIP_HANDLE; + lsrjt_iocb->nport_handle = a->nport_handle; + lsrjt_iocb->exchange_address = a->xchg_address; + lsrjt_iocb->vp_index = a->vp_idx; + + lsrjt_iocb->control_flags = cpu_to_le16(a->control_flags); + + put_unaligned_le64(a->tx_addr, &lsrjt_iocb->dsd[0].address); + lsrjt_iocb->dsd[0].length = cpu_to_le32(a->tx_byte_count); + lsrjt_iocb->tx_dseg_count = cpu_to_le16(1); + lsrjt_iocb->tx_byte_count = cpu_to_le32(a->tx_byte_count); + + put_unaligned_le64(a->rx_addr, &lsrjt_iocb->dsd[1].address); + lsrjt_iocb->dsd[1].length = 0; + lsrjt_iocb->rx_dseg_count = 0; + lsrjt_iocb->rx_byte_count = 0; +} + +static int +qla_nvme_ls_reject_iocb(struct scsi_qla_host *vha, struct qla_qpair *qp, + struct qla_nvme_lsrjt_pt_arg *a, bool is_xchg_terminate) +{ + struct pt_ls4_request *lsrjt_iocb; + + lsrjt_iocb = __qla2x00_alloc_iocbs(qp, NULL); + if (!lsrjt_iocb) { + ql_log(ql_log_warn, vha, 0x210e, + "qla2x00_alloc_iocbs failed.\n"); + return QLA_FUNCTION_FAILED; + } + + if (!is_xchg_terminate) { + qla_nvme_fc_format_rjt((void *)vha->hw->lsrjt.c, a->opcode, + a->reason, a->explanation, 0); + + a->tx_byte_count = sizeof(struct fcnvme_ls_rjt); + a->tx_addr = vha->hw->lsrjt.cdma; + a->control_flags = CF_LS4_RESPONDER << CF_LS4_SHIFT; + + ql_dbg(ql_dbg_unsol, vha, 0x211f, + "Sending nvme fc ls reject ox_id %04x op %04x\n", + a->ox_id, a->opcode); + ql_dump_buffer(ql_dbg_unsol + ql_dbg_verbose, vha, 0x210f, + vha->hw->lsrjt.c, sizeof(*vha->hw->lsrjt.c)); + } else { + a->tx_byte_count = 0; + a->control_flags = CF_LS4_RESPONDER_TERM << CF_LS4_SHIFT; + ql_dbg(ql_dbg_unsol, vha, 0x2110, + "Terminate nvme ls xchg 0x%x\n", a->xchg_address); + } + + qla_nvme_lsrjt_pt_iocb(vha, lsrjt_iocb, a); + /* flush iocb to mem before notifying hw doorbell */ + wmb(); + qla2x00_start_iocbs(vha, qp->req); + return 0; +} + +/* + * qla2xxx_process_purls_pkt() - Pass-up Unsolicited + * Received FC-NVMe Link Service pkt to nvme_fc_rcv_ls_req(). + * LLDD need to provide memory for response buffer, which + * will be used to reference the exchange corresponding + * to the LS when issuing an ls response. LLDD will have to free + * response buffer in lport->ops->xmt_ls_rsp(). + * + * @vha: SCSI qla host + * @item: ptr to purex_item + */ +static void +qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item) +{ + struct qla_nvme_unsol_ctx *uctx = item->purls_context; + struct qla_nvme_lsrjt_pt_arg a; + int ret = 1; + +#if (IS_ENABLED(CONFIG_NVME_FC)) + ret = nvme_fc_rcv_ls_req(uctx->fcport->nvme_remote_port, &uctx->lsrsp, + &item->iocb, item->size); +#endif + if (ret) { + ql_dbg(ql_dbg_unsol, vha, 0x2125, "NVMe transport ls_req failed\n"); + memset((void *)&a, 0, sizeof(a)); + a.vp_idx = vha->vp_idx; + a.nport_handle = uctx->nport_handle; + a.xchg_address = uctx->exchange_address; + qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, true); + list_del(&uctx->elem); + kfree(uctx); + } +} + +static scsi_qla_host_t * +qla2xxx_get_vha_from_vp_idx(struct qla_hw_data *ha, uint16_t vp_index) +{ + scsi_qla_host_t *base_vha, *vha, *tvp; + unsigned long flags; + + base_vha = pci_get_drvdata(ha->pdev); + + if (!vp_index && !ha->num_vhosts) + return base_vha; + + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry_safe(vha, tvp, &ha->vp_list, list) { + if (vha->vp_idx == vp_index) { + spin_unlock_irqrestore(&ha->vport_slock, flags); + return vha; + } + } + spin_unlock_irqrestore(&ha->vport_slock, flags); + + return NULL; +} + +void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp) +{ + struct nvme_fc_remote_port *rport; + struct qla_nvme_rport *qla_rport; + struct qla_nvme_lsrjt_pt_arg a; + struct pt_ls4_rx_unsol *p = *pkt; + struct qla_nvme_unsol_ctx *uctx; + struct rsp_que *rsp_q = *rsp; + struct qla_hw_data *ha; + scsi_qla_host_t *vha; + fc_port_t *fcport = NULL; + struct purex_item *item; + port_id_t d_id = {0}; + port_id_t id = {0}; + u8 *opcode; + bool xmt_reject = false; + + ha = rsp_q->hw; + + vha = qla2xxx_get_vha_from_vp_idx(ha, p->vp_index); + if (!vha) { + ql_log(ql_log_warn, NULL, 0x2110, "Invalid vp index %d\n", p->vp_index); + WARN_ON_ONCE(1); + return; + } + + memset((void *)&a, 0, sizeof(a)); + opcode = (u8 *)&p->payload[0]; + a.opcode = opcode[3]; + a.vp_idx = p->vp_index; + a.nport_handle = p->nport_handle; + a.ox_id = p->ox_id; + a.xchg_address = p->exchange_address; + + id.b.domain = p->s_id.domain; + id.b.area = p->s_id.area; + id.b.al_pa = p->s_id.al_pa; + d_id.b.domain = p->d_id[2]; + d_id.b.area = p->d_id[1]; + d_id.b.al_pa = p->d_id[0]; + + fcport = qla2x00_find_fcport_by_nportid(vha, &id, 0); + if (!fcport) { + ql_dbg(ql_dbg_unsol, vha, 0x211e, + "Failed to find sid=%06x did=%06x\n", + id.b24, d_id.b24); + a.reason = FCNVME_RJT_RC_INV_ASSOC; + a.explanation = FCNVME_RJT_EXP_NONE; + xmt_reject = true; + goto out; + } + rport = fcport->nvme_remote_port; + qla_rport = rport->private; + + item = qla27xx_copy_multiple_pkt(vha, pkt, rsp, true, false); + if (!item) { + a.reason = FCNVME_RJT_RC_LOGIC; + a.explanation = FCNVME_RJT_EXP_NONE; + xmt_reject = true; + goto out; + } + + uctx = kzalloc(sizeof(*uctx), GFP_ATOMIC); + if (!uctx) { + ql_log(ql_log_info, vha, 0x2126, "Failed allocate memory\n"); + a.reason = FCNVME_RJT_RC_LOGIC; + a.explanation = FCNVME_RJT_EXP_NONE; + xmt_reject = true; + kfree(item); + goto out; + } + + uctx->vha = vha; + uctx->fcport = fcport; + uctx->exchange_address = p->exchange_address; + uctx->nport_handle = p->nport_handle; + uctx->ox_id = p->ox_id; + qla_rport->uctx = uctx; + INIT_LIST_HEAD(&uctx->elem); + list_add_tail(&uctx->elem, &fcport->unsol_ctx_head); + item->purls_context = (void *)uctx; + + ql_dbg(ql_dbg_unsol, vha, 0x2121, + "PURLS OP[%01x] size %d xchg addr 0x%x portid %06x\n", + item->iocb.iocb[3], item->size, uctx->exchange_address, + fcport->d_id.b24); + /* +48 0 1 2 3 4 5 6 7 8 9 A B C D E F + * ----- ----------------------------------------------- + * 0000: 00 00 00 05 28 00 00 00 07 00 00 00 08 00 00 00 + * 0010: ab ec 0f cc 00 00 8d 7d 05 00 00 00 10 00 00 00 + * 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + */ + ql_dump_buffer(ql_dbg_unsol + ql_dbg_verbose, vha, 0x2120, + &item->iocb, item->size); + + qla24xx_queue_purex_item(vha, item, qla2xxx_process_purls_pkt); +out: + if (xmt_reject) { + qla_nvme_ls_reject_iocb(vha, (*rsp)->qpair, &a, false); + __qla_consume_iocb(vha, pkt, rsp); + } +} +#endif + #else void qla_nvme_unregister_remote_port(struct fc_port *fcport) diff --git a/qla2x00t-32gbit/qla_nvme.h b/qla2x00t-32gbit/qla_nvme.h index 78f9dd120..c36b7e808 100644 --- a/qla2x00t-32gbit/qla_nvme.h +++ b/qla2x00t-32gbit/qla_nvme.h @@ -24,6 +24,9 @@ #define Q2T_NVME_NUM_TAGS 2048 #define QLA_MAX_FC_SEGMENTS 64 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) +struct qla_nvme_unsol_ctx; +#endif struct scsi_qla_host; struct qla_hw_data; struct req_que; @@ -40,6 +43,9 @@ struct nvme_private { struct qla_nvme_rport { struct fc_port *fcport; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) + struct qla_nvme_unsol_ctx *uctx; +#endif }; #define COMMAND_NVME 0x88 /* Command Type FC-NVMe IOCB */ @@ -78,6 +84,9 @@ struct cmd_nvme { struct dsd64 nvme_dsd; }; +#define PURLS_MSLEEP_INTERVAL 1 +#define PURLS_RETRY_COUNT 5 + #define PT_LS4_REQUEST 0x89 /* Link Service pass-through IOCB (request) */ struct pt_ls4_request { uint8_t entry_type; @@ -121,21 +130,19 @@ struct pt_ls4_rx_unsol { __le32 exchange_address; uint8_t d_id[3]; uint8_t r_ctl; - be_id_t s_id; + le_id_t s_id; uint8_t cs_ctl; uint8_t f_ctl[3]; uint8_t type; __le16 seq_cnt; uint8_t df_ctl; uint8_t seq_id; - __le16 rx_id; - __le16 ox_id; - __le32 param; - __le32 desc0; + __le16 rx_id; + __le16 ox_id; + __le32 desc0; #define PT_LS4_PAYLOAD_OFFSET 0x2c #define PT_LS4_FIRST_PACKET_LEN 20 - __le32 desc_len; - __le32 payload[3]; + __le32 payload[5]; }; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) diff --git a/qla2x00t-32gbit/qla_nx.h b/qla2x00t-32gbit/qla_nx.h index 6dc80c8dd..5d1bdc15b 100644 --- a/qla2x00t-32gbit/qla_nx.h +++ b/qla2x00t-32gbit/qla_nx.h @@ -857,7 +857,9 @@ struct fcp_cmnd { uint8_t task_attribute; uint8_t task_management; uint8_t additional_cdb_len; - uint8_t cdb[260]; /* 256 for CDB len and 4 for FCP_DL */ +#define QLA_CDB_BUF_SIZE 256 +#define QLA_FCP_DL_SIZE 4 + uint8_t cdb[QLA_CDB_BUF_SIZE + QLA_FCP_DL_SIZE]; /* 256 for CDB len and 4 for FCP_DL */ }; struct dsd_dma { diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index 4b4b19fe9..dbdf67f71 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -61,10 +61,11 @@ module_param(ql2xfulldump_on_mpifail, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql2xfulldump_on_mpifail, "Set this to take full dump on MPI hang."); -int ql2xenforce_iocb_limit = 1; +int ql2xenforce_iocb_limit = 2; module_param(ql2xenforce_iocb_limit, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql2xenforce_iocb_limit, - "Enforce IOCB throttling, to avoid FW congestion. (default: 1)"); + "Enforce IOCB throttling, to avoid FW congestion. (default: 2) " + "1: track usage per queue, 2: track usage per adapter"); /* * CT6 CTX allocation cache @@ -471,6 +472,7 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, ha->base_qpair->msix = &ha->msix_entries[QLA_MSIX_RSP_Q]; ha->base_qpair->srb_mempool = ha->srb_mempool; INIT_LIST_HEAD(&ha->base_qpair->hints_list); + INIT_LIST_HEAD(&ha->base_qpair->dsd_list); ha->base_qpair->enable_class_2 = ql2xenableclass2; /* init qpair to this cpu. Will adjust at run time. */ qla_cpu_update(rsp->qpair, raw_smp_processor_id()); @@ -789,9 +791,9 @@ void qla2x00_sp_free_dma(srb_t *sp) dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd, ctx1->fcp_cmnd_dma); - list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list); - ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt; - ha->gbl_dsd_avail += ctx1->dsd_use_cnt; + list_splice(&ctx1->dsd_list, &sp->qpair->dsd_list); + sp->qpair->dsd_inuse -= ctx1->dsd_use_cnt; + sp->qpair->dsd_avail += ctx1->dsd_use_cnt; } if (sp->flags & SRB_GOT_BUF) @@ -875,9 +877,9 @@ void qla2xxx_qpair_sp_free_dma(srb_t *sp) dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd, ctx1->fcp_cmnd_dma); - list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list); - ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt; - ha->gbl_dsd_avail += ctx1->dsd_use_cnt; + list_splice(&ctx1->dsd_list, &sp->qpair->dsd_list); + sp->qpair->dsd_inuse -= ctx1->dsd_use_cnt; + sp->qpair->dsd_avail += ctx1->dsd_use_cnt; sp->flags &= ~SRB_FCP_CMND_DMA_VALID; } @@ -1119,43 +1121,6 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, return 0; } -/* - * qla2x00_eh_wait_on_command - * Waits for the command to be returned by the Firmware for some - * max time. - * - * Input: - * cmd = Scsi Command to wait on. - * - * Return: - * Completed in time : QLA_SUCCESS - * Did not complete in time : QLA_FUNCTION_FAILED - */ -static int -qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd) -{ -#define ABORT_POLLING_PERIOD 1000 -#define ABORT_WAIT_ITER ((2 * 1000) / (ABORT_POLLING_PERIOD)) - unsigned long wait_iter = ABORT_WAIT_ITER; - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - struct qla_hw_data *ha = vha->hw; - srb_t *sp = scsi_cmd_priv(cmd); - int ret = QLA_SUCCESS; - - if (unlikely(pci_channel_offline(ha->pdev)) || ha->flags.eeh_busy) { - ql_dbg(ql_dbg_taskm, vha, 0x8005, - "Return:eh_wait.\n"); - return ret; - } - - while (sp->type && wait_iter--) - msleep(ABORT_POLLING_PERIOD); - if (sp->type) - ret = QLA_FUNCTION_FAILED; - - return ret; -} - /* * qla2x00_wait_for_hba_online * Wait till the HBA is online after going through @@ -1406,6 +1371,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return ret; } +#define ABORT_POLLING_PERIOD 1000 +#define ABORT_WAIT_ITER ((2 * 1000) / (ABORT_POLLING_PERIOD)) + /* * Returns: QLA_SUCCESS or QLA_FUNCTION_FAILED. */ @@ -1419,41 +1387,73 @@ __qla2x00_eh_wait_for_pending_commands(struct qla_qpair *qpair, unsigned int t, struct req_que *req = qpair->req; srb_t *sp; struct scsi_cmnd *cmd; + unsigned long wait_iter = ABORT_WAIT_ITER; + bool found; + struct qla_hw_data *ha = vha->hw; status = QLA_SUCCESS; - spin_lock_irqsave(qpair->qp_lock_ptr, flags); - for (cnt = 1; status == QLA_SUCCESS && - cnt < req->num_outstanding_cmds; cnt++) { - sp = req->outstanding_cmds[cnt]; - if (!sp) - continue; - if (sp->type != SRB_SCSI_CMD) - continue; - if (vha->vp_idx != sp->vha->vp_idx) - continue; - match = 0; - cmd = GET_CMD_SP(sp); - switch (type) { - case WAIT_HOST: - match = 1; - break; - case WAIT_TARGET: - match = cmd->device->id == t; - break; - case WAIT_LUN: - match = (cmd->device->id == t && - cmd->device->lun == l); - break; - } - if (!match) - continue; + while (wait_iter--) { + found = false; - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - status = qla2x00_eh_wait_on_command(cmd); spin_lock_irqsave(qpair->qp_lock_ptr, flags); + for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { + sp = req->outstanding_cmds[cnt]; + if (!sp) + continue; + if (sp->type != SRB_SCSI_CMD) + continue; + if (vha->vp_idx != sp->vha->vp_idx) + continue; + match = 0; + cmd = GET_CMD_SP(sp); + switch (type) { + case WAIT_HOST: + match = 1; + break; + case WAIT_TARGET: + if (sp->fcport) + match = sp->fcport->d_id.b24 == t; + else + match = 0; + break; + case WAIT_LUN: + if (sp->fcport) + match = (sp->fcport->d_id.b24 == t && + cmd->device->lun == l); + else + match = 0; + break; + } + if (!match) + continue; + + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + + if (unlikely(pci_channel_offline(ha->pdev)) || + ha->flags.eeh_busy) { + ql_dbg(ql_dbg_taskm, vha, 0x8005, + "Return:eh_wait.\n"); + return status; + } + + /* + * SRB_SCSI_CMD is still in the outstanding_cmds array. + * it means scsi_done has not called. Wait for it to + * clear from outstanding_cmds. + */ + msleep(ABORT_POLLING_PERIOD); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + found = true; + } + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + + if (!found) + break; } - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + + if (wait_iter == -1) + status = QLA_FUNCTION_FAILED; return status; } @@ -1531,8 +1531,9 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) goto eh_reset_failed; } err = 3; - if (qla2x00_eh_wait_for_pending_commands(vha, sdev->id, - sdev->lun, WAIT_LUN) != QLA_SUCCESS) { + if (qla2x00_eh_wait_for_pending_commands(vha, fcport->d_id.b24, + cmd->device->lun, + WAIT_LUN) != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x800d, "wait for pending cmds failed for cmd=%p.\n", cmd); goto eh_reset_failed; @@ -1598,8 +1599,8 @@ qla2xxx_eh_target_reset(struct scsi_cmnd *cmd) goto eh_reset_failed; } err = 3; - if (qla2x00_eh_wait_for_pending_commands(vha, sdev->id, - 0, WAIT_TARGET) != QLA_SUCCESS) { + if (qla2x00_eh_wait_for_pending_commands(vha, fcport->d_id.b24, 0, + WAIT_TARGET) != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x800d, "wait for pending cmds failed for cmd=%p.\n", cmd); goto eh_reset_failed; @@ -3010,8 +3011,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ql2xallocfwdump = 0; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) /* This may fail but that's ok */ pci_enable_pcie_error_reporting(pdev); +#endif ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL); if (!ha) { @@ -3063,9 +3066,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->max_exchg = FW_MAX_EXCHANGES_CNT; atomic_set(&ha->num_pend_mbx_stage1, 0); atomic_set(&ha->num_pend_mbx_stage2, 0); - atomic_set(&ha->num_pend_mbx_stage3, 0); atomic_set(&ha->zio_threshold, DEFAULT_ZIO_THRESHOLD); ha->last_zio_threshold = DEFAULT_ZIO_THRESHOLD; + INIT_LIST_HEAD(&ha->tmf_pending); + INIT_LIST_HEAD(&ha->tmf_active); /* Assign ISP specific operations. */ if (IS_QLA2100(ha)) { @@ -3342,6 +3346,13 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->max_id = ha->max_fibre_devices; host->cmd_per_lun = 3; host->unique_id = host->host_no; + + if (ql2xenabledif && ql2xenabledif != 2) { + ql_log(ql_log_warn, base_vha, 0x302d, + "Invalid value for ql2xenabledif, resetting it to default (2)\n"); + ql2xenabledif = 2; + } + if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) host->max_cmd_len = 32; else @@ -3580,8 +3591,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) base_vha->flags.difdix_supported = 1; ql_dbg(ql_dbg_init, base_vha, 0x00f1, "Registering for DIF/DIX type 1 and 3 protection.\n"); - if (ql2xenabledif == 1) - prot = SHOST_DIX_TYPE0_PROTECTION; if (ql2xprotmask) scsi_host_set_prot(host, ql2xprotmask); else @@ -4022,7 +4031,9 @@ qla2x00_remove_one(struct pci_dev *pdev) pci_release_selected_regions(ha->pdev, ha->bars); kfree(ha); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) pci_disable_pcie_error_reporting(pdev); +#endif pci_disable_device(pdev); } @@ -4460,7 +4471,6 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, "sf_init_cb=%p.\n", ha->sf_init_cb); } - INIT_LIST_HEAD(&ha->gbl_dsd_list); /* Get consistent memory allocated for Async Port-Database. */ if (!IS_FWI2_CAPABLE(ha)) { @@ -4515,7 +4525,9 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, ha->elsrej.size = sizeof(struct fc_els_ls_rjt) + 16; ha->elsrej.c = dma_alloc_coherent(&ha->pdev->dev, - ha->elsrej.size, &ha->elsrej.cdma, GFP_KERNEL); + ha->elsrej.size, + &ha->elsrej.cdma, + GFP_KERNEL); if (!ha->elsrej.c) { ql_dbg_pci(ql_dbg_init, ha->pdev, 0xffff, @@ -4525,8 +4537,25 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, ha->elsrej.c->er_cmd = ELS_LS_RJT; ha->elsrej.c->er_reason = ELS_RJT_LOGIC; ha->elsrej.c->er_explan = ELS_EXPL_UNAB_DATA; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) + ha->lsrjt.size = sizeof(struct fcnvme_ls_rjt); + ha->lsrjt.c = dma_alloc_coherent(&ha->pdev->dev, ha->lsrjt.size, + &ha->lsrjt.cdma, GFP_KERNEL); + if (!ha->lsrjt.c) { + ql_dbg_pci(ql_dbg_init, ha->pdev, 0xffff, + "Alloc failed for nvme fc reject cmd.\n"); + goto fail_lsrjt; + } +#endif + return 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) +fail_lsrjt: + dma_free_coherent(&ha->pdev->dev, ha->elsrej.size, + ha->elsrej.c, ha->elsrej.cdma); +#endif fail_elsrej: dma_pool_destroy(ha->purex_dma_pool); fail_flt: @@ -4992,18 +5021,16 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->gid_list = NULL; ha->gid_list_dma = 0; - if (IS_QLA82XX(ha)) { - if (!list_empty(&ha->gbl_dsd_list)) { - struct dsd_dma *dsd_ptr, *tdsd_ptr; - - /* clean up allocated prev pool */ - list_for_each_entry_safe(dsd_ptr, - tdsd_ptr, &ha->gbl_dsd_list, list) { - dma_pool_free(ha->dl_dma_pool, - dsd_ptr->dsd_addr, dsd_ptr->dsd_list_dma); - list_del(&dsd_ptr->list); - kfree(dsd_ptr); - } + if (!list_empty(&ha->base_qpair->dsd_list)) { + struct dsd_dma *dsd_ptr, *tdsd_ptr; + + /* clean up allocated prev pool */ + list_for_each_entry_safe(dsd_ptr, tdsd_ptr, + &ha->base_qpair->dsd_list, list) { + dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr, + dsd_ptr->dsd_list_dma); + list_del(&dsd_ptr->list); + kfree(dsd_ptr); } } @@ -5058,6 +5085,14 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->elsrej.c = NULL; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) + if (ha->lsrjt.c) { + dma_free_coherent(&ha->pdev->dev, ha->lsrjt.size, ha->lsrjt.c, + ha->lsrjt.cdma); + ha->lsrjt.c = NULL; + } +#endif + ha->init_cb = NULL; ha->init_cb_dma = 0; @@ -5149,7 +5184,8 @@ struct scsi_qla_host *qla2x00_create_host(const struct scsi_host_template *sht, } INIT_DELAYED_WORK(&vha->scan.scan_work, qla_scan_work_fn); - sprintf(vha->host_str, "%s_%lu", QLA2XXX_DRIVER_NAME, vha->host_no); + snprintf(vha->host_str, sizeof(vha->host_str), "%s_%lu", + QLA2XXX_DRIVER_NAME, vha->host_no); ql_dbg(ql_dbg_init, vha, 0x0041, "Allocated the host=%p hw=%p vha=%p dev_name=%s", vha->host, vha->hw, vha, @@ -6899,7 +6935,9 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work) qla2x00_unmap_iobases(ha); pci_release_selected_regions(ha->pdev, ha->bars); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) pci_disable_pcie_error_reporting(pdev); +#endif pci_disable_device(pdev); /* diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 9c19ba172..6ef76bd52 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -1083,10 +1083,6 @@ void qlt_free_session_done(struct work_struct *work) (struct imm_ntfy_from_isp *)sess->iocb, SRB_NACK_LOGO); } - spin_lock_irqsave(&vha->work_lock, flags); - sess->flags &= ~FCF_ASYNC_SENT; - spin_unlock_irqrestore(&vha->work_lock, flags); - spin_lock_irqsave(&ha->tgt.sess_lock, flags); if (sess->se_sess) { sess->se_sess = NULL; @@ -1096,7 +1092,6 @@ void qlt_free_session_done(struct work_struct *work) qla2x00_set_fcport_disc_state(sess, DSC_DELETED); sess->fw_login_state = DSC_LS_PORT_UNAVAIL; - sess->deleted = QLA_SESS_DELETED; if (sess->login_succ && !IS_SW_RESV_ADDR(sess->d_id)) { vha->fcport_count--; @@ -1148,10 +1143,15 @@ void qlt_free_session_done(struct work_struct *work) sess->explicit_logout = 0; spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); - sess->free_pending = 0; qla2x00_dfs_remove_rport(vha, sess); + spin_lock_irqsave(&vha->work_lock, flags); + sess->flags &= ~FCF_ASYNC_SENT; + sess->deleted = QLA_SESS_DELETED; + sess->free_pending = 0; + spin_unlock_irqrestore(&vha->work_lock, flags); + ql_dbg(ql_dbg_disc, vha, 0xf001, "Unregistration of sess %p %8phC finished fcp_cnt %d\n", sess, sess->port_name, vha->fcport_count); @@ -1200,12 +1200,12 @@ void qlt_unreg_sess(struct fc_port *sess) * management from being sent. */ sess->flags |= FCF_ASYNC_SENT; + sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; spin_unlock_irqrestore(&sess->vha->work_lock, flags); if (sess->se_sess) vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess); - sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; qla2x00_set_fcport_disc_state(sess, DSC_DELETE_PEND); sess->last_rscn_gen = sess->rscn_gen; sess->last_login_gen = sess->login_gen; @@ -4481,8 +4481,7 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, #endif } else if (ha->msix_count) { if (cmd->atio.u.isp24.fcp_cmnd.rddata) - queue_work_on(raw_smp_processor_id(), qla_tgt_wq, - &cmd->work); + queue_work(qla_tgt_wq, &cmd->work); else #if HAVE_SE_CMD_CPUID queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq, diff --git a/qla2x00t-32gbit/qla_version.h b/qla2x00t-32gbit/qla_version.h index 42d69d898..d903563e9 100644 --- a/qla2x00t-32gbit/qla_version.h +++ b/qla2x00t-32gbit/qla_version.h @@ -6,9 +6,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.02.08.200-k" +#define QLA2XXX_VERSION "10.02.09.100-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 2 -#define QLA_DRIVER_PATCH_VER 8 -#define QLA_DRIVER_BETA_VER 200 +#define QLA_DRIVER_PATCH_VER 9 +#define QLA_DRIVER_BETA_VER 100 diff --git a/qla2x00t/Makefile b/qla2x00t/Makefile index dfaa980ff..4bdb5fa1b 100644 --- a/qla2x00t/Makefile +++ b/qla2x00t/Makefile @@ -43,7 +43,9 @@ ifeq ($(INSTALL_MOD_PATH),) export INSTALL_MOD_PATH := $(DESTDIR) endif -INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra +INSTALL_MOD_DIR=extra + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/$(INSTALL_MOD_DIR) all: $(MAKE) -C $(KDIR) M=$(shell pwd) \ @@ -54,6 +56,7 @@ install: all KDIR=$(KDIR) ../scripts/sign-modules $(MAKE) -C $(KDIR) M=$(shell pwd) BUILD_INI=m \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install @@ -69,7 +72,7 @@ clean: extraclean: clean rm -f *.orig *.rej -.PHONY: all tgt install uninstall clean extraclean +.PHONY: all install uninstall clean extraclean endif diff --git a/qla2x00t/qla2x00-target/Makefile b/qla2x00t/qla2x00-target/Makefile index b976e174c..5fdfcf878 100644 --- a/qla2x00t/qla2x00-target/Makefile +++ b/qla2x00t/qla2x00-target/Makefile @@ -61,7 +61,9 @@ ifndef PREFIX PREFIX=/usr/local endif -INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra +INSTALL_MOD_DIR=extra + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/$(INSTALL_MOD_DIR) SCST_DIR := $(shell echo "$$PWD/../../scst/src") @@ -76,6 +78,7 @@ endif KDIR=$(KDIR) ../../scripts/sign-modules $(MAKE) -C $(KDIR) M=$(shell pwd) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install @@ -101,4 +104,4 @@ endif extraclean: clean rm -f *.orig *.rej -.PHONY: all tgt install uninstall clean extraclean qla2xxx_scst +.PHONY: all install uninstall clean extraclean qla2xxx_scst diff --git a/qla2x00t/qla2x00-target/qla2x00t.c b/qla2x00t/qla2x00-target/qla2x00t.c index c6aa31e3b..06ade1a19 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.c +++ b/qla2x00t/qla2x00-target/qla2x00t.c @@ -1680,7 +1680,7 @@ static void q2t_target_stop(struct scst_tgt *scst_tgt) spin_lock_irq(&tgt->sess_work_lock); while (!list_empty(&tgt->sess_works_list)) { spin_unlock_irq(&tgt->sess_work_lock); - flush_scheduled_work(); + flush_work(&tgt->sess_work); spin_lock_irq(&tgt->sess_work_lock); } spin_unlock_irq(&tgt->sess_work_lock); diff --git a/qla2x00t/qla_def.h b/qla2x00t/qla_def.h index 19bdec1be..3e78f978a 100644 --- a/qla2x00t/qla_def.h +++ b/qla2x00t/qla_def.h @@ -7,7 +7,9 @@ #ifndef __QLA_DEF_H #define __QLA_DEF_H +#ifndef INSIDE_KERNEL_TREE #include +#endif #include #include #include @@ -24,7 +26,9 @@ #include #include #include +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) #include +#endif #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) || \ diff --git a/qla2x00t/qla_gs.c b/qla2x00t/qla_gs.c index ec763533d..119949fc8 100644 --- a/qla2x00t/qla_gs.c +++ b/qla2x00t/qla_gs.c @@ -1353,7 +1353,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Model name. */ eiter = (struct ct_fdmi_hba_attr *) (entries + size); eiter->type = cpu_to_be16(FDMI_HBA_MODEL); - strlcpy(eiter->a.model, ha->model_number, sizeof(eiter->a.model)); + strscpy(eiter->a.model, ha->model_number, sizeof(eiter->a.model)); alen = strlen(eiter->a.model); alen += (alen & 3) ? (4 - (alen & 3)) : 4; eiter->len = cpu_to_be16(4 + alen); @@ -1365,7 +1365,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Model description. */ eiter = (struct ct_fdmi_hba_attr *) (entries + size); eiter->type = cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); - strlcpy(eiter->a.model_desc, ha->model_desc, + strscpy(eiter->a.model_desc, ha->model_desc, sizeof(eiter->a.model_desc)); alen = strlen(eiter->a.model_desc); alen += (alen & 3) ? (4 - (alen & 3)) : 4; @@ -1378,7 +1378,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Hardware version. */ eiter = (struct ct_fdmi_hba_attr *) (entries + size); eiter->type = cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); - strlcpy(eiter->a.hw_version, ha->adapter_id, + strscpy(eiter->a.hw_version, ha->adapter_id, sizeof(eiter->a.hw_version)); alen = strlen(eiter->a.hw_version); alen += (alen & 3) ? (4 - (alen & 3)) : 4; @@ -1654,7 +1654,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha) ct_req->req.rpa.attrs.count = cpu_to_be32(FDMI_PORT_ATTR_COUNT); eiter = (struct ct_fdmi_port_attr *) (entries + size); eiter->type = cpu_to_be16(FDMI_PORT_HOST_NAME); - strlcpy(eiter->a.host_name, fc_host_system_hostname(vha->host), + strscpy(eiter->a.host_name, fc_host_system_hostname(vha->host), sizeof(eiter->a.host_name)); alen = strlen(eiter->a.host_name); alen += (alen & 3) ? (4 - (alen & 3)) : 4; diff --git a/qla2x00t/qla_init.c b/qla2x00t/qla_init.c index 8b50a71fd..bf91a3107 100644 --- a/qla2x00t/qla_init.c +++ b/qla2x00t/qla_init.c @@ -2162,7 +2162,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha); if (memcmp(model, BINZERO, len) != 0) { - strncpy(ha->model_number, model, len); + memcpy(ha->model_number, model, len); st = en = ha->model_number; en += len - 1; while (en > st) { @@ -2175,7 +2175,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, if (use_tbl && ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) - strlcpy(ha->model_desc, + strscpy(ha->model_desc, qla2x00_model_name[index * 2 + 1], sizeof(ha->model_desc)); } else { @@ -2183,14 +2183,14 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, if (use_tbl && ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) { - strlcpy(ha->model_number, + strscpy(ha->model_number, qla2x00_model_name[index * 2], sizeof(ha->model_number)); - strlcpy(ha->model_desc, + strscpy(ha->model_desc, qla2x00_model_name[index * 2 + 1], sizeof(ha->model_desc)); } else { - strlcpy(ha->model_number, def, + strscpy(ha->model_number, def, sizeof(ha->model_number)); } } diff --git a/qla2x00t/qla_nx.c b/qla2x00t/qla_nx.c index 780377fe6..4c3d90ca7 100644 --- a/qla2x00t/qla_nx.c +++ b/qla2x00t/qla_nx.c @@ -1599,7 +1599,7 @@ qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str, int str_len) pci_read_config_word(ha->pdev, pcie_reg + PCI_EXP_LNKSTA, &lnk); ha->link_width = (lnk >> 4) & 0x3f; - strlcpy(str, "PCIe (", str_len); + strscpy(str, "PCIe (", str_len); strncat(str, "2.5Gb/s ", str_len - (strlen(str)+1)); snprintf(lwstr, sizeof(lwstr), "x%d)", ha->link_width); strncat(str, lwstr, str_len - (strlen(str)+1)); diff --git a/qla2x00t/qla_os.c b/qla2x00t/qla_os.c index 4ffa2f6cd..f9c3ea8d7 100644 --- a/qla2x00t/qla_os.c +++ b/qla2x00t/qla_os.c @@ -450,7 +450,7 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) "Failed to create request queue.\n"); goto fail; } - ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 0); + ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1); vha->req = ha->req_q_map[req]; options |= BIT_1; for (ques = 1; ques < ha->max_rsp_queues; ques++) { @@ -494,7 +494,7 @@ qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str, int str_len) }; uint16_t pci_bus; - strlcpy(str, "PCI", str_len); + strscpy(str, "PCI", str_len); pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9; if (pci_bus) { strncat(str, "-X (", str_len - (strlen(str)+1)); @@ -2367,8 +2367,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_out; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) /* This may fail but that's ok */ pci_enable_pcie_error_reporting(pdev); +#endif ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL); if (!ha) { @@ -3020,7 +3022,9 @@ qla2x00_remove_one(struct pci_dev *pdev) kfree(ha); ha = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) pci_disable_pcie_error_reporting(pdev); +#endif pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } diff --git a/scst-dkms.spec.in b/scst-dkms.spec.in index 848a3ea7a..ab43bb12b 100644 --- a/scst-dkms.spec.in +++ b/scst-dkms.spec.in @@ -46,6 +46,10 @@ # Fedora %define kernel_devel_rpm kernel-devel %else +%if %([ %{kernel_rpm} = kernel-modules-core ]; echo $((1-$?))) +# CentOS Stream 9 +%define kernel_devel_rpm kernel-devel +%else %if %([ %{kernel_rpm} = kernel-uek-core ]; echo $((1-$?))) # UEK 7 %define kernel_devel_rpm kernel-uek-devel @@ -56,6 +60,7 @@ %endif %endif %endif +%endif %{echo:kernel_devel_rpm=%{kernel_devel_rpm} } %endif diff --git a/scst.spec.in b/scst.spec.in index b99bcb2c0..ba4f40d75 100644 --- a/scst.spec.in +++ b/scst.spec.in @@ -51,6 +51,10 @@ # Fedora %define kernel_devel_rpm kernel-devel %else +%if %([ %{kernel_rpm} = kernel-modules-core ]; echo $((1-$?))) +# CentOS Stream 9 +%define kernel_devel_rpm kernel-devel +%else %if %([ %{kernel_rpm} = kernel-uek-core ]; echo $((1-$?))) # UEK 7 %define kernel_devel_rpm kernel-uek-devel @@ -61,6 +65,7 @@ %endif %endif %endif +%endif %{echo:kernel_devel_rpm=%{kernel_devel_rpm} } %endif diff --git a/scst/include/backport.h b/scst/include/backport.h index 66671bcd4..56d25e4ee 100644 --- a/scst/include/backport.h +++ b/scst/include/backport.h @@ -31,6 +31,7 @@ #include #endif #include /* struct bsg_job */ +#include #include #include #include @@ -177,7 +178,9 @@ enum { }; #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) && \ + (!defined(RHEL_RELEASE_CODE) || \ + RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(9, 2)) /* * See also commit 342a72a33407 ("block: Introduce the type blk_opf_t") # v6.0 */ @@ -228,6 +231,55 @@ void blk_execute_rq_nowait_backport(struct request *rq, bool at_head) /* */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0) +/* + * See also commit 05bdb9965305 ("block: replace fmode_t with a block-specific + * type for block open flags") # v6.5. + */ +typedef fmode_t blk_mode_t; + +#define BLK_OPEN_READ ((__force blk_mode_t)FMODE_READ) +#define BLK_OPEN_WRITE ((__force blk_mode_t)FMODE_WRITE) +#define BLK_OPEN_EXCL ((__force blk_mode_t)FMODE_EXCL) + +/* + * See also commit 0718afd47f70 ("block: introduce holder ops") # v6.5. + */ +struct blk_holder_ops { + /* empty dummy */ +}; + +static inline struct block_device * +blkdev_get_by_path_backport(const char *path, blk_mode_t mode, + void *holder, const struct blk_holder_ops *hops) +{ + WARN_ON_ONCE(hops); + + /* + * See also commit 2736e8eeb0cc ("block: use the holder as + * indication for exclusive opens") # v6.5. + */ + if (holder) + mode |= BLK_OPEN_EXCL; + + return blkdev_get_by_path(path, mode, holder); +} + +#define blkdev_get_by_path blkdev_get_by_path_backport + +/* + * See also commit 2736e8eeb0cc ("block: use the holder as indication for + * exclusive opens") # v6.5. + */ +static inline void blkdev_put_backport(struct block_device *bdev, void *holder) +{ + blkdev_put(bdev, holder ? BLK_OPEN_EXCL : 0); +} + +#define blkdev_put blkdev_put_backport + +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) && \ (!defined(RHEL_RELEASE_CODE) || \ RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(9, 1)) @@ -235,8 +287,8 @@ void blk_execute_rq_nowait_backport(struct request *rq, bool at_head) * See also commit 44abff2c0b97 ("block: decouple REQ_OP_SECURE_ERASE * from REQ_OP_DISCARD") # v5.19. */ -static inline -int blkdev_issue_discard_backport(struct block_device *bdev, sector_t sector, +static inline int +blkdev_issue_discard_backport(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask) { return blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, 0); @@ -334,6 +386,39 @@ static inline ssize_t debugfs_attr_write(struct file *file, } #endif +/* + * See also commit ff9fb72bc077 ("debugfs: return error values, + * not NULL") # v5.0. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0) +static inline struct dentry *debugfs_create_dir_backport(const char *name, struct dentry *parent) +{ + struct dentry *dentry; + + dentry = debugfs_create_dir(name, parent); + if (!dentry) + return ERR_PTR(-ENOMEM); + + return dentry; +} + +static inline struct dentry *debugfs_create_file_backport(const char *name, umode_t mode, + struct dentry *parent, void *data, + const struct file_operations *fops) +{ + struct dentry *dentry; + + dentry = debugfs_create_file(name, mode, parent, data, fops); + if (!dentry) + return ERR_PTR(-ENOMEM); + + return dentry; +} + +#define debugfs_create_dir debugfs_create_dir_backport +#define debugfs_create_file debugfs_create_file_backport +#endif + /* */ #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) @@ -523,60 +608,49 @@ static inline u32 int_sqrt64(u64 x) } #endif -#if LINUX_VERSION_CODE >> 8 == KERNEL_VERSION(4, 4, 0) >> 8 && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 168) -/* - * See also commit 8e50b8b07f46 ("mm: replace get_user_pages() write/force - * parameters with gup_flags") # v4.4.168. - */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0) static inline long get_user_pages_backport(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, - struct page **pages, - struct vm_area_struct **vmas) + struct page **pages) { +#if LINUX_VERSION_CODE >> 8 == KERNEL_VERSION(4, 4, 0) >> 8 && \ + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 168) + /* + * See also commit 8e50b8b07f46 ("mm: replace get_user_pages() write/force + * parameters with gup_flags") # v4.4.168. + */ return get_user_pages(current, current->mm, start, nr_pages, gup_flags, - pages, vmas); -} -#define get_user_pages get_user_pages_backport -#elif !defined(CONFIG_SUSE_KERNEL) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) -/* - * See also commit cde70140fed8 ("mm/gup: Overload get_user_pages() functions") - * # v4.6. - */ -static inline long get_user_pages_backport(unsigned long start, - unsigned long nr_pages, - unsigned int gup_flags, - struct page **pages, - struct vm_area_struct **vmas) -{ - const bool write = gup_flags & FOLL_WRITE; - const bool force = 0; - - WARN_ON_ONCE(gup_flags & ~FOLL_WRITE); - return get_user_pages(current, current->mm, start, nr_pages, write, - force, pages, vmas); -} -#define get_user_pages get_user_pages_backport + pages, NULL); #elif (!defined(CONFIG_SUSE_KERNEL) && \ LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) || \ LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0) -/* - * See also commit 768ae309a961 ("mm: replace get_user_pages() write/force - * parameters with gup_flags") # v4.9. - */ -static inline long get_user_pages_backport(unsigned long start, - unsigned long nr_pages, - unsigned int gup_flags, - struct page **pages, - struct vm_area_struct **vmas) -{ const bool write = gup_flags & FOLL_WRITE; const bool force = 0; WARN_ON_ONCE(gup_flags & ~FOLL_WRITE); - return get_user_pages(start, nr_pages, write, force, pages, vmas); +#if !defined(CONFIG_SUSE_KERNEL) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) + /* + * See also commit cde70140fed8 ("mm/gup: Overload get_user_pages() functions") + * # v4.6. + */ + return get_user_pages(current, current->mm, start, nr_pages, write, + force, pages, NULL); +#else + /* + * See also commit 768ae309a961 ("mm: replace get_user_pages() write/force + * parameters with gup_flags") # v4.9. + */ + return get_user_pages(start, nr_pages, write, force, pages, NULL); +#endif +#else + /* + * See also commit 54d020692b34 ("mm/gup: remove unused vmas parameter from + * get_user_pages()") # v6.5. + */ + return get_user_pages(start, nr_pages, gup_flags, pages, NULL); +#endif } #define get_user_pages get_user_pages_backport #endif @@ -647,6 +721,19 @@ static inline bool list_entry_in_list(const struct list_head *entry) return !list_empty(entry); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0) && \ + (!defined(RHEL_RELEASE_CODE) || \ + RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(8, 1)) +/* + * See also commit 70b44595eafe ("mm, compaction: use free lists to quickly + * locate a migration source") # v5.1. + */ +static inline int list_is_first(const struct list_head *list, const struct list_head *head) +{ + return list->prev == head; +} +#endif + /* */ /* @@ -796,15 +883,39 @@ static inline void kvfree(void *addr) } #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) && \ + (LINUX_VERSION_CODE >> 8 != KERNEL_VERSION(5, 15, 0) >> 8 || \ + LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 54)) && \ + (!defined(RHEL_RELEASE_CODE) || \ + RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(9, 0)) && \ + (!defined(UEK_KABI_RENAME) || \ + LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) +/* + * See also commit a8749a35c3990 ("mm: vmalloc: introduce array allocation functions") # v5.18, + * v5.15.54. + */ +static inline void *vmalloc_array(size_t n, size_t size) +{ + return vmalloc(n * size); +} + +static inline void *vcalloc(size_t n, size_t size) +{ + return vzalloc(n * size); +} +#endif + /* */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) && \ + (!defined(RHEL_RELEASE_CODE) || \ + RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(9, 3)) /* * See also commit e33c267ab70d ("mm: shrinkers: provide shrinkers with * names") # v6.0. */ -static inline -int register_shrinker_backport(struct shrinker *shrinker, const char *fmt, ...) +static inline int +register_shrinker_backport(struct shrinker *shrinker, const char *fmt, ...) { /* * See also commit 1d3d4437eae1 ("vmscan: per-node deferred work") # v3.12 @@ -1096,13 +1207,21 @@ static inline void percpu_ref_put(struct percpu_ref *ref) ref->release(ref); } -static inline void percpu_ref_kill(struct percpu_ref *ref) +static inline void +percpu_ref_kill_and_confirm(struct percpu_ref *ref, percpu_ref_func_t *confirm_kill) { WARN_ON_ONCE(ref->dead); ref->dead = true; + if (confirm_kill) + confirm_kill(ref); percpu_ref_put(ref); } +static inline void percpu_ref_kill(struct percpu_ref *ref) +{ + percpu_ref_kill_and_confirm(ref, NULL); +} + static inline void percpu_ref_resurrect(struct percpu_ref *ref) { WARN_ON_ONCE(!ref->dead); @@ -1251,6 +1370,14 @@ static inline void __user *KERNEL_SOCKPTR(void *p) #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) #endif +#ifndef DECLARE_FLEX_ARRAY +#define DECLARE_FLEX_ARRAY(TYPE, NAME) \ + struct { \ + struct { } __empty_ ## NAME; \ + TYPE NAME[]; \ + } +#endif + /* */ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) && \ @@ -1274,6 +1401,29 @@ static inline void *memdup_user_nul(const void __user *src, size_t len) } #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) && \ + (LINUX_VERSION_CODE >> 8 != KERNEL_VERSION(3, 16, 0) >> 8 || \ + LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 60)) && \ + (LINUX_VERSION_CODE >> 8 != KERNEL_VERSION(3, 18, 0) >> 8 || \ + LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 64)) && \ + (!defined(RHEL_RELEASE_CODE) || \ + RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(7, 7)) +/* + * See also commit 30035e45753b ("string: provide strscpy()") # v4.3, v3.16.60, v3.18.64. + */ +static inline ssize_t strscpy(char *dest, const char *src, size_t count) +{ + size_t ret; + + if (count == 0) + return -E2BIG; + + ret = strlcpy(dest, src, count); + + return ret >= count ? -E2BIG : ret; +} +#endif + /* */ #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) && \ @@ -1644,7 +1794,9 @@ enum { #define wwn_to_u64(wwn) get_unaligned_be64(wwn) #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) && \ + (!defined(RHEL_RELEASE_CODE) || \ + RHEL_RELEASE_CODE -0 < RHEL_RELEASE_VERSION(9, 3)) /* * See also commit 64fd2ba977b1 ("scsi: scsi_transport_fc: Add an additional * flag to fc_host_fpin_rcv()") # v6.3 diff --git a/scst/include/scst.h b/scst/include/scst.h index 0723d759b..781aabb21 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -36,6 +36,9 @@ #endif #include #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include +#endif #include #include #include @@ -2713,6 +2716,7 @@ typedef void (*ext_blocker_done_fn_t) (struct scst_device *dev, struct scst_ext_blocker { struct list_head ext_blockers_list_entry; + struct kref refcount; ext_blocker_done_fn_t ext_blocker_done_fn; int ext_blocker_data_len; @@ -5382,58 +5386,149 @@ void scst_dev_inquiry_data_changed(struct scst_device *dev); */ #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) && \ !defined(CONFIG_SUSE_KERNEL) -static inline void prepare_to_wait_exclusive_head(wait_queue_head_t *q, - wait_queue_t *wait, int state) +static inline long +prepare_to_wait_exclusive_head(wait_queue_head_t *wq_head, + wait_queue_t *wq_entry, int state) { unsigned long flags; + long ret = 0; + + wq_entry->flags |= WQ_FLAG_EXCLUSIVE; + + spin_lock_irqsave(&wq_head->lock, flags); + if (signal_pending_state(state, current)) { + /* + * Exclusive waiter must not fail if it was selected by wakeup, + * it should "consume" the condition we were waiting for. + * + * The caller will recheck the condition and return success if + * we were already woken up, we can not miss the event because + * wakeup locks/unlocks the same wq_head->lock. + * + * But we need to ensure that set-condition + wakeup after that + * can't see us, it should wake up another exclusive waiter if + * we fail. + */ + list_del_init(&wq_entry->task_list); + ret = -ERESTARTSYS; + } else { + if (list_empty(&wq_entry->task_list)) + __add_wait_queue(wq_head, wq_entry); + set_current_state(state); + } + spin_unlock_irqrestore(&wq_head->lock, flags); - wait->flags |= WQ_FLAG_EXCLUSIVE; - spin_lock_irqsave(&q->lock, flags); - if (list_empty(&wait->task_list)) - __add_wait_queue(q, wait); - set_current_state(state); - spin_unlock_irqrestore(&q->lock, flags); + return ret; } #else -static inline void prepare_to_wait_exclusive_head(struct wait_queue_head *wq_head, - struct wait_queue_entry *wq_entry, int state) +static inline long +prepare_to_wait_exclusive_head(struct wait_queue_head *wq_head, + struct wait_queue_entry *wq_entry, int state) { unsigned long flags; + long ret = 0; wq_entry->flags |= WQ_FLAG_EXCLUSIVE; + spin_lock_irqsave(&wq_head->lock, flags); - if (list_empty(&wq_entry->entry)) - __add_wait_queue(wq_head, wq_entry); - set_current_state(state); + if (signal_pending_state(state, current)) { + /* + * Exclusive waiter must not fail if it was selected by wakeup, + * it should "consume" the condition we were waiting for. + * + * The caller will recheck the condition and return success if + * we were already woken up, we can not miss the event because + * wakeup locks/unlocks the same wq_head->lock. + * + * But we need to ensure that set-condition + wakeup after that + * can't see us, it should wake up another exclusive waiter if + * we fail. + */ + list_del_init(&wq_entry->entry); + ret = -ERESTARTSYS; + } else { + if (list_empty(&wq_entry->entry)) + __add_wait_queue(wq_head, wq_entry); + set_current_state(state); + } spin_unlock_irqrestore(&wq_head->lock, flags); + + return ret; } #endif -/** - * wait_event_locked() - Wait until a condition becomes true. - * @wq: Wait queue to wait on if @condition is false. - * @condition: Condition to wait for. Can be any C expression. - * @lock_type: One of lock, lock_bh or lock_irq. - * @lock: A spinlock. - * - * Caller must hold lock of type @lock_type on @lock. - */ -#define wait_event_locked(wq, condition, lock_type, lock) do { \ -if (!(condition)) { \ - DEFINE_WAIT(__wait); \ - \ - do { \ - prepare_to_wait_exclusive_head(&(wq), &__wait, \ - TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - spin_un ## lock_type(&(lock)); \ - schedule(); \ - spin_ ## lock_type(&(lock)); \ - } while (!(condition)); \ - finish_wait(&(wq), &__wait); \ -} \ -} while (0) +#define ___scst_wait_is_interruptible(state) \ + (!__builtin_constant_p(state) || \ + (state & (TASK_INTERRUPTIBLE | TASK_WAKEKILL))) + +#define ___scst_wait_event(wq_head, condition, state, ret, cmd) \ +({ \ + __label__ __out; \ + DEFINE_WAIT(__wq_entry); \ + long __ret = ret; /* explicit shadow */ \ + \ + for (;;) { \ + long __int = prepare_to_wait_exclusive_head(&wq_head, &__wq_entry,\ + state); \ + \ + if (condition) \ + break; \ + \ + if (___scst_wait_is_interruptible(state) && __int) { \ + __ret = __int; \ + goto __out; \ + } \ + \ + cmd; \ + } \ + finish_wait(&wq_head, &__wq_entry); \ +__out: __ret; \ +}) + +#define __scst_wait_event_interruptible_lock(wq_head, condition, lock) \ + ___scst_wait_event(wq_head, condition, TASK_INTERRUPTIBLE, 0, \ + spin_unlock(&lock); \ + schedule(); \ + spin_lock(&lock)) + +#define scst_wait_event_interruptible_lock(wq_head, condition, lock) \ +({ \ + int __ret = 0; \ + if (!(condition)) \ + __ret = __scst_wait_event_interruptible_lock(wq_head, \ + condition, lock); \ + __ret; \ +}) + +#define __scst_wait_event_interruptible_lock_bh(wq_head, condition, lock) \ + ___scst_wait_event(wq_head, condition, TASK_INTERRUPTIBLE, 0, \ + spin_unlock_bh(&lock); \ + schedule(); \ + spin_lock_bh(&lock)) + +#define scst_wait_event_interruptible_lock_bh(wq_head, condition, lock) \ +({ \ + int __ret = 0; \ + if (!(condition)) \ + __ret = __scst_wait_event_interruptible_lock_bh(wq_head, \ + condition, lock);\ + __ret; \ +}) + +#define __scst_wait_event_interruptible_lock_irq(wq_head, condition, lock) \ + ___scst_wait_event(wq_head, condition, TASK_INTERRUPTIBLE, 0, \ + spin_unlock_irq(&lock); \ + schedule(); \ + spin_lock_irq(&lock)) + +#define scst_wait_event_interruptible_lock_irq(wq_head, condition, lock) \ +({ \ + int __ret = 0; \ + if (!(condition)) \ + __ret = __scst_wait_event_interruptible_lock_irq(wq_head, \ + condition, lock);\ + __ret; \ +}) #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) const char *scst_get_opcode_name(struct scst_cmd *cmd); diff --git a/scst/src/Makefile b/scst/src/Makefile index 236d1d206..1d7914346 100644 --- a/scst/src/Makefile +++ b/scst/src/Makefile @@ -35,6 +35,9 @@ SHELL=/bin/bash DEV_HANDLERS_DIR = dev_handlers +SCST_MOD_DIR := $(shell pwd) +SCST_DH_MOD_DIR := $(shell pwd)/$(DEV_HANDLERS_DIR) + ifeq ($(KVER),) ifeq ($(KDIR),) KVER := $(shell uname -r) @@ -58,8 +61,13 @@ ifeq ($(SCST_INC_DIR),) SCST_INC_DIR := ../include endif +INSTALL_MOD_DIR=extra + SCST_INTF_VER_FILE := $(SCST_INC_DIR)/scst_itf_ver.h +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/$(INSTALL_MOD_DIR) +INSTALL_DIR_H := $(DESTDIR)$(PREFIX)/include/scst + $(SCST_INTF_VER_FILE): $(SCST_INC_DIR)/scst.h $(SCST_INC_DIR)/scst_const.h $(SCST_INC_DIR)/scst_user.h echo "/* Autogenerated, don't edit */" >$(SCST_INTF_VER_FILE) echo "" >>$(SCST_INTF_VER_FILE) @@ -73,13 +81,13 @@ $(SCST_INTF_VER_FILE): $(SCST_INC_DIR)/scst.h $(SCST_INC_DIR)/scst_const.h $(SCS all: $(SCST_INTF_VER_FILE) $(MAKE) -C certs KDIR=$(KDIR) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") - $(MAKE) -C $(KDIR) M=$(shell pwd) \ + $(MAKE) -C $(KDIR) M=$(SCST_MOD_DIR) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") - $(MAKE) -C $(KDIR) M=$(shell pwd)/dev_handlers \ + $(MAKE) -C $(KDIR) M=$(SCST_DH_MOD_DIR) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") scst: - $(MAKE) -C $(KDIR) M=$(shell pwd) \ + $(MAKE) -C $(KDIR) M=$(SCST_MOD_DIR) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") install: all @@ -89,13 +97,15 @@ install: all false; fi -rm -f $(INSTALL_DIR)/scsi_tgt.ko KDIR=$(KDIR) ../../scripts/sign-modules - $(MAKE) -C $(KDIR) M=$(shell pwd)/dev_handlers \ + $(MAKE) -C $(KDIR) M=$(SCST_MOD_DIR) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ - INSTALL_MOD_DIR=extra/dev_handlers \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install - $(MAKE) -C $(KDIR) M=$(shell pwd) \ + (cd $(SCST_DH_MOD_DIR) && KDIR=$(KDIR) ../../../scripts/sign-modules) + $(MAKE) -C $(KDIR) M=$(SCST_DH_MOD_DIR) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR)/dev_handlers \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install install -d $(INSTALL_DIR_H) @@ -130,16 +140,12 @@ uninstall: -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) rm -rf $(INSTALL_DIR_H) -INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra -INSTALL_DIR_H := $(DESTDIR)$(PREFIX)/include/scst - clean: - rm -f $(SCST_INTF_VER_FILE) - $(MAKE) -C $(KDIR) M=$(shell pwd) $@ $(MAKE) -C $(DEV_HANDLERS_DIR) $@ + rm -f $(SCST_INTF_VER_FILE) + $(MAKE) -C $(KDIR) M=$(SCST_MOD_DIR) $@ extraclean: clean - rm -f $(SCST_INTF_VER_FILE) cd $(DEV_HANDLERS_DIR) && $(MAKE) $@ rm -f *.orig *.rej diff --git a/scst/src/dev_handlers/Makefile b/scst/src/dev_handlers/Makefile index 2be974b99..8d5734d5e 100644 --- a/scst/src/dev_handlers/Makefile +++ b/scst/src/dev_handlers/Makefile @@ -48,7 +48,9 @@ ifeq ($(INSTALL_MOD_PATH),) export INSTALL_MOD_PATH := $(DESTDIR) endif -INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra +INSTALL_MOD_DIR=extra/dev_handlers + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/$(INSTALL_MOD_DIR) all: $(MAKE) -C $(KDIR) M=$(shell pwd) \ @@ -63,11 +65,13 @@ install: all KDIR=$(KDIR) ../../../scripts/sign-modules $(MAKE) -C $(KDIR) M=$(shell pwd) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install uninstall: - rm -f $(INSTALL_DIR)/dev_handlers/scst_*.ko + rm -f $(INSTALL_DIR)/scst_*.ko + -rmdir $(INSTALL_DIR) 2>/dev/null clean: $(MAKE) -C $(KDIR) M=$(shell pwd) $@ diff --git a/scst/src/dev_handlers/scst_tape.c b/scst/src/dev_handlers/scst_tape.c index 1bb030180..845b98e7f 100644 --- a/scst/src/dev_handlers/scst_tape.c +++ b/scst/src/dev_handlers/scst_tape.c @@ -171,12 +171,15 @@ static int tape_attach(struct scst_device *dev) TRACE_DBG("%s", "Doing MODE_SENSE"); rc = scsi_mode_sense(dev->scsi_dev, - ((dev->scsi_dev->scsi_level <= SCSI_2) ? - ((dev->scsi_dev->lun << 5) & 0xe0) : 0), - 0 /* Mode Page 0 */, - buffer, buffer_size, - SCST_GENERIC_TAPE_SMALL_TIMEOUT, TAPE_RETRIES, - &data, NULL); + ((dev->scsi_dev->scsi_level <= SCSI_2) ? + ((dev->scsi_dev->lun << 5) & 0xe0) : 0), + 0 /* Mode Page 0 */, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0) + 0 /* Sub Page */, +#endif + buffer, buffer_size, + SCST_GENERIC_TAPE_SMALL_TIMEOUT, TAPE_RETRIES, + &data, NULL); TRACE_DBG("MODE_SENSE done: %x", rc); if (rc == 0) { diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index b995f85a0..6f579b865 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -36,10 +36,6 @@ #endif #include "scst_dev_handler.h" -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) -#include -#endif - #ifndef INSIDE_KERNEL_TREE #if defined(CONFIG_HIGHMEM4G) || defined(CONFIG_HIGHMEM64G) #warning HIGHMEM kernel configurations are not supported by this module, \ @@ -1265,12 +1261,12 @@ static int dev_user_map_buf(struct scst_user_cmd *ucmd, unsigned long ubuff, #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0) down_read(&tsk->mm->mmap_sem); rc = get_user_pages(ubuff, ucmd->num_data_pages, FOLL_WRITE, - ucmd->data_pages, NULL); + ucmd->data_pages); up_read(&tsk->mm->mmap_sem); #else mmap_read_lock(tsk->mm); rc = get_user_pages(ubuff, ucmd->num_data_pages, FOLL_WRITE, - ucmd->data_pages, NULL); + ucmd->data_pages); mmap_read_unlock(tsk->mm); #endif @@ -2219,8 +2215,7 @@ static inline int test_cmd_threads(struct scst_user_dev *dev, bool can_block) { int res = !list_empty(&dev->udev_cmd_threads.active_cmd_list) || !list_empty(&dev->ready_cmd_list) || - !can_block || !dev->blocking || dev->cleanup_done || - signal_pending(current); + !can_block || !dev->blocking || dev->cleanup_done; return res; } @@ -2233,9 +2228,11 @@ static int dev_user_get_next_cmd(struct scst_user_dev *dev, TRACE_ENTRY(); while (1) { - wait_event_locked(dev->udev_cmd_threads.cmd_list_waitQ, - test_cmd_threads(dev, can_block), lock_irq, - dev->udev_cmd_threads.cmd_list_lock); + res = scst_wait_event_interruptible_lock_irq(dev->udev_cmd_threads.cmd_list_waitQ, + test_cmd_threads(dev, can_block), + dev->udev_cmd_threads.cmd_list_lock); + if (res) + break; dev_user_process_scst_commands(dev); @@ -2248,12 +2245,6 @@ static int dev_user_get_next_cmd(struct scst_user_dev *dev, TRACE_DBG("No ready commands, returning %d", res); break; } - - if (signal_pending(current)) { - res = -EINTR; - TRACE_DBG("Signal pending, returning %d", res); - break; - } } TRACE_EXIT_RES(res); @@ -3128,10 +3119,10 @@ static int dev_user_attach_tgt(struct scst_tgt_dev *tgt_dev) if (tgtt->get_scsi_transport_version != NULL) ucmd->user_cmd.sess.scsi_transport_version = tgtt->get_scsi_transport_version(tgt); - strlcpy(ucmd->user_cmd.sess.initiator_name, + strscpy(ucmd->user_cmd.sess.initiator_name, tgt_dev->sess->initiator_name, sizeof(ucmd->user_cmd.sess.initiator_name)-1); - strlcpy(ucmd->user_cmd.sess.target_name, + strscpy(ucmd->user_cmd.sess.target_name, tgt_dev->sess->tgt->tgt_name, sizeof(ucmd->user_cmd.sess.target_name)-1); @@ -3378,7 +3369,7 @@ static int dev_user_register_dev(struct file *file, scst_init_threads(&dev->udev_cmd_threads); - strlcpy(dev->name, dev_desc->name, sizeof(dev->name)-1); + strscpy(dev->name, dev_desc->name, sizeof(dev->name)-1); scst_init_mem_lim(&dev->udev_mem_lim); @@ -4053,8 +4044,8 @@ static int dev_user_cleanup_thread(void *arg) spin_lock(&cleanup_lock); while (!kthread_should_stop()) { - wait_event_locked(cleanup_list_waitQ, test_cleanup_list(), - lock, cleanup_lock); + scst_wait_event_interruptible_lock(cleanup_list_waitQ, test_cleanup_list(), + cleanup_lock); /* * We have to poll devices, because commands can go from SCST diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 95a3bf4d1..262e9c1eb 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -191,7 +191,6 @@ struct scst_vdisk_dev { struct file *fd; struct file *dif_fd; struct block_device *bdev; - fmode_t bdev_mode; struct bio_set *vdisk_bioset; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) struct bio_set vdisk_bioset_struct; @@ -503,12 +502,12 @@ static void vdisk_blockio_check_flush_support(struct scst_vdisk_dev *virt_dev) virt_dev->wt_flag || !virt_dev->dev_active) goto out; - bdev = blkdev_get_by_path(virt_dev->filename, FMODE_READ, - (void *)__func__); + bdev = blkdev_get_by_path(virt_dev->filename, BLK_OPEN_READ, NULL, NULL); if (IS_ERR(bdev)) { if (PTR_ERR(bdev) == -EMEDIUMTYPE) - TRACE(TRACE_MINOR, "Unable to open %s with EMEDIUMTYPE, " - "DRBD passive?", virt_dev->filename); + TRACE(TRACE_MINOR, + "Unable to open %s with EMEDIUMTYPE, DRBD passive?", + virt_dev->filename); else PRINT_ERROR("blkdev_get_by_path(%s) failed: %ld", virt_dev->filename, PTR_ERR(bdev)); @@ -516,13 +515,13 @@ static void vdisk_blockio_check_flush_support(struct scst_vdisk_dev *virt_dev) } if (vdisk_blockio_flush(bdev, GFP_KERNEL, false, NULL, false) != 0) { - PRINT_WARNING("Device %s doesn't support barriers, switching " - "to NV_CACHE mode. Read README for more details.", - virt_dev->filename); + PRINT_WARNING( +"Device %s doesn't support barriers, switching to NV_CACHE mode. Read README for more details.", + virt_dev->filename); virt_dev->nv_cache = 1; } - blkdev_put(bdev, FMODE_READ); + blkdev_put(bdev, NULL); out: TRACE_EXIT(); @@ -544,8 +543,7 @@ static void vdisk_check_tp_support(struct scst_vdisk_dev *virt_dev) goto check; if (virt_dev->blockio) { - bdev = blkdev_get_by_path(virt_dev->filename, FMODE_READ, - (void *)__func__); + bdev = blkdev_get_by_path(virt_dev->filename, BLK_OPEN_READ, NULL, NULL); res = PTR_ERR_OR_ZERO(bdev); } else { fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600); @@ -641,7 +639,7 @@ static void vdisk_check_tp_support(struct scst_vdisk_dev *virt_dev) if (fd_open) { if (virt_dev->blockio) - blkdev_put(bdev, FMODE_READ); + blkdev_put(bdev, NULL); else filp_close(fd, NULL); } @@ -966,8 +964,7 @@ static int vdisk_init_block_integrity(struct scst_vdisk_dev *virt_dev) TRACE_ENTRY(); - bdev = blkdev_get_by_path(virt_dev->filename, FMODE_READ, - (void *)__func__); + bdev = blkdev_get_by_path(virt_dev->filename, BLK_OPEN_READ, NULL, NULL); if (IS_ERR(bdev)) { res = PTR_ERR(bdev); goto out; @@ -1045,7 +1042,7 @@ static int vdisk_init_block_integrity(struct scst_vdisk_dev *virt_dev) res = 0; out_close: - blkdev_put(bdev, FMODE_READ); + blkdev_put(bdev, NULL); out: TRACE_EXIT_RES(res); @@ -1309,11 +1306,12 @@ static int vdisk_open_fd(struct scst_vdisk_dev *virt_dev, bool read_only) virt_dev->dev->virt_name); res = -EMEDIUMTYPE; } else if (virt_dev->blockio) { - virt_dev->bdev_mode = FMODE_READ; + blk_mode_t bdev_mode = BLK_OPEN_READ; + if (!read_only) - virt_dev->bdev_mode |= FMODE_WRITE; - virt_dev->bdev = blkdev_get_by_path(virt_dev->filename, - virt_dev->bdev_mode, (void *)__func__); + bdev_mode |= BLK_OPEN_WRITE; + + virt_dev->bdev = blkdev_get_by_path(virt_dev->filename, bdev_mode, virt_dev, NULL); res = PTR_ERR_OR_ZERO(virt_dev->bdev); } else { virt_dev->fd = vdev_open_fd(virt_dev, virt_dev->filename, @@ -1352,7 +1350,7 @@ static int vdisk_open_fd(struct scst_vdisk_dev *virt_dev, bool read_only) out_close_fd: if (virt_dev->blockio) { - blkdev_put(virt_dev->bdev, virt_dev->bdev_mode); + blkdev_put(virt_dev->bdev, virt_dev); virt_dev->bdev = NULL; } else { filp_close(virt_dev->fd, NULL); @@ -1367,7 +1365,7 @@ static void vdisk_close_fd(struct scst_vdisk_dev *virt_dev) virt_dev->fd, virt_dev->bdev, virt_dev->dif_fd); if (virt_dev->bdev) { - blkdev_put(virt_dev->bdev, virt_dev->bdev_mode); + blkdev_put(virt_dev->bdev, virt_dev); virt_dev->bdev = NULL; } else if (virt_dev->fd) { filp_close(virt_dev->fd, NULL); @@ -9368,7 +9366,7 @@ static ssize_t vdev_sysfs_bind_alua_state_store(struct kobject *kobj, dev = container_of(kobj, struct scst_device, dev_kobj); virt_dev = dev->dh_priv; - strlcpy(ch, buf, 16); + strscpy(ch, buf, 16); res = kstrtoul(ch, 0, &bind_alua_state); if (res < 0) goto out; diff --git a/scst/src/scst_debug.c b/scst/src/scst_debug.c index d211eb87e..a76a1bb24 100644 --- a/scst/src/scst_debug.c +++ b/scst/src/scst_debug.c @@ -67,7 +67,7 @@ int debug_print_with_prefix(unsigned long trace_flag, const char *severity, spin_lock_irqsave(&trace_buf_lock, flags); - strlcpy(trace_buf, severity, TRACE_BUF_SIZE); + strscpy(trace_buf, severity, TRACE_BUF_SIZE); i = strlen(trace_buf); if (trace_flag & TRACE_PID) diff --git a/scst/src/scst_dlm.c b/scst/src/scst_dlm.c index c3fb41190..7e634afcf 100644 --- a/scst/src/scst_dlm.c +++ b/scst/src/scst_dlm.c @@ -304,11 +304,10 @@ static int scst_copy_from_dlm(struct scst_device *dev, dlm_lockspace_t *ls, nr_registrants = be32_to_cpu(lvb->nr_registrants); if (nr_registrants) { - reg_lksb = vzalloc((sizeof(*reg_lksb) + PR_DLM_LVB_LEN) * - nr_registrants); + reg_lksb = vcalloc(nr_registrants, sizeof(*reg_lksb) + PR_DLM_LVB_LEN); if (!reg_lksb) { - PRINT_ERROR("%s: failed to allocate %d * %zd bytes of" - " memory", __func__, nr_registrants, + PRINT_ERROR("%s: failed to allocate %u * %zu bytes of memory", + __func__, nr_registrants, sizeof(*reg_lksb) + PR_DLM_LVB_LEN); goto out; } @@ -1831,6 +1830,4 @@ const struct scst_cl_ops scst_dlm_cl_ops = { .pr_reg_queue_rem_ua = scst_dlm_pr_reg_queue_rem_ua, }; -char *scst_dlm_cluster_name; - #endif diff --git a/scst/src/scst_event.c b/scst/src/scst_event.c index 593548ec1..b744e1766 100644 --- a/scst/src/scst_event.c +++ b/scst/src/scst_event.c @@ -278,7 +278,7 @@ void scst_event_queue(uint32_t event_code, const char *issuer_name, TRACE_DBG("Scheduling event entry %p", e); e->event.event_code = event_code; - strlcpy(e->event.issuer_name, issuer_name, sizeof(e->event.issuer_name)); + strscpy(e->event.issuer_name, issuer_name, sizeof(e->event.issuer_name)); queue_work(scst_event_wq, &e->scst_event_queue_work); @@ -317,9 +317,9 @@ int scst_event_queue_lun_not_found(const struct scst_cmd *cmd) payload = (struct scst_event_lun_not_found_payload *)event->payload; payload->lun = cmd->lun; - strlcpy(payload->initiator_name, cmd->sess->initiator_name, + strscpy(payload->initiator_name, cmd->sess->initiator_name, sizeof(payload->initiator_name)); - strlcpy(payload->target_name, cmd->tgt->tgt_name, + strscpy(payload->target_name, cmd->tgt->tgt_name, sizeof(payload->target_name)); scst_event_queue(SCST_EVENT_LUN_NOT_FOUND, @@ -358,9 +358,9 @@ int scst_event_queue_negative_luns_inquiry(const struct scst_tgt *tgt, event->payload_len = sizeof(*payload); payload = (struct scst_event_negative_luns_inquiry_payload *)event->payload; - strlcpy(payload->initiator_name, initiator_name, + strscpy(payload->initiator_name, initiator_name, sizeof(payload->initiator_name)); - strlcpy(payload->target_name, tgt->tgt_name, + strscpy(payload->target_name, tgt->tgt_name, sizeof(payload->target_name)); scst_event_queue(SCST_EVENT_NEGATIVE_LUNS_INQUIRY, @@ -399,7 +399,7 @@ int scst_event_queue_ext_blocking_done(struct scst_device *dev, void *data, int event->payload_len = sizeof(*payload) + len; payload = (struct scst_event_ext_blocking_done_payload *)event->payload; - strlcpy(payload->device_name, dev->virt_name, sizeof(payload->device_name)); + strscpy(payload->device_name, dev->virt_name, sizeof(payload->device_name)); if (len > 0) memcpy(payload->data, data, len); @@ -442,13 +442,13 @@ int scst_event_queue_tm_fn_received(struct scst_mgmt_cmd *mcmd) payload->fn = mcmd->fn; payload->lun = mcmd->lun; if (mcmd->mcmd_tgt_dev != NULL) - strlcpy(payload->device_name, mcmd->mcmd_tgt_dev->dev->virt_name, + strscpy(payload->device_name, mcmd->mcmd_tgt_dev->dev->virt_name, sizeof(payload->device_name)); - strlcpy(payload->initiator_name, mcmd->sess->initiator_name, + strscpy(payload->initiator_name, mcmd->sess->initiator_name, sizeof(payload->initiator_name)); - strlcpy(payload->target_name, mcmd->sess->tgt->tgt_name, + strscpy(payload->target_name, mcmd->sess->tgt->tgt_name, sizeof(payload->target_name)); - strlcpy(payload->session_sysfs_name, mcmd->sess->sess_name, + strscpy(payload->session_sysfs_name, mcmd->sess->sess_name, sizeof(payload->session_sysfs_name)); if (mcmd->cmd_to_abort != NULL) { payload->cmd_to_abort_tag = mcmd->cmd_to_abort->tag; @@ -493,7 +493,7 @@ int scst_event_queue_reg_vdev(const char *dev_name) event->payload_len = sizeof(*payload); payload = (struct scst_event_reg_vdev_payload *)event->payload; - strlcpy(payload->device_name, dev_name, + strscpy(payload->device_name, dev_name, sizeof(payload->device_name)); scst_event_queue(SCST_EVENT_REG_VIRT_DEV, @@ -1111,7 +1111,7 @@ int scst_event_init(void) TRACE_ENTRY(); - scst_event_wq = alloc_workqueue("scst_event_wq", WQ_MEM_RECLAIM, 0); + scst_event_wq = alloc_workqueue("scst_event_wq", 0, 0); if (unlikely(!scst_event_wq)) { PRINT_ERROR("Failed to allocate scst_event_wq"); res = -ENOMEM; diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 976dcc4c2..02d03ba15 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -70,7 +70,6 @@ static DEFINE_SPINLOCK(scst_global_stpg_list_lock); static LIST_HEAD(scst_global_stpg_list); -static void scst_put_acg_work(struct work_struct *work); static void scst_free_acn(struct scst_acn *acn, bool reassign); struct scsi_io_context { @@ -4826,49 +4825,47 @@ static void scst_free_acg(struct scst_acg *acg) kobject_put(&tgt->tgt_kobj); } -static void scst_release_acg(struct kref *kref) -{ - struct scst_acg *acg = container_of(kref, struct scst_acg, acg_kref); - - scst_free_acg(acg); -} - -struct scst_acg_put_work { +struct scst_acg_release_work { struct work_struct work; struct scst_acg *acg; }; -static void scst_put_acg_work(struct work_struct *work) +static void scst_release_acg_work(struct work_struct *work) { - struct scst_acg_put_work *put_work = - container_of(work, typeof(*put_work), work); - struct scst_acg *acg = put_work->acg; + struct scst_acg_release_work *release_work = + container_of(work, typeof(*release_work), work); + struct scst_acg *acg = release_work->acg; - kfree(put_work); - kref_put(&acg->acg_kref, scst_release_acg); + kfree(release_work); + scst_free_acg(acg); } -void scst_put_acg(struct scst_acg *acg) +static void scst_release_acg(struct kref *kref) { - struct scst_acg_put_work *put_work; + struct scst_acg *acg = container_of(kref, struct scst_acg, acg_kref); + struct scst_acg_release_work *release_work; bool rc; - put_work = kmalloc(sizeof(*put_work), GFP_KERNEL | __GFP_NOFAIL); - if (WARN_ON_ONCE(!put_work)) { - kref_put(&acg->acg_kref, scst_release_acg); + release_work = kmalloc(sizeof(*release_work), GFP_KERNEL | __GFP_NOFAIL); + if (WARN_ON_ONCE(!release_work)) { + scst_free_acg(acg); return; } - INIT_WORK(&put_work->work, scst_put_acg_work); - put_work->acg = acg; + INIT_WORK(&release_work->work, scst_release_acg_work); + release_work->acg = acg; /* * Schedule the kref_put() call instead of invoking it directly to * avoid deep recursion and a stack overflow. */ - rc = queue_work(scst_release_acg_wq, &put_work->work); + rc = queue_work(scst_release_acg_wq, &release_work->work); WARN_ON_ONCE(!rc); - return; +} + +void scst_put_acg(struct scst_acg *acg) +{ + kref_put(&acg->acg_kref, scst_release_acg); } void scst_get_acg(struct scst_acg *acg) @@ -5983,11 +5980,11 @@ loff_t scst_bdev_size(const char *path) struct block_device *bdev; loff_t res; - bdev = blkdev_get_by_path(path, FMODE_READ, (void *)__func__); + bdev = blkdev_get_by_path(path, BLK_OPEN_READ, NULL, NULL); if (IS_ERR(bdev)) return PTR_ERR(bdev); res = i_size_read(bdev->bd_inode); - blkdev_put(bdev, FMODE_READ); + blkdev_put(bdev, NULL); return res; } EXPORT_SYMBOL(scst_bdev_size); @@ -14820,15 +14817,52 @@ int scst_restore_global_mode_pages(struct scst_device *dev, char *params, } EXPORT_SYMBOL_GPL(scst_restore_global_mode_pages); +static inline struct scst_ext_blocker *scst_ext_blocker_create(size_t size) +{ + struct scst_ext_blocker *b; + + b = kzalloc(size, GFP_KERNEL); + if (unlikely(!b)) { + PRINT_ERROR("Unable to alloc struct scst_ext_blocker with data (size %zd)", + size); + return NULL; + } + + kref_init(&b->refcount); + + return b; +} + +static inline void scst_ext_blocker_get(struct scst_ext_blocker *b) +{ + kref_get(&b->refcount); +} + +static inline void scst_ext_blocker_release(struct kref *kref) +{ + struct scst_ext_blocker *b = container_of(kref, struct scst_ext_blocker, refcount); + + kfree(b); +} + +static inline void scst_ext_blocker_put(struct scst_ext_blocker *b) +{ + kref_put(&b->refcount, scst_ext_blocker_release); +} + /* Must be called under dev_lock and BHs off. Might release it, then reacquire. */ -void __scst_ext_blocking_done(struct scst_device *dev) +static void __scst_ext_blocking_done(struct scst_device *dev) + __releases(&dev->dev_lock) + __acquires(&dev->dev_lock) { bool stop; TRACE_ENTRY(); + lockdep_assert_held(&dev->dev_lock); + TRACE_BLOCK("Notifying ext blockers for dev %s (ext_blocks_cnt %d)", - dev->virt_name, dev->ext_blocks_cnt); + dev->virt_name, dev->ext_blocks_cnt); stop = list_empty(&dev->ext_blockers_list); while (!stop) { @@ -14837,8 +14871,8 @@ void __scst_ext_blocking_done(struct scst_device *dev) b = list_first_entry(&dev->ext_blockers_list, typeof(*b), ext_blockers_list_entry); - TRACE_DBG("Notifying async ext blocker %p (cnt %d)", b, - dev->ext_blocks_cnt); + TRACE_DBG("Notifying async ext blocker %p (cnt %d)", + b, dev->ext_blocks_cnt); list_del(&b->ext_blockers_list_entry); @@ -14851,13 +14885,12 @@ void __scst_ext_blocking_done(struct scst_device *dev) b->ext_blocker_done_fn(dev, b->ext_blocker_data, b->ext_blocker_data_len); - kfree(b); + scst_ext_blocker_put(b); spin_lock_bh(&dev->dev_lock); } TRACE_EXIT(); - return; } static void scst_ext_blocking_done_fn(struct work_struct *work) @@ -14911,37 +14944,19 @@ static void scst_sync_ext_blocking_done(struct scst_device *dev, TRACE_ENTRY(); - w = (void *)*((unsigned long *)data); + w = (void *) data; wake_up_all(w); TRACE_EXIT(); return; } -int scst_ext_block_dev(struct scst_device *dev, ext_blocker_done_fn_t done_fn, - const uint8_t *priv, int priv_len, int flags) +static void scst_dev_ext_block(struct scst_device *dev, bool block_stpg) { - int res; - struct scst_ext_blocker *b; + lockdep_assert_held(&dev->dev_lock); TRACE_ENTRY(); - if (flags & SCST_EXT_BLOCK_SYNC) - priv_len = sizeof(void *); - - b = kzalloc(sizeof(*b) + priv_len, GFP_KERNEL); - if (b == NULL) { - PRINT_ERROR("Unable to alloc struct scst_ext_blocker with data " - "(size %zd)", sizeof(*b) + priv_len); - res = -ENOMEM; - goto out; - } - - TRACE_MGMT_DBG("New %d ext blocker %p for dev %s (flags %x)", - dev->ext_blocks_cnt+1, b, dev->virt_name, flags); - - spin_lock_bh(&dev->dev_lock); - if (dev->strictly_serialized_cmd_waiting) { /* * Avoid deadlock when this strictly serialized cmd @@ -14951,10 +14966,11 @@ int scst_ext_block_dev(struct scst_device *dev, ext_blocker_done_fn_t done_fn, TRACE_DBG("Unstrictlyserialize dev %s", dev->virt_name); dev->strictly_serialized_cmd_waiting = 0; /* We will reuse blocking done by the strictly serialized cmd */ - } else + } else { scst_block_dev(dev); + } - if (flags & SCST_EXT_BLOCK_STPG) { + if (block_stpg) { WARN_ON(dev->stpg_ext_blocked); dev->stpg_ext_blocked = 1; } @@ -14962,53 +14978,101 @@ int scst_ext_block_dev(struct scst_device *dev, ext_blocker_done_fn_t done_fn, dev->ext_blocks_cnt++; TRACE_DBG("ext_blocks_cnt %d", dev->ext_blocks_cnt); - if ((flags & SCST_EXT_BLOCK_SYNC) && (dev->on_dev_cmd_count == 0)) { + TRACE_EXIT(); +} + +int scst_sync_ext_block_dev(struct scst_device *dev) +{ + struct scst_ext_blocker *b; + wait_queue_head_t *w; + int res = 0; + + TRACE_ENTRY(); + + b = scst_ext_blocker_create(sizeof(*b) + sizeof(wait_queue_head_t)); + if (unlikely(!b)) { + res = -ENOMEM; + goto out; + } + + w = (void *)b->ext_blocker_data; + init_waitqueue_head(w); + + TRACE_MGMT_DBG("New %d sync ext blocker %p for dev %s", + dev->ext_blocks_cnt + 1, b, dev->virt_name); + + spin_lock_bh(&dev->dev_lock); + + scst_dev_ext_block(dev, false); + + if (dev->on_dev_cmd_count == 0) { TRACE_DBG("No commands to wait for sync blocking (dev %s)", - dev->virt_name); + dev->virt_name); spin_unlock_bh(&dev->dev_lock); - goto out_free_success; + goto put_blocker; } list_add_tail(&b->ext_blockers_list_entry, &dev->ext_blockers_list); dev->ext_blocking_pending = 1; - if (flags & SCST_EXT_BLOCK_SYNC) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(w); + b->ext_blocker_done_fn = scst_sync_ext_blocking_done; + scst_ext_blocker_get(b); - b->ext_blocker_done_fn = scst_sync_ext_blocking_done; - *((void **)&b->ext_blocker_data[0]) = &w; + res = scst_wait_event_interruptible_lock_bh(*w, dev->on_dev_cmd_count == 0, dev->dev_lock); - wait_event_locked(w, (dev->on_dev_cmd_count == 0), - lock_bh, dev->dev_lock); + spin_unlock_bh(&dev->dev_lock); - spin_unlock_bh(&dev->dev_lock); - } else { - b->ext_blocker_done_fn = done_fn; - if (priv_len > 0) { - b->ext_blocker_data_len = priv_len; - memcpy(b->ext_blocker_data, priv, priv_len); - } - if (dev->on_dev_cmd_count == 0) { - TRACE_DBG("No commands to wait for async blocking " - "(dev %s)", dev->virt_name); - if (!dev->ext_unblock_scheduled) - __scst_ext_blocking_done(dev); - spin_unlock_bh(&dev->dev_lock); - } else - spin_unlock_bh(&dev->dev_lock); +put_blocker: + scst_ext_blocker_put(b); + +out: + TRACE_EXIT_RES(res); + return res; +} + +int scst_ext_block_dev(struct scst_device *dev, ext_blocker_done_fn_t done_fn, + const void *priv, size_t priv_len, bool block_stpg) +{ + struct scst_ext_blocker *b; + int res = 0; + + TRACE_ENTRY(); + + b = scst_ext_blocker_create(sizeof(*b) + priv_len); + if (unlikely(!b)) { + res = -ENOMEM; + goto out; } -out_success: - res = 0; + TRACE_MGMT_DBG("New %d ext blocker %p for dev %s (block_stpg %d)", + dev->ext_blocks_cnt + 1, b, dev->virt_name, block_stpg); + + spin_lock_bh(&dev->dev_lock); + + scst_dev_ext_block(dev, block_stpg); + + list_add_tail(&b->ext_blockers_list_entry, &dev->ext_blockers_list); + dev->ext_blocking_pending = 1; + + b->ext_blocker_done_fn = done_fn; + if (priv_len > 0) { + b->ext_blocker_data_len = priv_len; + memcpy(b->ext_blocker_data, priv, priv_len); + } + + if (dev->on_dev_cmd_count == 0) { + TRACE_DBG("No commands to wait for async blocking (dev %s)", + dev->virt_name); + + if (!dev->ext_unblock_scheduled) + __scst_ext_blocking_done(dev); + } + + spin_unlock_bh(&dev->dev_lock); out: TRACE_EXIT_RES(res); return res; - -out_free_success: - sBUG_ON(!(flags & SCST_EXT_BLOCK_SYNC)); - kfree(b); - goto out_success; } void scst_ext_unblock_dev(struct scst_device *dev, bool stpg) @@ -15045,7 +15109,7 @@ void scst_ext_unblock_dev(struct scst_device *dev, bool stpg) spin_unlock_bh(&dev->dev_lock); TRACE_DBG("Ext unblock (dev %s): still pending...", dev->virt_name); - rc = scst_ext_block_dev(dev, NULL, NULL, 0, SCST_EXT_BLOCK_SYNC); + rc = scst_sync_ext_block_dev(dev); if (rc != 0) { /* Oops, have to poll */ PRINT_WARNING("scst_ext_block_dev(dev %s) failed, " @@ -15432,7 +15496,7 @@ int __init scst_lib_init(void) scst_scsi_op_list_init(); - scst_release_acg_wq = alloc_workqueue("scst_release_acg", WQ_MEM_RECLAIM, 0); + scst_release_acg_wq = alloc_workqueue("scst_release_acg", 0, 1); if (unlikely(!scst_release_acg_wq)) { PRINT_ERROR("Failed to allocate scst_release_acg_wq"); res = -ENOMEM; diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 564488d74..5ca545f4e 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -93,6 +93,8 @@ struct kmem_cache *scst_sess_cachep; struct kmem_cache *scst_acgd_cachep; static struct kmem_cache *scst_thr_cachep; +char *scst_cluster_name; + unsigned int scst_setup_id; spinlock_t scst_init_lock; @@ -127,7 +129,8 @@ spinlock_t scst_mgmt_lock; struct list_head scst_sess_init_list; struct list_head scst_sess_shut_list; -wait_queue_head_t scst_dev_cmd_waitQ; +static wait_queue_head_t scst_dev_cmd_waitQ; +static struct completion scst_confirm_done; static struct mutex scst_cmd_threads_mutex; /* protected by scst_cmd_threads_mutex */ @@ -622,7 +625,7 @@ char *scst_get_cmd_state_name(char *name, int len, unsigned int state) { if (state < ARRAY_SIZE(scst_cmd_state_name) && scst_cmd_state_name[state]) - strlcpy(name, scst_cmd_state_name[state], len); + strscpy(name, scst_cmd_state_name[state], len); else snprintf(name, len, "%d", state); return name; @@ -700,7 +703,7 @@ static const char *const scst_tm_fn_name[] = { char *scst_get_tm_fn_name(char *name, int len, unsigned int fn) { if (fn < ARRAY_SIZE(scst_tm_fn_name) && scst_tm_fn_name[fn]) - strlcpy(name, scst_tm_fn_name[fn], len); + strscpy(name, scst_tm_fn_name[fn], len); else snprintf(name, len, "%d", fn); return name; @@ -720,7 +723,7 @@ char *scst_get_mcmd_state_name(char *name, int len, unsigned int state) { if (state < ARRAY_SIZE(scst_mcmd_state_name) && scst_mcmd_state_name[state]) - strlcpy(name, scst_mcmd_state_name[state], len); + strscpy(name, scst_mcmd_state_name[state], len); else snprintf(name, len, "%d", state); return name; @@ -790,7 +793,7 @@ static int scst_susp_wait(unsigned long timeout) t = min(timeout, SCST_SUSP_WAIT_REPORT_TIMEOUT); res = wait_event_interruptible_timeout(scst_dev_cmd_waitQ, - percpu_ref_killed, t); + percpu_ref_killed, t); if (res > 0) { res = 0; goto out; @@ -798,15 +801,16 @@ static int scst_susp_wait(unsigned long timeout) goto out; if (res == 0) { - PRINT_INFO("%d active commands to still not completed. See " - "README for possible reasons.", scst_get_cmd_counter()); + PRINT_INFO( + "%d active commands to still not completed. See README for possible reasons.", + scst_get_cmd_counter()); scst_trace_cmds(scst_to_syslog, &hp); scst_trace_mcmds(scst_to_syslog, &hp); } if (timeout != SCST_SUSPEND_TIMEOUT_UNLIMITED) { res = wait_event_interruptible_timeout(scst_dev_cmd_waitQ, - percpu_ref_killed, timeout - t); + percpu_ref_killed, timeout - t); if (res == 0) res = -EBUSY; else if (res > 0) @@ -824,6 +828,11 @@ static int scst_susp_wait(unsigned long timeout) #undef SCST_SUSP_WAIT_REPORT_TIMEOUT } +static void scst_suspend_counter_confirm(struct percpu_ref *ref) +{ + complete(&scst_confirm_done); +} + /* * scst_suspend_activity() - globally suspend activity * @@ -862,8 +871,12 @@ int scst_suspend_activity(unsigned long timeout) goto out_up; /* Cause scst_get_cmd() to fail. */ + init_completion(&scst_confirm_done); + percpu_ref_killed = false; - percpu_ref_kill(&scst_cmd_count); + percpu_ref_kill_and_confirm(&scst_cmd_count, scst_suspend_counter_confirm); + + wait_for_completion(&scst_confirm_done); /* * See comment in scst_user.c::dev_user_task_mgmt_fn() for more @@ -876,7 +889,7 @@ int scst_suspend_activity(unsigned long timeout) if (scst_get_cmd_counter() != 0) { PRINT_INFO("Waiting for %d active commands to complete...", - scst_get_cmd_counter()); + scst_get_cmd_counter()); rep = true; lock_contended(&scst_suspend_dep_map, _RET_IP_); @@ -885,15 +898,19 @@ int scst_suspend_activity(unsigned long timeout) res = scst_susp_wait(timeout); /* Cause scst_get_mcmd() to fail. */ + init_completion(&scst_confirm_done); + percpu_ref_killed = false; - percpu_ref_kill(&scst_mcmd_count); + percpu_ref_kill_and_confirm(&scst_mcmd_count, scst_suspend_counter_confirm); + + wait_for_completion(&scst_confirm_done); if (res != 0) goto out_resume; if (scst_get_cmd_counter() != 0) - TRACE_MGMT_DBG("Waiting for %d active commands finally to " - "complete", scst_get_cmd_counter()); + TRACE_MGMT_DBG("Waiting for %d active commands finally to complete", + scst_get_cmd_counter()); if (timeout != SCST_SUSPEND_TIMEOUT_UNLIMITED) { wait_time = jiffies - cur_time; @@ -911,7 +928,7 @@ int scst_suspend_activity(unsigned long timeout) goto out_resume; if (rep) - PRINT_INFO("%s", "All active commands completed"); + PRINT_INFO("All active commands completed"); out_up: mutex_unlock(&scst_suspend_mutex); @@ -971,8 +988,9 @@ static void __scst_resume_activity(void) spin_lock_irq(&scst_mcmd_lock); list_for_each_entry(m, &scst_delayed_mgmt_cmd_list, mgmt_cmd_list_entry) { - TRACE_MGMT_DBG("Moving delayed mgmt cmd %p to head of active " - "mgmt cmd list", m); + TRACE_MGMT_DBG( + "Moving delayed mgmt cmd %p to head of active mgmt cmd list", + m); } list_splice_init(&scst_delayed_mgmt_cmd_list, &scst_active_mgmt_cmd_list); @@ -2599,7 +2617,6 @@ static void __exit exit_scst(void) scst_cm_exit(); - scst_stop_global_threads(); scst_deinit_threads(&scst_main_cmd_threads); @@ -2609,13 +2626,14 @@ static void __exit exit_scst(void) scsi_unregister_interface(&scst_interface); - scst_sgv_pools_deinit(); scst_tg_cleanup(); scst_sysfs_cleanup(); + kfree(scst_cluster_name); + scst_event_exit(); rcu_barrier(); diff --git a/scst/src/scst_mem.c b/scst/src/scst_mem.c index fb438b505..af5cd48cd 100644 --- a/scst/src/scst_mem.c +++ b/scst/src/scst_mem.c @@ -1412,7 +1412,7 @@ static int sgv_pool_init(struct sgv_pool *pool, const char *name, name, sizeof(struct sgv_pool_obj), clustering_type, single_alloc_pages, pool->max_caches, pool->max_cached_pages); - strlcpy(pool->name, name, sizeof(pool->name)-1); + strscpy(pool->name, name, sizeof(pool->name)-1); pool->owner_mm = current->mm; diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index c2e2cf727..492763029 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -172,11 +172,10 @@ extern struct list_head scst_template_list; extern struct list_head scst_dev_list; extern struct list_head scst_dev_type_list; extern struct list_head scst_virtual_dev_type_list; -extern wait_queue_head_t scst_dev_cmd_waitQ; extern const struct scst_cl_ops scst_no_dlm_cl_ops; extern const struct scst_cl_ops scst_dlm_cl_ops; -extern char *scst_dlm_cluster_name; +extern char *scst_cluster_name; extern unsigned int scst_setup_id; @@ -418,7 +417,7 @@ static inline int scst_dlm_new_lockspace(const char *name, int namelen, uint32_t flags, int lvblen) { - return dlm_new_lockspace(name, scst_dlm_cluster_name, flags, lvblen, + return dlm_new_lockspace(name, scst_cluster_name, flags, lvblen, NULL, NULL, NULL, lockspace); } @@ -611,12 +610,10 @@ bool __scst_check_blocked_dev(struct scst_cmd *cmd); void __scst_check_unblock_dev(struct scst_cmd *cmd); void scst_check_unblock_dev(struct scst_cmd *cmd); -#define SCST_EXT_BLOCK_SYNC 1 -#define SCST_EXT_BLOCK_STPG 2 +int scst_sync_ext_block_dev(struct scst_device *dev); int scst_ext_block_dev(struct scst_device *dev, ext_blocker_done_fn_t done_fn, - const uint8_t *priv, int priv_len, int flags); + const void *priv, size_t priv_len, bool block_stpg); 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); diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 4fadd8605..f21362dc3 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -470,8 +470,8 @@ static int sysfs_work_thread_fn(void *arg) while (!kthread_should_stop()) { if (one_time_only && !test_sysfs_work_list()) break; - wait_event_locked(sysfs_work_waitQ, test_sysfs_work_list(), - lock, sysfs_work_lock); + scst_wait_event_interruptible_lock(sysfs_work_waitQ, test_sysfs_work_list(), + sysfs_work_lock); scst_process_sysfs_works(); } spin_unlock(&sysfs_work_lock); @@ -3805,10 +3805,10 @@ static ssize_t scst_dev_block_store(struct kobject *kobj, "data_len %d)", dev->virt_name, sync, data_start, data_len); if (sync) - res = scst_ext_block_dev(dev, NULL, NULL, 0, SCST_EXT_BLOCK_SYNC); + res = scst_sync_ext_block_dev(dev); else res = scst_ext_block_dev(dev, scst_sysfs_ext_blocking_done, - data_start, data_len, 0); + data_start, data_len, false); if (res != 0) goto out; @@ -7701,8 +7701,8 @@ static ssize_t scst_cluster_name_show(struct kobject *kobj, TRACE_ENTRY(); - if (scst_dlm_cluster_name != NULL) - res = sprintf(buf, "%s\n%s", scst_dlm_cluster_name, + if (scst_cluster_name != NULL) + res = sprintf(buf, "%s\n%s", scst_cluster_name, SCST_SYSFS_KEY_MARK "\n"); TRACE_EXIT_RES(res); @@ -7726,8 +7726,8 @@ static ssize_t scst_cluster_name_store(struct kobject *kobj, len--; if (len == 0) { - kfree(scst_dlm_cluster_name); - scst_dlm_cluster_name = NULL; + kfree(scst_cluster_name); + scst_cluster_name = NULL; goto out_done; } @@ -7737,11 +7737,11 @@ static ssize_t scst_cluster_name_store(struct kobject *kobj, goto out; } - kfree(scst_dlm_cluster_name); - scst_dlm_cluster_name = kstrndup(buf, len, GFP_KERNEL); - if (!scst_dlm_cluster_name) { + kfree(scst_cluster_name); + scst_cluster_name = kstrndup(buf, len, GFP_KERNEL); + if (!scst_cluster_name) { PRINT_ERROR("Unable to alloc cluster_name string (len %d)", - len+1); + len + 1); res = -ENOMEM; goto out; } @@ -8097,7 +8097,6 @@ void scst_sysfs_cleanup(void) TRACE_ENTRY(); PRINT_INFO("%s", "Exiting SCST sysfs hierarchy..."); - kfree(scst_dlm_cluster_name); scst_del_put_sgv_kobj(); diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index d69688326..4b4eac7dd 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -4510,9 +4510,9 @@ int scst_init_thread(void *arg) spin_lock_irq(&scst_init_lock); while (!kthread_should_stop()) { - wait_event_locked(scst_init_cmd_list_waitQ, - test_init_cmd_list(), - lock_irq, scst_init_lock); + scst_wait_event_interruptible_lock_irq(scst_init_cmd_list_waitQ, + test_init_cmd_list(), + scst_init_lock); scst_do_job_init(); } spin_unlock_irq(&scst_init_lock); @@ -4800,6 +4800,39 @@ static inline int test_cmd_threads(struct scst_cmd_thread_t *thr) return res; } +static inline int +scst_wait_for_cmd(struct scst_cmd_threads *p_cmd_threads, struct scst_cmd_thread_t *thr) +{ + DEFINE_WAIT(wq_entry); + int ret = 0; + + if (test_cmd_threads(thr)) + return 0; + + for (;;) { + long __int = prepare_to_wait_exclusive_head(&p_cmd_threads->cmd_list_waitQ, + &wq_entry, TASK_INTERRUPTIBLE); + + if (test_cmd_threads(thr)) + break; + + if (__int) { + ret = __int; + goto out; + } + + spin_unlock(&thr->thr_cmd_list_lock); + spin_unlock_irq(&p_cmd_threads->cmd_list_lock); + schedule(); + spin_lock_irq(&p_cmd_threads->cmd_list_lock); + spin_lock(&thr->thr_cmd_list_lock); + } + finish_wait(&p_cmd_threads->cmd_list_waitQ, &wq_entry); + +out: + return ret; +} + int scst_cmd_thread(void *arg) { struct scst_cmd_thread_t *thr = arg; @@ -4822,23 +4855,7 @@ int scst_cmd_thread(void *arg) spin_lock_irq(&p_cmd_threads->cmd_list_lock); spin_lock(&thr->thr_cmd_list_lock); while (!kthread_should_stop()) { - if (!test_cmd_threads(thr)) { - DEFINE_WAIT(wait); - - do { - prepare_to_wait_exclusive_head( - &p_cmd_threads->cmd_list_waitQ, - &wait, TASK_INTERRUPTIBLE); - if (test_cmd_threads(thr)) - break; - spin_unlock(&thr->thr_cmd_list_lock); - spin_unlock_irq(&p_cmd_threads->cmd_list_lock); - schedule(); - spin_lock_irq(&p_cmd_threads->cmd_list_lock); - spin_lock(&thr->thr_cmd_list_lock); - } while (!test_cmd_threads(thr)); - finish_wait(&p_cmd_threads->cmd_list_waitQ, &wait); - } + scst_wait_for_cmd(p_cmd_threads, thr); if (tm_dbg_is_release()) { spin_unlock_irq(&p_cmd_threads->cmd_list_lock); @@ -6794,9 +6811,9 @@ int scst_tm_thread(void *arg) spin_lock_irq(&scst_mcmd_lock); while (!kthread_should_stop()) { - wait_event_locked(scst_mgmt_cmd_list_waitQ, - test_mgmt_cmd_list(), lock_irq, - scst_mcmd_lock); + scst_wait_event_interruptible_lock_irq(scst_mgmt_cmd_list_waitQ, + test_mgmt_cmd_list(), + scst_mcmd_lock); while (!list_empty(&scst_active_mgmt_cmd_list)) { int rc; @@ -7610,8 +7627,8 @@ int scst_global_mgmt_thread(void *arg) spin_lock_irq(&scst_mgmt_lock); while (!kthread_should_stop()) { - wait_event_locked(scst_mgmt_waitQ, test_mgmt_list(), lock_irq, - scst_mgmt_lock); + scst_wait_event_interruptible_lock_irq(scst_mgmt_waitQ, test_mgmt_list(), + scst_mgmt_lock); while (!list_empty(&scst_sess_init_list)) { sess = list_first_entry(&scst_sess_init_list, diff --git a/scst/src/scst_tg.c b/scst/src/scst_tg.c index 72feb671d..0b8c72b4f 100644 --- a/scst/src/scst_tg.c +++ b/scst/src/scst_tg.c @@ -1739,9 +1739,8 @@ static int scst_emit_stpg_event(struct scst_cmd *cmd, struct scst_dev_group *dg, res = 1; - if (strlcpy(payload->device_name, dev->virt_name, - sizeof(payload->device_name)) >= - sizeof(payload->device_name)) { + if (strscpy(payload->device_name, dev->virt_name, + sizeof(payload->device_name)) < 0) { PRINT_ERROR("Device name %s too long", dev->virt_name); goto out_too_long; } @@ -1752,19 +1751,18 @@ static int scst_emit_stpg_event(struct scst_cmd *cmd, struct scst_dev_group *dg, if (osi[j].prev_state == osi[j].new_state) continue; - if (strlcpy(descr->prev_state, + if (strscpy(descr->prev_state, scst_alua_state_name(osi[j].prev_state), - sizeof(descr->prev_state)) >= - sizeof(descr->prev_state) || - strlcpy(descr->new_state, + sizeof(descr->prev_state)) < 0 || + strscpy(descr->new_state, scst_alua_state_name(osi[j].new_state), - sizeof(descr->new_state)) >= - sizeof(descr->new_state) || - strlcpy(descr->dg_name, dg->name, sizeof(descr->dg_name)) - >= sizeof(descr->dg_name) || - strlcpy(descr->tg_name, osi[j].tg->name, - sizeof(descr->tg_name)) >= - sizeof(descr->tg_name)) + sizeof(descr->new_state)) < 0 || + strscpy(descr->dg_name, + dg->name, + sizeof(descr->dg_name)) < 0 || + strscpy(descr->tg_name, + osi[j].tg->name, + sizeof(descr->tg_name)) < 0) goto out_too_long; descr->group_id = osi[j].group_id; @@ -1820,8 +1818,7 @@ static int scst_emit_stpg_event(struct scst_cmd *cmd, struct scst_dev_group *dg, rc = scst_ext_block_dev(dgd->dev, scst_stpg_ext_blocking_done, - (uint8_t *)&wait, sizeof(wait), - SCST_EXT_BLOCK_STPG); + &wait, sizeof(wait), true); if (rc != 0) { TRACE_DBG("scst_ext_block_dev() failed " "with %d, reverting (cmd %p)", rc, cmd); diff --git a/scst_local/Makefile b/scst_local/Makefile index 4e7626f6a..05e2c4c4e 100644 --- a/scst_local/Makefile +++ b/scst_local/Makefile @@ -29,7 +29,9 @@ ifeq ($(INSTALL_MOD_PATH),) export INSTALL_MOD_PATH := $(DESTDIR) endif -INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra +INSTALL_MOD_DIR=extra + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/$(INSTALL_MOD_DIR) SCST_DIR := $(shell echo "$$PWD")/../scst/src @@ -41,6 +43,7 @@ install: all KDIR=$(KDIR) ../scripts/sign-modules $(MAKE) -C $(KDIR) M=$(shell pwd) \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install @@ -57,5 +60,5 @@ extraclean: clean release-archive: ../scripts/generate-release-archive scst_local "$$(sed -n 's/^#define[[:blank:]]SCST_LOCAL_VERSION[[:blank:]]*\"\([^\"]*\)\".*/\1/p' scst_local.c)" -.PHONY: all tgt install uninstall clean extraclean +.PHONY: all install uninstall clean extraclean diff --git a/scstadmin/scstadmin.spec.in b/scstadmin/scstadmin.spec.in index 853c0631a..201652018 100644 --- a/scstadmin/scstadmin.spec.in +++ b/scstadmin/scstadmin.spec.in @@ -16,7 +16,7 @@ URL: http://scst.sourceforge.net/ Source: %{name}-%{version}.tar.bz2 BuildRoot: %{_tmppath}/%{name}-%{version}-build AutoReqProv: yes -Requires: %{expand:%%(for c in killall rm; do echo -n "$(which $c) "; done)} +Requires: psmisc, coreutils %description A tool for configuring SCST via the SCST sysfs interface. Allows to save, diff --git a/srpt/Makefile b/srpt/Makefile index 5f2a97a01..86ba92f53 100644 --- a/srpt/Makefile +++ b/srpt/Makefile @@ -31,7 +31,9 @@ ifeq ($(INSTALL_MOD_PATH),) export INSTALL_MOD_PATH := $(DESTDIR) endif -INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra +INSTALL_MOD_DIR=extra + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/$(INSTALL_MOD_DIR) SRC_FILES=$(wildcard */*.[ch]) @@ -125,6 +127,7 @@ install: all $(MAKE) -C $(KDIR) M=$(shell pwd)/src \ $(shell [ -n "$(PASS_CC_TO_MAKE)" ] && echo CC="$(CC)") \ CONFTEST_CFLAGS="$(CONFTEST_CFLAGS)" \ + INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) \ $$([ -n "$(DEPMOD)" ] && echo "DEPMOD=$(DEPMOD)") \ CONFIG_MODULE_SIG_ALL= modules_install diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index 8cfac94f8..751b7f68f 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -451,7 +451,7 @@ static void srpt_get_ioc(struct srpt_port *sport, u32 slot, memset(iocp, 0, sizeof(*iocp)); mutex_lock(&sport->mutex); - strlcpy(iocp->id_string, sport->port_id, sizeof(iocp->id_string)); + strscpy(iocp->id_string, sport->port_id, sizeof(iocp->id_string)); mutex_unlock(&sport->mutex); iocp->guid = cpu_to_be64(srpt_service_guid); iocp->vendor_id = cpu_to_be32(sdev->dev_attr.vendor_id); @@ -2707,7 +2707,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev, goto free_recv_ring; } - strlcpy(ch->sess_name, src_addr, sizeof(ch->sess_name)); + strscpy(ch->sess_name, src_addr, sizeof(ch->sess_name)); pr_debug("registering session %s\n", ch->sess_name); BUG_ON(!sport->scst_tgt); @@ -4258,7 +4258,7 @@ static void srpt_init_sport(struct srpt_port *sport, struct ib_device *ib_dev) INIT_LIST_HEAD(&sport->nexus_list); init_waitqueue_head(&sport->ch_releaseQ); mutex_init(&sport->mutex); - strlcpy(sport->port_id, DEFAULT_SRPT_ID_STRING, + strscpy(sport->port_id, DEFAULT_SRPT_ID_STRING, sizeof(sport->port_id)); for (i = 0; i < ib_dev->num_comp_vectors; i++) cpumask_set_cpu(i, &sport->comp_v_mask);