diff --git a/Makefile b/Makefile index 3e3637749..c85d9f619 100644 --- a/Makefile +++ b/Makefile @@ -402,9 +402,11 @@ scst-rpm: rpm: $(MAKE) scst-rpm $(MAKE) -C scstadmin rpm - @echo - @echo "The following RPMs have been built:" - @find -name '*.rpm' + @if [ "$$(id -u)" != 0 ]; then \ + echo; \ + echo "The following RPMs have been built:"; \ + find -name '*.rpm'; \ + fi 2perf: extraclean cd $(SCST_DIR) && $(MAKE) $@ diff --git a/fcst/Makefile b/fcst/Makefile index 5939c958a..1200bcb77 100644 --- a/fcst/Makefile +++ b/fcst/Makefile @@ -86,6 +86,7 @@ tgt: Modules.symvers Module.symvers install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ SCST_INC_DIR=$(SCST_INC_DIR) modules_install ins: diff --git a/fcst/fcst.h b/fcst/fcst.h index 5d3027514..50f25b4a5 100644 --- a/fcst/fcst.h +++ b/fcst/fcst.h @@ -174,4 +174,26 @@ struct ft_tpg *ft_lport_find_tpg(struct fc_lport *); struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *); void ft_cmd_dump(struct scst_cmd *, const char *); +/* #define FCST_INJECT_SEND_ERRORS 2 */ + +#ifdef FCST_INJECT_SEND_ERRORS +#define FCST_INJ_SEND_ERR(e) \ +({ \ + int _error = 0; \ + \ + if (scst_random() % 62929 == 0) \ + _error = -ENOMEM; \ + if (FCST_INJECT_SEND_ERRORS >= 2 && scst_random() % 69491 == 0) \ + _error = -ENXIO; \ + if (_error) \ + pr_warn("%s: injected seq_send() error %d\n", __func__, \ + _error); \ + else \ + _error = (e); \ + _error; \ +}) +#else +#define FCST_INJ_SEND_ERR(e) (e) +#endif + #endif /* __SCSI_FCST_H__ */ diff --git a/fcst/ft_cmd.c b/fcst/ft_cmd.c index aeb9241d8..8c3509a78 100644 --- a/fcst/ft_cmd.c +++ b/fcst/ft_cmd.c @@ -212,13 +212,10 @@ static void ft_abort_cmd(struct scst_cmd *cmd) struct ft_cmd *fcmd = scst_cmd_get_tgt_priv(cmd); struct fc_seq *sp = fcmd->seq; struct fc_exch *ep = fc_seq_exch(sp); - struct fc_lport *lport = ep->lp; pr_err("%s: cmd %p ox_id %#x rx_id %#x state %d\n", __func__, cmd, ep->oxid, ep->rxid, fcmd->state); - lport->tt.exch_done(sp); - spin_lock(&fcmd->lock); switch (fcmd->state) { case FT_STATE_NEW: @@ -257,10 +254,13 @@ static void ft_abort_cmd(struct scst_cmd *cmd) static void ft_cmd_done(struct ft_cmd *fcmd) { struct fc_frame *fp = fcmd->req_frame; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) - struct fc_lport *lport; + struct fc_seq *sp = fcmd->seq; + struct fc_lport *lport = fr_dev(fp); - lport = fr_dev(fp); + if (sp) + lport->tt.exch_done(sp); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) if (fr_seq(fp)) lport->tt.seq_release(fr_seq(fp)); #endif @@ -291,6 +291,7 @@ int ft_send_response(struct scst_cmd *cmd) struct fc_exch *ep; unsigned int slen; size_t len; + enum ft_cmd_state prev_state; int resid = 0; int bi_resid = 0; int error; @@ -303,7 +304,7 @@ int ft_send_response(struct scst_cmd *cmd) lport = ep->lp; WARN_ON(fcmd->state != FT_STATE_NEW && fcmd->state != FT_STATE_DATA_IN); - ft_set_cmd_state(fcmd, FT_STATE_CMD_RSP_SENT); + prev_state = ft_set_cmd_state(fcmd, FT_STATE_CMD_RSP_SENT); if (scst_cmd_aborted_on_xmit(cmd)) { FT_IO_DBG("cmd aborted did %x oxid %x\n", ep->did, ep->oxid); @@ -313,7 +314,8 @@ int ft_send_response(struct scst_cmd *cmd) if (!scst_cmd_get_is_send_status(cmd)) { FT_IO_DBG("send status not set. feature not implemented\n"); - return SCST_TGT_RES_FATAL_ERROR; + error = SCST_TGT_RES_FATAL_ERROR; + goto err; } status = scst_cmd_get_status(cmd); @@ -333,7 +335,7 @@ int ft_send_response(struct scst_cmd *cmd) error = ft_send_read_data(cmd); if (error) { FT_ERR("ft_send_read_data returned %d\n", error); - return error; + goto err; } if (dir == SCST_DATA_BIDI) { @@ -347,8 +349,10 @@ int ft_send_response(struct scst_cmd *cmd) } fp = fc_frame_alloc(lport, len); - if (!fp) - return SCST_TGT_RES_QUEUE_FULL; + if (!fp) { + error = SCST_TGT_RES_QUEUE_FULL; + goto err; + } fcp = fc_frame_payload_get(fp, len); memset(fcp, 0, sizeof(*fcp)); @@ -384,14 +388,26 @@ int ft_send_response(struct scst_cmd *cmd) fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP, FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0); - error = lport->tt.seq_send(lport, fcmd->seq, fp); - if (error < 0) + error = FCST_INJ_SEND_ERR(lport->tt.seq_send(lport, fcmd->seq, fp)); + if (error < 0) { pr_err("Sending response for exchange with OX_ID %#x and RX_ID" " %#x failed: %d\n", ep->oxid, ep->rxid, error); + error = error == -ENOMEM ? SCST_TGT_RES_QUEUE_FULL : + SCST_TGT_RES_FATAL_ERROR; + goto err; + } done: - lport->tt.exch_done(fcmd->seq); scst_tgt_cmd_done(cmd, SCST_CONTEXT_SAME); return SCST_TGT_RES_SUCCESS; + +err: + ft_set_cmd_state(fcmd, prev_state); + WARN_ONCE(error != SCST_TGT_RES_QUEUE_FULL && + error != SCST_TGT_RES_FATAL_ERROR, + "%s: invalid error code %d\n", + __func__, error); + return error; + } /* @@ -452,6 +468,7 @@ int ft_send_xfer_rdy(struct scst_cmd *cmd) struct fcp_txrdy *txrdy; struct fc_lport *lport; struct fc_exch *ep; + int error; fcmd = scst_cmd_get_tgt_priv(cmd); @@ -472,8 +489,17 @@ int ft_send_xfer_rdy(struct scst_cmd *cmd) fcmd->seq = lport->tt.seq_start_next(fcmd->seq); fc_fill_fc_hdr(fp, FC_RCTL_DD_DATA_DESC, ep->did, ep->sid, FC_TYPE_FCP, FC_FC_EX_CTX | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); - lport->tt.seq_send(lport, fcmd->seq, fp); - return SCST_TGT_RES_SUCCESS; + error = FCST_INJ_SEND_ERR(lport->tt.seq_send(lport, fcmd->seq, fp)); + switch (error) { + case 0: + return SCST_TGT_RES_SUCCESS; + case -ENOMEM: + ft_set_cmd_state(fcmd, FT_STATE_NEW); + return SCST_TGT_RES_QUEUE_FULL; + default: + ft_set_cmd_state(fcmd, FT_STATE_NEW); + return SCST_TGT_RES_FATAL_ERROR; + } } /* @@ -528,16 +554,14 @@ static void ft_send_resp_status(struct fc_frame *rx_fp, u32 status, lport->tt.seq_send(lport, sp, fp); out: - lport->tt.exch_done(fr_seq(rx_fp)); + ; #else fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_DD_CMD_STATUS, 0); sp = fr_seq(fp); - if (sp) { + if (sp) lport->tt.seq_send(lport, sp, fp); - lport->tt.exch_done(sp); - } else { + else lport->tt.frame_send(lport, fp); - } #endif } @@ -651,7 +675,7 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) { struct fc_seq *sp; struct scst_cmd *cmd; - struct ft_cmd *fcmd; + struct ft_cmd *fcmd = NULL; struct fcp_cmnd *fcp; struct fc_lport *lport; int data_dir; @@ -659,6 +683,15 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) int cdb_len; lport = sess->tport->lport; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + sp = fr_seq(fp); +#else + sp = lport->tt.seq_assign(lport, fp); + if (!sp) + goto busy; +#endif + fcmd = kzalloc(sizeof(*fcmd), GFP_ATOMIC); if (!fcmd) goto busy; @@ -702,13 +735,6 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) scst_cmd_set_tgt_priv(cmd, fcmd); cmd->state = FT_STATE_NEW; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) - sp = fr_seq(fp); -#else - sp = lport->tt.seq_assign(lport, fp); - if (!sp) - goto busy; -#endif fcmd->seq = sp; lport->tt.seq_set_resp(sp, ft_recv_seq, cmd); @@ -757,6 +783,8 @@ busy: ft_send_resp_status(fp, SAM_STAT_BUSY, 0); if (fcmd) ft_cmd_done(fcmd); + else if (sp) + lport->tt.exch_done(sp); } /* diff --git a/fcst/ft_io.c b/fcst/ft_io.c index 26305eecb..19be72e8b 100644 --- a/fcst/ft_io.c +++ b/fcst/ft_io.c @@ -17,8 +17,7 @@ * more details. * * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * this program. */ #include #include @@ -176,10 +175,17 @@ int ft_send_read_data(struct scst_cmd *cmd) remaining ? (FC_FC_EX_CTX | FC_FC_REL_OFF) : (FC_FC_EX_CTX | FC_FC_REL_OFF | FC_FC_END_SEQ), fh_off); - error = lport->tt.seq_send(lport, fcmd->seq, fp); + error = FCST_INJ_SEND_ERR(lport->tt.seq_send(lport, fcmd->seq, + fp)); if (error) { - WARN_ON(1); - /* XXX For now, initiator will retry */ + pr_warn("Sending frame with oid %#x oxid %#x resp_len" + " %d failed at frame_off %u / remaining %zu" + " with error code %d - %s", ep->oid, ep->oxid, + scst_cmd_get_resp_data_len(cmd), frame_off, + remaining, error, error == -ENOMEM ? + "retrying" : "giving up"); + return error == -ENOMEM ? SCST_TGT_RES_QUEUE_FULL : + SCST_TGT_RES_FATAL_ERROR; } else fcmd->read_data_len = frame_off; } diff --git a/fcst/ft_sess.c b/fcst/ft_sess.c index 3ce88bca4..1690a87d1 100644 --- a/fcst/ft_sess.c +++ b/fcst/ft_sess.c @@ -350,10 +350,8 @@ static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id) */ static void ft_sess_close(struct ft_sess *sess) { - struct fc_lport *lport; u32 port_id; - lport = sess->tport->lport; port_id = sess->port_id; if (port_id == -1) return; diff --git a/ibmvstgt/Makefile b/ibmvstgt/Makefile index daaf57f4e..2bc8ce127 100644 --- a/ibmvstgt/Makefile +++ b/ibmvstgt/Makefile @@ -38,7 +38,9 @@ all: src/$(MODULE_SYMVERS) $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src modules install: all src/ibmvstgt.ko - $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src modules_install + $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ + modules_install uninstall: rm -f $(INSTALL_DIR)/libsrp.ko $(INSTALL_DIR)/ibmvstgt.ko diff --git a/iscsi-scst/COPYING b/iscsi-scst/COPYING index afd5a9471..31b2c9e30 100644 --- a/iscsi-scst/COPYING +++ b/iscsi-scst/COPYING @@ -3,7 +3,6 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -305,8 +304,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + along with this program. Also add information on how to contact you by electronic and paper mail. diff --git a/iscsi-scst/Makefile b/iscsi-scst/Makefile index cb4f0a4f9..50c10a0a4 100644 --- a/iscsi-scst/Makefile +++ b/iscsi-scst/Makefile @@ -120,8 +120,10 @@ install: all @install -vD -m 755 usr/iscsi-scst-adm $(DESTDIR)$(SBINDIR)/iscsi-scst-adm @install -vD -m 644 doc/manpages/iscsi-scst-adm.8 $(DESTDIR)$(MANDIR)/man8/iscsi-scst-adm.8 $(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(KMOD) \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ modules_install $(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(ISERTMOD) \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ modules_install uninstall: diff --git a/iscsi-scst/README b/iscsi-scst/README index f265be6c3..d80e33f08 100644 --- a/iscsi-scst/README +++ b/iscsi-scst/README @@ -1,7 +1,7 @@ iSCSI SCST target driver ======================== -Version 3.0.0, XX XXXXX 2014 +Version 3.1.0, XX XXXXX 2014 ---------------------------- ISCSI-SCST is a deeply reworked fork of iSCSI Enterprise Target (IET) diff --git a/iscsi-scst/include/iscsi_scst_ver.h b/iscsi-scst/include/iscsi_scst_ver.h index 1f5388862..8e3790195 100644 --- a/iscsi-scst/include/iscsi_scst_ver.h +++ b/iscsi-scst/include/iscsi_scst_ver.h @@ -21,4 +21,4 @@ #define ISCSI_VERSION_STRING_SUFFIX #endif -#define ISCSI_VERSION_STRING "3.0.0-pre2" ISCSI_VERSION_STRING_SUFFIX +#define ISCSI_VERSION_STRING "3.1.0-pre1" ISCSI_VERSION_STRING_SUFFIX diff --git a/iscsi-scst/kernel/config.c b/iscsi-scst/kernel/config.c index 49d427ad0..b51a43293 100644 --- a/iscsi-scst/kernel/config.c +++ b/iscsi-scst/kernel/config.c @@ -407,9 +407,7 @@ static int add_session(void __user *ptr) TRACE_ENTRY(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target_mgmt_mutex); -#endif info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { diff --git a/iscsi-scst/kernel/conn.c b/iscsi-scst/kernel/conn.c index cceb7b698..a1f85843e 100644 --- a/iscsi-scst/kernel/conn.c +++ b/iscsi-scst/kernel/conn.c @@ -92,9 +92,7 @@ void conn_info_show(struct seq_file *seq, struct iscsi_session *session) struct sock *sk; char buf[64]; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&session->target->target_mutex); -#endif list_for_each_entry(conn, &session->conn_list, conn_list_entry) { sk = conn->sock->sk; @@ -246,9 +244,7 @@ int conn_sysfs_add(struct iscsi_conn *conn) TRACE_ENTRY(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&conn->target->target_mutex); -#endif iscsi_get_initiator_ip(conn, addr, sizeof(addr)); @@ -319,9 +315,7 @@ struct iscsi_conn *conn_lookup(struct iscsi_session *session, u16 cid) { struct iscsi_conn *conn; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&session->target->target_mutex); -#endif /* * We need to find the latest conn to correctly handle @@ -453,7 +447,11 @@ static void iscsi_state_change(struct sock *sk) return; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) +static void iscsi_data_ready(struct sock *sk) +#else static void iscsi_data_ready(struct sock *sk, int len) +#endif { struct iscsi_conn *conn = sk->sk_user_data; @@ -461,7 +459,11 @@ static void iscsi_data_ready(struct sock *sk, int len) iscsi_make_conn_rd_active(conn); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + conn->old_data_ready(sk); +#else conn->old_data_ready(sk, len); +#endif TRACE_EXIT(); return; @@ -807,9 +809,7 @@ void conn_free(struct iscsi_conn *conn) TRACE_MGMT_DBG("Freeing conn %p (sess=%p, %#Lx %u)", conn, session, (long long unsigned int)session->sid, conn->cid); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&conn->target->target_mutex); -#endif del_timer_sync(&conn->rsp_timer); @@ -914,9 +914,7 @@ int iscsi_conn_alloc(struct iscsi_session *session, struct iscsi_conn *conn; int res = 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&session->target->target_mutex); -#endif conn = kmem_cache_zalloc(iscsi_conn_cache, GFP_KERNEL); if (!conn) { @@ -980,9 +978,7 @@ int __add_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info) bool reinstatement = false; struct iscsit_transport *t; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&session->target->target_mutex); -#endif conn = conn_lookup(session, info->cid); if ((conn != NULL) && diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index fc72e23dd..cbc39e055 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -1017,7 +1017,7 @@ static void iscsi_tcp_set_sense_data(struct iscsi_cmnd *rsp, sg_init_table(sg, 2); sg_set_buf(&sg[0], &rsp->sense_hdr, sizeof(rsp->sense_hdr)); - sg_set_buf(&sg[1], sense_buf, sense_len); + sg_set_buf(&sg[1], (u8 *)sense_buf, sense_len); } static void iscsi_init_status_rsp(struct iscsi_cmnd *rsp, @@ -3271,7 +3271,8 @@ static ssize_t iscsi_tcp_get_initiator_ip(struct iscsi_conn *conn, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]", NIP6(inet6_sk(sk)->daddr)); #else -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) && \ + (!defined(RHEL_MAJOR) || RHEL_MAJOR -0 < 7) pos = scnprintf(buf, size, "[%p6]", &inet6_sk(sk)->daddr); #else pos = scnprintf(buf, size, "[%p6]", &sk->sk_v6_daddr); @@ -3732,7 +3733,7 @@ static void iscsi_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd) case SCST_ABORT_ALL_TASKS_SESS: case SCST_ABORT_ALL_TASKS: case SCST_NEXUS_LOSS: - sBUG_ON(1); + sBUG(); break; default: iscsi_send_task_mgmt_resp(req, status, scst_mgmt_cmd_dropped(scst_mcmd)); @@ -4149,8 +4150,7 @@ int iscsi_threads_pool_get(const cpumask_t *cpu_mask, list_for_each_entry(p, &iscsi_thread_pools_list, thread_pools_list_entry) { - if ((cpu_mask == NULL) || - __cpus_equal(cpu_mask, &p->cpu_mask, nr_cpumask_bits)) { + if (!cpu_mask || cpumask_equal(cpu_mask, &p->cpu_mask)) { p->thread_pool_ref++; TRACE_DBG("iSCSI thread pool %p found (new ref %d)", p, p->thread_pool_ref); @@ -4184,12 +4184,9 @@ int iscsi_threads_pool_get(const cpumask_t *cpu_mask, INIT_LIST_HEAD(&p->wr_list); init_waitqueue_head(&p->wr_waitQ); if (cpu_mask == NULL) - cpus_setall(p->cpu_mask); - else { - cpus_clear(p->cpu_mask); - for_each_cpu(i, cpu_mask) - cpu_set(i, p->cpu_mask); - } + cpumask_setall(&p->cpu_mask); + else + cpumask_copy(&p->cpu_mask, cpu_mask); p->thread_pool_ref = 1; INIT_LIST_HEAD(&p->threads_list); diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index d93c78d4f..6410a9cd0 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -253,7 +253,11 @@ struct iscsi_conn { struct socket *sock; void (*old_state_change)(struct sock *); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + void (*old_data_ready)(struct sock *); +#else void (*old_data_ready)(struct sock *, int); +#endif void (*old_write_space)(struct sock *); /* Both read only. Stay here for better CPU cache locality. */ diff --git a/iscsi-scst/kernel/isert-scst/iser_rdma.c b/iscsi-scst/kernel/isert-scst/iser_rdma.c index 8140bf6a9..6c30f28a8 100644 --- a/iscsi-scst/kernel/isert-scst/iser_rdma.c +++ b/iscsi-scst/kernel/isert-scst/iser_rdma.c @@ -807,9 +807,8 @@ static struct isert_device *isert_device_create(struct ib_device *ib_dev) INIT_LIST_HEAD(&isert_dev->conn_list); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&dev_list_mutex); -#endif + isert_dev_list_add(isert_dev); pr_info("iser created device:%p\n", isert_dev); @@ -843,9 +842,8 @@ static void isert_device_release(struct isert_device *isert_dev) TRACE_ENTRY(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&dev_list_mutex); -#endif + isert_dev_list_remove(isert_dev); /* remove from global list */ for (i = 0; i < isert_dev->num_cqs; ++i) { diff --git a/iscsi-scst/kernel/isert-scst/isert_login.c b/iscsi-scst/kernel/isert-scst/isert_login.c index fae0963e3..501b7ba81 100644 --- a/iscsi-scst/kernel/isert-scst/isert_login.c +++ b/iscsi-scst/kernel/isert-scst/isert_login.c @@ -205,9 +205,7 @@ int isert_conn_alloc(struct iscsi_session *session, TRACE_ENTRY(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&session->target->target_mutex); -#endif if (unlikely(!filp)) { res = -EBADF; diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 145174009..febf8d7d8 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -369,7 +369,7 @@ void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd) case SCST_ABORT_ALL_TASKS_SESS: case SCST_ABORT_ALL_TASKS: case SCST_NEXUS_LOSS: - sBUG_ON(1); + sBUG(); break; default: /* Nothing to do */ diff --git a/iscsi-scst/kernel/param.c b/iscsi-scst/kernel/param.c index 7b307530f..702d29ca3 100644 --- a/iscsi-scst/kernel/param.c +++ b/iscsi-scst/kernel/param.c @@ -257,9 +257,7 @@ static int iscsi_tgt_params_set(struct iscsi_session *session, struct iscsi_tgt_params *params = &session->tgt_params; int32_t *iparams = info->target_params; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&session->target->target_mutex); -#endif if (set) { struct iscsi_conn *conn; @@ -327,9 +325,7 @@ int iscsi_params_set(struct iscsi_target *target, int err; struct iscsi_session *session; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target->target_mutex); -#endif if (info->sid == 0) { PRINT_ERROR("sid must not be %d", 0); diff --git a/iscsi-scst/kernel/patches/put_page_callback-3.15.patch b/iscsi-scst/kernel/patches/put_page_callback-3.15.patch new file mode 100644 index 000000000..0bf0ce5e4 --- /dev/null +++ b/iscsi-scst/kernel/patches/put_page_callback-3.15.patch @@ -0,0 +1,364 @@ +=== modified file 'drivers/block/drbd/drbd_receiver.c' +--- old/drivers/block/drbd/drbd_receiver.c 2014-06-18 01:32:48 +0000 ++++ new/drivers/block/drbd/drbd_receiver.c 2014-06-18 01:44:08 +0000 +@@ -131,7 +131,7 @@ static int page_chain_free(struct page * + struct page *tmp; + int i = 0; + page_chain_for_each_safe(page, tmp) { +- put_page(page); ++ net_put_page(page); + ++i; + } + return i; + +=== modified file 'include/linux/mm_types.h' +--- old/include/linux/mm_types.h 2014-06-18 01:32:48 +0000 ++++ new/include/linux/mm_types.h 2014-06-18 01:44:08 +0000 +@@ -196,6 +196,17 @@ struct page { + #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS + int _last_cpupid; + #endif ++ ++#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) ++ /* ++ * Used to implement support for notification on zero-copy TCP transfer ++ * completion. It might look as not good to have this field here and ++ * it's better to have it in struct sk_buff, but it would make the code ++ * much more complicated and fragile, since all skb then would have to ++ * contain only pages with the same value in this field. ++ */ ++ void *net_priv; ++#endif + } + /* + * The struct page can be forced to be double word aligned so that atomic ops + +=== modified file 'include/linux/net.h' +--- old/include/linux/net.h 2014-06-18 01:32:48 +0000 ++++ new/include/linux/net.h 2014-06-18 01:44:08 +0000 +@@ -19,6 +19,7 @@ + #define _LINUX_NET_H + + #include ++#include + #include + #include + #include /* For O_CLOEXEC and O_NONBLOCK */ +@@ -285,6 +286,45 @@ int kernel_sendpage(struct socket *sock, + int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg); + int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how); + ++#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) ++/* Support for notification on zero-copy TCP transfer completion */ ++typedef void (*net_get_page_callback_t)(struct page *page); ++typedef void (*net_put_page_callback_t)(struct page *page); ++ ++extern net_get_page_callback_t net_get_page_callback; ++extern net_put_page_callback_t net_put_page_callback; ++ ++extern int net_set_get_put_page_callbacks( ++ net_get_page_callback_t get_callback, ++ net_put_page_callback_t put_callback); ++ ++/* ++ * See comment for net_set_get_put_page_callbacks() why those functions ++ * don't need any protection. ++ */ ++static inline void net_get_page(struct page *page) ++{ ++ if (page->net_priv != 0) ++ net_get_page_callback(page); ++ get_page(page); ++} ++static inline void net_put_page(struct page *page) ++{ ++ if (page->net_priv != 0) ++ net_put_page_callback(page); ++ put_page(page); ++} ++#else ++static inline void net_get_page(struct page *page) ++{ ++ get_page(page); ++} ++static inline void net_put_page(struct page *page) ++{ ++ put_page(page); ++} ++#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */ ++ + #define MODULE_ALIAS_NETPROTO(proto) \ + MODULE_ALIAS("net-pf-" __stringify(proto)) + + +=== modified file 'include/linux/skbuff.h' +--- old/include/linux/skbuff.h 2014-06-18 01:32:48 +0000 ++++ new/include/linux/skbuff.h 2014-06-18 01:44:08 +0000 +@@ -2113,7 +2113,7 @@ static inline struct page *skb_frag_page + */ + static inline void __skb_frag_ref(skb_frag_t *frag) + { +- get_page(skb_frag_page(frag)); ++ net_get_page(skb_frag_page(frag)); + } + + /** +@@ -2136,7 +2136,7 @@ static inline void skb_frag_ref(struct s + */ + static inline void __skb_frag_unref(skb_frag_t *frag) + { +- put_page(skb_frag_page(frag)); ++ net_put_page(skb_frag_page(frag)); + } + + /** + +=== modified file 'net/Kconfig' +--- old/net/Kconfig 2014-06-18 01:32:48 +0000 ++++ new/net/Kconfig 2014-06-18 01:44:08 +0000 +@@ -75,6 +75,18 @@ config INET + + Short answer: say Y. + ++config TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION ++ bool "TCP/IP zero-copy transfer completion notification" ++ depends on INET ++ default SCST_ISCSI ++ ---help--- ++ Adds support for sending a notification upon completion of a ++ zero-copy TCP/IP transfer. This can speed up certain TCP/IP ++ software. Currently this is only used by the iSCSI target driver ++ iSCSI-SCST. ++ ++ If unsure, say N. ++ + if INET + source "net/ipv4/Kconfig" + source "net/ipv6/Kconfig" + +=== modified file 'net/ceph/pagevec.c' +--- old/net/ceph/pagevec.c 2014-06-18 01:32:48 +0000 ++++ new/net/ceph/pagevec.c 2014-06-18 01:44:08 +0000 +@@ -51,7 +51,7 @@ void ceph_put_page_vector(struct page ** + for (i = 0; i < num_pages; i++) { + if (dirty) + set_page_dirty_lock(pages[i]); +- put_page(pages[i]); ++ net_put_page(pages[i]); + } + kfree(pages); + } + +=== modified file 'net/core/skbuff.c' +--- old/net/core/skbuff.c 2014-06-18 01:32:48 +0000 ++++ new/net/core/skbuff.c 2014-06-18 01:44:08 +0000 +@@ -425,7 +425,7 @@ struct sk_buff *__netdev_alloc_skb(struc + if (likely(data)) { + skb = build_skb(data, fragsz); + if (unlikely(!skb)) +- put_page(virt_to_head_page(data)); ++ net_put_page(virt_to_head_page(data)); + } + } else { + skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, +@@ -483,7 +483,7 @@ static void skb_clone_fraglist(struct sk + static void skb_free_head(struct sk_buff *skb) + { + if (skb->head_frag) +- put_page(virt_to_head_page(skb->head)); ++ net_put_page(virt_to_head_page(skb->head)); + else + kfree(skb->head); + } +@@ -804,7 +804,7 @@ int skb_copy_ubufs(struct sk_buff *skb, + if (!page) { + while (head) { + struct page *next = (struct page *)page_private(head); +- put_page(head); ++ net_put_page(head); + head = next; + } + return -ENOMEM; +@@ -1647,7 +1647,7 @@ EXPORT_SYMBOL(skb_copy_bits); + */ + static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i) + { +- put_page(spd->pages[i]); ++ net_put_page(spd->pages[i]); + } + + static struct page *linear_to_page(struct page *page, unsigned int *len, +@@ -1700,7 +1700,7 @@ static bool spd_fill_page(struct splice_ + spd->partial[spd->nr_pages - 1].len += *len; + return false; + } +- get_page(page); ++ net_get_page(page); + spd->pages[spd->nr_pages] = page; + spd->partial[spd->nr_pages].len = *len; + spd->partial[spd->nr_pages].offset = offset; +@@ -2159,7 +2159,7 @@ skb_zerocopy(struct sk_buff *to, struct + page = virt_to_head_page(from->head); + offset = from->data - (unsigned char *)page_address(page); + __skb_fill_page_desc(to, 0, page, offset, plen); +- get_page(page); ++ net_get_page(page); + j = 1; + len -= plen; + } +@@ -2813,7 +2813,7 @@ int skb_append_datato_frags(struct sock + copy); + frg_cnt++; + pfrag->offset += copy; +- get_page(pfrag->page); ++ net_get_page(pfrag->page); + + skb->truesize += copy; + atomic_add(copy, &sk->sk_wmem_alloc); + +=== modified file 'net/core/sock.c' +--- old/net/core/sock.c 2014-06-18 01:32:48 +0000 ++++ new/net/core/sock.c 2014-06-18 01:44:08 +0000 +@@ -1888,7 +1888,7 @@ bool skb_page_frag_refill(unsigned int s + } + if (pfrag->offset + sz <= pfrag->size) + return true; +- put_page(pfrag->page); ++ net_put_page(pfrag->page); + } + + order = SKB_FRAG_PAGE_ORDER; +@@ -2651,7 +2651,7 @@ void sk_common_release(struct sock *sk) + sk_refcnt_debug_release(sk); + + if (sk->sk_frag.page) { +- put_page(sk->sk_frag.page); ++ net_put_page(sk->sk_frag.page); + sk->sk_frag.page = NULL; + } + + +=== modified file 'net/ipv4/Makefile' +--- old/net/ipv4/Makefile 2014-06-18 01:32:48 +0000 ++++ new/net/ipv4/Makefile 2014-06-18 01:44:08 +0000 +@@ -53,6 +53,7 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah. + obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o + obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o + obj-$(CONFIG_NETLABEL) += cipso_ipv4.o ++obj-$(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) += tcp_zero_copy.o + + obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ + xfrm4_output.o xfrm4_protocol.o + +=== modified file 'net/ipv4/ip_output.c' +--- old/net/ipv4/ip_output.c 2014-06-18 01:32:48 +0000 ++++ new/net/ipv4/ip_output.c 2014-06-18 01:44:08 +0000 +@@ -1047,7 +1047,7 @@ alloc_new_skb: + __skb_fill_page_desc(skb, i, pfrag->page, + pfrag->offset, 0); + skb_shinfo(skb)->nr_frags = ++i; +- get_page(pfrag->page); ++ net_get_page(pfrag->page); + } + copy = min_t(int, copy, pfrag->size - pfrag->offset); + if (getfrag(from, +@@ -1272,7 +1272,7 @@ ssize_t ip_append_page(struct sock *sk, + if (skb_can_coalesce(skb, i, page, offset)) { + skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len); + } else if (i < MAX_SKB_FRAGS) { +- get_page(page); ++ net_get_page(page); + skb_fill_page_desc(skb, i, page, offset, len); + } else { + err = -EMSGSIZE; + +=== modified file 'net/ipv4/tcp.c' +--- old/net/ipv4/tcp.c 2014-06-18 01:32:48 +0000 ++++ new/net/ipv4/tcp.c 2014-06-18 01:44:08 +0000 +@@ -939,7 +939,7 @@ new_segment: + if (can_coalesce) { + skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); + } else { +- get_page(page); ++ net_get_page(page); + skb_fill_page_desc(skb, i, page, offset, copy); + } + skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; +@@ -1238,7 +1238,7 @@ new_segment: + } else { + skb_fill_page_desc(skb, i, pfrag->page, + pfrag->offset, copy); +- get_page(pfrag->page); ++ net_get_page(pfrag->page); + } + pfrag->offset += copy; + } + +=== added file 'net/ipv4/tcp_zero_copy.c' +--- old/net/ipv4/tcp_zero_copy.c 1970-01-01 00:00:00 +0000 ++++ new/net/ipv4/tcp_zero_copy.c 2014-06-18 01:44:08 +0000 +@@ -0,0 +1,50 @@ ++/* ++ * Support routines for TCP zero copy transmit ++ * ++ * Created by Vladislav Bolkhovitin ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++ ++net_get_page_callback_t net_get_page_callback __read_mostly; ++EXPORT_SYMBOL_GPL(net_get_page_callback); ++ ++net_put_page_callback_t net_put_page_callback __read_mostly; ++EXPORT_SYMBOL_GPL(net_put_page_callback); ++ ++/* ++ * Caller of this function must ensure that at the moment when it's called ++ * there are no pages in the system with net_priv field set to non-zero ++ * value. Hence, this function, as well as net_get_page() and net_put_page(), ++ * don't need any protection. ++ */ ++int net_set_get_put_page_callbacks( ++ net_get_page_callback_t get_callback, ++ net_put_page_callback_t put_callback) ++{ ++ int res = 0; ++ ++ if ((net_get_page_callback != NULL) && (get_callback != NULL) && ++ (net_get_page_callback != get_callback)) { ++ res = -EBUSY; ++ goto out; ++ } ++ ++ if ((net_put_page_callback != NULL) && (put_callback != NULL) && ++ (net_put_page_callback != put_callback)) { ++ res = -EBUSY; ++ goto out; ++ } ++ ++ net_get_page_callback = get_callback; ++ net_put_page_callback = put_callback; ++ ++out: ++ return res; ++} ++EXPORT_SYMBOL_GPL(net_set_get_put_page_callbacks); + +=== modified file 'net/ipv6/ip6_output.c' +--- old/net/ipv6/ip6_output.c 2014-06-18 01:32:48 +0000 ++++ new/net/ipv6/ip6_output.c 2014-06-18 01:44:08 +0000 +@@ -1461,7 +1461,7 @@ alloc_new_skb: + __skb_fill_page_desc(skb, i, pfrag->page, + pfrag->offset, 0); + skb_shinfo(skb)->nr_frags = ++i; +- get_page(pfrag->page); ++ net_get_page(pfrag->page); + } + copy = min_t(int, copy, pfrag->size - pfrag->offset); + if (getfrag(from, + diff --git a/iscsi-scst/kernel/session.c b/iscsi-scst/kernel/session.c index ddd64adf1..953492276 100644 --- a/iscsi-scst/kernel/session.c +++ b/iscsi-scst/kernel/session.c @@ -25,9 +25,7 @@ struct iscsi_session *session_lookup(struct iscsi_target *target, u64 sid) { struct iscsi_session *session; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target->target_mutex); -#endif list_for_each_entry(session, &target->session_list, session_list_entry) { @@ -46,9 +44,7 @@ static int iscsi_session_alloc(struct iscsi_target *target, struct iscsi_session *session; char *name = NULL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target_mgmt_mutex); -#endif session = kmem_cache_zalloc(iscsi_sess_cache, GFP_KERNEL); if (!session) @@ -138,9 +134,7 @@ void sess_reinst_finished(struct iscsi_session *sess) TRACE_MGMT_DBG("Enabling reinstate successor sess %p", sess); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&sess->target->target_mutex); -#endif sBUG_ON(!sess->sess_reinstating); @@ -165,9 +159,7 @@ int __add_session(struct iscsi_target *target, TRACE_MGMT_DBG("Adding session SID %llx", info->sid); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target_mgmt_mutex); -#endif err = iscsi_session_alloc(target, info, &new_sess); if (err != 0) @@ -318,9 +310,7 @@ int session_free(struct iscsi_session *session, bool del) TRACE_MGMT_DBG("Freeing session %p (SID %llx)", session, session->sid); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&session->target->target_mutex); -#endif sBUG_ON(!list_empty(&session->conn_list)); if (unlikely(atomic_read(&session->active_cmds) != 0)) { @@ -376,9 +366,7 @@ int __del_session(struct iscsi_target *target, u64 sid) { struct iscsi_session *session; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target->target_mutex); -#endif session = session_lookup(target, sid); if (!session) @@ -400,9 +388,7 @@ void iscsi_sess_force_close(struct iscsi_session *sess) TRACE_ENTRY(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&sess->target->target_mutex); -#endif PRINT_INFO("Deleting session %llx with initiator %s (%p)", (long long unsigned int)sess->sid, sess->initiator_name, sess); @@ -424,9 +410,7 @@ static void iscsi_session_info_show(struct seq_file *seq, { struct iscsi_session *session; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target->target_mutex); -#endif list_for_each_entry(session, &target->session_list, session_list_entry) { @@ -442,7 +426,12 @@ static void iscsi_session_info_show(struct seq_file *seq, static int iscsi_session_seq_open(struct inode *inode, struct file *file) { int res; + +#if defined(RHEL_MAJOR) && RHEL_MAJOR -0 <= 5 + res = seq_open(file, (struct seq_operations *)&iscsi_seq_op); +#else res = seq_open(file, &iscsi_seq_op); +#endif if (!res) ((struct seq_file *)file->private_data)->private = iscsi_session_info_show; diff --git a/iscsi-scst/kernel/target.c b/iscsi-scst/kernel/target.c index ef364e541..0c3280d3f 100644 --- a/iscsi-scst/kernel/target.c +++ b/iscsi-scst/kernel/target.c @@ -34,9 +34,7 @@ struct iscsi_target *target_lookup_by_id(u32 id) { struct iscsi_target *target; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target_mgmt_mutex); -#endif list_for_each_entry(target, &target_list, target_list_entry) { if (target->tid == id) @@ -50,9 +48,7 @@ static struct iscsi_target *target_lookup_by_name(const char *name) { struct iscsi_target *target; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target_mgmt_mutex); -#endif list_for_each_entry(target, &target_list, target_list_entry) { if (!strcmp(target->name, name)) @@ -71,9 +67,7 @@ static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid, TRACE_MGMT_DBG("Creating target tid %u, name %s", tid, name); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target_mgmt_mutex); -#endif len = strlen(name); if (!len) { @@ -144,9 +138,7 @@ int __add_target(struct iscsi_kern_target_info *info) struct iscsi_kern_attr __user *attrs_ptr; #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target_mgmt_mutex); -#endif if (nr_targets > MAX_NR_TARGETS) { err = -EBUSY; @@ -262,9 +254,7 @@ int __del_target(u32 id) struct iscsi_target *target; int err; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target_mgmt_mutex); -#endif target = target_lookup_by_id(id); if (!target) { @@ -302,9 +292,7 @@ void target_del_session(struct iscsi_target *target, TRACE_MGMT_DBG("Deleting session %p", session); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target->target_mutex); -#endif if (!list_empty(&session->conn_list)) { struct iscsi_conn *conn, *tc; @@ -330,9 +318,7 @@ void target_del_all_sess(struct iscsi_target *target, int flags) TRACE_ENTRY(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&target->target_mutex); -#endif if (!list_empty(&target->session_list)) { TRACE_MGMT_DBG("Deleting all sessions from target %p", target); diff --git a/iscsi-scst/resource_agents/SCSTLun b/iscsi-scst/resource_agents/SCSTLun index 4e20bd069..eb84596be 100644 --- a/iscsi-scst/resource_agents/SCSTLun +++ b/iscsi-scst/resource_agents/SCSTLun @@ -26,8 +26,7 @@ # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# along with this program. # ####################################################################### diff --git a/iscsi-scst/resource_agents/SCSTTarget b/iscsi-scst/resource_agents/SCSTTarget index c1f4e2ad1..008eeb745 100644 --- a/iscsi-scst/resource_agents/SCSTTarget +++ b/iscsi-scst/resource_agents/SCSTTarget @@ -22,8 +22,7 @@ # other software, or any other product whatsoever. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write the Free Software Foundation, -# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# along with this program. # ####################################################################### diff --git a/iscsi-scst/usr/chap.c b/iscsi-scst/usr/chap.c index 287210a1f..a54309be4 100644 --- a/iscsi-scst/usr/chap.c +++ b/iscsi-scst/usr/chap.c @@ -344,7 +344,8 @@ static int chap_rand(void) fd = open("/dev/urandom", O_RDONLY); assert(fd != -1); - (void)read(fd, &r, sizeof(r)); + if (read(fd, &r, sizeof(r)) < sizeof(r)) { + } close(fd); return r; } diff --git a/iscsi-scst/usr/isns.c b/iscsi-scst/usr/isns.c index 8fa916099..cdd7c3e4e 100644 --- a/iscsi-scst/usr/isns.c +++ b/iscsi-scst/usr/isns.c @@ -16,9 +16,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA + * along with this program. */ #include diff --git a/iscsi-scst/usr/isns_proto.h b/iscsi-scst/usr/isns_proto.h index c9ab970d4..49e45556f 100644 --- a/iscsi-scst/usr/isns_proto.h +++ b/iscsi-scst/usr/isns_proto.h @@ -16,9 +16,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA + * along with this program. */ #ifndef ISNS_PROTO_H diff --git a/mpt/Makefile b/mpt/Makefile index 957c39a1e..f75c73761 100644 --- a/mpt/Makefile +++ b/mpt/Makefile @@ -74,6 +74,7 @@ tgt: Modules.symvers Module.symvers install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ modules_install SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null) diff --git a/mvsas_tgt/Makefile b/mvsas_tgt/Makefile index 5b4db8d9c..30af54767 100644 --- a/mvsas_tgt/Makefile +++ b/mvsas_tgt/Makefile @@ -89,6 +89,7 @@ tgt: Modules.symvers Module.symvers install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ modules_install ins: diff --git a/mvsas_tgt/mv_64xx.c b/mvsas_tgt/mv_64xx.c index 48a450b4f..4b5b00e91 100644 --- a/mvsas_tgt/mv_64xx.c +++ b/mvsas_tgt/mv_64xx.c @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ #include "mv_sas.h" diff --git a/mvsas_tgt/mv_64xx.h b/mvsas_tgt/mv_64xx.h index 179135222..8f3d07f2e 100644 --- a/mvsas_tgt/mv_64xx.h +++ b/mvsas_tgt/mv_64xx.h @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ #ifndef _MVS64XX_REG_H_ diff --git a/mvsas_tgt/mv_94xx.c b/mvsas_tgt/mv_94xx.c index b7404d5f5..ec9612608 100644 --- a/mvsas_tgt/mv_94xx.c +++ b/mvsas_tgt/mv_94xx.c @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ #include "mv_sas.h" diff --git a/mvsas_tgt/mv_94xx.h b/mvsas_tgt/mv_94xx.h index cd1a1f5e7..634cfcb41 100644 --- a/mvsas_tgt/mv_94xx.h +++ b/mvsas_tgt/mv_94xx.h @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ #ifndef _MVS94XX_REG_H_ diff --git a/mvsas_tgt/mv_chips.h b/mvsas_tgt/mv_chips.h index fdad49204..99aa58ed8 100644 --- a/mvsas_tgt/mv_chips.h +++ b/mvsas_tgt/mv_chips.h @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ diff --git a/mvsas_tgt/mv_defs.h b/mvsas_tgt/mv_defs.h index c2bf56ded..090896ae3 100644 --- a/mvsas_tgt/mv_defs.h +++ b/mvsas_tgt/mv_defs.h @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ #ifndef _MV_DEFS_H_ diff --git a/mvsas_tgt/mv_init.c b/mvsas_tgt/mv_init.c index 1994912e4..4e381ba9d 100644 --- a/mvsas_tgt/mv_init.c +++ b/mvsas_tgt/mv_init.c @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ @@ -195,7 +193,7 @@ static void mvs_tasklet(unsigned long opaque) mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; if (unlikely(!mvi)) - BUG_ON(1); + BUG(); for (i = 0; i < core_nr; i++) { mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; diff --git a/mvsas_tgt/mv_sas.c b/mvsas_tgt/mv_sas.c index c3736c705..fe778dc93 100644 --- a/mvsas_tgt/mv_sas.c +++ b/mvsas_tgt/mv_sas.c @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. * * Changelog: * - Praveen Murali May 15, 2012 diff --git a/mvsas_tgt/mv_sas.h b/mvsas_tgt/mv_sas.h index b698fd97f..731343877 100644 --- a/mvsas_tgt/mv_sas.h +++ b/mvsas_tgt/mv_sas.h @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ #ifndef _MV_SAS_H_ diff --git a/mvsas_tgt/mv_spi.c b/mvsas_tgt/mv_spi.c index 2e51e3f2b..35bf89a5c 100644 --- a/mvsas_tgt/mv_spi.c +++ b/mvsas_tgt/mv_spi.c @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ diff --git a/mvsas_tgt/mv_spi.h b/mvsas_tgt/mv_spi.h index f60892b38..04648c62e 100644 --- a/mvsas_tgt/mv_spi.h +++ b/mvsas_tgt/mv_spi.h @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ #ifdef SUPPORT_TARGET diff --git a/mvsas_tgt/mv_tgt.c b/mvsas_tgt/mv_tgt.c index b2c6ff8dd..86c5a49fa 100644 --- a/mvsas_tgt/mv_tgt.c +++ b/mvsas_tgt/mv_tgt.c @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ #ifdef SUPPORT_TARGET @@ -1226,7 +1224,7 @@ static void mvst_do_cmd_completion(struct mvs_info *mvi, TRACE_DBG("Read data command %p finished", cmd); if (err) { cmd->cmd_state = MVST_STATE_SEND_DATA_RETRY; - sBUG_ON(1); + sBUG(); } goto out; } else if (cmd->cmd_state == MVST_STATE_ABORTED) { diff --git a/mvsas_tgt/mv_tgt.h b/mvsas_tgt/mv_tgt.h index 97c422135..0058854f7 100644 --- a/mvsas_tgt/mv_tgt.h +++ b/mvsas_tgt/mv_tgt.h @@ -17,9 +17,7 @@ * General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. */ #ifdef SUPPORT_TARGET diff --git a/nightly/conf/nightly.conf b/nightly/conf/nightly.conf index 268ce0bb2..8248a5a78 100644 --- a/nightly/conf/nightly.conf +++ b/nightly/conf/nightly.conf @@ -3,17 +3,18 @@ ABT_DETAILS="x86_64" ABT_JOBS=5 ABT_KERNELS=" \ -3.14.4 \ -3.13.11 \ -3.12.20-nc \ +3.15.3 \ +3.14.10-nc \ +3.13.11-nc \ +3.12.21-nc \ 3.11.10-nc \ -3.10.40-nc \ +3.10.46-nc \ 3.9.11-nc \ -3.8.13.14-nc \ +3.8.13-nc \ 3.7.10-nc \ -3.6.11.9-nc \ +3.6.11-nc \ 3.5.7-nc \ -3.4.91-nc \ +3.4.96-nc \ 3.3.8-nc \ 3.2.59-nc \ 3.1.10-nc \ @@ -26,7 +27,7 @@ ABT_KERNELS=" \ 2.6.35.14-u-nc \ 2.6.34.14-nc \ 2.6.33.20-nc \ -2.6.32.61-nc \ +2.6.32.62-nc \ 2.6.31.14-nc \ 2.6.30.10-nc \ 2.6.29.6-nc \ diff --git a/qla2x00t/Makefile b/qla2x00t/Makefile index ac628ce9b..b1651b067 100644 --- a/qla2x00t/Makefile +++ b/qla2x00t/Makefile @@ -61,6 +61,7 @@ all: install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ modules_install uninstall: diff --git a/qla2x00t/qla2x00-target/Makefile b/qla2x00t/qla2x00-target/Makefile index 7dbbf0117..67aacf8a1 100644 --- a/qla2x00t/qla2x00-target/Makefile +++ b/qla2x00t/qla2x00-target/Makefile @@ -105,6 +105,7 @@ ifneq ($(BUILD_2X_MODULE),) SCST_INC_DIR=$(SCST_INC_DIR) endif $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ SCST_INC_DIR=$(SCST_INC_DIR) modules_install uninstall: diff --git a/qla2x00t/qla2x00-target/Makefile_in-tree-3.15 b/qla2x00t/qla2x00-target/Makefile_in-tree-3.15 new file mode 100644 index 000000000..9657aee84 --- /dev/null +++ b/qla2x00t/qla2x00-target/Makefile_in-tree-3.15 @@ -0,0 +1,5 @@ +ccflags-y += -Idrivers/scsi/qla2xxx + +qla2x00tgt-y := qla2x00t.o + +obj-$(CONFIG_SCST_QLA_TGT_ADDON) += qla2x00tgt.o diff --git a/qla2x00t/qla2x00-target/README b/qla2x00t/qla2x00-target/README index 386eb4801..d06a7757a 100644 --- a/qla2x00t/qla2x00-target/README +++ b/qla2x00t/qla2x00-target/README @@ -1,7 +1,7 @@ Target driver for QLogic 22xx/23xx/24xx/25xx Fibre Channel cards ================================================================ -Version 3.0.0, XX XXXXX 2014 +Version 3.1.0, XX XXXXX 2014 ---------------------------- This driver consists from two parts: the target mode driver itself and @@ -157,7 +157,7 @@ particular port. Setting this attribute to 1 will reverse current status of the initiator mode from enabled to disabled and vice versa. -Explicit conformation +Explicit confirmation --------------------- This option should (actually, almost always must) be enabled by echoing @@ -281,7 +281,7 @@ Each target subdirectory contains the following entries: of this FC port. It allows to finish configuring it before it starts accepting new connections. 0 by default. - - explicit_confirmation - allows to enable explicit conformations, see + - explicit_confirmation - allows to enable explicit confirmations, see above. - rel_tgt_id - allows to read or write SCSI Relative Target Port diff --git a/qla2x00t/qla2x00-target/qla2x00t.c b/qla2x00t/qla2x00-target/qla2x00t.c index 346d6df25..3741f88fa 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.c +++ b/qla2x00t/qla2x00-target/qla2x00t.c @@ -4956,7 +4956,7 @@ static void q2x_send_busy(scsi_qla_host_t *ha, atio_entry_t *atio) ctio->flags |= cpu_to_le16(OF_INC_RC); /* * CTIO from fw w/o scst_cmd doesn't provide enough info to retry it, - * if the explicit conformation is used. + * if the explicit confirmation is used. */ TRACE_BUFFER("CTIO BUSY packet data", ctio, REQUEST_ENTRY_SIZE); @@ -5017,7 +5017,7 @@ static void q24_send_busy(scsi_qla_host_t *ha, atio7_entry_t *atio, CTIO7_FLAGS_DONT_RET_CTIO); /* * CTIO from fw w/o scst_cmd doesn't provide enough info to retry it, - * if the explicit conformation is used. + * if the explicit confirmation is used. */ ctio->ox_id = swab16(atio->fcp_hdr.ox_id); ctio->scsi_status = cpu_to_le16(status); @@ -5606,7 +5606,7 @@ static void q2t_exec_sess_work(struct q2t_tgt *tgt, loop_id = GET_TARGET_ID(ha, &prm->tm_iocb); break; default: - sBUG_ON(1); + sBUG(); break; } @@ -5683,7 +5683,7 @@ send: break; } default: - sBUG_ON(1); + sBUG(); break; } @@ -5733,7 +5733,7 @@ out_term: 0, 0, 0, 0, 0); break; default: - sBUG_ON(1); + sBUG(); break; } goto out_put; @@ -6355,12 +6355,12 @@ static ssize_t q2t_store_expl_conf_enabled(struct kobject *kobj, switch (buffer[0]) { case '0': ha->enable_explicit_conf = 0; - PRINT_INFO("qla2x00t(%ld): explicit conformations disabled", + PRINT_INFO("qla2x00t(%ld): explicit confirmations disabled", ha->instance); break; case '1': ha->enable_explicit_conf = 1; - PRINT_INFO("qla2x00t(%ld): explicit conformations enabled", + PRINT_INFO("qla2x00t(%ld): explicit confirmations enabled", ha->instance); break; default: diff --git a/qla2x00t/qla2x00-target/qla2x00t.h b/qla2x00t/qla2x00-target/qla2x00t.h index e8bae79c9..21c4632d1 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.h +++ b/qla2x00t/qla2x00-target/qla2x00t.h @@ -30,8 +30,8 @@ /* Version numbers, the same as for the kernel */ #define Q2T_VERSION(a, b, c, d) (((a) << 030) + ((b) << 020) + (c) << 010 + (d)) -#define Q2T_VERSION_CODE Q2T_VERSION(3, 0, 0, 0) -#define Q2T_VERSION_STRING "3.0.0-pre2" +#define Q2T_VERSION_CODE Q2T_VERSION(3, 1, 0, 0) +#define Q2T_VERSION_STRING "3.1.0-pre1" #define Q2T_PROC_VERSION_NAME "version" #define Q2T_MAX_CDB_LEN 16 diff --git a/qla2x00t/qla_attr.c b/qla2x00t/qla_attr.c index 993c404e3..1df02d8ee 100644 --- a/qla2x00t/qla_attr.c +++ b/qla2x00t/qla_attr.c @@ -192,12 +192,12 @@ qla2x00_store_expl_conf_enabled(struct device *dev, switch (buffer[0]) { case '0': ha->enable_explicit_conf = 0; - qla_printk(KERN_INFO, ha, "qla2xxx(%ld): explicit conformation " + qla_printk(KERN_INFO, ha, "qla2xxx(%ld): explicit confirmation " "disabled\n", ha->instance); break; case '1': ha->enable_explicit_conf = 1; - qla_printk(KERN_INFO, ha, "qla2xxx(%ld): explicit conformation " + qla_printk(KERN_INFO, ha, "qla2xxx(%ld): explicit confirmation " "enabled\n", ha->instance); break; default: diff --git a/qla_isp/LICENSE b/qla_isp/LICENSE index 5a91588b4..93e55eea9 100644 --- a/qla_isp/LICENSE +++ b/qla_isp/LICENSE @@ -38,8 +38,7 @@ is the GNU Public License: GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. Matthew Jacob diff --git a/qla_isp/common/isp.c b/qla_isp/common/isp.c index a66e95772..6ef236ad8 100644 --- a/qla_isp/common/isp.c +++ b/qla_isp/common/isp.c @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/common/isp_library.c b/qla_isp/common/isp_library.c index 256cdda41..fc7247e7e 100644 --- a/qla_isp/common/isp_library.c +++ b/qla_isp/common/isp_library.c @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/common/isp_library.h b/qla_isp/common/isp_library.h index 95fb49dad..9a2f65610 100644 --- a/qla_isp/common/isp_library.h +++ b/qla_isp/common/isp_library.h @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/common/isp_stds.h b/qla_isp/common/isp_stds.h index 5c4ee3fcb..432551def 100644 --- a/qla_isp/common/isp_stds.h +++ b/qla_isp/common/isp_stds.h @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/common/isp_target.c b/qla_isp/common/isp_target.c index fe8966d0a..b25da91fb 100644 --- a/qla_isp/common/isp_target.c +++ b/qla_isp/common/isp_target.c @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/common/isp_target.h b/qla_isp/common/isp_target.h index c957d1290..d3d380bd5 100644 --- a/qla_isp/common/isp_target.h +++ b/qla_isp/common/isp_target.h @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/common/isp_tpublic.h b/qla_isp/common/isp_tpublic.h index 364d76f1b..f55cdaf13 100644 --- a/qla_isp/common/isp_tpublic.h +++ b/qla_isp/common/isp_tpublic.h @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/common/ispmbox.h b/qla_isp/common/ispmbox.h index 9e1a829dd..a4ad35f1d 100644 --- a/qla_isp/common/ispmbox.h +++ b/qla_isp/common/ispmbox.h @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/common/ispreg.h b/qla_isp/common/ispreg.h index 1d2894581..a3eb744bb 100644 --- a/qla_isp/common/ispreg.h +++ b/qla_isp/common/ispreg.h @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/common/ispvar.h b/qla_isp/common/ispvar.h index 008e6ded9..4e627fdf5 100644 --- a/qla_isp/common/ispvar.h +++ b/qla_isp/common/ispvar.h @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/firmware/fwbin b/qla_isp/firmware/fwbin index fe00b5980..71d282c99 100755 --- a/qla_isp/firmware/fwbin +++ b/qla_isp/firmware/fwbin @@ -42,8 +42,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# along with this program. # # # Matthew Jacob diff --git a/qla_isp/linux-2.6/Makefile b/qla_isp/linux-2.6/Makefile index 5c669c9e1..8a3fdd83c 100644 --- a/qla_isp/linux-2.6/Makefile +++ b/qla_isp/linux-2.6/Makefile @@ -14,8 +14,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# along with this program. # # # Matthew Jacob @@ -53,7 +52,9 @@ extraclean: clean rm -f *.orig *.rej install: - @$(MAKE) -C ${LINUX} M=${CURDIR}/build modules_install + @$(MAKE) -C ${LINUX} M=${CURDIR}/build \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ + modules_install install_host_progs: @$(MAKE) -C build $@ diff --git a/qla_isp/linux-2.6/build/Makefile b/qla_isp/linux-2.6/build/Makefile index 96ba94801..db836c075 100644 --- a/qla_isp/linux-2.6/build/Makefile +++ b/qla_isp/linux-2.6/build/Makefile @@ -12,8 +12,7 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# along with this program. # # # Matthew Jacob diff --git a/qla_isp/linux/isp_cb_ops.c b/qla_isp/linux/isp_cb_ops.c index b906047d0..fc8ec4b5b 100644 --- a/qla_isp/linux/isp_cb_ops.c +++ b/qla_isp/linux/isp_cb_ops.c @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/linux/isp_ioctl.h b/qla_isp/linux/isp_ioctl.h index 9d64ca277..8184ca9ff 100644 --- a/qla_isp/linux/isp_ioctl.h +++ b/qla_isp/linux/isp_ioctl.h @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/linux/isp_linux.c b/qla_isp/linux/isp_linux.c index 60049a804..f907c3bec 100644 --- a/qla_isp/linux/isp_linux.c +++ b/qla_isp/linux/isp_linux.c @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/linux/isp_linux.h b/qla_isp/linux/isp_linux.h index 3a10e2588..331d4f896 100644 --- a/qla_isp/linux/isp_linux.h +++ b/qla_isp/linux/isp_linux.h @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/linux/isp_pci.c b/qla_isp/linux/isp_pci.c index c5d2b5bb2..b6d9ffa0e 100644 --- a/qla_isp/linux/isp_pci.c +++ b/qla_isp/linux/isp_pci.c @@ -40,8 +40,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/qla_isp/linux/isp_scst.c b/qla_isp/linux/isp_scst.c index 1d683a0b3..f9e0c7102 100644 --- a/qla_isp/linux/isp_scst.c +++ b/qla_isp/linux/isp_scst.c @@ -39,8 +39,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * along with this program. * * * Matthew Jacob diff --git a/scripts/generate-patched-kernel b/scripts/generate-patched-kernel index 94d139b77..a0cbdbb96 100755 --- a/scripts/generate-patched-kernel +++ b/scripts/generate-patched-kernel @@ -19,37 +19,24 @@ ############################################################################ -######################## -# Function definitions # -######################## - -source $(dirname $0)/kernel-functions - function usage { echo "Usage: $0 " } -######################### -# Argument verification # -######################### +script_dir="$(dirname $0)" +if [ "${script_dir#/}" = "${script_dir}" ]; then + script_dir="$PWD/$script_dir" +fi +scst_dir="$(dirname "${script_dir}")" -set -e +source "${script_dir}/kernel-functions" if [ "$1" = "" ]; then echo "Error: missing kernel version argument." exit 1 fi - -########################## -# Kernel tree generation # -########################## - -scriptname="$0" -if [ "${scriptname#/}" = "${scriptname}" ]; then - scriptname="$PWD/$scriptname" -fi target="linux-$1" kernel_version="$(kernel_version "$1")" patchlevel="$(patchlevel "$1")" @@ -60,15 +47,13 @@ extract_kernel_tree "$1" || exit $? cd "${target}" || exit $? -list-source-files "$(dirname "$(dirname "$scriptname")")" \ -| grep -- "-${kernel_version}.*.patch$" \ -| grep -v /in-tree/ \ -| while read p - do +list-source-files "${scst_dir}" | + grep -- "-${kernel_version}.*.patch$" | + grep -v /in-tree/ | + while read p; do if [ "${p/readahead-2.6.32.below11.patch//}" = "$p" \ - -o "${patchlevel:-0}" -lt 11 ] - then + -o "${patchlevel:-0}" -lt 11 ]; then echo "==== $p" - patch -p1 <$p + patch -p1 <"${scst_dir}/$p" fi done diff --git a/scripts/kernel-functions b/scripts/kernel-functions index 58751563f..ce527498e 100644 --- a/scripts/kernel-functions +++ b/scripts/kernel-functions @@ -2,7 +2,7 @@ # Shell functions for parsing the Linux kernel version and for downloading # from kernel.org. -kernel_mirror="ftp://ftp.kernel.org/pub/linux/kernel" +kernel_mirror="http://ftp.kernel.org/pub/linux/kernel" kernel_longterm="http://www.kernel.org/pub/linux/kernel" kernel_sources="$HOME/software/downloads" @@ -53,9 +53,9 @@ function download_kernel { test -w "${kernel_sources}" || return $? ( cd "${kernel_sources}" || return $? - if [ "$plevel" = "" ] \ - || download_file "${kernel_mirror}/v$series/patch-$1.xz" \ - || download_file "${kernel_mirror}/v$series/longterm/v${kver}/patch-$1.xz" + if [ "$plevel" = "" -o "$plevel" = "0" ] || + download_file "${kernel_mirror}/v$series/patch-$1.xz" || + download_file "${kernel_mirror}/v$series/longterm/v${kver}/patch-$1.xz" then download_file "${kernel_mirror}/v$series/linux-${kver}.tar.xz" \ || download_file "${kernel_mirror}/v$series/longterm/v${kver}/linux-${kver}.tar.xz" \ @@ -87,14 +87,17 @@ function extract_kernel_tree { mkdir "${tmpdir}" || return $? ( cd "${tmpdir}" || return $? - if [ "$plevel" != "" -a -e "${kernel_sources}/patch-$1.xz" ]; then + if [ "$plevel" != "" -a "$plevel" != "0" -a \ + -e "${kernel_sources}/patch-$1.xz" ]; then extract_kernel_archive $kver || return $? mv linux-$kver linux-$1 ( cd linux-$1 && xz -cd "${kernel_sources}/patch-$1.xz" \ | patch -p1 -f -s; ) \ || return $? else - extract_kernel_archive $1 || return $? + extract_kernel_archive $1 || + { extract_kernel_archive $kver && mv linux-$kver linux-$1; } || + return $? fi mv "linux-$1" ".." || return $? cd "../linux-$1" || return $? diff --git a/scripts/rebuild-rhel-kernel-rpm b/scripts/rebuild-rhel-kernel-rpm index b881fe4db..88c93d16d 100755 --- a/scripts/rebuild-rhel-kernel-rpm +++ b/scripts/rebuild-rhel-kernel-rpm @@ -85,6 +85,9 @@ case "$distro" in srpm_url=("http://ftp.scientificlinux.org/linux/scientific/$releasevermajor$releaseverminor/SRPMS/vendor") fi ;; + "Fedora") + srpm_url="http://ftp.redhat.com/redhat/rhel/rc/7/Server/source/tree/Packages" + ;; *) echo "Unknown type of distribution: $distro" exit 1 @@ -183,7 +186,10 @@ log "Copying SCST patches to the SOURCES directory" cd ${rpmbuild_dir}/SOURCES copy_patch $scst_dir/scst/kernel/rhel/scst_exec_req_fifo-${kver}.patch scst_exec_req_fifo.patch -copy_patch $scst_dir/iscsi-scst/kernel/patches/rhel/put_page_callback-${kver}.patch put_page_callback.patch +f="$scst_dir/iscsi-scst/kernel/patches/rhel/put_page_callback-${kver}.patch" +if [ -e "$f" ]; then + copy_patch "$f" put_page_callback.patch +fi log "Adding SCST patches in kernel.spec" @@ -319,6 +325,49 @@ diff -u SPECS/kernel.spec{.orig,} make ARCH=$Arch %{oldconfig_target} > /dev/null echo "# $Arch" > configs/$i EOF +elif [ ${kver#3.10.0-121} != $kver ]; then +# RHEL/CentOS/SL 7.0 +patch -p1 ${rpmbuild_dir}/SPECS/kernel.spec <<'EOF' || exit $? +--- kernel.spec.orig 2014-05-23 10:09:17.707202148 +0200 ++++ kernel.spec 2014-05-23 10:15:50.883937952 +0200 +@@ -4,6 +4,7 @@ + Summary: The Linux kernel + + # % define buildid .local ++%define buildid .scst + + # For a stable, released kernel, released_kernel should be 1. For rawhide + # and/or a kernel built from an rc or git snapshot, released_kernel should +@@ -367,6 +368,9 @@ + Source2000: cpupower.service + Source2001: cpupower.config + ++Patch200: scst_exec_req_fifo.patch ++#Patch201: put_page_callback.patch ++ + # empty final patch to facilitate testing of kernel patches + Patch999999: linux-kernel-test.patch + +@@ -668,6 +672,9 @@ + # Drop some necessary files from the source dir into the buildroot + cp $RPM_SOURCE_DIR/kernel-%{version}-*.config . + ++ApplyPatch scst_exec_req_fifo.patch ++#ApplyPatch put_page_callback.patch ++ + ApplyOptionalPatch linux-kernel-test.patch + + # Any further pre-build tree manipulations happen here. +@@ -700,6 +707,8 @@ + for i in *.config + do + mv $i .config ++ echo "CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION=y" >> .config ++ sed -i.tmp -e 's/^CONFIG_SCSI_QLA_FC=.*/CONFIG_SCSI_QLA_FC=n/' .config + Arch=`head -1 .config | cut -b 3-` + make %{?cross_opts} ARCH=$Arch listnewconfig | grep -E '^CONFIG_' >.newoptions || true + %if %{listnewconfig_fail} +EOF else log "Unrecognized kernel version ${kver}" fi @@ -327,7 +376,7 @@ log "Rebuilding kernel" cd ${rpmbuild_dir}/SPECS { - rpmbuild -bb --target=${arch} --with baseonly --with firmware --without kabichk kernel*.spec + rpmbuild -bb --target=${arch} --nodeps --with baseonly --with firmware --without kabichk kernel*.spec rc=$? if [ $rc != 0 ]; then exit $rc diff --git a/scripts/run-regression-tests b/scripts/run-regression-tests index bae2ad0a5..f792254c4 100755 --- a/scripts/run-regression-tests +++ b/scripts/run-regression-tests @@ -263,30 +263,32 @@ CONFIG_TRACING CONFIG_X86_32 \ " echo "Patching and configuring kernel ..." + if [ "$ipv6" = "false" ]; then + disable="$disable CONFIG_IPV6" + fi ( local srcdir="$PWD" - cd "${outputdir}/linux-$1" \ - && if [ "${multiple_patches}" = "false" ]; then - patch -p1 -f -s <"${patchfile}" >"${patchoutput}" - else - rm -f "${patchoutput}" - for p in "${outputdir}/${patchdir}"/* - do - echo "==== $p" >>"${patchoutput}" - patch -p1 -f -s <"${p}" >>"${patchoutput}" 2>&1 - done - fi \ - && if [ -e $srcdir/srpt/patches/kernel-${kver}-pre-cflags.patch ]; then - echo "$srcdir/srpt/patches/kernel-${kver}-pre-cflags.patch ..." \ + cd "${outputdir}/linux-$1" && + if [ "${multiple_patches}" = "false" ]; then + patch -p1 -f -s <"${patchfile}" >"${patchoutput}" + else + rm -f "${patchoutput}" + for p in "${outputdir}/${patchdir}"/*; do + echo "==== $p" >>"${patchoutput}" + patch -p1 -f -s <"${p}" >>"${patchoutput}" 2>&1 + done + fi && + if [ -e $srcdir/srpt/patches/kernel-${kver}-pre-cflags.patch ]; then + echo "$srcdir/srpt/patches/kernel-${kver}-pre-cflags.patch ..." \ >>"${patchoutput}" - patch -p1 -f -s <$srcdir/srpt/patches/kernel-${kver}-pre-cflags.patch \ - >>"${patchoutput}"; - else - echo "srpt/patches/kernel-${kver}-pre-cflags.patch not found."; \ - fi \ - && make -s allmodconfig &>"${outputdir}/make-config-output.txt" \ - && for c in $disable; do sed -i.tmp "s/^$c=y\$/$c=n/" .config; done \ - && make -s oldconfig &>/dev/null + patch -p1 -f -s <$srcdir/srpt/patches/kernel-${kver}-pre-cflags.patch \ + >>"${patchoutput}" + else + echo "srpt/patches/kernel-${kver}-pre-cflags.patch not found." + fi && + make -s allmodconfig &>"${outputdir}/make-config-output.txt" && + for c in $disable; do sed -i.tmp "s/^$c=[ym]\$/$c=n/" .config; done && + make -s oldconfig &>/dev/null ) } @@ -492,7 +494,7 @@ fi # Where to store persistenly downloaded kernel tarballs and kernel patches. kernel_sources="$HOME/software/downloads" # URL for downloading kernel tarballs and kernel patches. -kernel_mirror="ftp://ftp.kernel.org/pub/linux/kernel" +kernel_mirror="http://ftp.kernel.org/pub/linux/kernel" kernel_longterm="http://www.kernel.org/pub/linux/kernel" kernel_versions="" # Directory in which the regression test output files will be stored. Must be @@ -585,6 +587,7 @@ do run_checkpatch="true" run_sparse="true" run_smatch="true" + ipv6="true" global_multiple_patches="${multiple_patches}" while [ "${kv%-?}" != "${kv}" -o "${kv%-??}" != "${kv}" ]; do kv_without_opt="${kv%-?}" @@ -593,6 +596,7 @@ do fi kopt="${kv#${kv_without_opt}}" case "${kopt}" in + '-4') ipv6="false";; '-f') full_check="true";; '-i') ibmvio="true";; '-nc') run_checkpatch="false";; diff --git a/scst.spec.in b/scst.spec.in index 579888487..535875b0d 100644 --- a/scst.spec.in +++ b/scst.spec.in @@ -90,6 +90,8 @@ rm -f /usr/local/man/man8/iscsi-scstd.8 rm -f /usr/local/sbin/iscsi-scst-adm rm -f /usr/local/sbin/iscsi-scstd rm -rf /usr/local/include/scst +# Remove existing ib_srpt.ko kernel modules +find /lib/modules/%{kver} -name ib_srpt.ko -exec rm {} \; %post /sbin/depmod -a %{kver} diff --git a/scst/COPYING b/scst/COPYING index 6fa77f597..d2469d5dd 100644 --- a/scst/COPYING +++ b/scst/COPYING @@ -2,7 +2,6 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -304,8 +303,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + along with this program. Also add information on how to contact you by electronic and paper mail. diff --git a/scst/README b/scst/README index 1f42e569e..110630d72 100644 --- a/scst/README +++ b/scst/README @@ -1,7 +1,7 @@ Generic SCSI target mid-level for Linux (SCST) ============================================== -Version 3.0.0, XX XXXXX 2014 +Version 3.1.0, XX XXXXX 2014 ---------------------------- SCST is designed to provide unified, consistent interface between SCSI @@ -982,7 +982,7 @@ Intended to be used for performance measurements at the same way as blocksize, read_only, removable, tst. See vdisk_fileio above for description of those parameters. -vdisk_nullio also has extra attribute: +vdisk_nullio devices have the following two additional attributes: - dummy - if this flag is set, LUNs corresponding to this device will not appear at the initiator side. This is because SCST will set the @@ -991,6 +991,13 @@ vdisk_nullio also has extra attribute: See also SPC-4 for more information. It is designed to be used as a "dummy" placeholder on LUN 0, if LUN 0 is not desired. + - read_zero - if this flag is set, reading from a vdisk_nullio device + returns a buffer filled with byte 0x00. If this flag is cleared + (which is the default behavior), the buffer returned to the + initiator is not cleared. Although this results in slightly faster + operation this is a security hole since any data that is present in + kernel memory can be returned to the initiator. + Handler vcdrom allows emulation of a virtual CDROM device using an ISO file as backend. It has only single parameter: tst. diff --git a/scst/README_in-tree b/scst/README_in-tree index 739647867..18b10cded 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -840,7 +840,7 @@ Intended to be used for performance measurements at the same way as blocksize, read_only, removable, tst. See vdisk_fileio above for description of those parameters. -vdisk_nullio also has extra attribute: +vdisk_nullio devices have the following two additional attributes: - dummy - if this flag is set, LUNs corresponding to this device will not appear at the initiator side. This is because SCST will set the @@ -849,6 +849,13 @@ vdisk_nullio also has extra attribute: See also SPC-4 for more information. It is designed to be used as a "dummy" placeholder on LUN 0, if LUN 0 is not desired. + - read_zero - if this flag is set, reading from a vdisk_nullio device + returns a buffer filled with byte 0x00. If this flag is cleared + (which is the default behavior), the buffer returned to the + initiator is not cleared. Although this results in slightly faster + operation this is a security hole since any data that is present in + kernel memory can be returned to the initiator. + Handler vcdrom allows emulation of a virtual CDROM device using an ISO file as backend. It has only single parameter: tst. diff --git a/scst/include/scst.h b/scst/include/scst.h index 66cb6d685..28e79fc02 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -79,6 +79,14 @@ typedef _Bool bool; #define __aligned __attribute__((aligned)) #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) +char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap); +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) +#define lockdep_assert_held(l) do { (void)(l); } while (0) +#endif + #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32) #ifndef O_DSYNC #define O_DSYNC O_SYNC @@ -119,13 +127,6 @@ typedef _Bool bool; #define nr_cpumask_bits NR_CPUS #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) -#ifndef swap -#define swap(a, b) \ - do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) -#endif -#endif - /* verify cpu argument to cpumask_* operators */ static inline unsigned int cpumask_check(unsigned int cpu) { @@ -172,6 +173,27 @@ static inline void cpumask_copy(cpumask_t *dstp, { bitmap_copy(cpumask_bits(dstp), cpumask_bits(srcp), nr_cpumask_bits); } + +/** + * cpumask_setall - set all cpus (< nr_cpu_ids) in a cpumask + * @dstp: the cpumask pointer + */ +static inline void cpumask_setall(cpumask_t *dstp) +{ + bitmap_fill(cpumask_bits(dstp), nr_cpumask_bits); +} + +/** + * cpumask_equal - *src1p == *src2p + * @src1p: the first input + * @src2p: the second input + */ +static inline bool cpumask_equal(const cpumask_t *src1p, + const cpumask_t *src2p) +{ + return bitmap_equal(cpumask_bits(src1p), cpumask_bits(src2p), + nr_cpumask_bits); +} #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) && \ @@ -179,6 +201,13 @@ static inline void cpumask_copy(cpumask_t *dstp, #define set_cpus_allowed_ptr(p, new_mask) set_cpus_allowed((p), *(new_mask)) #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) +#ifndef swap +#define swap(a, b) \ + do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) +#endif +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) static inline unsigned int queue_max_hw_sectors(struct request_queue *q) { @@ -186,6 +215,16 @@ static inline unsigned int queue_max_hw_sectors(struct request_queue *q) } #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) +/* + * See also patch "kernel.h: add pr_warn for symmetry to dev_warn, + * netdev_warn" (commit fc62f2f19edf46c9bdbd1a54725b56b18c43e94f). + */ +#ifndef pr_warn +#define pr_warn pr_warning +#endif +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) /* * See also patch "sched: Fix softirq time accounting" (commit ID @@ -1909,6 +1948,13 @@ struct scst_order_data { spinlock_t init_done_lock; }; +struct scst_orig_sg_data { + int *p_orig_sg_cnt; + int orig_sg_cnt; + struct scatterlist *orig_sg_entry; + int orig_entry_offs, orig_entry_len; +}; + /* * SCST command, analog of I_T_L_Q nexus or task */ @@ -1998,9 +2044,7 @@ struct scst_cmd { /* Set if the target driver called scst_set_expected() */ unsigned int expected_values_set:1; - /* - * Set if the SG buffer was modified by scst_adjust_sg() - */ + /* Set if the SG buffer was modified by scst_adjust_sg() */ unsigned int sg_buff_modified:1; /* @@ -2229,11 +2273,8 @@ struct scst_cmd { /* Used for storage of dev handler private stuff */ void *dh_priv; - /* Used to restore sg if it was modified by scst_adjust_sg() */ - int *p_orig_sg_cnt; - int orig_sg_cnt; - struct scatterlist *orig_sg_entry; - int orig_entry_offs, orig_entry_len; + /* List entry for dev's blocked_cmd_list */ + struct list_head blocked_cmd_list_entry; /* Used to retry commands in case of double UA */ int dbl_ua_orig_resp_data_len, dbl_ua_orig_data_direction; @@ -2244,18 +2285,24 @@ struct scst_cmd { */ struct list_head mgmt_cmd_list; - /* List entry for dev's blocked_cmd_list */ - struct list_head blocked_cmd_list_entry; + /* Used to restore sg if it was modified by scst_adjust_sg() */ + struct scst_orig_sg_data orig_sg; - /* Counter of the corresponding SCST_PR_ABORT_ALL TM commands */ - struct scst_pr_abort_all_pending_mgmt_cmds_counter *pr_abort_counter; + /* Per opcode stuff */ + union { + /* Counter of the corresponding SCST_PR_ABORT_ALL TM commands */ + struct scst_pr_abort_all_pending_mgmt_cmds_counter *pr_abort_counter; - /* - * List of parsed data descriptors for commands operating with - * several lba and data_len pairs, like UNMAP, and its size in elements. - */ - void *cmd_data_descriptors; - int cmd_data_descriptors_cnt; + /* + * List of parsed data descriptors for commands operating with + * several lba and data_len pairs, like UNMAP, and its size + * in elements. + */ + struct { + void *cmd_data_descriptors; + int cmd_data_descriptors_cnt; + }; + }; #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) char not_parsed_op_name[8]; @@ -2780,6 +2827,9 @@ struct scst_acg_dev { * control information. */ struct scst_acg { + /* One more than the number of sessions in acg_sess_list */ + struct kref acg_kref; + /* Owner target */ struct scst_tgt *tgt; @@ -4277,11 +4327,16 @@ static inline int cancel_delayed_work_sync(struct delayed_work *work) #endif #endif -#ifdef CONFIG_DEBUG_LOCK_ALLOC +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && \ + defined(CONFIG_DEBUG_LOCK_ALLOC) extern struct lockdep_map scst_suspend_dep_map; #define scst_assert_activity_suspended() \ WARN_ON(debug_locks && !lock_is_held(&scst_suspend_dep_map)); #else +/* + * See also patch "lockdep: Introduce lockdep_assert_held()" (commit ID + * f607c6685774811b8112e124f10a053d77015485) + */ #define scst_assert_activity_suspended() do { } while (0) #endif diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h index da40be827..3b0e57201 100644 --- a/scst/include/scst_const.h +++ b/scst/include/scst_const.h @@ -42,13 +42,13 @@ * and FIO_REV in usr/fileio/common.h as well. */ #define SCST_VERSION(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + d) -#define SCST_VERSION_CODE SCST_VERSION(3, 0, 0, 0) +#define SCST_VERSION_CODE SCST_VERSION(3, 1, 0, 0) #ifdef CONFIG_SCST_PROC #define SCST_VERSION_STRING_SUFFIX "-procfs" #else #define SCST_VERSION_STRING_SUFFIX #endif -#define SCST_VERSION_NAME "3.0.0-pre2" +#define SCST_VERSION_NAME "3.1.0-pre1" #define SCST_VERSION_STRING SCST_VERSION_NAME SCST_VERSION_STRING_SUFFIX #define SCST_CONST_VERSION "$Revision$" diff --git a/scst/include/scst_debug.h b/scst/include/scst_debug.h index 29b7c6c5f..11a4e5fff 100644 --- a/scst/include/scst_debug.h +++ b/scst/include/scst_debug.h @@ -116,11 +116,13 @@ #endif #endif -#ifdef CONFIG_SCST_EXTRACHECKS +#if defined(CONFIG_SCST_EXTRACHECKS) || defined(__COVERITY__) +#define EXTRACHECKS_BUG() sBUG() #define EXTRACHECKS_BUG_ON(a) sBUG_ON(a) #define EXTRACHECKS_WARN_ON(a) WARN_ON(a) #define EXTRACHECKS_WARN_ON_ONCE(a) WARN_ON_ONCE(a) #else +#define EXTRACHECKS_BUG() do { } while (0) #define EXTRACHECKS_BUG_ON(a) do { } while (0) #define EXTRACHECKS_WARN_ON(a) do { } while (0) #define EXTRACHECKS_WARN_ON_ONCE(a) do { } while (0) diff --git a/scst/kernel/in-tree/Kconfig.drivers.Linux-3.15.patch b/scst/kernel/in-tree/Kconfig.drivers.Linux-3.15.patch new file mode 100644 index 000000000..0d5a19f0f --- /dev/null +++ b/scst/kernel/in-tree/Kconfig.drivers.Linux-3.15.patch @@ -0,0 +1,13 @@ +diff --git a/drivers/Kconfig b/drivers/Kconfig +index aa43b91..c96860e 100644 +--- a/drivers/Kconfig ++++ b/drivers/Kconfig +@@ -24,6 +24,8 @@ source "drivers/ide/Kconfig" + + source "drivers/scsi/Kconfig" + ++source "drivers/scst/Kconfig" ++ + source "drivers/ata/Kconfig" + + source "drivers/md/Kconfig" diff --git a/scst/kernel/in-tree/Makefile.dev_handlers-3.15 b/scst/kernel/in-tree/Makefile.dev_handlers-3.15 new file mode 100644 index 000000000..f933b36f7 --- /dev/null +++ b/scst/kernel/in-tree/Makefile.dev_handlers-3.15 @@ -0,0 +1,14 @@ +ccflags-y += -Wno-unused-parameter + +obj-m := scst_cdrom.o scst_changer.o scst_disk.o scst_modisk.o scst_tape.o \ + scst_vdisk.o scst_raid.o scst_processor.o scst_user.o + +obj-$(CONFIG_SCST_DISK) += scst_disk.o +obj-$(CONFIG_SCST_TAPE) += scst_tape.o +obj-$(CONFIG_SCST_CDROM) += scst_cdrom.o +obj-$(CONFIG_SCST_MODISK) += scst_modisk.o +obj-$(CONFIG_SCST_CHANGER) += scst_changer.o +obj-$(CONFIG_SCST_RAID) += scst_raid.o +obj-$(CONFIG_SCST_PROCESSOR) += scst_processor.o +obj-$(CONFIG_SCST_VDISK) += scst_vdisk.o +obj-$(CONFIG_SCST_USER) += scst_user.o diff --git a/scst/kernel/in-tree/Makefile.drivers.Linux-3.15.patch b/scst/kernel/in-tree/Makefile.drivers.Linux-3.15.patch new file mode 100644 index 000000000..f7213ed4c --- /dev/null +++ b/scst/kernel/in-tree/Makefile.drivers.Linux-3.15.patch @@ -0,0 +1,12 @@ +diff --git a/drivers/Makefile b/drivers/Makefile +index ab93de8..45077ec 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -128,6 +128,7 @@ obj-$(CONFIG_SSB) += ssb/ + obj-$(CONFIG_BCMA) += bcma/ + obj-$(CONFIG_VHOST_RING) += vhost/ + obj-$(CONFIG_VLYNQ) += vlynq/ ++obj-$(CONFIG_SCST) += scst/ + obj-$(CONFIG_STAGING) += staging/ + obj-y += platform/ + #common clk code diff --git a/scst/kernel/in-tree/Makefile.scst-3.15 b/scst/kernel/in-tree/Makefile.scst-3.15 new file mode 100644 index 000000000..53af5f388 --- /dev/null +++ b/scst/kernel/in-tree/Makefile.scst-3.15 @@ -0,0 +1,13 @@ +ccflags-y += -Wno-unused-parameter + +scst-y += scst_main.o +scst-y += scst_pres.o +scst-y += scst_targ.o +scst-y += scst_lib.o +scst-y += scst_sysfs.o +scst-y += scst_mem.o +scst-y += scst_tg.o +scst-y += scst_debug.o + +obj-$(CONFIG_SCST) += scst.o dev_handlers/ fcst/ iscsi-scst/ qla2xxx-target/ \ + srpt/ scst_local/ diff --git a/scst/kernel/rhel/scst_exec_req_fifo-3.10.0-121.el7.patch b/scst/kernel/rhel/scst_exec_req_fifo-3.10.0-121.el7.patch new file mode 120000 index 000000000..6a3acd053 --- /dev/null +++ b/scst/kernel/rhel/scst_exec_req_fifo-3.10.0-121.el7.patch @@ -0,0 +1 @@ +../scst_exec_req_fifo-3.10.patch \ No newline at end of file diff --git a/scst/kernel/scst_exec_req_fifo-3.15.patch b/scst/kernel/scst_exec_req_fifo-3.15.patch new file mode 100644 index 000000000..665cc2606 --- /dev/null +++ b/scst/kernel/scst_exec_req_fifo-3.15.patch @@ -0,0 +1,528 @@ +=== modified file 'block/blk-map.c' +--- old/block/blk-map.c 2014-06-18 01:32:48 +0000 ++++ new/block/blk-map.c 2014-06-18 01:40:34 +0000 +@@ -5,6 +5,8 @@ + #include + #include + #include ++#include ++#include + #include /* for struct sg_iovec */ + + #include "blk.h" +@@ -275,6 +277,337 @@ int blk_rq_unmap_user(struct bio *bio) + } + EXPORT_SYMBOL(blk_rq_unmap_user); + ++struct blk_kern_sg_work { ++ atomic_t bios_inflight; ++ struct sg_table sg_table; ++ struct scatterlist *src_sgl; ++}; ++ ++static void blk_free_kern_sg_work(struct blk_kern_sg_work *bw) ++{ ++ struct sg_table *sgt = &bw->sg_table; ++ struct scatterlist *sg; ++ int i; ++ ++ for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) { ++ struct page *pg = sg_page(sg); ++ if (pg == NULL) ++ break; ++ __free_page(pg); ++ } ++ ++ sg_free_table(sgt); ++ kfree(bw); ++ return; ++} ++ ++static void blk_bio_map_kern_endio(struct bio *bio, int err) ++{ ++ struct blk_kern_sg_work *bw = bio->bi_private; ++ ++ if (bw != NULL) { ++ /* Decrement the bios in processing and, if zero, free */ ++ BUG_ON(atomic_read(&bw->bios_inflight) <= 0); ++ if (atomic_dec_and_test(&bw->bios_inflight)) { ++ if ((bio_data_dir(bio) == READ) && (err == 0)) { ++ unsigned long flags; ++ ++ local_irq_save(flags); /* to protect KMs */ ++ sg_copy(bw->src_sgl, bw->sg_table.sgl, 0, 0); ++ local_irq_restore(flags); ++ } ++ blk_free_kern_sg_work(bw); ++ } ++ } ++ ++ bio_put(bio); ++ return; ++} ++ ++static int blk_rq_copy_kern_sg(struct request *rq, struct scatterlist *sgl, ++ int nents, struct blk_kern_sg_work **pbw, ++ gfp_t gfp, gfp_t page_gfp) ++{ ++ int res = 0, i; ++ struct scatterlist *sg; ++ struct scatterlist *new_sgl; ++ int new_sgl_nents; ++ size_t len = 0, to_copy; ++ struct blk_kern_sg_work *bw; ++ ++ bw = kzalloc(sizeof(*bw), gfp); ++ if (bw == NULL) ++ goto out; ++ ++ bw->src_sgl = sgl; ++ ++ for_each_sg(sgl, sg, nents, i) ++ len += sg->length; ++ to_copy = len; ++ ++ new_sgl_nents = PFN_UP(len); ++ ++ res = sg_alloc_table(&bw->sg_table, new_sgl_nents, gfp); ++ if (res != 0) ++ goto err_free; ++ ++ new_sgl = bw->sg_table.sgl; ++ ++ for_each_sg(new_sgl, sg, new_sgl_nents, i) { ++ struct page *pg; ++ ++ pg = alloc_page(page_gfp); ++ if (pg == NULL) ++ goto err_free; ++ ++ sg_assign_page(sg, pg); ++ sg->length = min_t(size_t, PAGE_SIZE, len); ++ ++ len -= PAGE_SIZE; ++ } ++ ++ if (rq_data_dir(rq) == WRITE) { ++ /* ++ * We need to limit amount of copied data to to_copy, because ++ * sgl might have the last element in sgl not marked as last in ++ * SG chaining. ++ */ ++ sg_copy(new_sgl, sgl, 0, to_copy); ++ } ++ ++ *pbw = bw; ++ /* ++ * REQ_COPY_USER name is misleading. It should be something like ++ * REQ_HAS_TAIL_SPACE_FOR_PADDING. ++ */ ++ rq->cmd_flags |= REQ_COPY_USER; ++ ++out: ++ return res; ++ ++err_free: ++ blk_free_kern_sg_work(bw); ++ res = -ENOMEM; ++ goto out; ++} ++ ++static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, ++ int nents, struct blk_kern_sg_work *bw, gfp_t gfp) ++{ ++ int res; ++ struct request_queue *q = rq->q; ++ int rw = rq_data_dir(rq); ++ int max_nr_vecs, i; ++ size_t tot_len; ++ bool need_new_bio; ++ struct scatterlist *sg, *prev_sg = NULL; ++ struct bio *bio = NULL, *hbio = NULL, *tbio = NULL; ++ int bios; ++ ++ if (unlikely((sgl == NULL) || (sgl->length == 0) || (nents <= 0))) { ++ WARN_ON(1); ++ res = -EINVAL; ++ goto out; ++ } ++ ++ /* ++ * Let's keep each bio allocation inside a single page to decrease ++ * probability of failure. ++ */ ++ max_nr_vecs = min_t(size_t, ++ ((PAGE_SIZE - sizeof(struct bio)) / sizeof(struct bio_vec)), ++ BIO_MAX_PAGES); ++ ++ need_new_bio = true; ++ tot_len = 0; ++ bios = 0; ++ for_each_sg(sgl, sg, nents, i) { ++ struct page *page = sg_page(sg); ++ void *page_addr = page_address(page); ++ size_t len = sg->length, l; ++ size_t offset = sg->offset; ++ ++ tot_len += len; ++ prev_sg = sg; ++ ++ /* ++ * Each segment must be aligned on DMA boundary and ++ * not on stack. The last one may have unaligned ++ * length as long as the total length is aligned to ++ * DMA padding alignment. ++ */ ++ if (i == nents - 1) ++ l = 0; ++ else ++ l = len; ++ if (((sg->offset | l) & queue_dma_alignment(q)) || ++ (page_addr && object_is_on_stack(page_addr + sg->offset))) { ++ res = -EINVAL; ++ goto out_free_bios; ++ } ++ ++ while (len > 0) { ++ size_t bytes; ++ int rc; ++ ++ if (need_new_bio) { ++ bio = bio_kmalloc(gfp, max_nr_vecs); ++ if (bio == NULL) { ++ res = -ENOMEM; ++ goto out_free_bios; ++ } ++ ++ if (rw == WRITE) ++ bio->bi_rw |= REQ_WRITE; ++ ++ bios++; ++ bio->bi_private = bw; ++ bio->bi_end_io = blk_bio_map_kern_endio; ++ ++ if (hbio == NULL) ++ hbio = tbio = bio; ++ else ++ tbio = tbio->bi_next = bio; ++ } ++ ++ bytes = min_t(size_t, len, PAGE_SIZE - offset); ++ ++ rc = bio_add_pc_page(q, bio, page, bytes, offset); ++ if (rc < bytes) { ++ if (unlikely(need_new_bio || (rc < 0))) { ++ if (rc < 0) ++ res = rc; ++ else ++ res = -EIO; ++ goto out_free_bios; ++ } else { ++ need_new_bio = true; ++ len -= rc; ++ offset += rc; ++ continue; ++ } ++ } ++ ++ need_new_bio = false; ++ offset = 0; ++ len -= bytes; ++ page = nth_page(page, 1); ++ } ++ } ++ ++ if (hbio == NULL) { ++ res = -EINVAL; ++ goto out_free_bios; ++ } ++ ++ /* Total length must be aligned on DMA padding alignment */ ++ if ((tot_len & q->dma_pad_mask) && ++ !(rq->cmd_flags & REQ_COPY_USER)) { ++ res = -EINVAL; ++ goto out_free_bios; ++ } ++ ++ if (bw != NULL) ++ atomic_set(&bw->bios_inflight, bios); ++ ++ while (hbio != NULL) { ++ bio = hbio; ++ hbio = hbio->bi_next; ++ bio->bi_next = NULL; ++ ++ blk_queue_bounce(q, &bio); ++ ++ res = blk_rq_append_bio(q, rq, bio); ++ if (unlikely(res != 0)) { ++ bio->bi_next = hbio; ++ hbio = bio; ++ /* We can have one or more bios bounced */ ++ goto out_unmap_bios; ++ } ++ } ++ ++ res = 0; ++ ++ rq->buffer = NULL; ++out: ++ return res; ++ ++out_unmap_bios: ++ blk_rq_unmap_kern_sg(rq, res); ++ ++out_free_bios: ++ while (hbio != NULL) { ++ bio = hbio; ++ hbio = hbio->bi_next; ++ bio_put(bio); ++ } ++ goto out; ++} ++ ++/** ++ * blk_rq_map_kern_sg - map kernel data to a request, for REQ_TYPE_BLOCK_PC ++ * @rq: request to fill ++ * @sgl: area to map ++ * @nents: number of elements in @sgl ++ * @gfp: memory allocation flags ++ * ++ * Description: ++ * Data will be mapped directly if possible. Otherwise a bounce ++ * buffer will be used. ++ */ ++int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, ++ int nents, gfp_t gfp) ++{ ++ int res; ++ ++ res = __blk_rq_map_kern_sg(rq, sgl, nents, NULL, gfp); ++ if (unlikely(res != 0)) { ++ struct blk_kern_sg_work *bw = NULL; ++ ++ res = blk_rq_copy_kern_sg(rq, sgl, nents, &bw, ++ gfp, rq->q->bounce_gfp | gfp); ++ if (unlikely(res != 0)) ++ goto out; ++ ++ res = __blk_rq_map_kern_sg(rq, bw->sg_table.sgl, ++ bw->sg_table.nents, bw, gfp); ++ if (res != 0) { ++ blk_free_kern_sg_work(bw); ++ goto out; ++ } ++ } ++ ++ rq->buffer = NULL; ++ ++out: ++ return res; ++} ++EXPORT_SYMBOL(blk_rq_map_kern_sg); ++ ++/** ++ * blk_rq_unmap_kern_sg - unmap a request with kernel sg ++ * @rq: request to unmap ++ * @err: non-zero error code ++ * ++ * Description: ++ * Unmap a rq previously mapped by blk_rq_map_kern_sg(). Must be called ++ * only in case of an error! ++ */ ++void blk_rq_unmap_kern_sg(struct request *rq, int err) ++{ ++ struct bio *bio = rq->bio; ++ ++ while (bio) { ++ struct bio *b = bio; ++ bio = bio->bi_next; ++ b->bi_end_io(b, err); ++ } ++ rq->bio = NULL; ++ ++ return; ++} ++EXPORT_SYMBOL(blk_rq_unmap_kern_sg); ++ + /** + * blk_rq_map_kern - map kernel data to a request, for REQ_TYPE_BLOCK_PC usage + * @q: request queue where request should be inserted + +=== modified file 'include/linux/blkdev.h' +--- old/include/linux/blkdev.h 2014-06-18 01:32:48 +0000 ++++ new/include/linux/blkdev.h 2014-06-18 01:40:34 +0000 +@@ -717,6 +717,8 @@ extern unsigned long blk_max_low_pfn, bl + #define BLK_DEFAULT_SG_TIMEOUT (60 * HZ) + #define BLK_MIN_SG_TIMEOUT (7 * HZ) + ++#define SCSI_EXEC_REQ_FIFO_DEFINED ++ + #ifdef CONFIG_BOUNCE + extern int init_emergency_isa_pool(void); + extern void blk_queue_bounce(struct request_queue *q, struct bio **bio); +@@ -837,6 +839,9 @@ extern int blk_rq_map_kern(struct reques + extern int blk_rq_map_user_iov(struct request_queue *, struct request *, + struct rq_map_data *, const struct sg_iovec *, + int, unsigned int, gfp_t); ++extern int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl, ++ int nents, gfp_t gfp); ++extern void blk_rq_unmap_kern_sg(struct request *rq, int err); + extern int blk_execute_rq(struct request_queue *, struct gendisk *, + struct request *, int); + extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *, + +=== modified file 'include/linux/scatterlist.h' +--- old/include/linux/scatterlist.h 2014-06-18 01:32:48 +0000 ++++ new/include/linux/scatterlist.h 2014-06-18 01:40:34 +0000 +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + struct sg_table { + struct scatterlist *sgl; /* the list */ +@@ -249,6 +250,9 @@ size_t sg_pcopy_from_buffer(struct scatt + size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents, + void *buf, size_t buflen, off_t skip); + ++int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg, ++ int nents_to_copy, size_t copy_len); ++ + /* + * Maximum number of entries that will be allocated in one piece, if + * a list larger than this is required then chaining will be utilized. + +=== modified file 'lib/scatterlist.c' +--- old/lib/scatterlist.c 2014-06-18 01:32:48 +0000 ++++ new/lib/scatterlist.c 2014-06-18 01:40:34 +0000 +@@ -718,3 +718,127 @@ size_t sg_pcopy_to_buffer(struct scatter + return sg_copy_buffer(sgl, nents, buf, buflen, skip, true); + } + EXPORT_SYMBOL(sg_pcopy_to_buffer); ++ ++ ++/* ++ * Can switch to the next dst_sg element, so, to copy to strictly only ++ * one dst_sg element, it must be either last in the chain, or ++ * copy_len == dst_sg->length. ++ */ ++static int sg_copy_elem(struct scatterlist **pdst_sg, size_t *pdst_len, ++ size_t *pdst_offs, struct scatterlist *src_sg, ++ size_t copy_len) ++{ ++ int res = 0; ++ struct scatterlist *dst_sg; ++ size_t src_len, dst_len, src_offs, dst_offs; ++ struct page *src_page, *dst_page; ++ ++ dst_sg = *pdst_sg; ++ dst_len = *pdst_len; ++ dst_offs = *pdst_offs; ++ dst_page = sg_page(dst_sg); ++ ++ src_page = sg_page(src_sg); ++ src_len = src_sg->length; ++ src_offs = src_sg->offset; ++ ++ do { ++ void *saddr, *daddr; ++ size_t n; ++ ++ saddr = kmap_atomic(src_page + (src_offs >> PAGE_SHIFT)) + ++ (src_offs & ~PAGE_MASK); ++ daddr = kmap_atomic(dst_page + (dst_offs >> PAGE_SHIFT)) + ++ (dst_offs & ~PAGE_MASK); ++ ++ if (((src_offs & ~PAGE_MASK) == 0) && ++ ((dst_offs & ~PAGE_MASK) == 0) && ++ (src_len >= PAGE_SIZE) && (dst_len >= PAGE_SIZE) && ++ (copy_len >= PAGE_SIZE)) { ++ copy_page(daddr, saddr); ++ n = PAGE_SIZE; ++ } else { ++ n = min_t(size_t, PAGE_SIZE - (dst_offs & ~PAGE_MASK), ++ PAGE_SIZE - (src_offs & ~PAGE_MASK)); ++ n = min(n, src_len); ++ n = min(n, dst_len); ++ n = min_t(size_t, n, copy_len); ++ memcpy(daddr, saddr, n); ++ } ++ dst_offs += n; ++ src_offs += n; ++ ++ kunmap_atomic(saddr); ++ kunmap_atomic(daddr); ++ ++ res += n; ++ copy_len -= n; ++ if (copy_len == 0) ++ goto out; ++ ++ src_len -= n; ++ dst_len -= n; ++ if (dst_len == 0) { ++ dst_sg = sg_next(dst_sg); ++ if (dst_sg == NULL) ++ goto out; ++ dst_page = sg_page(dst_sg); ++ dst_len = dst_sg->length; ++ dst_offs = dst_sg->offset; ++ } ++ } while (src_len > 0); ++ ++out: ++ *pdst_sg = dst_sg; ++ *pdst_len = dst_len; ++ *pdst_offs = dst_offs; ++ return res; ++} ++ ++/** ++ * sg_copy - copy one SG vector to another ++ * @dst_sg: destination SG ++ * @src_sg: source SG ++ * @nents_to_copy: maximum number of entries to copy ++ * @copy_len: maximum amount of data to copy. If 0, then copy all. ++ * ++ * Description: ++ * Data from the source SG vector will be copied to the destination SG ++ * vector. End of the vectors will be determined by sg_next() returning ++ * NULL. Returns number of bytes copied. ++ */ ++int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg, ++ int nents_to_copy, size_t copy_len) ++{ ++ int res = 0; ++ size_t dst_len, dst_offs; ++ ++ if (copy_len == 0) ++ copy_len = 0x7FFFFFFF; /* copy all */ ++ ++ if (nents_to_copy == 0) ++ nents_to_copy = 0x7FFFFFFF; /* copy all */ ++ ++ dst_len = dst_sg->length; ++ dst_offs = dst_sg->offset; ++ ++ do { ++ int copied = sg_copy_elem(&dst_sg, &dst_len, &dst_offs, ++ src_sg, copy_len); ++ copy_len -= copied; ++ res += copied; ++ if ((copy_len == 0) || (dst_sg == NULL)) ++ goto out; ++ ++ nents_to_copy--; ++ if (nents_to_copy == 0) ++ goto out; ++ ++ src_sg = sg_next(src_sg); ++ } while (src_sg != NULL); ++ ++out: ++ return res; ++} ++EXPORT_SYMBOL(sg_copy); + diff --git a/scst/src/dev_handlers/Makefile b/scst/src/dev_handlers/Makefile index 464ff06db..f3f8b960d 100644 --- a/scst/src/dev_handlers/Makefile +++ b/scst/src/dev_handlers/Makefile @@ -73,6 +73,7 @@ all: install: all mkdir -p $(DESTDIR)/var/lib/scst/vdev_mode_pages $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ modules_install uninstall: diff --git a/scst/src/dev_handlers/scst_tape.c b/scst/src/dev_handlers/scst_tape.c index 1d4b34faf..ec4e85bc8 100644 --- a/scst/src/dev_handlers/scst_tape.c +++ b/scst/src/dev_handlers/scst_tape.c @@ -214,9 +214,9 @@ static int tape_attach(struct scst_device *dev) mode = (buffer[2] & 0x70) >> 4; speed = buffer[2] & 0x0f; density = buffer[4]; - TRACE_DBG("Tape: lun %d. bs %d. type 0x%02x mode 0x%02x " - "speed 0x%02x dens 0x%02x", dev->scsi_dev->lun, - dev->block_size, medium_type, mode, speed, density); + TRACE_DBG("Tape: lun %lld. bs %d. type 0x%02x mode 0x%02x " + "speed 0x%02x dens 0x%02x", (u64)dev->scsi_dev->lun, + dev->block_size, medium_type, mode, speed, density); } else { PRINT_ERROR("MODE_SENSE failed: %x", rc); res = -ENODEV; diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index e2cf60d26..9f8d9e316 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -826,7 +826,6 @@ static int dev_user_parse(struct scst_cmd *cmd) default: sBUG(); - goto out; } done: @@ -1911,7 +1910,7 @@ again: dev_user_unjam_cmd(u, 0, NULL); goto again; case UCMD_STATE_EXECING: - EXTRACHECKS_BUG_ON(1); + EXTRACHECKS_BUG(); } } } diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index e06591426..f1d752b15 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -80,7 +80,7 @@ static struct scst_trace_log vdisk_local_trace_tbl[] = { #define SCST_FIO_VENDOR "SCST_FIO" #define SCST_BIO_VENDOR "SCST_BIO" /* 4 byte ASCII Product Revision Level - left aligned */ -#define SCST_FIO_REV " 300" +#define SCST_FIO_REV " 310" #define MAX_USN_LEN (20+1) /* For '\0' */ #define MAX_INQ_VEND_SPECIFIC_LEN (INQ_BUF_SZ - 96) @@ -109,6 +109,7 @@ static struct scst_trace_log vdisk_local_trace_tbl[] = { #define DEF_NV_CACHE 0 #define DEF_O_DIRECT 0 #define DEF_DUMMY 0 +#define DEF_READ_ZERO 0 #define DEF_REMOVABLE 0 #define DEF_ROTATIONAL 1 #define DEF_THIN_PROVISIONED 0 @@ -160,6 +161,7 @@ struct scst_vdisk_dev { unsigned int blockio:1; unsigned int cdrom_empty:1; unsigned int dummy:1; + unsigned int read_zero:1; unsigned int removable:1; unsigned int thin_provisioned:1; unsigned int thin_provisioned_manually_set:1; @@ -168,6 +170,7 @@ struct scst_vdisk_dev { unsigned int wt_flag_saved:1; unsigned int tst:3; unsigned int format_active:1; + unsigned int discard_zeroes_data:1; struct file *fd; struct block_device *bdev; @@ -200,6 +203,9 @@ struct scst_vdisk_dev { uint8_t inq_vend_specific[MAX_INQ_VEND_SPECIFIC_LEN]; int inq_vend_specific_len; + /* Unmap INQUIRY parameters */ + uint32_t unmap_opt_gran, unmap_align, unmap_max_lba_cnt; + struct scst_device *dev; struct list_head vdev_list_entry; @@ -349,6 +355,10 @@ static ssize_t vdisk_sysfs_o_direct_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); static ssize_t vdev_sysfs_dummy_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_rz_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_rz_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); static ssize_t vdisk_sysfs_removable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); static ssize_t vdev_sysfs_filename_show(struct kobject *kobj, @@ -421,6 +431,9 @@ static struct kobj_attribute vdisk_o_direct_attr = __ATTR(o_direct, S_IRUGO, vdisk_sysfs_o_direct_show, NULL); static struct kobj_attribute vdev_dummy_attr = __ATTR(dummy, S_IRUGO, vdev_sysfs_dummy_show, NULL); +static struct kobj_attribute vdev_read_zero_attr = + __ATTR(read_zero, S_IWUSR|S_IRUGO, vdev_sysfs_rz_show, + vdev_sysfs_rz_store); static struct kobj_attribute vdisk_removable_attr = __ATTR(removable, S_IRUGO, vdisk_sysfs_removable_show, NULL); static struct kobj_attribute vdisk_filename_attr = @@ -516,6 +529,7 @@ static const struct attribute *vdisk_nullio_attrs[] = { &vdisk_rd_only_attr.attr, &vdisk_tst_attr.attr, &vdev_dummy_attr.attr, + &vdev_read_zero_attr.attr, &vdisk_removable_attr.attr, &vdev_t10_vend_id_attr.attr, &vdev_vend_specific_id_attr.attr, @@ -837,28 +851,30 @@ out: static void vdisk_check_tp_support(struct scst_vdisk_dev *virt_dev) { - struct file *fd; + struct file *fd = NULL; + bool fd_open = false; TRACE_ENTRY(); virt_dev->dev_thin_provisioned = 0; if (virt_dev->rd_only || (virt_dev->filename == NULL)) - goto out_check; + goto check; fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600); if (IS_ERR(fd)) { PRINT_ERROR("filp_open(%s) failed: %ld", virt_dev->filename, PTR_ERR(fd)); - goto out_check; + goto check; } + fd_open = true; if (virt_dev->blockio) { struct inode *inode = fd->f_dentry->d_inode; if (!S_ISBLK(inode->i_mode)) { PRINT_ERROR("%s is NOT a block device", virt_dev->filename); - goto out_close; + goto check; } #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) || (defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6) virt_dev->dev_thin_provisioned = @@ -872,10 +888,7 @@ static void vdisk_check_tp_support(struct scst_vdisk_dev *virt_dev) #endif } -out_close: - filp_close(fd, NULL); - -out_check: +check: if (virt_dev->thin_provisioned_manually_set) { if (virt_dev->thin_provisioned && !virt_dev->dev_thin_provisioned) { PRINT_WARNING("Device %s doesn't support thin " @@ -891,6 +904,45 @@ out_check: } + if (virt_dev->thin_provisioned) { + int block_shift = virt_dev->dev->block_shift; + if (virt_dev->blockio) { + struct request_queue *q; + sBUG_ON(!fd_open); + q = bdev_get_queue(fd->f_dentry->d_inode->i_bdev); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) || \ + (defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6) + virt_dev->unmap_opt_gran = q->limits.discard_granularity >> block_shift; + virt_dev->unmap_align = q->limits.discard_alignment >> block_shift; + virt_dev->unmap_max_lba_cnt = q->limits.max_discard_sectors >> (block_shift - 9); + virt_dev->discard_zeroes_data = q->limits.discard_zeroes_data; +#else + sBUG(); +#endif + } else { + virt_dev->unmap_opt_gran = 1; + virt_dev->unmap_align = 0; + /* 256 MB */ + virt_dev->unmap_max_lba_cnt = (256 * 1024 * 1024) >> block_shift; +#if 0 /* + * Might be a big performance and functionality win, but might be + * dangerous as well. But let's be on the safe side and disable it + * for now. + */ + virt_dev->discard_zeroes_data = 1; +#else + virt_dev->discard_zeroes_data = 0; +#endif + } + TRACE_DBG("unmap_gran %d, unmap_alignment %d, max_unmap_lba %u, " + "discard_zeroes_data %d", virt_dev->unmap_opt_gran, + virt_dev->unmap_align, virt_dev->unmap_max_lba_cnt, + virt_dev->discard_zeroes_data); + } + + if (fd_open) + filp_close(fd, NULL); + TRACE_EXIT(); return; } @@ -1347,9 +1399,7 @@ static void vdisk_detach(struct scst_device *dev) TRACE_ENTRY(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif TRACE_DBG("virt_id %d", dev->virt_id); @@ -1367,9 +1417,7 @@ static int vdisk_open_fd(struct scst_vdisk_dev *virt_dev, bool read_only) { int res; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif sBUG_ON(!virt_dev->filename); virt_dev->fd = vdev_open_fd(virt_dev, read_only); @@ -1390,9 +1438,7 @@ out: static void vdisk_close_fd(struct scst_vdisk_dev *virt_dev) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif if (virt_dev->fd) { filp_close(virt_dev->fd, NULL); @@ -1409,9 +1455,7 @@ static int vdisk_attach_tgt(struct scst_tgt_dev *tgt_dev) TRACE_ENTRY(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif if (virt_dev->tgt_dev_cnt++ > 0) goto out; @@ -1437,9 +1481,7 @@ static void vdisk_detach_tgt(struct scst_tgt_dev *tgt_dev) TRACE_ENTRY(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif if (--virt_dev->tgt_dev_cnt == 0) vdisk_close_fd(virt_dev); @@ -1664,7 +1706,7 @@ static enum compl_status_e vdisk_exec_format_unit(struct vdisk_cmd_params *p) } break; default: - sBUG_ON(1); + sBUG(); break; } } @@ -2407,7 +2449,9 @@ static int prepare_read_page(struct file *filp, int len, unsigned long index, last_index; long end_index, nr; loff_t isize; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) read_descriptor_t desc = { .count = len }; +#endif int error; TRACE_ENTRY(); @@ -2460,8 +2504,13 @@ find_page: /* Did it get truncated before we got the lock? */ if (!page->mapping) goto page_not_up_to_date_locked; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) + if (!mapping->a_ops->is_partially_uptodate(page, + offset & ~PAGE_CACHE_MASK, len)) +#else if (!mapping->a_ops->is_partially_uptodate(page, &desc, offset & ~PAGE_CACHE_MASK)) +#endif goto page_not_up_to_date_locked; unlock_page(page); } @@ -2952,13 +3001,11 @@ static int vdisk_unmap_file_range(struct scst_cmd *cmd, scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_write_error)); res = -EIO; - goto out; } #else res = 0; #endif -out: TRACE_EXIT_RES(res); return res; } @@ -2966,7 +3013,11 @@ out: static int vdisk_unmap_range(struct scst_cmd *cmd, struct scst_vdisk_dev *virt_dev, uint64_t start_lba, uint32_t blocks) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27) int res, err; +#else + int res; +#endif struct file *fd = virt_dev->fd; TRACE_ENTRY(); @@ -3053,6 +3104,14 @@ static void vdisk_exec_write_same_unmap(struct vdisk_cmd_params *p) goto out; } + if (unlikely((uint64_t)cmd->data_len > cmd->dev->max_write_same_len)) { + PRINT_WARNING("Invalid WRITE SAME data len %lld (max allowed " + "%lld)", (long long)cmd->data_len, + (long long)cmd->dev->max_write_same_len); + scst_set_invalid_field_in_cdb(cmd, cmd->len_off, 0); + goto out; + } + rc = vdisk_unmap_range(cmd, virt_dev, cmd->lba, cmd->data_len >> dev->block_shift); if (rc != 0) @@ -3130,6 +3189,7 @@ static enum compl_status_e vdisk_exec_unmap(struct vdisk_cmd_params *p) struct scst_vdisk_dev *virt_dev = cmd->dev->dh_priv; struct scst_data_descriptor *pd = cmd->cmd_data_descriptors; int i, cnt = cmd->cmd_data_descriptors_cnt; + uint32_t blocks_to_unmap; TRACE_ENTRY(); @@ -3150,6 +3210,20 @@ static enum compl_status_e vdisk_exec_unmap(struct vdisk_cmd_params *p) if (pd == NULL) goto out; + /* Sanity check to avoid too long latencies */ + blocks_to_unmap = 0; + for (i = 0; i < cnt; i++) { + blocks_to_unmap += pd[i].sdd_blocks; + if (blocks_to_unmap > virt_dev->unmap_max_lba_cnt) { + PRINT_WARNING("Too many UNMAP LBAs %u (max allowed %u, " + "dev %s)", blocks_to_unmap, + virt_dev->unmap_max_lba_cnt, + virt_dev->dev->virt_name); + scst_set_invalid_field_in_parm_list(cmd, 0, 0); + goto out; + } + } + for (i = 0; i < cnt; i++) { int rc; @@ -3169,68 +3243,339 @@ out: return CMD_SUCCEEDED; } -static void vdev_blockio_get_unmap_params(struct scst_vdisk_dev *virt_dev, - uint32_t *unmap_gran, uint32_t *unmap_alignment, - uint32_t *max_unmap_lba) +/* Supported VPD Pages VPD page (00h). */ +static int vdisk_sup_vpd(uint8_t *buf, struct scst_cmd *cmd, + struct scst_vdisk_dev *virt_dev) { - int block_shift = virt_dev->dev->block_shift; - - TRACE_ENTRY(); - - sBUG_ON(!virt_dev->filename); - - if (virt_dev->blockio) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) || (defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6) - struct file *fd; - struct request_queue *q; - - fd = filp_open(virt_dev->filename, O_LARGEFILE, 0600); - if (IS_ERR(fd)) { - PRINT_ERROR("filp_open(%s) failed: %ld", - virt_dev->filename, PTR_ERR(fd)); - goto out; + buf[3] = 4; + buf[4] = 0x0; /* this page */ + buf[5] = 0x80; /* unit serial number */ + buf[6] = 0x83; /* device identification */ + buf[7] = 0x86; /* extended inquiry */ + if (cmd->dev->type == TYPE_DISK) { + buf[3] += 2; + buf[8] = 0xB0; /* block limits */ + buf[9] = 0xB1; /* block device charachteristics */ + if (virt_dev->thin_provisioned) { + buf[3] += 1; + buf[10] = 0xB2; /* thin provisioning */ } + } + return buf[3] + 4; +} - q = bdev_get_queue(fd->f_dentry->d_inode->i_bdev); - if (q == NULL) { - PRINT_ERROR("No queue for device %s", virt_dev->filename); - goto out_close; - } - - *unmap_gran = q->limits.discard_granularity >> block_shift; - *unmap_alignment = q->limits.discard_alignment >> block_shift; - *max_unmap_lba = q->limits.max_discard_sectors >> (block_shift - 9); - -out_close: - filp_close(fd, NULL); -#else - sBUG_ON(1); -#endif +/* Unit Serial Number VPD page (80h) */ +static int vdisk_usn_vpd(uint8_t *buf, struct scst_cmd *cmd, + struct scst_vdisk_dev *virt_dev) +{ + buf[1] = 0x80; + if (cmd->tgtt->get_serial) { + buf[3] = cmd->tgtt->get_serial(cmd->tgt_dev, &buf[4], + INQ_BUF_SZ - 4); } else { - *unmap_gran = 1; - *unmap_alignment = 0; - *max_unmap_lba = min_t(loff_t, 0xFFFFFFFF, virt_dev->file_size >> block_shift); + int usn_len; + + read_lock(&vdisk_serial_rwlock); + usn_len = strlen(virt_dev->usn); + buf[3] = usn_len; + strncpy(&buf[4], virt_dev->usn, usn_len); + read_unlock(&vdisk_serial_rwlock); + } + return buf[3] + 4; +} + +/* Device Identification VPD page (83h) */ +static int vdisk_dev_id_vpd(uint8_t *buf, struct scst_cmd *cmd, + struct scst_vdisk_dev *virt_dev) +{ + int i, resp_len, num = 4; + uint16_t tg_id; + + buf[1] = 0x83; + + read_lock(&vdisk_serial_rwlock); + i = strlen(virt_dev->scsi_device_name); + if (i > 0) { + /* SCSI target device name */ + buf[num + 0] = 0x3; /* ASCII */ + buf[num + 1] = 0x20 | 0x8; /* Target device SCSI name */ + i += 4 - i % 4; /* align to required 4 bytes */ + scst_copy_and_fill_b(&buf[num + 4], virt_dev->scsi_device_name, + i, '\0'); + + buf[num + 3] = i; + num += buf[num + 3]; + + num += 4; + } + read_unlock(&vdisk_serial_rwlock); + + /* T10 vendor identifier field format (faked) */ + buf[num + 0] = 0x2; /* ASCII */ + buf[num + 1] = 0x1; /* Vendor ID */ + read_lock(&vdisk_serial_rwlock); + scst_copy_and_fill(&buf[num + 4], virt_dev->t10_vend_id, 8); + i = strlen(virt_dev->vend_specific_id); + memcpy(&buf[num + 12], virt_dev->vend_specific_id, i); + read_unlock(&vdisk_serial_rwlock); + + buf[num + 3] = 8 + i; + num += buf[num + 3]; + + num += 4; + + /* + * Relative target port identifier + */ + buf[num + 0] = 0x01; /* binary */ + /* Relative target port id */ + buf[num + 1] = 0x10 | 0x04; + + put_unaligned_be16(cmd->tgt->rel_tgt_id, &buf[num + 4 + 2]); + + buf[num + 3] = 4; + num += buf[num + 3]; + + num += 4; + + tg_id = scst_lookup_tg_id(cmd->dev, cmd->tgt); + if (tg_id) { + /* + * Target port group designator + */ + buf[num + 0] = 0x01; /* binary */ + /* Target port group id */ + buf[num + 1] = 0x10 | 0x05; + + put_unaligned_be16(tg_id, &buf[num + 4 + 2]); + + buf[num + 3] = 4; + num += 4 + buf[num + 3]; } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 32) || (defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6) -out: -#endif - TRACE_DBG("unmap_gran %d, unmap_alignment %d, max_unmap_lba %u", - *unmap_gran, *unmap_alignment, *max_unmap_lba); + /* + * IEEE id + */ + buf[num + 0] = 0x01; /* binary */ - TRACE_EXIT(); - return; + /* EUI-64 */ + buf[num + 1] = 0x02; + buf[num + 2] = 0x00; + buf[num + 3] = 0x08; + + /* IEEE id */ + buf[num + 4] = virt_dev->t10_dev_id[0]; + buf[num + 5] = virt_dev->t10_dev_id[1]; + buf[num + 6] = virt_dev->t10_dev_id[2]; + + /* IEEE ext id */ + buf[num + 7] = virt_dev->t10_dev_id[3]; + buf[num + 8] = virt_dev->t10_dev_id[4]; + buf[num + 9] = virt_dev->t10_dev_id[5]; + buf[num + 10] = virt_dev->t10_dev_id[6]; + buf[num + 11] = virt_dev->t10_dev_id[7]; + num += buf[num + 3]; + + resp_len = num; + put_unaligned_be16(resp_len, &buf[2]); + resp_len += 4; + + return resp_len; +} + +/* Extended INQUIRY Data (86h) */ +static int vdisk_ext_inq(uint8_t *buf, struct scst_cmd *cmd, + struct scst_vdisk_dev *virt_dev) +{ + buf[1] = 0x86; + buf[3] = 0x3C; + buf[5] = 7; /* HEADSUP=1, ORDSUP=1, SIMPSUP=1 */ + buf[6] = (virt_dev->wt_flag || virt_dev->nv_cache) ? 0 : 1; /* V_SUP */ + buf[7] = 1; /* LUICLR=1 */ + return buf[3] + 4; +} + +/* Block Limits VPD page (B0h) */ +static int vdisk_block_limits(uint8_t *buf, struct scst_cmd *cmd, + struct scst_vdisk_dev *virt_dev) +{ + struct scst_device *dev = cmd->dev; + int max_transfer; + + buf[1] = 0xB0; + buf[3] = 0x3C; + buf[4] = 1; /* WSNZ set */ + buf[5] = 0xFF; /* No MAXIMUM COMPARE AND WRITE LENGTH limit */ + /* Optimal transfer granuality is PAGE_SIZE */ + put_unaligned_be16(max_t(int, PAGE_SIZE / dev->block_size, 1), &buf[6]); + + /* Max transfer len is min of sg limit and 8M */ + max_transfer = min_t(int, cmd->tgt_dev->max_sg_cnt << PAGE_SHIFT, + 8*1024*1024) / dev->block_size; + put_unaligned_be32(max_transfer, &buf[8]); + + /* + * Let's have optimal transfer len 512KB. Better to not + * set it at all, because we don't have such limit, + * but some initiators may not understand that (?). + * From other side, too big transfers are not optimal, + * because SGV cache supports only <4M buffers. + */ + put_unaligned_be32(min_t(int, max_transfer, 512*1024 / dev->block_size), + &buf[12]); + + if (virt_dev->thin_provisioned) { + /* MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT is UNLIMITED */ + put_unaligned_be32(0xFFFFFFFF, &buf[24]); + /* + * MAXIMUM UNMAP LBA COUNT, OPTIMAL UNMAP + * GRANULARITY and ALIGNMENT + */ + put_unaligned_be32(virt_dev->unmap_max_lba_cnt, &buf[20]); + put_unaligned_be32(virt_dev->unmap_opt_gran, &buf[28]); + if (virt_dev->unmap_align != 0) { + put_unaligned_be32(virt_dev->unmap_align, &buf[32]); + buf[32] |= 0x80; + } + } + + /* MAXIMUM WRITE SAME LENGTH (measured in blocks) */ + put_unaligned_be64(dev->max_write_same_len >> dev->block_shift, + &buf[36]); + + return buf[3] + 4; +} + +/* Block Device Characteristics VPD Page (B1h) */ +static int vdisk_bdev_char(uint8_t *buf, struct scst_cmd *cmd, + struct scst_vdisk_dev *virt_dev) +{ + buf[1] = 0xB1; + buf[3] = 0x3C; + if (virt_dev->rotational) { + /* 15K RPM */ + put_unaligned_be16(0x3A98, &buf[4]); + } else + put_unaligned_be16(1, &buf[4]); + return buf[3] + 4; +} + +/* Logical Block Provisioning a.k.a. Thin Provisioning VPD page (B2h) */ +static int vdisk_tp_vpd(uint8_t *buf, struct scst_cmd *cmd, + struct scst_vdisk_dev *virt_dev) +{ + buf[1] = 0xB2; + buf[3] = 4; + buf[5] = 0xE0; + if (virt_dev->discard_zeroes_data) + buf[5] |= 0x4; /* LBPRZ */ + buf[6] = 2; /* thin provisioned */ + return buf[3] + 4; +} + +/* Standard INQUIRY response */ +static int vdisk_inq(uint8_t *buf, struct scst_cmd *cmd, + struct scst_vdisk_dev *virt_dev) +{ + int num; + + if (virt_dev->removable) + buf[1] = 0x80; /* removable */ + buf[2] = 6; /* Device complies to SPC-4 */ + buf[3] = 0x02; /* Data in format specified in SPC */ + if (cmd->tgtt->fake_aca) + buf[3] |= 0x20; + buf[4] = 31;/* n - 4 = 35 - 4 = 31 for full 36 byte data */ + if (scst_impl_alua_configured(cmd->dev)) + buf[5] = SCST_INQ_TPGS_MODE_IMPLICIT; + buf[6] = 0x10; /* MultiP 1 */ + buf[7] = 2; /* CMDQUE 1, BQue 0 => commands queuing supported */ + + read_lock(&vdisk_serial_rwlock); + + /* + * 8 byte ASCII Vendor Identification of the target + * - left aligned. + */ + scst_copy_and_fill(&buf[8], virt_dev->t10_vend_id, 8); + + /* + * 16 byte ASCII Product Identification of the target - left + * aligned. + */ + scst_copy_and_fill(&buf[16], virt_dev->prod_id, 16); + + /* + * 4 byte ASCII Product Revision Level of the target - left + * aligned. + */ + scst_copy_and_fill(&buf[32], virt_dev->prod_rev_lvl, 4); + + /* Vendor specific information. */ + if (virt_dev->inq_vend_specific_len <= 20) + memcpy(&buf[36], virt_dev->inq_vend_specific, + virt_dev->inq_vend_specific_len); + + /** Version descriptors **/ + + buf[4] += 58 - 36; + num = 0; + + /* SAM-4 T10/1683-D revision 14 */ + buf[58 + num] = 0x0; + buf[58 + num + 1] = 0x8B; + num += 2; + + /* Physical transport */ + if (cmd->tgtt->get_phys_transport_version != NULL) { + uint16_t v = cmd->tgtt->get_phys_transport_version(cmd->tgt); + if (v != 0) { + put_unaligned_be16(v, &buf[58 + num]); + num += 2; + } + } + + /* SCSI transport */ + if (cmd->tgtt->get_scsi_transport_version != NULL) { + put_unaligned_be16( + cmd->tgtt->get_scsi_transport_version(cmd->tgt), + &buf[58 + num]); + num += 2; + } + + /* SPC-4 T10/1731-D revision 23 */ + buf[58 + num] = 0x4; + buf[58 + num + 1] = 0x63; + num += 2; + + /* Device command set */ + if (virt_dev->command_set_version != 0) { + put_unaligned_be16(virt_dev->command_set_version, + &buf[58 + num]); + num += 2; + } + + /* Vendor specific information. */ + if (virt_dev->inq_vend_specific_len > 20) { + memcpy(&buf[96], virt_dev->inq_vend_specific, + virt_dev->inq_vend_specific_len); + num = 96 - 58 + virt_dev->inq_vend_specific_len; + } + + read_unlock(&vdisk_serial_rwlock); + + buf[4] += num; + return buf[4] + 5; } static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p) { struct scst_cmd *cmd = p->cmd; - int32_t length, i, resp_len = 0; + int32_t length, resp_len; uint8_t *address; uint8_t *buf; struct scst_device *dev = cmd->dev; struct scst_vdisk_dev *virt_dev = dev->dh_priv; - uint16_t tg_id; TRACE_ENTRY(); @@ -3257,322 +3602,32 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p) /* Vital Product */ if (cmd->cdb[1] & EVPD) { if (0 == cmd->cdb[2]) { - /* supported vital product data pages */ - buf[3] = 4; - buf[4] = 0x0; /* this page */ - buf[5] = 0x80; /* unit serial number */ - buf[6] = 0x83; /* device identification */ - buf[7] = 0x86; /* extended inquiry */ - if (dev->type == TYPE_DISK) { - buf[3] += 2; - buf[8] = 0xB0; /* block limits */ - buf[9] = 0xB1; /* block device charachteristics */ - if (virt_dev->thin_provisioned) { - buf[3] += 1; - buf[10] = 0xB2; /* thin provisioning */ - } - } - resp_len = buf[3] + 4; + resp_len = vdisk_sup_vpd(buf, cmd, virt_dev); } else if (0x80 == cmd->cdb[2]) { - /* unit serial number */ - buf[1] = 0x80; - if (cmd->tgtt->get_serial) { - buf[3] = cmd->tgtt->get_serial(cmd->tgt_dev, - &buf[4], INQ_BUF_SZ - 4); - } else { - int usn_len; - read_lock(&vdisk_serial_rwlock); - usn_len = strlen(virt_dev->usn); - buf[3] = usn_len; - strncpy(&buf[4], virt_dev->usn, usn_len); - read_unlock(&vdisk_serial_rwlock); - } - resp_len = buf[3] + 4; + resp_len = vdisk_usn_vpd(buf, cmd, virt_dev); } else if (0x83 == cmd->cdb[2]) { - /* device identification */ - int num = 4; - - buf[1] = 0x83; - - read_lock(&vdisk_serial_rwlock); - i = strlen(virt_dev->scsi_device_name); - if (i > 0) { - /* SCSI target device name */ - buf[num + 0] = 0x3; /* ASCII */ - buf[num + 1] = 0x20 | 0x8; /* Target device SCSI name */ - i += 4 - i % 4; /* align to required 4 bytes */ - scst_copy_and_fill_b(&buf[num + 4], virt_dev->scsi_device_name, i, '\0'); - - buf[num + 3] = i; - num += buf[num + 3]; - - num += 4; - } - read_unlock(&vdisk_serial_rwlock); - - /* T10 vendor identifier field format (faked) */ - buf[num + 0] = 0x2; /* ASCII */ - buf[num + 1] = 0x1; /* Vendor ID */ - read_lock(&vdisk_serial_rwlock); - scst_copy_and_fill(&buf[num + 4], virt_dev->t10_vend_id, 8); - i = strlen(virt_dev->vend_specific_id); - memcpy(&buf[num + 12], virt_dev->vend_specific_id, i); - read_unlock(&vdisk_serial_rwlock); - - buf[num + 3] = 8 + i; - num += buf[num + 3]; - - num += 4; - - /* - * Relative target port identifier - */ - buf[num + 0] = 0x01; /* binary */ - /* Relative target port id */ - buf[num + 1] = 0x10 | 0x04; - - put_unaligned_be16(cmd->tgt->rel_tgt_id, - &buf[num + 4 + 2]); - - buf[num + 3] = 4; - num += buf[num + 3]; - - num += 4; - - tg_id = scst_lookup_tg_id(dev, cmd->tgt); - if (tg_id) { - /* - * Target port group designator - */ - buf[num + 0] = 0x01; /* binary */ - /* Target port group id */ - buf[num + 1] = 0x10 | 0x05; - - put_unaligned_be16(tg_id, &buf[num + 4 + 2]); - - buf[num + 3] = 4; - num += 4 + buf[num + 3]; - } - - /* - * IEEE id - */ - buf[num + 0] = 0x01; /* binary */ - - /* EUI-64 */ - buf[num + 1] = 0x02; - buf[num + 2] = 0x00; - buf[num + 3] = 0x08; - - /* IEEE id */ - buf[num + 4] = virt_dev->t10_dev_id[0]; - buf[num + 5] = virt_dev->t10_dev_id[1]; - buf[num + 6] = virt_dev->t10_dev_id[2]; - - /* IEEE ext id */ - buf[num + 7] = virt_dev->t10_dev_id[3]; - buf[num + 8] = virt_dev->t10_dev_id[4]; - buf[num + 9] = virt_dev->t10_dev_id[5]; - buf[num + 10] = virt_dev->t10_dev_id[6]; - buf[num + 11] = virt_dev->t10_dev_id[7]; - num += buf[num + 3]; - - resp_len = num; - put_unaligned_be16(resp_len, &buf[2]); - resp_len += 4; + resp_len = vdisk_dev_id_vpd(buf, cmd, virt_dev); } else if (0x86 == cmd->cdb[2]) { - /* Extended INQUIRY */ - buf[1] = 0x86; - buf[3] = 0x3C; - buf[5] = 7; /* HEADSUP=1, ORDSUP=1, SIMPSUP=1 */ - buf[6] = (virt_dev->wt_flag || virt_dev->nv_cache) ? 0 : 1; /* V_SUP */ - buf[7] = 1; /* LUICLR=1 */ - resp_len = buf[3] + 4; + resp_len = vdisk_ext_inq(buf, cmd, virt_dev); } else if ((0xB0 == cmd->cdb[2]) && (dev->type == TYPE_DISK)) { - /* Block Limits */ - int max_transfer; - buf[1] = 0xB0; - buf[3] = 0x3C; - buf[4] = 1; /* WSNZ set */ - buf[5] = 0xFF; /* No MAXIMUM COMPARE AND WRITE LENGTH limit */ - /* Optimal transfer granuality is PAGE_SIZE */ - put_unaligned_be16(max_t(int, PAGE_SIZE/dev->block_size, 1), &buf[6]); - - /* Max transfer len is min of sg limit and 8M */ - max_transfer = min_t(int, - cmd->tgt_dev->max_sg_cnt << PAGE_SHIFT, - 8*1024*1024) / dev->block_size; - put_unaligned_be32(max_transfer, &buf[8]); - - /* - * Let's have optimal transfer len 512KB. Better to not - * set it at all, because we don't have such limit, - * but some initiators may not understand that (?). - * From other side, too big transfers are not optimal, - * because SGV cache supports only <4M buffers. - */ - put_unaligned_be32(min_t(int, - max_transfer, 512*1024 / dev->block_size), - &buf[12]); - - if (virt_dev->thin_provisioned) { - uint32_t gran = 1, align = 0, max_lba = 1; - - /* MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT is UNLIMITED */ - put_unaligned_be32(0xFFFFFFFF, &buf[24]); - if (virt_dev->blockio) { - vdev_blockio_get_unmap_params(virt_dev, - &gran, &align, &max_lba); - } else { - max_lba = min_t(loff_t, 0xFFFFFFFFU, - virt_dev->file_size >> - dev->block_shift); - } - /* - * MAXIMUM UNMAP LBA COUNT, OPTIMAL UNMAP - * GRANULARITY and ALIGNMENT - */ - put_unaligned_be32(max_lba, &buf[20]); - put_unaligned_be32(gran, &buf[28]); - if (align != 0) { - put_unaligned_be32(align, &buf[32]); - buf[32] |= 0x80; - } - } - - /* MAXIMUM WRITE SAME LENGTH (measured in blocks) */ - put_unaligned_be64(dev->max_write_same_len >> - dev->block_shift, &buf[36]); - - resp_len = buf[3] + 4; + resp_len = vdisk_block_limits(buf, cmd, virt_dev); } else if ((0xB1 == cmd->cdb[2]) && (dev->type == TYPE_DISK)) { - /* Block Device Characteristics */ - buf[1] = 0xB1; - buf[3] = 0x3C; - if (virt_dev->rotational) { - /* 15K RPM */ - put_unaligned_be16(0x3A98, &buf[4]); - } else - put_unaligned_be16(1, &buf[4]); - resp_len = buf[3] + 4; + resp_len = vdisk_bdev_char(buf, cmd, virt_dev); } else if ((0xB2 == cmd->cdb[2]) && (dev->type == TYPE_DISK) && virt_dev->thin_provisioned) { - /* Thin Provisioning */ - buf[1] = 0xB2; - buf[3] = 4; - buf[5] = 0xE0; -#if 0 /* - * Might be a big performance and functionality win, but might be - * dangerous as well, although generally nearly always it should be set, - * because nearly all devices should return zero for unmapped blocks. - * But let's be on the safe side and disable it for now. - * - * Changing it change also READ CAPACITY(16)! - */ - buf[5] |= 0x4; /* LBPRZ */ -#endif - buf[6] = 2; /* thin provisioned */ - resp_len = buf[3] + 4; + resp_len = vdisk_tp_vpd(buf, cmd, virt_dev); } else { TRACE_DBG("INQUIRY: Unsupported EVPD page %x", cmd->cdb[2]); scst_set_invalid_field_in_cdb(cmd, 2, 0); goto out_put; } } else { - int num; - if (cmd->cdb[2] != 0) { TRACE_DBG("INQUIRY: Unsupported page %x", cmd->cdb[2]); scst_set_invalid_field_in_cdb(cmd, 2, 0); goto out_put; } - - if (virt_dev->removable) - buf[1] = 0x80; /* removable */ - buf[2] = 6; /* Device complies to SPC-4 */ - buf[3] = 0x02; /* Data in format specified in SPC */ - if (cmd->tgtt->fake_aca) - buf[3] |= 0x20; - buf[4] = 31;/* n - 4 = 35 - 4 = 31 for full 36 byte data */ - if (scst_impl_alua_configured(dev)) - buf[5] = SCST_INQ_TPGS_MODE_IMPLICIT; - buf[6] = 0x10; /* MultiP 1 */ - buf[7] = 2; /* CMDQUE 1, BQue 0 => commands queuing supported */ - - read_lock(&vdisk_serial_rwlock); - - /* - * 8 byte ASCII Vendor Identification of the target - * - left aligned. - */ - scst_copy_and_fill(&buf[8], virt_dev->t10_vend_id, 8); - - /* - * 16 byte ASCII Product Identification of the target - left - * aligned. - */ - scst_copy_and_fill(&buf[16], virt_dev->prod_id, 16); - - /* - * 4 byte ASCII Product Revision Level of the target - left - * aligned. - */ - scst_copy_and_fill(&buf[32], virt_dev->prod_rev_lvl, 4); - - /* Vendor specific information. */ - if (virt_dev->inq_vend_specific_len <= 20) - memcpy(&buf[36], virt_dev->inq_vend_specific, - virt_dev->inq_vend_specific_len); - - /** Version descriptors **/ - - buf[4] += 58 - 36; - num = 0; - - /* SAM-4 T10/1683-D revision 14 */ - buf[58 + num] = 0x0; - buf[58 + num + 1] = 0x8B; - num += 2; - - /* Physical transport */ - if (cmd->tgtt->get_phys_transport_version != NULL) { - uint16_t v = cmd->tgtt->get_phys_transport_version(cmd->tgt); - if (v != 0) { - *((__be16 *)&buf[58 + num]) = cpu_to_be16(v); - num += 2; - } - } - - /* SCSI transport */ - if (cmd->tgtt->get_scsi_transport_version != NULL) { - *((__be16 *)&buf[58 + num]) = - cpu_to_be16(cmd->tgtt->get_scsi_transport_version(cmd->tgt)); - num += 2; - } - - /* SPC-4 T10/1731-D revision 23 */ - buf[58 + num] = 0x4; - buf[58 + num + 1] = 0x63; - num += 2; - - /* Device command set */ - if (virt_dev->command_set_version != 0) { - *((__be16 *)&buf[58 + num]) = - cpu_to_be16(virt_dev->command_set_version); - num += 2; - } - - /* Vendor specific information. */ - if (virt_dev->inq_vend_specific_len > 20) { - memcpy(&buf[96], virt_dev->inq_vend_specific, - virt_dev->inq_vend_specific_len); - num = 96 - 58 + virt_dev->inq_vend_specific_len; - } - - read_unlock(&vdisk_serial_rwlock); - - buf[4] += num; - resp_len = buf[4] + 5; + resp_len = vdisk_inq(buf, cmd, virt_dev); } sBUG_ON(resp_len > INQ_BUF_SZ); @@ -3752,7 +3807,7 @@ static int vdisk_caching_pg(unsigned char *p, int pcontrol, p[2] |= (virt_dev->wt_flag_saved || virt_dev->nv_cache) ? 0 : WCE; break; default: - sBUG_ON(1); + sBUG(); break; } @@ -4428,17 +4483,9 @@ static enum compl_status_e vdisk_exec_read_capacity16(struct vdisk_cmd_params *p } if (virt_dev->thin_provisioned) { - buffer[14] |= 0x80; /* Add LBPME */ -#if 0 /* - * Might be a big performance and functionality win, but might be - * dangerous as well, although generally nearly always it should be set, - * because nearly all devices should return zero for unmapped blocks. - * But let's be on the safe side and disable it for now. - * - * Changing it change also 0xB2 INQUIRY page! - */ - buffer[14] |= 0x40; /* Add LBPRZ */ -#endif + buffer[14] |= 0x80; /* LBPME */ + if (virt_dev->discard_zeroes_data) + buffer[14] |= 0x40; /* LBPRZ */ } length = scst_get_buf_full_sense(cmd, &address); @@ -4745,6 +4792,30 @@ out: static enum compl_status_e nullio_exec_read(struct vdisk_cmd_params *p) { + struct scst_cmd *cmd = p->cmd; + struct scst_device *dev = cmd->dev; + struct scst_vdisk_dev *virt_dev = dev->dh_priv; + + TRACE_ENTRY(); + + if (virt_dev->read_zero) { + struct scatterlist *sge; + struct page *page; + int i; + void *p; + + for_each_sg(cmd->sg, sge, cmd->sg_cnt, i) { + page = sg_page(sge); + p = kmap(page); + if (sge->offset == 0 && sge->length == PAGE_SIZE) + clear_page(p); + else + memset(p + sge->offset, 0, sge->length); + kunmap(page); + } + } + + TRACE_EXIT(); return CMD_SUCCEEDED; } @@ -4883,7 +4954,7 @@ static enum compl_status_e fileio_exec_write(struct vdisk_cmd_params *p) loff_t loff = p->loff; mm_segment_t old_fs; loff_t err = 0; - ssize_t length, full_len, saved_full_len; + ssize_t length, full_len; uint8_t __user *address; struct scst_vdisk_dev *virt_dev = cmd->dev->dh_priv; struct file *fd = virt_dev->fd; @@ -4939,7 +5010,6 @@ static enum compl_status_e fileio_exec_write(struct vdisk_cmd_params *p) goto out_set_fs; } - saved_full_len = full_len; eiv = iv; eiv_count = iv_count; restart: @@ -5942,6 +6012,7 @@ static int vdev_create(struct scst_dev_type *devt, virt_dev->rd_only = DEF_RD_ONLY; virt_dev->dummy = DEF_DUMMY; + virt_dev->read_zero = DEF_READ_ZERO; virt_dev->removable = DEF_REMOVABLE; virt_dev->rotational = DEF_ROTATIONAL; virt_dev->thin_provisioned = DEF_THIN_PROVISIONED; @@ -6015,7 +6086,7 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev, char *params, const char *const allowed_params[]) { int res = 0; - unsigned long val; + unsigned long long val; char *param, *p, *pp; TRACE_ENTRY(); @@ -6093,9 +6164,9 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev, } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) - res = kstrtoul(pp, 0, &val); + res = kstrtoull(pp, 0, &val); #else - res = strict_strtoul(pp, 0, &val); + res = strict_strtoull(pp, 0, &val); #endif if (res != 0) { PRINT_ERROR("strtoul() for %s failed: %d (device %s)", @@ -6137,7 +6208,7 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev, } else if (!strcasecmp("tst", p)) { if ((val != SCST_TST_0_SINGLE_TASK_SET) && (val != SCST_TST_1_SEP_TASK_SETS)) { - PRINT_ERROR("Invalid TST value %d", (int)val); + PRINT_ERROR("Invalid TST value %lld", val); res = -EINVAL; goto out; } @@ -6160,7 +6231,7 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev, res = -EINVAL; goto out; } - TRACE_DBG("block size %ld, block shift %d", + TRACE_DBG("block size %lld, block shift %d", val, virt_dev->blk_shift); } else { PRINT_ERROR("Unknown parameter %s (device %s)", p, @@ -6170,7 +6241,7 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev, } } - if (virt_dev->file_size % (1 << virt_dev->blk_shift) != 0) { + if ((virt_dev->file_size & ((1 << virt_dev->blk_shift) - 1)) != 0) { PRINT_ERROR("Device size %lld is not a multiple of the block" " size %d", virt_dev->file_size, 1 << virt_dev->blk_shift); @@ -6463,7 +6534,7 @@ out: static ssize_t __vcdrom_add_device(const char *device_name, char *params) { int res = 0; - const char *allowed_params[] = { "tst", NULL }; + static const char *const allowed_params[] = { "tst", NULL }; struct scst_vdisk_dev *virt_dev; TRACE_ENTRY(); @@ -6765,7 +6836,7 @@ static int vdev_size_process_store(struct scst_sysfs_work_item *work) int size_shift, res = -EINVAL; if (sscanf(work->buf, "%d %lld", &size_shift, &new_size) != 2 || - new_size > (ULONG_MAX >> size_shift)) + new_size > (ULLONG_MAX >> size_shift)) goto put; new_size <<= size_shift; @@ -6783,7 +6854,7 @@ static int vdev_size_process_store(struct scst_sysfs_work_item *work) if (!virt_dev->nullio) { res = -EPERM; sBUG(); - } else if (new_size % (1 << virt_dev->blk_shift) == 0) { + } else if ((new_size & ((1 << virt_dev->blk_shift) - 1)) == 0) { virt_dev->file_size = new_size; virt_dev->nblocks = virt_dev->file_size >> dev->block_shift; } else { @@ -7012,6 +7083,51 @@ static ssize_t vdev_sysfs_dummy_show(struct kobject *kobj, virt_dev->dummy != DEF_DUMMY ? SCST_SYSFS_KEY_MARK "\n" : ""); } +static ssize_t vdev_sysfs_rz_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_device *dev = container_of(kobj, struct scst_device, + dev_kobj); + struct scst_vdisk_dev *virt_dev = dev->dh_priv; + bool read_zero = virt_dev->read_zero; + + return sprintf(buf, "%d\n%s", read_zero, read_zero != DEF_READ_ZERO ? + SCST_SYSFS_KEY_MARK "\n" : ""); +} + +static ssize_t vdev_sysfs_rz_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + struct scst_device *dev = container_of(kobj, struct scst_device, + dev_kobj); + struct scst_vdisk_dev *virt_dev = dev->dh_priv; + long read_zero; + int res; + char ch[16]; + + sprintf(ch, "%.*s", min_t(int, sizeof(ch) - 1, count), buf); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) + res = kstrtol(ch, 0, &read_zero); +#else + res = strict_strtol(ch, 0, &read_zero); +#endif + if (res) + goto out; + res = -EINVAL; + if (read_zero != 0 && read_zero != 1) + goto out; + + spin_lock(&virt_dev->flags_lock); + virt_dev->read_zero = read_zero; + spin_unlock(&virt_dev->flags_lock); + + res = count; + +out: + return res; +} + static ssize_t vdisk_sysfs_removable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index afc92707a..4a8236f98 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -52,6 +52,9 @@ #include "scst_mem.h" #include "scst_pres.h" +static void scst_del_acn(struct scst_acn *acn); +static void scst_free_acn(struct scst_acn *acn, bool reassign); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) struct scsi_io_context { void *data; @@ -76,6 +79,27 @@ static int strncasecmp(const char *s1, const char *s2, size_t n) } #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) +char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap) +{ + unsigned int len; + char *p; + va_list aq; + + va_copy(aq, ap); + len = vsnprintf(NULL, 0, fmt, aq); + va_end(aq); + + p = kmalloc_track_caller(len + 1, gfp); + if (!p) + return NULL; + + vsnprintf(p, len + 1, fmt, ap); + + return p; +} +#endif + #if !((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)) && !defined(HAVE_SG_COPY) static int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg, #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) @@ -2397,21 +2421,22 @@ void scst_free_aen(struct scst_aen *aen) void scst_gen_aen_or_ua(struct scst_tgt_dev *tgt_dev, int key, int asc, int ascq) { - struct scst_tgt_template *tgtt = tgt_dev->sess->tgt->tgtt; + struct scst_session *sess = tgt_dev->sess; + struct scst_tgt_template *tgtt = sess->tgt->tgtt; uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN]; int sl; TRACE_ENTRY(); - if ((tgt_dev->sess->init_phase != SCST_SESS_IPH_READY) || - (tgt_dev->sess->shut_phase != SCST_SESS_SPH_READY)) + if (sess->init_phase != SCST_SESS_IPH_READY || + sess->shut_phase != SCST_SESS_SPH_READY) goto out; if (tgtt->report_aen != NULL) { struct scst_aen *aen; int rc; - aen = scst_alloc_aen(tgt_dev->sess, tgt_dev->lun); + aen = scst_alloc_aen(sess, tgt_dev->lun); if (aen == NULL) goto queue_ua; @@ -2514,6 +2539,7 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess, local_bh_disable(); +#if !defined(__CHECKER__) for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) { head = &sess->sess_tgt_dev_list[i]; @@ -2523,6 +2549,7 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess, spin_lock(&tgt_dev->tgt_dev_lock); } } +#endif for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) { head = &sess->sess_tgt_dev_list[i]; @@ -2543,6 +2570,7 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess, } } +#if !defined(__CHECKER__) for (i = SESS_TGT_DEV_LIST_HASH_SIZE-1; i >= 0; i--) { head = &sess->sess_tgt_dev_list[i]; @@ -2551,6 +2579,7 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess, spin_unlock(&tgt_dev->tgt_dev_lock); } } +#endif local_bh_enable(); @@ -2673,7 +2702,7 @@ void scst_aen_done(struct scst_aen *aen) SCST_SET_UA_FLAG_AT_HEAD); mutex_unlock(&scst_mutex); } else { - struct list_head *head; + struct scst_session *sess = aen->sess; struct scst_tgt_dev *tgt_dev; uint64_t lun; @@ -2682,17 +2711,13 @@ void scst_aen_done(struct scst_aen *aen) mutex_lock(&scst_mutex); /* tgt_dev might get dead, so we need to reseek it */ - head = &aen->sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(lun)]; - list_for_each_entry(tgt_dev, head, - sess_tgt_dev_list_entry) { - if (tgt_dev->lun == lun) { - TRACE_MGMT_DBG("Requeuing failed AEN UA for " - "tgt_dev %p", tgt_dev); - scst_check_set_UA(tgt_dev, aen->aen_sense, - aen->aen_sense_len, - SCST_SET_UA_FLAG_AT_HEAD); - break; - } + tgt_dev = scst_lookup_tgt_dev(sess, lun); + if (tgt_dev) { + TRACE_MGMT_DBG("Requeuing failed AEN UA for tgt_dev %p", + tgt_dev); + scst_check_set_UA(tgt_dev, aen->aen_sense, + aen->aen_sense_len, + SCST_SET_UA_FLAG_AT_HEAD); } mutex_unlock(&scst_mutex); @@ -2840,6 +2865,8 @@ next: TRACE_DBG("Moving sess %p from acg %s to acg %s", sess, old_acg->acg_name, acg->acg_name); list_move_tail(&sess->acg_sess_list_entry, &acg->acg_sess_list); + scst_get_acg(acg); + scst_put_acg(old_acg); #ifndef CONFIG_SCST_PROC scst_recreate_sess_luns_link(sess); @@ -3105,19 +3132,20 @@ next: return; } -static void scst_adjust_sg(struct scst_cmd *cmd, struct scatterlist *sg, - int *sg_cnt, int adjust_len) +static bool __scst_adjust_sg(struct scst_cmd *cmd, struct scatterlist *sg, + int *sg_cnt, int adjust_len, struct scst_orig_sg_data *orig_sg) { struct scatterlist *sgi; int i, l; + bool res = false; TRACE_ENTRY(); l = 0; for_each_sg(sg, sgi, *sg_cnt, i) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - TRACE_DBG("i %d, sg_cnt %d, sg %p, page_link %lx", i, - *sg_cnt, sg, sgi->page_link); + TRACE_DBG("i %d, sg_cnt %d, sg %p, page_link %lx, len %d", i, + *sg_cnt, sg, sgi->page_link, sgi->length); #else TRACE_DBG("i %d, sg_cnt %d, sg %p, page_link %lx", i, *sg_cnt, sg, 0UL); @@ -3125,26 +3153,57 @@ static void scst_adjust_sg(struct scst_cmd *cmd, struct scatterlist *sg, l += sgi->length; if (l >= adjust_len) { int left = adjust_len - (l - sgi->length); -#ifdef CONFIG_SCST_DEBUG - TRACE(TRACE_SG_OP|TRACE_MEMORY, "cmd %p (tag %llu), " - "sg %p, sg_cnt %d, adjust_len %d, i %d, " - "sg[j].length %d, left %d", + + TRACE_DBG_FLAG(TRACE_SG_OP|TRACE_MEMORY|TRACE_DEBUG, + "cmd %p (tag %llu), sg %p, sg_cnt %d, " + "adjust_len %d, i %d, sg[j].length %d, left %d", cmd, (long long unsigned int)cmd->tag, sg, *sg_cnt, adjust_len, i, sgi->length, left); -#endif - cmd->p_orig_sg_cnt = sg_cnt; - cmd->orig_sg_cnt = *sg_cnt; - cmd->orig_sg_entry = sgi; - cmd->orig_entry_offs = sgi->offset; - cmd->orig_entry_len = sgi->length; + + orig_sg->p_orig_sg_cnt = sg_cnt; + orig_sg->orig_sg_cnt = *sg_cnt; + orig_sg->orig_sg_entry = sgi; + orig_sg->orig_entry_offs = sgi->offset; + orig_sg->orig_entry_len = sgi->length; *sg_cnt = (left > 0) ? i+1 : i; sgi->length = left; - cmd->sg_buff_modified = 1; + res = true; break; } } + TRACE_EXIT_RES(res); + return res; +} + +/* + * Makes cmd's SG shorter on adjust_len bytes. Reg_sg is true for cmd->sg + * and false for cmd->write_sg. + */ +static void scst_adjust_sg(struct scst_cmd *cmd, bool reg_sg, + int adjust_len) +{ + struct scatterlist *sg; + int *sg_cnt; + + TRACE_ENTRY(); + + EXTRACHECKS_BUG_ON(cmd->sg_buff_modified); + + if (reg_sg) { + sg = cmd->sg; + sg_cnt = &cmd->sg_cnt; + } else { + sg = *cmd->write_sg; + sg_cnt = cmd->write_sg_cnt; + } + + TRACE_DBG("reg_sg %d, adjust_len %d", reg_sg, adjust_len); + + cmd->sg_buff_modified = __scst_adjust_sg(cmd, sg, sg_cnt, adjust_len, + &cmd->orig_sg); + TRACE_EXIT(); return; } @@ -3156,13 +3215,20 @@ static void scst_adjust_sg(struct scst_cmd *cmd, struct scatterlist *sg, */ void scst_restore_sg_buff(struct scst_cmd *cmd) { - TRACE_MEM("cmd %p, sg %p, orig_sg_entry %p, orig_entry_offs %d, " - "orig_entry_len %d, orig_sg_cnt %d", cmd, cmd->sg, - cmd->orig_sg_entry, cmd->orig_entry_offs, cmd->orig_entry_len, - cmd->orig_sg_cnt); - cmd->orig_sg_entry->offset = cmd->orig_entry_offs; - cmd->orig_sg_entry->length = cmd->orig_entry_len; - *cmd->p_orig_sg_cnt = cmd->orig_sg_cnt; + TRACE_DBG_FLAG(TRACE_DEBUG|TRACE_MEMORY, "cmd %p, sg %p, " + "orig_sg_entry %p, orig_entry_offs %d, orig_entry_len %d, " + "orig_sg_cnt %d", cmd, cmd->sg, cmd->orig_sg.orig_sg_entry, + cmd->orig_sg.orig_entry_offs, cmd->orig_sg.orig_entry_len, + cmd->orig_sg.orig_sg_cnt); + + EXTRACHECKS_BUG_ON(!cmd->sg_buff_modified); + + if (cmd->sg_buff_modified) { + cmd->orig_sg.orig_sg_entry->offset = cmd->orig_sg.orig_entry_offs; + cmd->orig_sg.orig_sg_entry->length = cmd->orig_sg.orig_entry_len; + *cmd->orig_sg.p_orig_sg_cnt = cmd->orig_sg.orig_sg_cnt; + } + cmd->sg_buff_modified = 0; } EXPORT_SYMBOL(scst_restore_sg_buff); @@ -3200,7 +3266,7 @@ void scst_set_resp_data_len(struct scst_cmd *cmd, int resp_data_len) goto out; } - scst_adjust_sg(cmd, cmd->sg, &cmd->sg_cnt, resp_data_len); + scst_adjust_sg(cmd, true, resp_data_len); cmd->resid_possible = 1; @@ -3218,7 +3284,7 @@ void scst_limit_sg_write_len(struct scst_cmd *cmd) cmd->write_len, cmd, *cmd->write_sg, *cmd->write_sg_cnt); scst_check_restore_sg_buff(cmd); - scst_adjust_sg(cmd, *cmd->write_sg, cmd->write_sg_cnt, cmd->write_len); + scst_adjust_sg(cmd, false, cmd->write_len); TRACE_EXIT(); return; @@ -3241,8 +3307,7 @@ void scst_adjust_resp_data_len(struct scst_cmd *cmd) "sg_cnt %d)", cmd->adjusted_resp_data_len, cmd, cmd->sg, cmd->sg_cnt); scst_check_restore_sg_buff(cmd); - scst_adjust_sg(cmd, cmd->sg, &cmd->sg_cnt, - cmd->adjusted_resp_data_len); + scst_adjust_sg(cmd, true, cmd->adjusted_resp_data_len); } out: @@ -3761,9 +3826,7 @@ void scst_free_device(struct scst_device *dev) bool scst_device_is_exported(struct scst_device *dev) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif WARN_ON_ONCE(!dev->dev_tgt_dev_list.next); @@ -3811,20 +3874,35 @@ out: * The activity supposed to be suspended and scst_mutex held or the * corresponding target supposed to be stopped. */ -static void scst_del_free_acg_dev(struct scst_acg_dev *acg_dev, bool del_sysfs) +static void scst_del_acg_dev(struct scst_acg_dev *acg_dev, bool del_sysfs) { - TRACE_ENTRY(); - - TRACE_DBG("Removing acg_dev %p from acg_dev_list and dev_acg_dev_list", - acg_dev); - list_del(&acg_dev->acg_dev_list_entry); + TRACE_DBG("Removing acg_dev %p from dev_acg_dev_list", acg_dev); list_del(&acg_dev->dev_acg_dev_list_entry); if (del_sysfs) scst_acg_dev_sysfs_del(acg_dev); +} +/* + * The activity supposed to be suspended and scst_mutex held or the + * corresponding target supposed to be stopped. + */ +static void scst_free_acg_dev(struct scst_acg_dev *acg_dev) +{ kmem_cache_free(scst_acgd_cachep, acg_dev); +} +/* + * The activity supposed to be suspended and scst_mutex held or the + * corresponding target supposed to be stopped. + */ +static void scst_del_free_acg_dev(struct scst_acg_dev *acg_dev, bool del_sysfs) +{ + TRACE_ENTRY(); + TRACE_DBG("Removing acg_dev %p from acg_dev_list", acg_dev); + list_del(&acg_dev->acg_dev_list_entry); + scst_del_acg_dev(acg_dev, del_sysfs); + scst_free_acg_dev(acg_dev); TRACE_EXIT(); return; } @@ -3949,6 +4027,7 @@ struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, goto out; } + kref_init(&acg->acg_kref); acg->tgt = tgt; INIT_LIST_HEAD(&acg->acg_dev_list); INIT_LIST_HEAD(&acg->acg_sess_list); @@ -4000,37 +4079,28 @@ out_free: goto out; } -/* The activity supposed to be suspended and scst_mutex held */ -void scst_del_free_acg(struct scst_acg *acg) +/** + * scst_del_acg - delete an ACG from the per-target ACG list and from sysfs + * + * The caller must hold scst_mutex and activity must have been suspended. + * + * Note: It is the responsibility of the caller to make sure that + * scst_put_acg() gets invoked. + */ +static void scst_del_acg(struct scst_acg *acg) { struct scst_acn *acn, *acnt; struct scst_acg_dev *acg_dev, *acg_dev_tmp; - TRACE_ENTRY(); + scst_assert_activity_suspended(); + lockdep_assert_held(&scst_mutex); - TRACE_DBG("Clearing acg %s from list", acg->acg_name); - - sBUG_ON(!list_empty(&acg->acg_sess_list)); - - /* Freeing acg_devs */ list_for_each_entry_safe(acg_dev, acg_dev_tmp, &acg->acg_dev_list, - acg_dev_list_entry) { - struct scst_tgt_dev *tgt_dev, *tt; - list_for_each_entry_safe(tgt_dev, tt, - &acg_dev->dev->dev_tgt_dev_list, - dev_tgt_dev_list_entry) { - if (tgt_dev->acg_dev == acg_dev) - scst_free_tgt_dev(tgt_dev); - } - scst_del_free_acg_dev(acg_dev, true); - } + acg_dev_list_entry) + scst_del_acg_dev(acg_dev, true); - /* Freeing names */ - list_for_each_entry_safe(acn, acnt, &acg->acn_list, acn_list_entry) { - scst_del_free_acn(acn, - list_is_last(&acn->acn_list_entry, &acg->acn_list)); - } - INIT_LIST_HEAD(&acg->acn_list); + list_for_each_entry_safe(acn, acnt, &acg->acn_list, acn_list_entry) + scst_del_acn(acn); #ifdef CONFIG_SCST_PROC list_del(&acg->acg_list_entry); @@ -4040,19 +4110,99 @@ void scst_del_free_acg(struct scst_acg *acg) list_del(&acg->acg_list_entry); scst_acg_sysfs_del(acg); - } else + } else { acg->tgt->default_acg = NULL; + } #endif +} - sBUG_ON(!list_empty(&acg->acg_sess_list)); - sBUG_ON(!list_empty(&acg->acg_dev_list)); - sBUG_ON(!list_empty(&acg->acn_list)); +/** + * scst_free_acg - free an ACG + * + * The caller must hold scst_mutex and activity must have been suspended. + */ +static void scst_free_acg(struct scst_acg *acg) +{ + struct scst_acg_dev *acg_dev, *acg_dev_tmp; + struct scst_acn *acn, *acnt; + + TRACE_DBG("Freeing acg %s/%s", acg->tgt->tgt_name, acg->acg_name); + + list_for_each_entry_safe(acg_dev, acg_dev_tmp, &acg->acg_dev_list, + acg_dev_list_entry) { + struct scst_tgt_dev *tgt_dev, *tt; + list_for_each_entry_safe(tgt_dev, tt, + &acg_dev->dev->dev_tgt_dev_list, + dev_tgt_dev_list_entry) { + if (tgt_dev->acg_dev == acg_dev) + scst_free_tgt_dev(tgt_dev); + } + scst_free_acg_dev(acg_dev); + } + + list_for_each_entry_safe(acn, acnt, &acg->acn_list, acn_list_entry) { + scst_free_acn(acn, + list_is_last(&acn->acn_list_entry, &acg->acn_list)); + } kfree(acg->acg_name); kfree(acg); +} - TRACE_EXIT(); - return; +static void scst_release_acg(struct kref *kref) +{ + struct scst_acg *acg = container_of(kref, struct scst_acg, acg_kref); + + scst_free_acg(acg); +} + +void scst_put_acg(struct scst_acg *acg) +{ + kref_put(&acg->acg_kref, scst_release_acg); +} + +void scst_get_acg(struct scst_acg *acg) +{ + kref_get(&acg->acg_kref); +} + +/** + * scst_close_del_free_acg - close sessions, delete and free an ACG + * + * The caller must hold scst_mutex and activity must have been suspended. + * + * Note: deleting and freeing the ACG happens asynchronously. Each time a + * session is closed the ACG reference count is decremented, and if that + * reference count drops to zero the ACG is freed. + */ +int scst_del_free_acg(struct scst_acg *acg, bool close_sessions) +{ + struct scst_tgt *tgt = acg->tgt; + struct scst_session *sess, *sess_tmp; + + scst_assert_activity_suspended(); + lockdep_assert_held(&scst_mutex); + + if ((!close_sessions && !list_empty(&acg->acg_sess_list)) || + (close_sessions && !tgt->tgtt->close_session)) + return -EBUSY; + + scst_del_acg(acg); + + if (close_sessions) { + TRACE_DBG("Closing sessions for group %s/%s", tgt->tgt_name, + acg->acg_name); + list_for_each_entry_safe(sess, sess_tmp, &acg->acg_sess_list, + acg_sess_list_entry) { + TRACE_DBG("Closing session %s/%s/%s", tgt->tgt_name, + acg->acg_name, sess->initiator_name); + tgt->tgtt->close_session(sess); + } + } + + scst_put_acg(acg); + + return 0; } #ifndef CONFIG_SCST_PROC @@ -4082,17 +4232,18 @@ static struct scst_tgt_dev *scst_find_shared_io_tgt_dev( struct scst_tgt_dev *tgt_dev) { struct scst_tgt_dev *res = NULL; + struct scst_session *sess = tgt_dev->sess; struct scst_acg *acg = tgt_dev->acg_dev->acg; struct scst_tgt_dev *t; TRACE_ENTRY(); TRACE_DBG("tgt_dev %s (acg %p, io_grouping_type %d)", - tgt_dev->sess->initiator_name, acg, acg->acg_io_grouping_type); + sess->initiator_name, acg, acg->acg_io_grouping_type); switch (acg->acg_io_grouping_type) { case SCST_IO_GROUPING_AUTO: - if (tgt_dev->sess->initiator_name == NULL) + if (sess->initiator_name == NULL) goto out; list_for_each_entry(t, &tgt_dev->dev->dev_tgt_dev_list, @@ -4107,7 +4258,7 @@ static struct scst_tgt_dev *scst_find_shared_io_tgt_dev( /* We check other ACG's as well */ if (strcmp(t->sess->initiator_name, - tgt_dev->sess->initiator_name) == 0) + sess->initiator_name) == 0) goto found; } break; @@ -4243,6 +4394,8 @@ static int scst_ioc_keeper_thread(void *arg) int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev) { int res = 0; + struct scst_session *sess = tgt_dev->sess; + struct scst_tgt_template *tgtt = sess->tgt->tgtt; struct scst_device *dev = tgt_dev->dev; struct scst_async_io_context_keeper *aic_keeper; @@ -4300,7 +4453,7 @@ int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev) tgt_dev->aic_keeper = aic_keeper; res = scst_add_threads(tgt_dev->active_cmd_threads, NULL, NULL, - tgt_dev->sess->tgt->tgtt->threads_num); + tgtt->threads_num); goto out; } @@ -4325,8 +4478,8 @@ int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev) } res = scst_add_threads(tgt_dev->active_cmd_threads, NULL, - tgt_dev, - dev->threads_num + tgt_dev->sess->tgt->tgtt->threads_num); + tgt_dev, + dev->threads_num + tgtt->threads_num); if (res != 0) { /* Let's clear here, because no threads could be run */ tgt_dev->active_cmd_threads->io_context = NULL; @@ -4338,7 +4491,7 @@ int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev) tgt_dev->active_cmd_threads = &dev->dev_cmd_threads; res = scst_add_threads(tgt_dev->active_cmd_threads, dev, NULL, - tgt_dev->sess->tgt->tgtt->threads_num); + tgtt->threads_num); break; } default: @@ -4380,6 +4533,8 @@ static void scst_aic_keeper_release(struct kref *kref) /* scst_mutex supposed to be held */ void scst_tgt_dev_stop_threads(struct scst_tgt_dev *tgt_dev) { + struct scst_tgt_template *tgtt = tgt_dev->sess->tgt->tgtt; + TRACE_ENTRY(); if (tgt_dev->dev->threads_num < 0) @@ -4394,7 +4549,7 @@ void scst_tgt_dev_stop_threads(struct scst_tgt_dev *tgt_dev) } else if (tgt_dev->active_cmd_threads == &tgt_dev->dev->dev_cmd_threads) { /* Per device shared threads */ scst_del_threads(tgt_dev->active_cmd_threads, - tgt_dev->sess->tgt->tgtt->threads_num); + tgtt->threads_num); } else if (tgt_dev->active_cmd_threads == &tgt_dev->tgt_dev_cmd_threads) { /* Per tgt_dev threads */ scst_del_threads(tgt_dev->active_cmd_threads, -1); @@ -4418,6 +4573,7 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess, struct scst_acg_dev *acg_dev, struct scst_tgt_dev **out_tgt_dev) { int res = 0; + struct scst_tgt_template *tgtt = sess->tgt->tgtt; int ini_sg, ini_unchecked_isa_dma, ini_use_clustering; struct scst_tgt_dev *tgt_dev; struct scst_device *dev = acg_dev->dev; @@ -4558,7 +4714,7 @@ out_pr_clear: scst_pr_clear_tgt_dev(tgt_dev); out_dec_free: - if (tgt_dev->sess->tgt->tgtt->get_initiator_port_transport_id == NULL) + if (tgtt->get_initiator_port_transport_id == NULL) dev->not_pr_supporting_tgt_devs_num--; out_free: @@ -4591,6 +4747,7 @@ void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA) */ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev) { + struct scst_tgt_template *tgtt = tgt_dev->sess->tgt->tgtt; struct scst_device *dev = tgt_dev->dev; TRACE_ENTRY(); @@ -4603,7 +4760,7 @@ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev) scst_tgt_dev_sysfs_del(tgt_dev); - if (tgt_dev->sess->tgt->tgtt->get_initiator_port_transport_id == NULL) + if (tgtt->get_initiator_port_transport_id == NULL) dev->not_pr_supporting_tgt_devs_num--; scst_clear_reservation(tgt_dev); @@ -4737,20 +4894,29 @@ out_free: } /* The activity supposed to be suspended and scst_mutex held */ -void scst_del_free_acn(struct scst_acn *acn, bool reassign) +static void scst_del_acn(struct scst_acn *acn) { - TRACE_ENTRY(); - list_del(&acn->acn_list_entry); scst_acn_sysfs_del(acn); +} +/* The activity supposed to be suspended and scst_mutex held */ +static void scst_free_acn(struct scst_acn *acn, bool reassign) +{ kfree(acn->name); kfree(acn); if (reassign) scst_check_reassign_sessions(); +} +/* The activity supposed to be suspended and scst_mutex held */ +void scst_del_free_acn(struct scst_acn *acn, bool reassign) +{ + TRACE_ENTRY(); + scst_del_acn(acn); + scst_free_acn(acn, reassign); TRACE_EXIT(); return; } @@ -4982,7 +5148,6 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp, { struct scst_cmd *ws_cmd = wsp->ws_orig_cmd; struct scatterlist *ws_sg = wsp->ws_sg; - int ws_sg_cnt = wsp->ws_sg_cnt; int res; uint8_t write16_cdb[16]; int len = blocks << ws_cmd->dev->block_shift; @@ -4990,7 +5155,7 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp, TRACE_ENTRY(); - EXTRACHECKS_BUG_ON(blocks > ws_sg_cnt); + EXTRACHECKS_BUG_ON(blocks > wsp->ws_sg_cnt); if (unlikely(test_bit(SCST_CMD_ABORTED, &ws_cmd->cmd_flags)) || unlikely(ws_cmd->completed)) { @@ -5434,6 +5599,7 @@ void scst_free_session(struct scst_session *sess) TRACE_DBG("Removing session %p from acg %s", sess, sess->acg->acg_name); list_del(&sess->acg_sess_list_entry); + scst_put_acg(sess->acg); mutex_unlock(&scst_mutex); @@ -6410,7 +6576,12 @@ int scst_get_buf_full(struct scst_cmd *cmd, uint8_t **buf) len = scst_get_buf_next(cmd, &tmp_buf); } +#ifdef __COVERITY__ + /* Help Coverity recognize that vmalloc(0) returns NULL. */ + *buf = full_size ? vmalloc(full_size) : NULL; +#else *buf = vmalloc(full_size); +#endif if (*buf == NULL) { TRACE(TRACE_OUT_OF_MEM, "vmalloc() failed for opcode " "%s", scst_get_opcode_name(cmd)); @@ -8126,20 +8297,18 @@ again: goto out_unlock; } else TRACE_MGMT_DBG("Setting pending UA cmd %p (tgt_dev %p, dev %s, " - "initiator %s)", cmd->tgt_dev, cmd, cmd->dev->virt_name, + "initiator %s)", cmd, cmd->tgt_dev, cmd->dev->virt_name, cmd->sess->initiator_name); UA_entry = list_first_entry(&cmd->tgt_dev->UA_list, typeof(*UA_entry), UA_list_entry); - TRACE_MGMT_DBG("Setting pending UA %p to cmd %p", UA_entry, cmd); - - TRACE_DBG("next %p UA_entry %p", - cmd->tgt_dev->UA_list.next, UA_entry); + TRACE_DBG("Setting pending UA %p to cmd %p", UA_entry, cmd); if (UA_entry->global_UA && first) { TRACE_MGMT_DBG("Global UA %p detected", UA_entry); +#if !defined(__CHECKER__) spin_unlock_bh(&cmd->tgt_dev->tgt_dev_lock); /* @@ -8159,6 +8328,7 @@ again: spin_lock(&tgt_dev->tgt_dev_lock); } } +#endif first = false; global_unlock = true; @@ -8221,6 +8391,7 @@ again: out_unlock: if (global_unlock) { +#if !defined(__CHECKER__) for (i = SESS_TGT_DEV_LIST_HASH_SIZE-1; i >= 0; i--) { struct list_head *head = &sess->sess_tgt_dev_list[i]; struct scst_tgt_dev *tgt_dev; @@ -8232,6 +8403,7 @@ out_unlock: local_bh_enable(); spin_lock_bh(&cmd->tgt_dev->tgt_dev_lock); +#endif } spin_unlock_bh(&cmd->tgt_dev->tgt_dev_lock); @@ -9023,16 +9195,11 @@ static void scst_process_qerr(struct scst_cmd *cmd) int scst_process_check_condition(struct scst_cmd *cmd) { int res; - struct scst_order_data *order_data; - struct scst_device *dev; TRACE_ENTRY(); EXTRACHECKS_BUG_ON(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags)); - order_data = cmd->cur_order_data; - dev = cmd->dev; - TRACE_DBG("CHECK CONDITION for cmd %p (tgt_dev %p)", cmd, cmd->tgt_dev); scst_process_qerr(cmd); @@ -9394,7 +9561,7 @@ int scst_parse_descriptors(struct scst_cmd *cmd) res = scst_parse_unmap_descriptors(cmd); break; default: - sBUG_ON(1); + sBUG(); res = -1; break; } @@ -9412,7 +9579,7 @@ static void scst_free_descriptors(struct scst_cmd *cmd) scst_free_unmap_descriptors(cmd); break; default: - sBUG_ON(1); + sBUG(); break; } @@ -9749,7 +9916,8 @@ void scst_vfs_unlink_and_put(struct nameidata *nd) #else void scst_vfs_unlink_and_put(struct path *path) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) && \ + (!defined(RHEL_MAJOR) || RHEL_MAJOR -0 < 7) vfs_unlink(path->dentry->d_parent->d_inode, path->dentry); #else vfs_unlink(path->dentry->d_parent->d_inode, path->dentry, NULL); diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 867e7f6b5..209e9ce54 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -179,6 +179,7 @@ cpumask_t default_cpu_mask; static unsigned int scst_max_cmd_mem; unsigned int scst_max_dev_cmd_mem; +int scst_forcibly_close_sessions; module_param_named(scst_threads, scst_threads, int, 0); MODULE_PARM_DESC(scst_threads, "SCSI target threads count"); @@ -191,6 +192,13 @@ module_param_named(scst_max_dev_cmd_mem, scst_max_dev_cmd_mem, int, S_IRUGO); MODULE_PARM_DESC(scst_max_dev_cmd_mem, "Maximum memory allowed to be consumed " "by all SCSI commands of a device at any given time in MB"); +module_param_named(forcibly_close_sessions, scst_forcibly_close_sessions, int, + S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(forcibly_close_sessions, +"If enabled, close the sessions associated with an access control group (ACG)" +" when an ACG is deleted via sysfs instead of returning -EBUSY"); + + struct scst_dev_type scst_null_devtype = { .name = "none", .threads_num = -1, @@ -669,11 +677,11 @@ again: scst_tg_tgt_remove_by_tgt(tgt); #ifndef CONFIG_SCST_PROC - scst_del_free_acg(tgt->default_acg); + scst_del_free_acg(tgt->default_acg, false); list_for_each_entry_safe(acg, acg_tmp, &tgt->tgt_acg_list, acg_list_entry) { - scst_del_free_acg(acg); + scst_del_free_acg(acg, false); } #endif @@ -1051,6 +1059,7 @@ EXPORT_SYMBOL_GPL(scst_suspend_activity); static void __scst_resume_activity(void) { struct scst_cmd_threads *l; + struct scst_mgmt_cmd *m; TRACE_ENTRY(); @@ -1077,15 +1086,14 @@ static void __scst_resume_activity(void) wake_up_all(&scst_init_cmd_list_waitQ); spin_lock_irq(&scst_mcmd_lock); - if (!list_empty(&scst_delayed_mgmt_cmd_list)) { - struct scst_mgmt_cmd *m; - m = list_first_entry(&scst_delayed_mgmt_cmd_list, typeof(*m), - mgmt_cmd_list_entry); + 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); - list_move(&m->mgmt_cmd_list_entry, &scst_active_mgmt_cmd_list); } + list_splice(&scst_delayed_mgmt_cmd_list, &scst_active_mgmt_cmd_list); spin_unlock_irq(&scst_mcmd_lock); + wake_up_all(&scst_mgmt_cmd_list_waitQ); out: @@ -1145,9 +1153,9 @@ static int scst_register_device(struct scsi_device *scsidp) dev->type = scsidp->type; - dev->virt_name = kasprintf(GFP_KERNEL, "%d:%d:%d:%d", - scsidp->host->host_no, - scsidp->channel, scsidp->id, scsidp->lun); + dev->virt_name = kasprintf(GFP_KERNEL, "%d:%d:%d:%lld", + scsidp->host->host_no, scsidp->channel, + scsidp->id, (u64)scsidp->lun); if (dev->virt_name == NULL) { PRINT_ERROR("%s", "Unable to alloc device name"); res = -ENOMEM; @@ -1190,9 +1198,9 @@ static int scst_register_device(struct scsi_device *scsidp) goto out_del_unlocked; #endif - PRINT_INFO("Attached to scsi%d, channel %d, id %d, lun %d, " - "type %d", scsidp->host->host_no, scsidp->channel, - scsidp->id, scsidp->lun, scsidp->type); + PRINT_INFO("Attached to scsi%d, channel %d, id %d, lun %lld, type %d", + scsidp->host->host_no, scsidp->channel, scsidp->id, + (u64)scsidp->lun, scsidp->type); out: TRACE_EXIT_RES(res); @@ -1226,9 +1234,7 @@ static struct scst_device *__scst_lookup_device(struct scsi_device *scsidp) { struct scst_device *d; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(d, &scst_dev_list, dev_list_entry) if (d->scsi_dev == scsidp) @@ -1261,9 +1267,9 @@ static void scst_unregister_device(struct scsi_device *scsidp) } if (dev == NULL) { - PRINT_ERROR("SCST device for SCSI device %d:%d:%d:%d not found", - scsidp->host->host_no, scsidp->channel, scsidp->id, - scsidp->lun); + PRINT_ERROR("SCST device for SCSI device %d:%d:%d:%lld not found", + scsidp->host->host_no, scsidp->channel, scsidp->id, + (u64)scsidp->lun); goto out_unlock; } @@ -1287,9 +1293,9 @@ static void scst_unregister_device(struct scsi_device *scsidp) scst_dev_sysfs_del(dev); - PRINT_INFO("Detached from scsi%d, channel %d, id %d, lun %d, type %d", - scsidp->host->host_no, scsidp->channel, scsidp->id, - scsidp->lun, scsidp->type); + PRINT_INFO("Detached from scsi%d, channel %d, id %d, lun %lld, type %d", + scsidp->host->host_no, scsidp->channel, scsidp->id, + (u64)scsidp->lun, scsidp->type); scst_free_device(dev); @@ -2089,7 +2095,7 @@ assign: dev->threads_num = handler->threads_num; dev->threads_pool_type = handler->threads_pool_type; - dev->max_write_same_len = 512 * 1024 * 1024; /* 512 MB */ + dev->max_write_same_len = 256 * 1024 * 1024; /* 256 MB */ if (handler->attach) { TRACE_DBG("Calling new dev handler's attach(%p)", dev); @@ -2455,7 +2461,7 @@ static int __init init_scst(void) mutex_init(&scst_suspend_mutex); mutex_init(&scst_cmd_threads_mutex); INIT_LIST_HEAD(&scst_cmd_threads_list); - cpus_setall(default_cpu_mask); + cpumask_setall(&default_cpu_mask); scst_init_threads(&scst_main_cmd_threads); @@ -2656,7 +2662,7 @@ out_thread_free: #ifdef CONFIG_SCST_PROC out_free_acg: - scst_del_free_acg(scst_default_acg); + scst_del_free_acg(scst_default_acg, false); #endif out_destroy_sgv_pool: @@ -2738,7 +2744,7 @@ static void __exit exit_scst(void) scsi_unregister_interface(&scst_interface); #ifdef CONFIG_SCST_PROC - scst_del_free_acg(scst_default_acg); + scst_del_free_acg(scst_default_acg, false); #endif scst_sgv_pools_deinit(); diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index c20edd010..15981530d 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -456,8 +456,10 @@ static struct scst_dev_registrant *scst_pr_add_registrant( * We can't use scst_mutex here, because of the circular * locking dependency with dev_pr_mutex. */ +#if !defined(__CHECKER__) if (!dev_lock_locked) spin_lock_bh(&dev->dev_lock); +#endif list_for_each_entry(t, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { if (tid_equal(t->sess->transport_id, transport_id) && (t->sess->tgt->rel_tgt_id == rel_tgt_id) && @@ -472,8 +474,10 @@ static struct scst_dev_registrant *scst_pr_add_registrant( break; } } +#if !defined(__CHECKER__) if (!dev_lock_locked) spin_unlock_bh(&dev->dev_lock); +#endif list_add_tail(®->dev_registrants_list_entry, &dev->dev_registrants_list); @@ -858,15 +862,16 @@ out: static void scst_pr_remove_device_files(struct scst_tgt_dev *tgt_dev) { - int res = 0; struct scst_device *dev = tgt_dev->dev; TRACE_ENTRY(); scst_assert_pr_mutex_held(dev); - res = dev->pr_file_name ? scst_remove_file(dev->pr_file_name) : -ENOENT; - res = dev->pr_file_name1 ? scst_remove_file(dev->pr_file_name1) : -ENOENT; + if (dev->pr_file_name) + scst_remove_file(dev->pr_file_name); + if (dev->pr_file_name1) + scst_remove_file(dev->pr_file_name1); TRACE_EXIT(); return; @@ -2566,7 +2571,7 @@ void scst_pr_read_reservation(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size) { struct scst_device *dev = cmd->dev; - uint8_t b[24]; + uint8_t b[24] = { }; int size = 0; TRACE_ENTRY(); @@ -2579,8 +2584,6 @@ void scst_pr_read_reservation(struct scst_cmd *cmd, uint8_t *buffer, goto out; } - memset(b, 0, sizeof(b)); - put_unaligned_be32(dev->pr_generation, &b[0]); if (!dev->pr_is_set) { diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index ac0eeee89..bba383e43 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -148,6 +148,8 @@ extern int scst_threads; extern unsigned int scst_max_dev_cmd_mem; +extern int scst_forcibly_close_sessions; + extern mempool_t *scst_mgmt_mempool; extern mempool_t *scst_mgmt_stub_mempool; extern mempool_t *scst_ua_mempool; @@ -339,7 +341,9 @@ bool scst_device_is_exported(struct scst_device *dev); struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, const char *acg_name, bool tgt_acg); -void scst_del_free_acg(struct scst_acg *acg); +int scst_del_free_acg(struct scst_acg *acg, bool close_sessions); +void scst_get_acg(struct scst_acg *acg); +void scst_put_acg(struct scst_acg *acg); struct scst_acg *scst_tgt_find_acg(struct scst_tgt *tgt, const char *name); struct scst_acg *scst_find_acg(const struct scst_session *sess); @@ -348,6 +352,7 @@ void scst_check_reassign_sessions(void); int scst_sess_alloc_tgt_devs(struct scst_session *sess); void scst_sess_free_tgt_devs(struct scst_session *sess); +struct scst_tgt_dev *scst_lookup_tgt_dev(struct scst_session *sess, u64 lun); void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA); int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent, @@ -628,9 +633,7 @@ static inline void scst_reserve_dev(struct scst_device *dev, static inline void scst_clear_dev_reservation(struct scst_device *dev) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&dev->dev_lock); -#endif dev->reserved_by = NULL; } diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c index 2a3bc1981..d00101511 100644 --- a/scst/src/scst_proc.c +++ b/scst/src/scst_proc.c @@ -991,7 +991,7 @@ static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc) } if (remove_proc) scst_proc_del_acg_tree(acg_proc_root, acg->acg_name); - scst_del_free_acg(acg); + scst_del_free_acg(acg, false); } out: TRACE_EXIT_RES(res); diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index d9768fa5a..88e714933 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -1885,7 +1885,7 @@ static ssize_t __scst_acg_cpu_mask_show(struct scst_acg *acg, char *buf) res = cpumask_scnprintf(buf, SCST_SYSFS_BLOCK_SIZE, &acg->acg_cpu_mask); #endif - if (!cpus_equal(acg->acg_cpu_mask, default_cpu_mask)) + if (!cpumask_equal(&acg->acg_cpu_mask, &default_cpu_mask)) res += sprintf(&buf[res], "\n%s\n", SCST_SYSFS_KEY_MARK); return res; @@ -1991,7 +1991,7 @@ static ssize_t __scst_acg_cpu_mask_store(struct scst_acg *acg, goto out_release; } - if (cpus_equal(acg->acg_cpu_mask, work->cpu_mask)) + if (cpumask_equal(&acg->acg_cpu_mask, &work->cpu_mask)) goto out; work->tgt = acg->tgt; @@ -2122,12 +2122,16 @@ static int scst_process_ini_group_mgmt_store(char *buffer, res = -EINVAL; goto out_unlock; } - if (!scst_acg_sess_is_empty(acg)) { - PRINT_ERROR("Group %s is not empty", acg->acg_name); - res = -EBUSY; + res = scst_del_free_acg(acg, scst_forcibly_close_sessions); + if (res) { + if (scst_forcibly_close_sessions) + PRINT_ERROR("Removing group %s failed", + acg->acg_name); + else + PRINT_ERROR("Group %s is not empty", + acg->acg_name); goto out_unlock; } - scst_del_free_acg(acg); break; } @@ -5081,7 +5085,8 @@ static int scst_process_devt_pass_through_mgmt_store(char *buffer, { int res = 0; char *pp, *action, *devstr; - unsigned int host, channel, id, lun; + unsigned int host, channel, id; + u64 lun; struct scst_device *d, *dev = NULL; TRACE_ENTRY(); @@ -5103,10 +5108,10 @@ static int scst_process_devt_pass_through_mgmt_store(char *buffer, goto out_syntax_err; } - if (sscanf(devstr, "%u:%u:%u:%u", &host, &channel, &id, &lun) != 4) + if (sscanf(devstr, "%u:%u:%u:%llu", &host, &channel, &id, &lun) != 4) goto out_syntax_err; - TRACE_DBG("Dev %d:%d:%d:%d", host, channel, id, lun); + TRACE_DBG("Dev %d:%d:%d:%lld", host, channel, id, lun); res = mutex_lock_interruptible(&scst_mutex); if (res != 0) @@ -5123,13 +5128,13 @@ static int scst_process_devt_pass_through_mgmt_store(char *buffer, d->scsi_dev->id == id && d->scsi_dev->lun == lun) { dev = d; - TRACE_DBG("Dev %p (%d:%d:%d:%d) found", + TRACE_DBG("Dev %p (%d:%d:%d:%lld) found", dev, host, channel, id, lun); break; } } if (dev == NULL) { - PRINT_ERROR("Device %d:%d:%d:%d not found", + PRINT_ERROR("Device %d:%d:%d:%lld not found", host, channel, id, lun); res = -EINVAL; goto out_unlock; diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index c1465cd1d..a490321d7 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -1697,7 +1697,6 @@ static int scst_tgt_pre_exec(struct scst_cmd *cmd) goto out; default: sBUG(); - goto out; } } @@ -1801,8 +1800,6 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state, { TRACE_ENTRY(); - EXTRACHECKS_BUG_ON(cmd->pr_abort_counter != NULL); - scst_set_exec_time(cmd); TRACE(TRACE_SCSI, "cmd %p, status %x, msg_status %x, host_status %x, " @@ -2288,7 +2285,7 @@ static int scst_report_supported_opcodes(struct scst_cmd *cmd) } break; default: - sBUG_ON(1); + sBUG(); goto out_compl; } @@ -4330,6 +4327,25 @@ out: return; } +struct scst_tgt_dev *scst_lookup_tgt_dev(struct scst_session *sess, u64 lun) +{ + struct list_head *head; + struct scst_tgt_dev *tgt_dev; + +#ifdef CONFIG_SCST_EXTRACHECKS + if (scst_get_cmd_counter() == 0) + lockdep_assert_held(&scst_mutex); +#endif + + head = &sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(lun)]; + list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) { + if (tgt_dev->lun == lun) + return tgt_dev; + } + + return NULL; +} + /* * Returns 0 on success, > 0 when we need to wait for unblock, * < 0 if there is no device (lun) or device type handler. @@ -4341,30 +4357,21 @@ static int scst_translate_lun(struct scst_cmd *cmd) { struct scst_tgt_dev *tgt_dev = NULL; int res; + bool nul_dev = false; TRACE_ENTRY(); cmd->cpu_cmd_counter = scst_get(); if (likely(!test_bit(SCST_FLAG_SUSPENDED, &scst_flags))) { - struct list_head *head = - &cmd->sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(cmd->lun)]; TRACE_DBG("Finding tgt_dev for cmd %p (lun %lld)", cmd, (long long unsigned int)cmd->lun); res = -1; - list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) { - if (tgt_dev->lun == cmd->lun) { - TRACE_DBG("tgt_dev %p found", tgt_dev); - - if (unlikely(tgt_dev->dev->handler == - &scst_null_devtype)) { - PRINT_INFO("Dev handler for device " - "%lld is NULL, the device will not " - "be visible remotely", - (long long unsigned int)cmd->lun); - break; - } + tgt_dev = scst_lookup_tgt_dev(cmd->sess, cmd->lun); + if (tgt_dev) { + TRACE_DBG("tgt_dev %p found", tgt_dev); + if (likely(tgt_dev->dev->handler != &scst_null_devtype)) { cmd->cmd_threads = tgt_dev->active_cmd_threads; cmd->tgt_dev = tgt_dev; cmd->cur_order_data = tgt_dev->curr_order_data; @@ -4372,15 +4379,21 @@ static int scst_translate_lun(struct scst_cmd *cmd) cmd->devt = tgt_dev->dev->handler; res = 0; - break; + } else { + PRINT_INFO("Dev handler for device %lld is NULL, " + "the device will not be visible remotely", + (long long unsigned int)cmd->lun); + nul_dev = true; } } - if (res != 0) { - TRACE(TRACE_MINOR, - "tgt_dev for LUN %lld not found, command to " - "unexisting LU (initiator %s, target %s)?", - (long long unsigned int)cmd->lun, - cmd->sess->initiator_name, cmd->tgt->tgt_name); + if (unlikely(res != 0)) { + if (!nul_dev) { + TRACE(TRACE_MINOR, + "tgt_dev for LUN %lld not found, command to " + "unexisting LU (initiator %s, target %s)?", + (long long unsigned int)cmd->lun, + cmd->sess->initiator_name, cmd->tgt->tgt_name); + } scst_put(cmd->cpu_cmd_counter); } } else { @@ -4855,12 +4868,10 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic) default: PRINT_CRIT_ERROR("cmd %p is in invalid state %d)", cmd, cmd->state); +#if !defined(__CHECKER__) spin_unlock_irq(&cmd->cmd_threads->cmd_list_lock); - sBUG(); -#if defined(RHEL_MAJOR) && RHEL_MAJOR -0 < 6 - spin_lock_irq(&cmd->cmd_threads->cmd_list_lock); - break; #endif + sBUG(); } #endif wake_up(&cmd->cmd_threads->cmd_list_waitQ); @@ -4993,7 +5004,6 @@ out: static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd) { struct scst_tgt_dev *tgt_dev; - struct list_head *head; int res; TRACE_ENTRY(); @@ -5005,19 +5015,15 @@ static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd) if (unlikely(res != 0)) goto out; - res = -1; - - head = &mcmd->sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(mcmd->lun)]; - list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) { - if (tgt_dev->lun == mcmd->lun) { - TRACE_DBG("tgt_dev %p found", tgt_dev); - mcmd->mcmd_tgt_dev = tgt_dev; - res = 0; - break; - } - } - if (mcmd->mcmd_tgt_dev == NULL) + tgt_dev = scst_lookup_tgt_dev(mcmd->sess, mcmd->lun); + if (tgt_dev) { + TRACE_DBG("tgt_dev %p found", tgt_dev); + mcmd->mcmd_tgt_dev = tgt_dev; + res = 0; + } else { scst_put(mcmd->cpu_cmd_counter); + res = -1; + } out: TRACE_EXIT_HRES(res); @@ -5475,15 +5481,15 @@ static int scst_set_mcmd_next_state(struct scst_mgmt_cmd *mcmd) "cmd_finish_wait_count %d, cmd_done_wait_count %d)", mcmd, mcmd->state, mcmd->fn, mcmd->cmd_finish_wait_count, mcmd->cmd_done_wait_count); +#if !defined(__CHECKER__) spin_unlock_irq(&scst_mcmd_lock); +#endif res = -1; sBUG(); - goto out; } spin_unlock_irq(&scst_mcmd_lock); -out: return res; } @@ -5645,28 +5651,20 @@ static int scst_abort_task_set(struct scst_mgmt_cmd *mcmd) return res; } -static int scst_is_cmd_belongs_to_dev(struct scst_cmd *cmd, - struct scst_device *dev) +static bool scst_is_cmd_belongs_to_dev(struct scst_cmd *cmd, + struct scst_device *dev) { - struct scst_tgt_dev *tgt_dev = NULL; - struct list_head *head; - int res = 0; + struct scst_tgt_dev *tgt_dev; + bool res; TRACE_ENTRY(); - TRACE_DBG("Finding match for dev %s and cmd %p (lun %lld)", dev->virt_name, - cmd, (long long unsigned int)cmd->lun); + TRACE_DBG("Finding match for dev %s and cmd %p (lun %lld)", + dev->virt_name, cmd, (long long unsigned int)cmd->lun); - head = &cmd->sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(cmd->lun)]; - list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) { - if (tgt_dev->lun == cmd->lun) { - TRACE_DBG("dev %s found", tgt_dev->dev->virt_name); - res = (tgt_dev->dev == dev); - goto out; - } - } + tgt_dev = scst_lookup_tgt_dev(cmd->sess, cmd->lun); + res = tgt_dev && tgt_dev->dev == dev; -out: TRACE_EXIT_HRES(res); return res; } @@ -5996,6 +5994,8 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd) TRACE(TRACE_MGMT, "Resetting host %d bus ", dev->scsi_dev->host->host_no); rc = scsi_reset_provider(dev->scsi_dev, SCSI_TRY_RESET_DEVICE); + TRACE(TRACE_MGMT, "scsi_reset_provider(%s) returned %d", + dev->virt_name, rc); #if 0 if (rc != SUCCESS && mcmd->status == SCST_MGMT_STATUS_SUCCESS) scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_FAILED); @@ -6506,11 +6506,6 @@ static int scst_process_mgmt_cmd(struct scst_mgmt_cmd *mcmd) mcmd->cmd_finish_wait_count, mcmd->cmd_done_wait_count); sBUG(); -#if defined(RHEL_MAJOR) && RHEL_MAJOR -0 < 6 - /* For suppressing a gcc compiler warning */ - res = -1; - goto out; -#endif } } @@ -6991,9 +6986,7 @@ static char *scst_get_unique_sess_name(struct list_head *sysfs_sess_list, int len = 0, n = 1; BUG_ON(!initiator_name); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif restart: list_for_each_entry(s, sysfs_sess_list, sysfs_sess_list_entry) { @@ -7024,7 +7017,7 @@ restart: static int scst_init_session(struct scst_session *sess) { int res = 0; - struct scst_cmd *cmd; + struct scst_cmd *cmd, *cmd_tmp; struct scst_mgmt_cmd *mcmd, *tm; int mwake = 0; @@ -7038,6 +7031,7 @@ static int scst_init_session(struct scst_session *sess) "(target %s)", sess->acg->acg_name, sess->initiator_name, sess->tgt->tgt_name); + scst_get_acg(sess->acg); list_add_tail(&sess->acg_sess_list_entry, &sess->acg->acg_sess_list); TRACE_DBG("Adding sess %p to tgt->sess_list", sess); @@ -7094,16 +7088,14 @@ failed: else sess->init_phase = SCST_SESS_IPH_FAILED; -restart: - list_for_each_entry(cmd, &sess->init_deferred_cmd_list, - cmd_list_entry) { + list_for_each_entry_safe(cmd, cmd_tmp, &sess->init_deferred_cmd_list, + cmd_list_entry) { TRACE_DBG("Deleting cmd %p from init deferred cmd list", cmd); list_del(&cmd->cmd_list_entry); atomic_dec(&sess->sess_cmd_count); spin_unlock_irq(&sess->sess_list_lock); scst_cmd_init_done(cmd, SCST_CONTEXT_THREAD); spin_lock_irq(&sess->sess_list_lock); - goto restart; } spin_lock(&scst_mcmd_lock); diff --git a/scst/src/scst_tg.c b/scst/src/scst_tg.c index e9a3c91b9..62c7b70f5 100644 --- a/scst/src/scst_tg.c +++ b/scst/src/scst_tg.c @@ -77,9 +77,7 @@ static struct scst_device *__lookup_dev(const char *name) { struct scst_device *dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(dev, &scst_dev_list, dev_list_entry) if (strcmp(dev->virt_name, name) == 0) @@ -94,9 +92,7 @@ static struct scst_tgt *__lookup_tgt(const char *name) struct scst_tgt_template *t; struct scst_tgt *tgt; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(t, &scst_template_list, scst_template_list_entry) list_for_each_entry(tgt, &t->tgt_list, tgt_list_entry) @@ -113,9 +109,7 @@ static struct scst_tg_tgt *__lookup_dg_tgt(struct scst_dev_group *dg, struct scst_target_group *tg; struct scst_tg_tgt *tg_tgt; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif BUG_ON(!dg); BUG_ON(!tgt_name); @@ -133,9 +127,7 @@ __lookup_tg_by_name(struct scst_dev_group *dg, const char *name) { struct scst_target_group *tg; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(tg, &dg->tg_list, entry) if (strcmp(tg->name, name) == 0) @@ -151,9 +143,7 @@ __lookup_tg_by_tgt(struct scst_dev_group *dg, const struct scst_tgt *tgt) struct scst_target_group *tg; struct scst_tg_tgt *tg_tgt; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(tg, &dg->tg_list, entry) list_for_each_entry(tg_tgt, &tg->tgt_list, entry) @@ -169,9 +159,7 @@ static struct scst_dg_dev *__lookup_dg_dev_by_dev(struct scst_dev_group *dg, { struct scst_dg_dev *dgd; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(dgd, &dg->dev_list, entry) if (dgd->dev == dev) @@ -186,9 +174,7 @@ static struct scst_dg_dev *__lookup_dg_dev_by_name(struct scst_dev_group *dg, { struct scst_dg_dev *dgd; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(dgd, &dg->dev_list, entry) if (strcmp(dgd->dev->virt_name, name) == 0) @@ -203,9 +189,7 @@ static struct scst_dg_dev *__global_lookup_dg_dev_by_name(const char *name) struct scst_dev_group *dg; struct scst_dg_dev *dgd; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(dg, &scst_dev_group_list, entry) { dgd = __lookup_dg_dev_by_name(dg, name); @@ -220,9 +204,7 @@ static struct scst_dev_group *__lookup_dg_by_name(const char *name) { struct scst_dev_group *dg; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(dg, &scst_dev_group_list, entry) if (strcmp(dg->name, name) == 0) @@ -236,9 +218,7 @@ static struct scst_dev_group *__lookup_dg_by_dev(struct scst_device *dev) { struct scst_dev_group *dg; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(dg, &scst_dev_group_list, entry) if (__lookup_dg_dev_by_dev(dg, dev)) @@ -355,9 +335,7 @@ static void scst_check_alua_invariant(void) struct scst_target_group *tg; enum scst_tg_state expected_state; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif if (!alua_invariant_check) return; @@ -392,9 +370,7 @@ static void scst_check_alua_invariant(void) static void scst_update_tgt_dev_alua_filter(struct scst_tgt_dev *tgt_dev, enum scst_tg_state state) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif tgt_dev->alua_filter = scst_alua_filter[state]; } @@ -404,9 +380,7 @@ static void scst_tg_change_tgt_dev_state(struct scst_tgt_dev *tgt_dev, enum scst_tg_state state, bool gen_ua) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif TRACE_MGMT_DBG("ALUA state of tgt_dev %p has changed", tgt_dev); scst_update_tgt_dev_alua_filter(tgt_dev, state); @@ -421,9 +395,7 @@ void scst_tg_init_tgt_dev(struct scst_tgt_dev *tgt_dev) struct scst_dev_group *dg; struct scst_target_group *tg; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif dg = __lookup_dg_by_dev(tgt_dev->dev); if (dg) { @@ -445,9 +417,7 @@ static void scst_update_tgt_alua_filter(struct scst_target_group *tg, struct scst_dg_dev *dgd; struct scst_tgt_dev *tgt_dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(dgd, &tg->dg->dev_list, entry) { list_for_each_entry(tgt_dev, &dgd->dev->dev_tgt_dev_list, @@ -471,9 +441,7 @@ static void scst_reset_tgt_alua_filter(struct scst_target_group *tg, struct scst_dg_dev *dgd; struct scst_tgt_dev *tgt_dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(dgd, &tg->dg->dev_list, entry) { list_for_each_entry(tgt_dev, &dgd->dev->dev_tgt_dev_list, @@ -584,9 +552,7 @@ void scst_tg_tgt_remove_by_tgt(struct scst_tgt *tgt) struct scst_target_group *tg; struct scst_tg_tgt *t, *t2; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif BUG_ON(!tgt); list_for_each_entry(dg, &scst_dev_group_list, entry) @@ -723,9 +689,7 @@ static void __scst_tg_set_state(struct scst_target_group *tg, struct scst_tgt *tgt; sBUG_ON(state >= ARRAY_SIZE(scst_alua_filter)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif if (tg->state == state) return; @@ -789,9 +753,7 @@ static void __scst_gen_alua_state_changed_ua(struct scst_target_group *tg) struct scst_tg_tgt *tg_tgt; struct scst_tgt *tgt; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(dg_dev, &tg->dg->dev_list, entry) { dev = dg_dev->dev; @@ -814,9 +776,7 @@ static void __scst_tg_set_preferred(struct scst_target_group *tg, { bool prev_preferred; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif if (tg->preferred == preferred) return; @@ -859,9 +819,7 @@ static void scst_update_dev_alua_filter(struct scst_dev_group *dg, struct scst_tgt_dev *tgt_dev; struct scst_target_group *tg; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { @@ -881,9 +839,7 @@ static void scst_reset_dev_alua_filter(struct scst_device *dev) { struct scst_tgt_dev *tgt_dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) @@ -1063,9 +1019,7 @@ static void __scst_dg_remove(struct scst_dev_group *dg) struct scst_dg_dev *dgdev; struct scst_target_group *tg; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&scst_mutex); -#endif list_del(&dg->entry); scst_dg_sysfs_del(dg); diff --git a/scst_local/Makefile b/scst_local/Makefile index 2dee7552a..7eba6e431 100644 --- a/scst_local/Makefile +++ b/scst_local/Makefile @@ -61,6 +61,7 @@ all: Modules.symvers Module.symvers install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ SCST_INC_DIR=$(SCST_INC_DIR) modules_install SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null) diff --git a/scst_local/in-tree/Makefile-3.15 b/scst_local/in-tree/Makefile-3.15 new file mode 100644 index 000000000..8cbbbff63 --- /dev/null +++ b/scst_local/in-tree/Makefile-3.15 @@ -0,0 +1,2 @@ +obj-$(CONFIG_SCST_LOCAL) += scst_local.o + diff --git a/scst_local/scst_local.c b/scst_local/scst_local.c index e872bdeaa..31d18165c 100644 --- a/scst_local/scst_local.c +++ b/scst_local/scst_local.c @@ -88,7 +88,7 @@ static unsigned long scst_local_trace_flag = SCST_LOCAL_DEFAULT_LOG_FLAGS; #define scsi_bufflen(cmd) ((cmd)->request_bufflen) #endif -#define SCST_LOCAL_VERSION "3.0" +#define SCST_LOCAL_VERSION "3.1" static const char *scst_local_version_date = "20110901"; /* Some statistics */ @@ -142,6 +142,8 @@ struct scst_local_sess { spinlock_t aen_lock; struct list_head aen_work_list; /* protected by aen_lock */ + struct work_struct remove_work; + struct list_head sessions_list_entry; }; @@ -152,6 +154,8 @@ static int __scst_local_add_adapter(struct scst_local_tgt *tgt, const char *initiator_name, bool locked); static int scst_local_add_adapter(struct scst_local_tgt *tgt, const char *initiator_name); +static void scst_local_close_session_impl(struct scst_local_sess *sess, + bool async); static void scst_local_remove_adapter(struct scst_local_sess *sess); static int scst_local_add_target(const char *target_name, struct scst_local_tgt **out_tgt); @@ -786,7 +790,7 @@ static ssize_t scst_local_sysfs_mgmt_cmd(char *buf) res = -EINVAL; goto out_unlock; } - scst_local_remove_adapter(sess); + scst_local_close_session_impl(sess, false); } res = 0; @@ -831,7 +835,7 @@ static int scst_local_abort(struct scsi_cmnd *SCpnt) static int scst_local_device_reset(struct scsi_cmnd *SCpnt) { struct scst_local_sess *sess; - __be16 lun; + struct scsi_lun lun; int ret; DECLARE_COMPLETION_ONSTACK(dev_reset_completion); @@ -839,10 +843,11 @@ static int scst_local_device_reset(struct scsi_cmnd *SCpnt) sess = to_scst_lcl_sess(scsi_get_device(SCpnt->device->host)); - lun = cpu_to_be16(SCpnt->device->lun); + int_to_scsilun(SCpnt->device->lun, &lun); ret = scst_rx_mgmt_fn_lun(sess->scst_sess, SCST_LUN_RESET, - &lun, sizeof(lun), false, &dev_reset_completion); + lun.scsi_lun, sizeof(lun), false, + &dev_reset_completion); /* Now wait for the completion ... */ wait_for_completion_interruptible(&dev_reset_completion); @@ -860,7 +865,7 @@ static int scst_local_device_reset(struct scsi_cmnd *SCpnt) static int scst_local_target_reset(struct scsi_cmnd *SCpnt) { struct scst_local_sess *sess; - __be16 lun; + struct scsi_lun lun; int ret; DECLARE_COMPLETION_ONSTACK(dev_reset_completion); @@ -868,10 +873,11 @@ static int scst_local_target_reset(struct scsi_cmnd *SCpnt) sess = to_scst_lcl_sess(scsi_get_device(SCpnt->device->host)); - lun = cpu_to_be16(SCpnt->device->lun); + int_to_scsilun(SCpnt->device->lun, &lun); ret = scst_rx_mgmt_fn_lun(sess->scst_sess, SCST_TARGET_RESET, - &lun, sizeof(lun), false, &dev_reset_completion); + lun.scsi_lun, sizeof(lun), false, + &dev_reset_completion); /* Now wait for the completion ... */ wait_for_completion_interruptible(&dev_reset_completion); @@ -953,13 +959,14 @@ static int scst_local_queuecommand_lck(struct scsi_cmnd *SCpnt, struct scst_local_sess *sess; struct scatterlist *sgl = NULL; int sgl_count = 0; - __be16 lun; + struct scsi_lun lun; struct scst_cmd *scst_cmd = NULL; scst_data_direction dir; TRACE_ENTRY(); - TRACE_DBG("lun %d, cmd: 0x%02X", SCpnt->device->lun, SCpnt->cmnd[0]); + TRACE_DBG("lun %lld, cmd: 0x%02X", (u64)SCpnt->device->lun, + SCpnt->cmnd[0]); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) /* @@ -1002,9 +1009,9 @@ static int scst_local_queuecommand_lck(struct scsi_cmnd *SCpnt, * get into mem alloc deadlock when mounting file systems over * our devices. */ - lun = cpu_to_be16(SCpnt->device->lun); - scst_cmd = scst_rx_cmd(sess->scst_sess, (const uint8_t *)&lun, - sizeof(lun), SCpnt->cmnd, SCpnt->cmd_len, true); + int_to_scsilun(SCpnt->device->lun, &lun); + scst_cmd = scst_rx_cmd(sess->scst_sess, lun.scsi_lun, sizeof(lun), + SCpnt->cmnd, SCpnt->cmd_len, true); if (!scst_cmd) { PRINT_ERROR("%s", "scst_rx_cmd() failed"); return SCSI_MLQUEUE_HOST_BUSY; @@ -1148,14 +1155,15 @@ static int scst_local_get_max_queue_depth(struct scsi_device *sdev) { int res; struct scst_local_sess *sess; - __be16 lun; + struct scsi_lun lun; TRACE_ENTRY(); sess = to_scst_lcl_sess(scsi_get_device(sdev->host)); - lun = cpu_to_be16(sdev->lun); + int_to_scsilun(sdev->lun, &lun); res = scst_get_max_lun_commands(sess->scst_sess, - scst_unpack_lun((const uint8_t *)&lun, sizeof(lun))); + scst_unpack_lun(lun.scsi_lun, + sizeof(lun))); TRACE_EXIT_RES(res); return res; @@ -1385,6 +1393,56 @@ static int scst_local_targ_release(struct scst_tgt *tgt) return 0; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static void scst_remove_work_fn(void *ctx) +#else +static void scst_remove_work_fn(struct work_struct *work) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + struct scst_local_sess *sess = ctx; +#else + struct scst_local_sess *sess = + container_of(work, struct scst_local_sess, remove_work); +#endif + + scst_local_remove_adapter(sess); +} + +static void scst_local_close_session_impl(struct scst_local_sess *sess, + bool async) +{ + bool unregistering; + + spin_lock(&sess->aen_lock); + unregistering = sess->unregistering; + sess->unregistering = 1; + spin_unlock(&sess->aen_lock); + + if (!unregistering) { + if (async) + schedule_work(&sess->remove_work); + else + scst_local_remove_adapter(sess); + } +} + +/* + * Perform removal from the context of another thread since the caller may + * already hold an SCST mutex, since scst_local_remove_adapter() triggers a + * call of device_unregister(), since device_unregister() invokes + * device_del(), since device_del() locks the same mutex that is held while + * invoking scst_add() from class_interface_register() and since scst_add() + * also may lock an SCST mutex. + */ +static int scst_local_close_session(struct scst_session *scst_sess) +{ + struct scst_local_sess *sess = scst_sess_get_tgt_priv(scst_sess); + + scst_local_close_session_impl(sess, true); + return 0; +} + static int scst_local_targ_xmit_response(struct scst_cmd *scst_cmd) { #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) @@ -1525,6 +1583,7 @@ static struct scst_tgt_template scst_local_targ_tmpl = { #endif .detect = scst_local_targ_detect, .release = scst_local_targ_release, + .close_session = scst_local_close_session, .pre_exec = scst_local_targ_pre_exec, .xmit_response = scst_local_targ_xmit_response, #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) @@ -1619,7 +1678,7 @@ static int scst_local_driver_probe(struct device *dev) sess->shost = hpnt; hpnt->max_id = 0; /* Don't want more than one id */ - hpnt->max_lun = 0xFFFF; + hpnt->max_lun = -1ll; /* * Because of a change in the size of this field at 2.6.26 @@ -1783,8 +1842,10 @@ static int __scst_local_add_adapter(struct scst_local_tgt *tgt, */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) INIT_WORK(&sess->aen_work, scst_aen_work_fn, sess); + INIT_WORK(&sess->remove_work, scst_remove_work_fn, sess); #else INIT_WORK(&sess->aen_work, scst_aen_work_fn); + INIT_WORK(&sess->remove_work, scst_remove_work_fn); #endif spin_lock_init(&sess->aen_lock); INIT_LIST_HEAD(&sess->aen_work_list); @@ -1927,11 +1988,7 @@ static void __scst_local_remove_target(struct scst_local_tgt *tgt) list_for_each_entry_safe(sess, ts, &tgt->sessions_list, sessions_list_entry) { - spin_lock(&sess->aen_lock); - sess->unregistering = 1; - spin_unlock(&sess->aen_lock); - - scst_local_remove_adapter(sess); + scst_local_close_session_impl(sess, false); } list_del(&tgt->tgts_list_entry); diff --git a/scstadmin/LICENSE b/scstadmin/LICENSE index 08ddefd04..2a3b0f804 100644 --- a/scstadmin/LICENSE +++ b/scstadmin/LICENSE @@ -2,7 +2,6 @@ Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -304,8 +303,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + with this program. Also add information on how to contact you by electronic and paper mail. diff --git a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/03-targets.t b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/03-targets.t index 10f88b048..f1b6bcac7 100644 --- a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/03-targets.t +++ b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/03-targets.t @@ -8,6 +8,7 @@ BEGIN { } use Data::Dumper; +$Data::Dumper::Sortkeys = 1; use SCST::SCST; sub addTargets { diff --git a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/04-alua.t b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/04-alua.t index c2b39a7d1..72db337a2 100644 --- a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/04-alua.t +++ b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/04-alua.t @@ -8,6 +8,7 @@ BEGIN { } use Data::Dumper; +$Data::Dumper::Sortkeys = 1; use SCST::SCST; sub setup { diff --git a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/05-dynattr.t b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/05-dynattr.t index 02ff569ca..d31c739bf 100644 --- a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/05-dynattr.t +++ b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/05-dynattr.t @@ -8,6 +8,7 @@ BEGIN { } use Data::Dumper; +$Data::Dumper::Sortkeys = 1; use SCST::SCST; sub setup { diff --git a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/after-restore.conf b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/after-restore.conf index 5e248d128..77c6f5389 100644 --- a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/after-restore.conf +++ b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/after-restore.conf @@ -45,7 +45,6 @@ DEVICE_GROUP dg01 { TARGET_GROUP tg01b { group_id 2 - preferred 0 state active TARGET tgt_b { diff --git a/scstadmin/scstadmin.sysfs/scstadmin b/scstadmin/scstadmin.sysfs/scstadmin index 8ee27556c..2d37936b7 100755 --- a/scstadmin/scstadmin.sysfs/scstadmin +++ b/scstadmin/scstadmin.sysfs/scstadmin @@ -1,6 +1,6 @@ #!/usr/bin/perl -$Version = 'SCST Configurator v3.0.0-pre2'; +$Version = 'SCST Configurator v3.1.0-pre1'; # Configures SCST # diff --git a/srpt/LICENSE b/srpt/LICENSE index 7dd67d52b..bfaa85cb7 100644 --- a/srpt/LICENSE +++ b/srpt/LICENSE @@ -40,6 +40,5 @@ is the GNU Public License: GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. diff --git a/srpt/Makefile b/srpt/Makefile index a97d930df..95bb21216 100644 --- a/srpt/Makefile +++ b/srpt/Makefile @@ -48,44 +48,50 @@ MODULE_SYMVERS:=$(shell if [ -e $(KDIR)/Module.symvers ]; then \ echo Module.symvers; else echo Modules.symvers; fi) # Name of the OFED kernel RPM. -OFED_KERNEL_IB_RPM:=$(shell for r in kernel-ib mlnx-ofa_kernel compat-rdma; do rpm -q $$r 2>/dev/null | grep -q "^$$r" && echo $$r && break; done) +OFED_KERNEL_IB_RPM:=$(shell for r in mlnx-ofa_kernel compat-rdma kernel-ib; do rpm -q $$r 2>/dev/null | grep -q "^$$r" && echo $$r && break; done) # Name of the OFED kernel development RPM. -OFED_KERNEL_IB_DEVEL_RPM:=$(shell for r in kernel-ib-devel mlnx-ofa_kernel-devel compat-rdma-devel; do rpm -q $$r 2>/dev/null | grep -q "^$$r" && echo $$r && break; done) +OFED_KERNEL_IB_DEVEL_RPM:=$(shell for r in mlnx-ofa_kernel-devel compat-rdma-devel kernel-ib-devel; do rpm -q $$r 2>/dev/null | grep -q "^$$r" && echo $$r && break; done) -ifeq ($(OFED_KERNEL_IB_RPM),kernel-ib) +OFED_FLAVOR=$(shell /usr/bin/ofed_info 2>/dev/null | head -n1 | sed -n 's/^MLNX_OFED.*/MOFED/p;s/^OFED-.*/OFED/p') + +ifneq ($(OFED_KERNEL_IB_RPM),) +ifeq ($(OFED_KERNEL_IB_RPM),compat-rdma) +# OFED 3.x +OFED_KERNEL_DIR:=/usr/src/compat-rdma +OFED_CFLAGS:=-I$(OFED_KERNEL_DIR)/include +else OFED_KERNEL_DIR:=/usr/src/ofa_kernel -# Read OFED 1.x's config.mk, which contains the definition of the variable -# BACKPORT_INCLUDES. +ifeq ($(OFED_FLAVOR),MOFED) +# Mellanox OFED with or without kernel-ib RPM +OFED_CFLAGS:=-I$(OFED_KERNEL_DIR)/include +else +# OFED 1.5 include $(OFED_KERNEL_DIR)/config.mk OFED_CFLAGS:=$(BACKPORT_INCLUDES) -I$(OFED_KERNEL_DIR)/include endif -ifeq ($(OFED_KERNEL_IB_RPM),mlnx-ofa_kernel) -OFED_KERNEL_DIR:=/usr/src/ofa_kernel/default -OFED_CFLAGS:=-I$(OFED_KERNEL_DIR)/default/include endif -ifeq ($(OFED_KERNEL_IB_RPM),compat-rdma) -OFED_KERNEL_DIR:=/usr/src/compat-rdma -OFED_CFLAGS:=-I$(OFED_KERNEL_DIR)/include -endif -ifneq ($(OFED_KERNEL_IB_RPM),) +# Any OFED version OFED_MODULE_SYMVERS:=$(OFED_KERNEL_DIR)/Module.symvers endif -# Path of the OFED ib_srpt.ko kernel module. -OFED_SRPT_PATH:=/lib/modules/$(KVER)/updates/kernel/drivers/infiniband/ulp/srpt/ib_srpt.ko - -# Whether or not the OFED ib_srpt.ko kernel module has been installed. -OFED_SRPT_INSTALLED:=$(shell if [ -e $(OFED_SRPT_PATH) ]; then echo true; else echo false; fi) +HAVE_KCFLAGS = $(shell $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/conftest/kcflags KCFLAGS=-DKCFLAGS_MACRO=1 >/dev/null 2>&1 && echo true || echo false) +HAVE_PRE_CFLAGS = $(shell $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/conftest/pre_cflags PRE_CFLAGS=-DPRE_CFLAGS_MACRO=1 >/dev/null 2>&1 && echo true || echo false) +AUTOCONF_FLAGS = $(shell $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/conftest/gid_change PRE_CFLAGS="$(OFED_CFLAGS)" >/dev/null 2>&1 && echo -DHAVE_IB_EVENT_GID_CHANGE) all: src/$(MODULE_SYMVERS) $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src \ - PRE_CFLAGS="$(OFED_CFLAGS)" SCST_INC_DIR=$(SCST_INC_DIR) modules + PRE_CFLAGS="$(OFED_CFLAGS) $(AUTOCONF_FLAGS)" \ + KCFLAGS="$(AUTOCONF_FLAGS)" SCST_INC_DIR=$(SCST_INC_DIR) modules install: all src/ib_srpt.ko + @[ -z "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && \ + find /lib/modules/$(KVER) -name ib_srpt.ko -exec rm {} \; ; \ + true $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src \ PRE_CFLAGS="$(OFED_CFLAGS)" SCST_INC_DIR=$(SCST_INC_DIR) \ + $$([ -n "$(DESTDIR)$(INSTALL_MOD_PATH)" ] && echo DEPMOD=true) \ modules_install uninstall: @@ -93,6 +99,11 @@ uninstall: -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) src/Module.symvers src/Modules.symvers: $(SCST_SYMVERS_DIR)/$(MODULE_SYMVERS) + @if [ "$(HAVE_KCFLAGS)" = false -a "$(HAVE_PRE_CFLAGS)" = false -a \ + -n "$(AUTOCONF_FLAGS)" ]; then \ + echo "Error: the kernel build system has not yet been patched.";\ + false; \ + fi @if [ -n "$(OFED_KERNEL_IB_RPM)" ]; then \ if [ -z "$(OFED_KERNEL_IB_DEVEL_RPM)" ]; then \ echo "Error: the OFED package $(OFED_KERNEL_IB_RPM)-devel has" \ @@ -103,20 +114,12 @@ src/Module.symvers src/Modules.symvers: $(SCST_SYMVERS_DIR)/$(MODULE_SYMVERS) "must be removed first" \ " (/lib/modules/$(KVER)/kernel/drivers/infiniband)."; \ false; \ - elif $(OFED_SRPT_INSTALLED); then \ - echo "Error: OFED has been built with srpt=y in ofed.conf."; \ - echo "Rebuild OFED with srpt=n."; \ - false; \ - elif [ -e $(KDIR)/scripts/Makefile.lib ] \ - && ! grep -wq '^c_flags .*PRE_CFLAGS' \ - $(KDIR)/scripts/Makefile.lib \ - && ! grep -wq '^LINUXINCLUDE .*PRE_CFLAGS' \ - $(KDIR)/Makefile; then \ + elif [ "$(HAVE_PRE_CFLAGS)" = false ]; then \ echo "Error: the kernel build system has not yet been patched.";\ false; \ else \ - echo " Building against $(OFED_KERNEL_IB_RPM) InfiniBand" \ - "kernel headers."; \ + echo " Building against $(OFED_FLAVOR) $(OFED_KERNEL_IB_RPM)" \ + "InfiniBand kernel headers."; \ ( \ grep -v drivers/infiniband/ $<; \ cat $(OFED_MODULE_SYMVERS) \ diff --git a/srpt/README b/srpt/README index f5940962c..ae06ffd62 100644 --- a/srpt/README +++ b/srpt/README @@ -50,7 +50,8 @@ The ib_srpt kernel module supports the following parameters: Mode (1) is choosen if both one_target_per_port and use_node_guid_in_target_name are false. Mode (2) is choosen if one_target_per_port is false and use_node_guid_in_target_name is true. Mode - (3) is choosen if one_target_per_port is true. + (3) is choosen if one_target_per_port is true. This last mode is the + default mode. * rdma_cm_port (number) A 16-bit number that specifies the port number to be registered via the RDMA/CM. Must be specified to make communication over RoCE or iWARP diff --git a/srpt/conftest/gid_change/Makefile b/srpt/conftest/gid_change/Makefile new file mode 100644 index 000000000..e81c05753 --- /dev/null +++ b/srpt/conftest/gid_change/Makefile @@ -0,0 +1 @@ +obj-m += gid_change.o diff --git a/srpt/conftest/gid_change/gid_change.c b/srpt/conftest/gid_change/gid_change.c new file mode 100644 index 000000000..bb60773fb --- /dev/null +++ b/srpt/conftest/gid_change/gid_change.c @@ -0,0 +1,9 @@ +#include +#include + +static int modinit(void) +{ + return IB_EVENT_GID_CHANGE; +} + +module_init(modinit); diff --git a/srpt/conftest/kcflags/Makefile b/srpt/conftest/kcflags/Makefile new file mode 100644 index 000000000..59e12dda0 --- /dev/null +++ b/srpt/conftest/kcflags/Makefile @@ -0,0 +1 @@ +obj-m += kcflags.o diff --git a/srpt/conftest/kcflags/kcflags.c b/srpt/conftest/kcflags/kcflags.c new file mode 100644 index 000000000..fff6e202f --- /dev/null +++ b/srpt/conftest/kcflags/kcflags.c @@ -0,0 +1,8 @@ +#include + +static int modinit(void) +{ + return KCFLAGS_MACRO; +} + +module_init(modinit); diff --git a/srpt/conftest/pre_cflags/Makefile b/srpt/conftest/pre_cflags/Makefile new file mode 100644 index 000000000..3c8c550f2 --- /dev/null +++ b/srpt/conftest/pre_cflags/Makefile @@ -0,0 +1 @@ +obj-m += pre_cflags.o diff --git a/srpt/conftest/pre_cflags/pre_cflags.c b/srpt/conftest/pre_cflags/pre_cflags.c new file mode 100644 index 000000000..1602d7115 --- /dev/null +++ b/srpt/conftest/pre_cflags/pre_cflags.c @@ -0,0 +1,8 @@ +#include + +static int modinit(void) +{ + return PRE_CFLAGS_MACRO; +} + +module_init(modinit); diff --git a/srpt/patches/kernel-3.15-pre-cflags.patch b/srpt/patches/kernel-3.15-pre-cflags.patch new file mode 100644 index 000000000..3964ee179 --- /dev/null +++ b/srpt/patches/kernel-3.15-pre-cflags.patch @@ -0,0 +1,12 @@ +diff --git a/Makefile b/Makefile +index 540f7b2..078307f 100644 +--- a/Makefile ++++ b/Makefile +@@ -361,6 +361,7 @@ USERINCLUDE := \ + # Use LINUXINCLUDE when you must reference the include/ directory. + # Needed to be compatible with the O= option + LINUXINCLUDE := \ ++ $(PRE_CFLAGS) \ + -I$(srctree)/arch/$(hdr-arch)/include \ + -Iarch/$(hdr-arch)/include/generated \ + $(if $(KBUILD_SRC), -I$(srctree)/include) \ diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index 62acead56..8b5998914 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -151,9 +151,9 @@ MODULE_PARM_DESC(use_node_guid_in_target_name, #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) \ || defined(RHEL_MAJOR) && RHEL_MAJOR -0 <= 5 -static int one_target_per_port; +static int one_target_per_port = true; #else -static bool one_target_per_port; +static bool one_target_per_port = true; #endif module_param(one_target_per_port, bool, 0444); MODULE_PARM_DESC(one_target_per_port, @@ -1542,8 +1542,9 @@ static int srpt_build_cmd_rsp(struct srpt_rdma_ch *ch, int status, const u8 *sense_data, int sense_data_len) { + struct scst_cmd *cmd = &ioctx->scmnd; struct srp_rsp *srp_rsp; - int max_sense_len; + int resid, max_sense_len; /* * The lowest bit of all SAM-3 status codes is zero (see also @@ -1560,6 +1561,23 @@ static int srpt_build_cmd_rsp(struct srpt_rdma_ch *ch, srp_rsp->tag = tag; srp_rsp->status = status; + if (unlikely(scst_get_resid(cmd, &resid, NULL) && resid != 0)) { + if (scst_cmd_get_data_direction(cmd) & SCST_DATA_READ) { + if (resid > 0) + srp_rsp->flags |= SRP_RSP_FLAG_DIUNDER; + else if (resid < 0) + srp_rsp->flags |= SRP_RSP_FLAG_DIOVER; + srp_rsp->data_in_res_cnt = cpu_to_be32(abs(resid)); + } + if (scst_cmd_get_data_direction(cmd) & SCST_DATA_WRITE) { + if (resid > 0) + srp_rsp->flags |= SRP_RSP_FLAG_DOUNDER; + else if (resid < 0) + srp_rsp->flags |= SRP_RSP_FLAG_DOOVER; + srp_rsp->data_out_res_cnt = cpu_to_be32(abs(resid)); + } + } + if (!scst_sense_valid(sense_data)) sense_data_len = 0; else { @@ -1938,9 +1956,11 @@ static void srpt_process_send_completion(struct ib_cq *cq, } else if (opcode == SRPT_RDMA_READ_LAST || opcode == SRPT_RDMA_WRITE_LAST) { PRINT_INFO("RDMA t %d for idx %u failed with status %d." + "%s", opcode, index, wc->status, + wc->status == IB_WC_WR_FLUSH_ERR ? " If this has not been triggered by a cable" " pull, please check the involved IB HCA's" - " and cables.", opcode, index, wc->status); + " and cables." : ""); srpt_handle_rdma_err_comp(ch, ch->ioctx_ring[index], opcode, srpt_xmt_rsp_context); } else if (opcode == SRPT_RDMA_ZEROLENGTH_WRITE) { @@ -2057,6 +2077,16 @@ static int srpt_compl_thread(void *arg) ch = arg; BUG_ON(!ch); + while (ch->state < CH_LIVE) { + set_current_state(TASK_INTERRUPTIBLE); + if (srpt_process_completion(ch, poll_budget) >= poll_budget) + cond_resched(); + else + schedule(); + } + + srpt_process_wait_list(ch); + while (ch->state < CH_DISCONNECTED) { set_current_state(TASK_INTERRUPTIBLE); if (srpt_process_completion(ch, poll_budget) >= poll_budget) @@ -2247,9 +2277,7 @@ static void __srpt_close_all_ch(struct srpt_tgt *srpt_tgt) struct srpt_nexus *nexus; struct srpt_rdma_ch *ch; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&srpt_tgt->mutex); -#endif list_for_each_entry(nexus, &srpt_tgt->nexus_list, entry) { list_for_each_entry(ch, &nexus->ch_list, list) { diff --git a/srpt/src/ib_srpt.h b/srpt/src/ib_srpt.h index 135091311..0e30e16ea 100644 --- a/srpt/src/ib_srpt.h +++ b/srpt/src/ib_srpt.h @@ -51,7 +51,7 @@ #if defined(RHEL_MAJOR) && RHEL_MAJOR -0 == 5 #define vlan_dev_vlan_id(dev) (panic("RHEL 5 misses vlan_dev_vlan_id()"),0) #endif -#if defined(RHEL_MAJOR) +#if defined(RHEL_MAJOR) && RHEL_MAJOR -0 <= 6 #define __ethtool_get_settings(dev, cmd) (panic("RHEL misses __ethtool_get_settings()"),0) #endif #include @@ -142,12 +142,7 @@ enum { }; #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) && \ - !(defined(CONFIG_SUSE_KERNEL) && \ - LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 76)) && \ - !(defined(RHEL_MAJOR) && \ - (RHEL_MAJOR -0 > 6 || \ - RHEL_MAJOR -0 == 6 && RHEL_MINOR -0 >= 5 || \ - RHEL_MAJOR -0 == 5 && RHEL_MINOR -0 >= 9)) + !defined(HAVE_IB_EVENT_GID_CHANGE) /* See also patch "IB/core: Add GID change event" (commit 761d90ed4). */ enum { IB_EVENT_GID_CHANGE = 18 }; #endif diff --git a/usr/fileio/README b/usr/fileio/README index 79e43ccc8..2411bf479 100644 --- a/usr/fileio/README +++ b/usr/fileio/README @@ -1,7 +1,7 @@ User space FILEIO handler ========================= -Version 3.0.0, XX XXXXX 2014 +Version 3.1.0, XX XXXXX 2014 ---------------------------- User space program fileio_tgt uses interface of SCST's scst_user dev diff --git a/usr/fileio/common.h b/usr/fileio/common.h index 4f23fc46d..957377795 100644 --- a/usr/fileio/common.h +++ b/usr/fileio/common.h @@ -25,7 +25,7 @@ /* 8 byte ASCII Vendor */ #define VENDOR "SCST_USR" /* 4 byte ASCII Product Revision Level - left aligned */ -#define FIO_REV " 300" +#define FIO_REV " 310" #define MAX_USN_LEN (20+1) /* For '\0' */ diff --git a/usr/fileio/fileio.c b/usr/fileio/fileio.c index 9d583c4e5..cfb5d21b6 100644 --- a/usr/fileio/fileio.c +++ b/usr/fileio/fileio.c @@ -66,7 +66,7 @@ unsigned long trace_flag = DEFAULT_LOG_FLAGS; #endif /* defined(DEBUG) || defined(TRACING) */ #define DEF_BLOCK_SHIFT 9 -#define VERSION_STR "3.0.0-pre2" +#define VERSION_STR "3.1.0-pre1" #define THREADS 7 #define MAX_VDEVS 10 diff --git a/www/downloads.html b/www/downloads.html index 93e59c599..6d1253267 100644 --- a/www/downloads.html +++ b/www/downloads.html @@ -39,6 +39,11 @@

The latest stable version of SCST core is 2.2.1. The latest updates for it you can find it in the SVN branch 2.2.x.

+

SCST 3.0 release candidate is available for download from the SCST SVN branch 3.0.x. You can download it using either + web-based SVN repository viewer or using anonymous access:

+ +

svn checkout svn://svn.code.sf.net/p/scst/svn/branches/3.0.x scst-3.0

+

You can also download prebuilt SCST modules for Scientific Linux CERN 5 (RHEL5-based), Ubuntu, @@ -52,11 +57,11 @@ NOTE! Both those projects are very early in the development process, so not recommended for production use yet.

-

The latest development version of SCST core is 3.0. You can download it as well as target drivers and user space +

The latest development version of SCST is 3.1. You can download it as well as target drivers and user space utilities directly from the SCST SVN. You can access it using either - web-based SVN repository viewer or using anonymous access:

+ web-based SVN repository viewer or using anonymous access:

-

svn checkout svn://svn.code.sf.net/p/scst/svn/trunk scst-svn

+

svn checkout svn://svn.code.sf.net/p/scst/svn/trunk scst-trunk

Also you can find in the SCST SVN the latest updates for the stable branches. More information about accessing SVN repository may be found here. Or, alternatively, you can download it as a GNU tarball from diff --git a/www/target_qla2x00t.html b/www/target_qla2x00t.html index d804fdbf1..b4dd81ba8 100644 --- a/www/target_qla2x00t.html +++ b/www/target_qla2x00t.html @@ -63,6 +63,8 @@

The latest stable version is 2.2.0. Requires Linux kernel version 2.6.26.x or higher and SCST version 2.2.0 or higher.

+

Driver for the latest QLogic 16Gb/10G FC/FCoE adapters you can find in git.qlogic.com/scst.git

+