Merge of the pr branch with additional fixes for problems found during extra testing

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1714 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2010-05-26 17:46:46 +00:00
parent bc1cda46df
commit b53e4cb4c1
41 changed files with 4491 additions and 617 deletions
+12
View File
@@ -82,6 +82,18 @@ help:
@echo " srpt_install : srp target: install"
@echo " srpt_uninstall : srp target: uninstall"
@echo ""
@echo " mvsas : make MVSAS target"
@echo " mvsas_clean : mvsas target: clean "
@echo " mvsas_extraclean : mvsas target: clean + clean dependencies"
@echo " mvsas_install : mvsas target: install"
@echo " mvsas_uninstall : mvsas target: uninstall"
@echo ""
@echo " fcst : make FCoE target"
@echo " fcst_clean : FCoE target: clean "
@echo " fcst_extraclean : FCoE target: clean + clean dependencies"
@echo " fcst_install : FCoE target: install"
@echo " fcst_uninstall : FCoE target: uninstall"
@echo ""
@echo " scst_local : make scst_local target"
@echo " scst_local_install : scst_local target: install"
@echo " scst_local_uninstall : scst_local target: uninstall"
+5 -5
View File
@@ -56,7 +56,7 @@ static struct ft_tport *ft_tport_create(struct fc_lport *lport)
if (!tport)
return NULL;
tport->tgt = scst_register(&ft_scst_template, name);
tport->tgt = scst_register_target(&ft_scst_template, name);
if (!tport->tgt) {
kfree(tport);
return NULL;
@@ -94,7 +94,7 @@ static void ft_tport_delete(struct ft_tport *tport)
tgt = tport->tgt;
BUG_ON(!tgt);
FT_SESS_DBG("delete %s\n", scst_get_tgt_name(tgt));
scst_unregister(tgt);
scst_unregister_target(tgt);
lport = tport->lport;
BUG_ON(tport != lport->prov[FC_TYPE_FCP]);
rcu_assign_pointer(lport->prov[FC_TYPE_FCP], NULL);
@@ -214,7 +214,8 @@ static int ft_sess_create(struct ft_tport *tport, struct fc_rport_priv *rdata,
ft_format_wwn(name, sizeof(name), rdata->ids.port_name);
FT_SESS_DBG("register %s\n", name);
scst_sess = scst_register_session(tport->tgt, 0, name, NULL, NULL);
scst_sess = scst_register_session(tport->tgt, 0, name, sess, NULL,
NULL);
if (!scst_sess) {
kfree(sess);
return FC_SPP_RESP_RES; /* out of resources */
@@ -236,7 +237,6 @@ static int ft_sess_create(struct ft_tport *tport, struct fc_rport_priv *rdata,
sess->params = fcp_parm;
rdata->prli_count++;
scst_sess_set_tgt_priv(scst_sess, sess);
return 0;
}
@@ -474,7 +474,7 @@ void ft_recv(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame *fp)
/*
* Release all sessions for a target.
* Called through scst_unregister() as well as directly.
* Called through scst_unregister_target() as well as directly.
* Caller holds ft_lport_lock.
*/
int ft_tgt_release(struct scst_tgt *tgt)
+7
View File
@@ -805,6 +805,13 @@ in/out in the kernel's module Makefile:
- CONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES - simulates digest failures in
random places.
- CONFIG_SCST_ISCSI_SKIP_ISID - makes iSCSI-SCST to always use iSCSI
initiator port TransportID format 0, i.e. always identify initiators
only by names and ignore ISID part in TransportIDs. This is useful
for Persistent Reservations with initiators which don't use ISID in a
standards confirming way, for instance by always incrementing it on
each reconnect, as well as to debug Persistent Reservations.
Creating version of put_page_callback patch for your kernel
+7
View File
@@ -701,6 +701,13 @@ in/out in the kernel's module Makefile:
- CONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES - simulates digest failures in
random places.
- CONFIG_SCST_ISCSI_SKIP_ISID - makes iSCSI-SCST to always use iSCSI
initiator port TransportID format 0, i.e. always identify initiators
only by names and ignore ISID part in TransportIDs. This is useful
for Persistent Reservations with initiators which don't use ISID in a
standards confirming way, for instance by always incrementing it on
each reconnect, as well as to debug Persistent Reservations.
Credits
-------
+14
View File
@@ -23,3 +23,17 @@ config SCST_ISCSI_DEBUG_DIGEST_FAILURES
iSCSI initiator that is talking to SCST.
If unsure, say "N".
config CONFIG_SCST_ISCSI_SKIP_ISID
bool "Do not use ISID in initiator port transport id"
depends on SCST_ISCSI
help
Makes iSCSI-SCST to always use iSCSI initiator port
TransportID format 0, i.e. always identify initiators only by
names and ignore ISID part in TransportIDs. This is useful for
Persistent Reservations with initiators which don't use ISID
in a standards confirming way, for instance by always
incrementing it on each reconnect, as well as to debug
Persistent Reservations.
If unsure, say "N".
+2
View File
@@ -29,6 +29,8 @@ EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions
#EXTRA_CFLAGS += -DCONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES
#EXTRA_CFLAGS += -DCONFIG_SCST_ISCSI_SKIP_ISID
obj-m += iscsi-scst.o
iscsi-scst-objs := iscsi.o nthread.o config.o digest.o \
conn.o session.o target.o event.o param.o
+4
View File
@@ -260,6 +260,10 @@ static ssize_t iscsi_version_show(struct kobject *kobj,
strcat(buf, "DEBUG_DIGEST_FAILURES\n");
#endif
#ifdef CONFIG_SCST_ISCSI_SKIP_ISID
strcat(buf, "CONFIG_SCST_ISCSI_SKIP_ISID\n");
#endif
TRACE_EXIT();
return strlen(buf);
}
+2 -2
View File
@@ -613,12 +613,12 @@ static int conn_setup_sock(struct iscsi_conn *conn)
mm_segment_t oldfs;
struct iscsi_session *session = conn->session;
TRACE_DBG("%llu", (long long unsigned int)session->sid);
TRACE_DBG("%llx", (long long unsigned int)session->sid);
conn->sock = SOCKET_I(conn->file->f_dentry->d_inode);
if (conn->sock->ops->sendpage == NULL) {
PRINT_ERROR("Socket for sid %llu doesn't support sendpage()",
PRINT_ERROR("Socket for sid %llx doesn't support sendpage()",
(long long unsigned int)session->sid);
res = -EINVAL;
goto out;
+67 -2
View File
@@ -18,8 +18,11 @@
#include <linux/hash.h>
#include <linux/kthread.h>
#include <linux/scatterlist.h>
#include <linux/ctype.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include "iscsi.h"
#include "digest.h"
@@ -3118,8 +3121,7 @@ static int iscsi_xmit_response(struct scst_cmd *scst_cmd)
u8 *sense = scst_cmd_get_sense_buffer(scst_cmd);
int sense_len = scst_cmd_get_sense_buffer_len(scst_cmd);
if (unlikely(scst_cmd_atomic(scst_cmd)))
return SCST_TGT_RES_NEED_THREAD_CTX;
EXTRACHECKS_BUG_ON(scst_cmd_atomic(scst_cmd));
scst_cmd_set_tgt_priv(scst_cmd, NULL);
@@ -3494,6 +3496,56 @@ static int iscsi_report_aen(struct scst_aen *aen)
return res;
}
int iscsi_get_initiator_port_transport_id(struct scst_session *scst_sess,
uint8_t **transport_id)
{
struct iscsi_session *sess;
int res = 0;
union iscsi_sid sid;
int tr_id_size;
uint8_t *tr_id;
uint8_t q;
TRACE_ENTRY();
sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
sid = *(union iscsi_sid *)&sess->sid;
sid.id.tsih = 0;
tr_id_size = 4 + strlen(sess->initiator_name) + 5 +
snprintf(&q, sizeof(q), "%llx", sid.id64) + 1;
tr_id_size = (tr_id_size + 3) & -4;
tr_id = kzalloc(tr_id_size, GFP_KERNEL);
if (tr_id == NULL) {
PRINT_ERROR("Allocation of TrandportID (size %d) failed",
tr_id_size);
res = -ENOMEM;
goto out;
}
#ifdef CONFIG_SCST_ISCSI_SKIP_ISID
tr_id[0] = 0x0 | SCSI_TRANSPORTID_PROTOCOLID_ISCSI;
tr_id_size = 4 + sprintf(&tr_id[4], "%s", sess->initiator_name) + 1;
tr_id_size = (tr_id_size + 3) & -4;
#else
tr_id[0] = 0x40 | SCSI_TRANSPORTID_PROTOCOLID_ISCSI;
sprintf(&tr_id[4], "%s,i,0x%llx", sess->initiator_name, sid.id64);
#endif
put_unaligned(cpu_to_be16(tr_id_size - 4),
(__be16 *)&tr_id[2]);
*transport_id = tr_id;
TRACE_DBG("Created tid '%s'", &tr_id[4]);
out:
TRACE_EXIT_RES(res);
return res;
}
void iscsi_send_nop_in(struct iscsi_conn *conn)
{
struct iscsi_cmnd *req, *rsp;
@@ -3615,6 +3667,7 @@ struct scst_tgt_template iscsi_template = {
.task_mgmt_affected_cmds_done = iscsi_task_mgmt_affected_cmds_done,
.task_mgmt_fn_done = iscsi_task_mgmt_fn_done,
.report_aen = iscsi_report_aen,
.get_initiator_port_transport_id = iscsi_get_initiator_port_transport_id,
};
static __init int iscsi_run_threads(int count, char *name, int (*fn)(void *))
@@ -3691,6 +3744,12 @@ static int __init iscsi_init(void)
#endif
#endif
#ifdef CONFIG_SCST_ISCSI_SKIP_ISID
PRINT_WARNING("%s", "CONFIG_SCST_ISCSI_SKIP_ISID defined: identifying "
"initiators only by names and ignoring ISID part in "
"TransportIDs");
#endif
ctr_major = register_chrdev(0, ctr_name, &ctr_fops);
if (ctr_major < 0) {
PRINT_ERROR("failed to register the control device %d",
@@ -3729,6 +3788,12 @@ static int __init iscsi_init(void)
if (err != 0)
goto out_thr;
#ifdef CONFIG_SCST_ISCSI_SKIP_ISID
iscsi_tid_name_only = true;
#else
iscsi_tid_name_only = false;
#endif
out:
return err;
+22 -5
View File
@@ -326,12 +326,17 @@ void iscsi_task_mgmt_affected_cmds_done(struct scst_mgmt_cmd *scst_mcmd)
struct iscsi_session *sess = conn->session;
struct iscsi_conn *c;
if (sess->sess_reinst_successor != NULL)
scst_reassign_persistent_sess_states(
sess->sess_reinst_successor->scst_sess,
sess->scst_sess);
mutex_lock(&sess->target->target_mutex);
/*
* We can't mark sess as shutting down earlier, because until
* now it might have pending commands. Otherwise, in case of
* reinstatement it might lead to data corruption, because
* reinstatement, it might lead to data corruption, because
* commands in being reinstated session can be executed
* after commands in the new session.
*/
@@ -374,6 +379,8 @@ static void close_conn(struct iscsi_conn *conn)
typeof(jiffies) shut_start_waiting = start_waiting;
bool pending_reported = 0, wait_expired = 0, shut_expired = 0;
bool reinst;
uint32_t tid, cid;
uint64_t sid;
#define CONN_PENDING_TIMEOUT ((typeof(jiffies))10*HZ)
#define CONN_WAIT_TIMEOUT ((typeof(jiffies))10*HZ)
@@ -548,10 +555,9 @@ static void close_conn(struct iscsi_conn *conn)
wait_for_completion(&conn->ready_to_free);
TRACE_CONN_CLOSE("Notifying user space about closing connection %p",
conn);
event_send(target->tid, session->sid, conn->cid, 0, E_CONN_CLOSE,
NULL, NULL);
tid = target->tid;
sid = session->sid;
cid = conn->cid;
#ifdef CONFIG_SCST_PROC
mutex_lock(&target->target_mutex);
@@ -561,6 +567,17 @@ static void close_conn(struct iscsi_conn *conn)
kobject_put(&conn->iscsi_conn_kobj);
#endif
/*
* We can't send E_CONN_CLOSE earlier, because otherwise we would have
* a race, when the user space tried to destroy session, which still
* has connections.
*
* !! All target, session and conn can be already dead here !!
*/
TRACE_CONN_CLOSE("Notifying user space about closing connection %p",
conn);
event_send(tid, sid, cid, 0, E_CONN_CLOSE, NULL, NULL);
TRACE_EXIT();
return;
}
+3 -5
View File
@@ -81,7 +81,7 @@ static int iscsi_session_alloc(struct iscsi_target *target,
session->next_ttt = 1;
session->scst_sess = scst_register_session(target->scst_tgt, 0,
name, NULL, NULL);
name, session, NULL, NULL);
if (session->scst_sess == NULL) {
PRINT_ERROR("%s", "scst_register_session() failed");
err = -ENOMEM;
@@ -92,8 +92,6 @@ static int iscsi_session_alloc(struct iscsi_target *target,
kfree(name);
#endif
scst_sess_set_tgt_priv(session->scst_sess, session);
TRACE_MGMT_DBG("Session %p created: target %p, tid %u, sid %#Lx",
session, target, target->tid, info->sid);
@@ -346,7 +344,7 @@ int __del_session(struct iscsi_target *target, u64 sid)
return -ENOENT;
if (!list_empty(&session->conn_list)) {
PRINT_ERROR("%llu still have connections",
PRINT_ERROR("%llx still have connections",
(long long unsigned int)session->sid);
return -EBUSY;
}
@@ -523,7 +521,7 @@ static ssize_t iscsi_sess_force_close_store(struct kobject *kobj,
goto out;
}
PRINT_INFO("Deleting session %llu with initiator %s (%p)",
PRINT_INFO("Deleting session %llx with initiator %s (%p)",
(long long unsigned int)sess->sid, sess->initiator_name, sess);
list_for_each_entry(conn, &sess->conn_list, conn_list_entry) {
+3 -3
View File
@@ -89,9 +89,9 @@ static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid,
INIT_LIST_HEAD(&target->attrs_list);
#endif
target->scst_tgt = scst_register(&iscsi_template, target->name);
target->scst_tgt = scst_register_target(&iscsi_template, target->name);
if (!target->scst_tgt) {
PRINT_ERROR("%s", "scst_register() failed");
PRINT_ERROR("%s", "scst_register_target() failed");
err = -EBUSY;
goto out_free;
}
@@ -233,7 +233,7 @@ static void target_destroy(struct iscsi_target *target)
}
#endif
scst_unregister(target->scst_tgt);
scst_unregister_target(target->scst_tgt);
kfree(target);
+6 -8
View File
@@ -381,9 +381,9 @@ mptstm_probe(struct pci_dev *pdev, const struct pci_device_id *id)
atomic_set(&tgt->sess_count, 0);
init_waitqueue_head(&tgt->waitQ);
tgt->scst_tgt = scst_register(&tgt_template, MYNAM);
tgt->scst_tgt = scst_register_target(&tgt_template, MYNAM);
if (tgt->scst_tgt == NULL) {
PRINT_ERROR(MYNAM ": scst_register() "
PRINT_ERROR(MYNAM ": scst_register_target() "
"failed for host %p", pdev);
ret = -ENODEV;
@@ -399,7 +399,7 @@ mptstm_probe(struct pci_dev *pdev, const struct pci_device_id *id)
PRINT_ERROR("Not enough memory to register "
"target driver %s entry %s in /proc",
tgt_template.name, name);
scst_unregister(tgt->scst_tgt);
scst_unregister_target(tgt->scst_tgt);
ret = -ENOMEM;
goto out;
}
@@ -437,7 +437,7 @@ static struct mpt_pci_driver mptstm_driver = {
*
* this function is intended to detect the target adapters that are present in
* the system. Each found adapter should be registered by calling
* scst_register(). The function should return a value >= 0 to signify
* scst_register_target(). The function should return a value >= 0 to signify
* the number of detected target adapters. A negative value should be
* returned whenever there is an error.
*/
@@ -592,8 +592,6 @@ mpt_alloc_session_done(struct scst_session *scst_sess, void *data, int result)
TRACE_ENTRY();
if (result == 0) {
scst_sess_set_tgt_priv(scst_sess, sess);
while (!list_empty(&sess->delayed_cmds)) {
cmd = list_entry(sess->delayed_cmds.next,
typeof(*cmd), delayed_cmds_entry);
@@ -979,7 +977,8 @@ stmapp_tgt_command(MPT_STM_PRIV *priv, u32 reply_word)
INIT_LIST_HEAD(&sess->delayed_cmds);
sess->scst_sess = scst_register_session(tgt->scst_tgt, 1,
"", sess, mpt_alloc_session_done);
"", sess, sess,
mpt_alloc_session_done);
if (sess->scst_sess == NULL) {
PRINT_ERROR(MYNAM ": scst_register_session failed %p",
tgt);
@@ -990,7 +989,6 @@ stmapp_tgt_command(MPT_STM_PRIV *priv, u32 reply_word)
__set_bit(MPT_SESS_INITING, &sess->sess_flags);
tgt->sess[init_index] = sess;
scst_sess_set_tgt_priv(sess->scst_sess, sess);
cmd->sess = sess;
list_add_tail(&cmd->delayed_cmds_entry, &sess->delayed_cmds);
+8 -8
View File
@@ -1593,7 +1593,7 @@ int mvst_send_cmd_to_scst(struct mvs_info *mvi,
}
sess->scst_sess = scst_register_session(
tgt->scst_tgt, SCST_ATOMIC, name, sess,
tgt->scst_tgt, SCST_ATOMIC, name, sess, sess,
mvst_alloc_session_done);
kfree(name);
}
@@ -1606,7 +1606,6 @@ int mvst_send_cmd_to_scst(struct mvs_info *mvi,
res = -EFAULT;
goto out_free_sess;
}
scst_sess_set_tgt_priv(sess->scst_sess, sess);
/* add session data to host data structure */
list_add(&sess->sess_entry, &tgt->sess_list);
@@ -2112,9 +2111,9 @@ static void mvst_register_tgt_handler(struct mvs_info *mvi)
INIT_LIST_HEAD(&tgt->sess_list);
init_waitqueue_head(&tgt->waitQ);
tgt->scst_tgt = scst_register(&tgt_template, MVST_NAME);
tgt->scst_tgt = scst_register_target(&tgt_template, MVST_NAME);
if (!tgt->scst_tgt) {
PRINT_ERROR("mvst tgt(%ld): scst_register() "
PRINT_ERROR("mvst tgt(%ld): scst_register_target() "
"failed for host %ld(%p)", mvi->instance,
mvi->host_no, mvi);
kfree(tgt);
@@ -2141,11 +2140,11 @@ static void mvst_unregister_tgt_handler(struct mvs_info *mvi)
TRACE_DBG("Shutting down host %ld(%ld,%p)",
mvi->host_no, mvi->instance, mvi);
scst_unregister(tgt->scst_tgt);
scst_unregister_target(tgt->scst_tgt);
mvi->flags &= ~MVF_TARGET_MODE_ENABLE;
/*
* Free of tgt happens via callback mvst_target_release
* called from scst_unregister, so we shouldn't touch it again
* called from scst_unregister_target, so we shouldn't touch it again
*/
tgt = NULL;
}
@@ -2340,11 +2339,12 @@ static void mvst_host_action(struct mvs_info *mvi,
TRACE_DBG("Shutting down host %ld(%ld,%p)",
mvi->host_no, mvi->instance, mvi);
scst_unregister(tgt->scst_tgt);
scst_unregister_target(tgt->scst_tgt);
mvi->flags &= ~MVF_TARGET_MODE_ENABLE;
/*
* Free of tgt happens via callback mvst_target_release
* called from scst_unregister, so we shouldn't touch it again
* called from scst_unregister_target, so we shouldn't touch
* it again
*/
tgt = NULL;
break;
+6 -9
View File
@@ -625,8 +625,7 @@ static struct q2t_sess *q2t_create_sess(scsi_qla_host_t *ha, fc_port_t *fcport,
/* Let's do the session creation async'ly */
sess->scst_sess = scst_register_session(tgt->scst_tgt, 1, wwn_str,
sess, q2t_alloc_session_done);
sess, sess, q2t_alloc_session_done);
if (sess->scst_sess == NULL) {
PRINT_CRIT_ERROR("qla2x00t(%ld): scst_register_session() "
"failed for host %ld (wwn %s, loop_id %d), all "
@@ -634,7 +633,6 @@ static struct q2t_sess *q2t_create_sess(scsi_qla_host_t *ha, fc_port_t *fcport,
ha->host_no, wwn_str, fcport->loop_id);
goto out_free_sess_wwn;
}
scst_sess_set_tgt_priv(sess->scst_sess, sess);
spin_lock_irq(&ha->hardware_lock);
TRACE_MGMT_DBG("Adding sess %p to tgt %p", sess, tgt);
@@ -2125,8 +2123,7 @@ static int q2x_xmit_response(struct scst_cmd *scst_cmd)
#endif
#ifdef CONFIG_QLA_TGT_DEBUG_WORK_IN_THREAD
if (scst_cmd_atomic(scst_cmd))
return SCST_TGT_RES_NEED_THREAD_CTX;
EXTRACHECKS_BUG_ON(scst_cmd_atomic(scst_cmd));
#endif
if (is_send_status)
@@ -5020,12 +5017,12 @@ static int q2t_add_target(scsi_qla_host_t *ha)
if (q2t_get_target_name(ha, &wwn) != 0)
goto out_free;
tgt->scst_tgt = scst_register(&tgt2x_template, wwn);
tgt->scst_tgt = scst_register_target(&tgt2x_template, wwn);
kfree(wwn);
if (!tgt->scst_tgt) {
PRINT_ERROR("qla2x00t(%ld): scst_register() "
PRINT_ERROR("qla2x00t(%ld): scst_register_target() "
"failed for host %ld(%p)", ha->instance,
ha->host_no, ha);
res = -ENOMEM;
@@ -5093,10 +5090,10 @@ static int q2t_remove_target(scsi_qla_host_t *ha)
}
TRACE_DBG("Unregistering target for host %ld(%p)", ha->host_no, ha);
scst_unregister(ha->tgt->scst_tgt);
scst_unregister_target(ha->tgt->scst_tgt);
/*
* Free of tgt happens via callback q2t_target_release
* called from scst_unregister, so we shouldn't touch
* called from scst_unregister_target, so we shouldn't touch
* it again.
*/
+4 -4
View File
@@ -288,7 +288,7 @@ alloc_ini(bus_chan_t *bc, uint64_t iid)
GET(7), GET(6), GET(5) , GET(4), GET(3), GET(2), GET(1), GET(0));
#undef GET
nptr->ini_scst_sess = scst_register_session(bc->scst_tgt, 0, ini_name, NULL, NULL);
nptr->ini_scst_sess = scst_register_session(bc->scst_tgt, 0, ini_name, NULL, NULL, NULL);
if (!nptr->ini_scst_sess) {
Eprintk("cannot register SCST session\n");
kfree(nptr);
@@ -1637,7 +1637,7 @@ register_hba(bus_t *bp)
}
isp_tgt_template.sg_tablesize = get_sg_tablesize(bp->h.r_identity);
scst_tgt = scst_register(&isp_tgt_template, name);
scst_tgt = scst_register_target(&isp_tgt_template, name);
if (scst_tgt == NULL) {
Eprintk("cannot register scst device %s for %s%d\n", name, bp->h.r_name, bp->h.r_inst);
goto err_free_chan;
@@ -1672,7 +1672,7 @@ register_hba(bus_t *bp)
err_free_chan:
for (chan = bp->h.r_nchannels -1; chan >= 0; chan--) {
if (bchan[chan].scst_tgt) {
scst_unregister(bchan[chan].scst_tgt);
scst_unregister_target(bchan[chan].scst_tgt);
}
}
kfree(bchan);
@@ -1726,7 +1726,7 @@ unregister_hba(bus_t *bp, hba_register_t *unreg_hp)
BUS_DBG(bp, "Chan %d waiting for finishing %d sessions\n", chan, atomic_read(&bc->sess_count));
wait_event(bc->wait_queue, atomic_read(&bc->sess_count) == 0);
BUS_DBG(bp, "Chan %d all sessions finished\n", chan);
scst_unregister(bc->scst_tgt);
scst_unregister_target(bc->scst_tgt);
}
}
kfree(bp->bchan);
+46 -18
View File
@@ -271,17 +271,20 @@ in/out in Makefile:
patching is necessary for pass-through device handlers (scst_disk,
etc.).
- CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be
allowed to submit pass-through commands to real SCSI devices via the SCSI
middle layer using scsi_execute_async() function from soft IRQ
context (tasklets). This used to be the default, but currently it
seems the SCSI middle layer starts expecting only thread context on
the IO submit path, so it is disabled now by default. Enabling it
will decrease amount of context switches and improve performance. It
is more or less safe, in the worst case, if in your configuration the
SCSI middle layer really doesn't expect SIRQ context in
scsi_execute_async() function, you will get a warning message in the
kernel log.
- CONFIG_SCST_TEST_IO_IN_SIRQ - if defined, allows SCST to submit selected
SCSI commands (TUR and READ/WRITE) from soft-IRQ context (tasklets).
Enabling it will decrease amount of context switches and slightly
improve performance. The goal of this option is to be able to measure
overhead of the context switches. If after enabling this option you
don't see under load in vmstat output on the target significant
decrease of amount of context switches, then your target driver
doesn't submit commands to SCST in IRQ context. For instance,
iSCSI-SCST doesn't do that, but qla2x00t with
CONFIG_QLA_TGT_DEBUG_WORK_IN_THREAD disabled - does. This option is
designed to be used with vdisk NULLIO backend.
WARNING! Using with other backend than vdisk NULLIO is unsafe and can
lead you to a kernel crash!
- CONFIG_SCST_STRICT_SECURITY - if defined, makes SCST zero allocated data
buffers. Undefining it (default) considerably improves performance
@@ -1285,6 +1288,34 @@ IMPORTANT: Some disk and partition table management utilities don't support
work with files on such file system.
Persistent Reservations
-----------------------
SCST implements Persistent Reservations with full set of capabilities,
including "Persistence Through Power Loss".
The "Persistence Through Power Loss" data are saved in /var/lib/scst/pr
with files with names the same as the names of the corresponding
devices. Also this directory contains backup versions of those files
with suffix ".1". Those backup files are used in case of power or other
failure to prevent Persistent Reservation information from corruption
during update.
The Persistent Reservations available on all transports implementing
get_initiator_port_transport_id() callback. Transports not implementing
this callback will act in one of 2 possible scenarios ("all or
nothing"):
1. If a device has such transport connected and doesn't have persistent
reservations, it will refuse Persistent Reservations commands as if it
doesn't support them.
2. If a device has persistent reservations, all initiators newly
connecting via such transports will not see this device. After all
persistent reservations from this device are released, upon reconnect
the initiators will see it.
Caching
-------
@@ -1473,7 +1504,8 @@ you, so the resulting performance will, in average, be better
you can by manual tuning improve it even more.
If you want to get maximum performance from your target, RHEL/CentOS 5.x
kernels are not recommended, because they are based on very outdated
kernels are not recommended on both target and initiators, if you are
using Linux initiators, because those kernels are based on very outdated
2.6.18 kernel, hence, missed >3 years of important improvements in the
kernel's storage area. You should use at least long maintained vanilla
2.6.27.x kernel, although 2.6.29+ would be even better.
@@ -1490,9 +1522,6 @@ In order to get the maximum performance you should:
- Disable in Makefile CONFIG_SCST_STRICT_SERIALIZING, CONFIG_SCST_EXTRACHECKS,
CONFIG_SCST_TRACING, CONFIG_SCST_DEBUG*, CONFIG_SCST_STRICT_SECURITY
- For pass-through devices enable
CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ.
2. For target drivers:
- Disable in Makefiles CONFIG_SCST_EXTRACHECKS, CONFIG_SCST_TRACING,
@@ -1502,14 +1531,13 @@ In order to get the maximum performance you should:
- Disable in Makefile CONFIG_SCST_TRACING and CONFIG_SCST_DEBUG.
IMPORTANT: The development version of SCST in the SVN is optimized for
========= development and bug hunting, not for performance. To reconfigure
it for performance you should run "make debug2perf" in the
root of your source code (e.g. trunk/). It will set the above
options as needed. The only option it doesn't set is
CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ, so, if
needed, you should change it manually.
CONFIG_SCST_TEST_IO_IN_SIRQ, so, if needed, you should change
it manually.
IMPORTANT: You can't use debug SCST drivers with non-debug SCST core.
========= So, after disabling both CONFIG_SCST_TRACING and CONFIG_SCST_DEBUG
+42 -14
View File
@@ -196,17 +196,20 @@ your favorite kernel configuration Makefile target, e.g. "make xconfig":
patching is necessary for pass-through device handlers (scst_disk,
etc.).
- CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - if defined, it will be
allowed to submit pass-through commands to real SCSI devices via the SCSI
middle layer using scsi_execute_async() function from soft IRQ
context (tasklets). This used to be the default, but currently it
seems the SCSI middle layer starts expecting only thread context on
the IO submit path, so it is disabled now by default. Enabling it
will decrease amount of context switches and improve performance. It
is more or less safe, in the worst case, if in your configuration the
SCSI middle layer really doesn't expect SIRQ context in
scsi_execute_async() function, you will get a warning message in the
kernel log.
- CONFIG_SCST_TEST_IO_IN_SIRQ - if defined, allows SCST to submit selected
SCSI commands (TUR and READ/WRITE) from soft-IRQ context (tasklets).
Enabling it will decrease amount of context switches and slightly
improve performance. The goal of this option is to be able to measure
overhead of the context switches. If after enabling this option you
don't see under load in vmstat output on the target significant
decrease of amount of context switches, then your target driver
doesn't submit commands to SCST in IRQ context. For instance,
iSCSI-SCST doesn't do that, but qla2x00t with
CONFIG_QLA_TGT_DEBUG_WORK_IN_THREAD disabled - does. This option is
designed to be used with vdisk NULLIO backend.
WARNING! Using with other backend than vdisk NULLIO is unsafe and can
lead you to a kernel crash!
- CONFIG_SCST_STRICT_SECURITY - if defined, makes SCST zero allocated data
buffers. Undefining it (default) considerably improves performance
@@ -869,6 +872,34 @@ IMPORTANT: Some disk and partition table management utilities don't support
work with files on such file system.
Persistent Reservations
-----------------------
SCST implements Persistent Reservations with full set of capabilities,
including "Persistence Through Power Loss".
The "Persistence Through Power Loss" data are saved in /var/lib/scst/pr
with files with names the same as the names of the corresponding
devices. Also this directory contains backup versions of those files
with suffix ".1". Those backup files are used in case of power or other
failure to prevent Persistent Reservation information from corruption
during update.
The Persistent Reservations available on all transports implementing
get_initiator_port_transport_id() callback. Transports not implementing
this callback will act in one of 2 possible scenarios ("all or
nothing"):
1. If a device has such transport connected and doesn't have persistent
reservations, it will refuse Persistent Reservations commands as if it
doesn't support them.
2. If a device has persistent reservations, all initiators newly
connecting via such transports will not see this device. After all
persistent reservations from this device are released, upon reconnect
the initiators will see it.
Caching
-------
@@ -1068,9 +1099,6 @@ In order to get the maximum performance you should:
- Disable in Makefile CONFIG_SCST_STRICT_SERIALIZING, CONFIG_SCST_EXTRACHECKS,
CONFIG_SCST_TRACING, CONFIG_SCST_DEBUG*, CONFIG_SCST_STRICT_SECURITY
- For pass-through devices enable
CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ.
2. For target drivers:
- Disable in Makefiles CONFIG_SCST_EXTRACHECKS, CONFIG_SCST_TRACING,
+182 -61
View File
@@ -64,7 +64,7 @@ typedef _Bool bool;
#else
#define SCST_VERSION_STRING_SUFFIX
#endif
#define SCST_VERSION_STRING "2.0.0-pre1" SCST_VERSION_STRING_SUFFIX
#define SCST_VERSION_STRING "2.0.0-rc1" SCST_VERSION_STRING_SUFFIX
#define SCST_INTERFACE_VERSION \
SCST_VERSION_STRING "$Revision$" SCST_CONST_VERSION
@@ -200,22 +200,25 @@ static inline int list_is_last(const struct list_head *list,
*************************************************************/
/* LUN translation (mcmd->tgt_dev assignment) */
#define SCST_MCMD_STATE_INIT 0
#define SCST_MCMD_STATE_INIT 0
/* Mgmt cmd is ready for processing */
#define SCST_MCMD_STATE_READY 1
/* Mgmt cmd is being processed */
#define SCST_MCMD_STATE_EXEC 1
/* Mgmt cmd is being executing */
#define SCST_MCMD_STATE_EXECUTING 2
/* Waiting for affected commands done */
#define SCST_MCMD_STATE_WAITING_AFFECTED_CMDS_DONE 2
/* Post check when affected commands done */
#define SCST_MCMD_STATE_POST_AFFECTED_CMDS_DONE 3
/* Post actions when affected commands done */
#define SCST_MCMD_STATE_AFFECTED_CMDS_DONE 3
/* Waiting for affected local commands finished */
#define SCST_MCMD_STATE_WAITING_AFFECTED_CMDS_FINISHED 4
/* Target driver's task_mgmt_fn_done() is going to be called */
#define SCST_MCMD_STATE_DONE 4
#define SCST_MCMD_STATE_DONE 5
/* The mcmd finished */
#define SCST_MCMD_STATE_FINISHED 5
#define SCST_MCMD_STATE_FINISHED 6
/*************************************************************
** Constants for "atomic" parameter of SCST's functions
@@ -309,9 +312,6 @@ enum scst_exec_context {
*/
#define SCST_PREPROCESS_STATUS_ERROR_FATAL 3
/* Thread context requested */
#define SCST_PREPROCESS_STATUS_NEED_THREAD 4
/*************************************************************
** Values for AEN functions
*************************************************************/
@@ -374,12 +374,6 @@ enum scst_exec_context {
/* The cmd should be sent to SCSI mid-level */
#define SCST_EXEC_NOT_COMPLETED 1
/*
* Thread context is required to execute the command.
* Exec() will be called again in the thread context.
*/
#define SCST_EXEC_NEED_THREAD 2
/*
* Set if cmd is finished and there is status/sense to be sent.
* The status should be not sent (i.e. the flag not set) if the
@@ -463,11 +457,7 @@ enum scst_exec_context {
/* Set if the corresponding context is atomic */
#define SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC 5
#define SCST_TGT_DEV_AFTER_INIT_OTH_ATOMIC 6
#define SCST_TGT_DEV_AFTER_RESTART_WR_ATOMIC 7
#define SCST_TGT_DEV_AFTER_RESTART_OTH_ATOMIC 8
#define SCST_TGT_DEV_AFTER_RX_DATA_ATOMIC 9
#define SCST_TGT_DEV_AFTER_EXEC_ATOMIC 10
#define SCST_TGT_DEV_AFTER_EXEC_ATOMIC 6
#define SCST_TGT_DEV_CLUST_POOL 11
@@ -735,10 +725,6 @@ struct scst_tgt_template {
* This command is expected to be NON-BLOCKING.
* If it is blocking, consider to set threads_num to some none 0 number.
*
* Pay attention to "atomic" attribute of the cmd, which can be get
* by scst_cmd_atomic(): it is true if the function called in the
* atomic (non-sleeping) context.
*
* OPTIONAL
*/
int (*pre_exec) (struct scst_cmd *cmd);
@@ -816,6 +802,20 @@ struct scst_tgt_template {
int length, int *eof, struct scst_tgt *tgt);
#endif
/*
* This function returns in tr_id the corresponding to sess initiator
* port TransporID in the form as it's used by PR commands, see
* "Transport Identifiers" in SPC. Space for the initiator port
* TransporID must be allocated via kmalloc(). Caller supposed to
* kfree() it, when it isn't needed anymore.
*
* Returns 0 on success or negative error code otherwise.
*
* SHOULD HAVE, because it's required for Persistent Reservations.
*/
int (*get_initiator_port_transport_id) (struct scst_session *sess,
uint8_t **transport_id);
/*
* This function allows to enable or disable particular target.
* A disabled target doesn't receive and process any SCSI commands.
@@ -972,7 +972,6 @@ struct scst_dev_type {
*/
unsigned parse_atomic:1;
unsigned alloc_data_buf_atomic:1;
unsigned exec_atomic:1;
unsigned dev_done_atomic:1;
#ifdef CONFIG_SCST_PROC
@@ -986,6 +985,13 @@ struct scst_dev_type {
*/
unsigned exec_sync:1;
/*
* Should be set if the device wants to receive notification of
* Persistent Reservation commands (PR OUT only)
* Note: The notification will not be send if the command failed
*/
unsigned pr_cmds_notifications:1;
/*
* Called to parse CDB from the cmd and initialize
* cmd->bufflen and cmd->data_direction (both - REQUIRED).
@@ -1032,15 +1038,9 @@ struct scst_dev_type {
* cmd->scst_cmd_done() callback.
* Returns:
* - SCST_EXEC_COMPLETED - the cmd is done, go to other ones
* - SCST_EXEC_NEED_THREAD - thread context is required to execute
* the command. Exec() will be called again in the thread context.
* - SCST_EXEC_NOT_COMPLETED - the cmd should be sent to SCSI
* mid-level.
*
* Pay attention to "atomic" attribute of the cmd, which can be get
* by scst_cmd_atomic(): it is true if the function called in the
* atomic (non-sleeping) context.
*
* If this function provides sync execution, you should set
* exec_sync flag and consider to setup dedicated threads by
* setting threads_num > 0.
@@ -1385,6 +1385,9 @@ struct scst_session {
/* Access control for this session and list entry there */
struct scst_acg *acg;
/* Initiator port transport id */
uint8_t *transport_id;
/* List entry for the sessions list inside ACG */
struct list_head acg_sess_list_entry;
@@ -1459,6 +1462,29 @@ struct scst_session {
#endif
};
/*
* SCST_PR_ABORT_ALL TM function helper structure
*/
struct scst_pr_abort_all_pending_mgmt_cmds_counter {
/*
* How many there are pending for this cmd SCST_PR_ABORT_ALL TM
* commands.
*/
atomic_t pr_abort_pending_cnt;
/* Saved completition routine */
void (*saved_cmd_done) (struct scst_cmd *cmd, int next_state,
enum scst_exec_context pref_context);
/*
* How many there are pending for this cmd SCST_PR_ABORT_ALL TM
* commands, which not yet aborted all affected commands and
* a completion to signal, when it's done.
*/
atomic_t pr_aborting_cnt;
struct completion pr_aborting_cmpl;
};
/*
* Structure to control commands' queuing and threads pool processing the queue
*/
@@ -1567,6 +1593,12 @@ struct scst_cmd {
*/
unsigned int sg_buff_modified:1;
/*
* Set if cmd buffer was vmallocated and copied from more
* then one sg chunk
*/
unsigned int sg_buff_vmallocated:1;
/*
* Set if scst_cmd_init_stage1_done() called and the target
* want that preprocessing_done() will be called
@@ -1761,12 +1793,18 @@ struct scst_cmd {
/* Used to retry commands in case of double UA */
int dbl_ua_orig_resp_data_len, dbl_ua_orig_data_direction;
/* List corresponding mgmt cmd, if any, protected by sess_list_lock */
/*
* List of the corresponding mgmt cmds, if any. Protected by
* sess_list_lock.
*/
struct list_head mgmt_cmd_list;
/* List entry for dev's blocked_cmd_list */
struct list_head blocked_cmd_list_entry;
/* Counter of the corresponding SCST_PR_ABORT_ALL TM commands */
struct scst_pr_abort_all_pending_mgmt_cmds_counter *pr_abort_counter;
struct scst_cmd *orig_cmd; /* Used to issue REQUEST SENSE */
#ifdef CONFIG_SCST_MEASURE_LATENCY
@@ -1806,8 +1844,11 @@ struct scst_mgmt_cmd_stub {
/* List entry in cmd->mgmt_cmd_list */
struct list_head cmd_mgmt_cmd_list_entry;
/* set if the cmd was counted in mcmd->cmd_done_wait_count */
/* Set if the cmd was counted in mcmd->cmd_done_wait_count */
unsigned int done_counted:1;
/* Set if the cmd was counted in mcmd->cmd_finish_wait_count */
unsigned int finish_counted:1;
};
/*
@@ -1824,13 +1865,10 @@ struct scst_mgmt_cmd {
int fn; /* task management function */
unsigned int completed:1; /* set, if the mcmd is completed */
/* Set if device(s) should be unblocked after mcmd's finish */
unsigned int needs_unblocking:1;
unsigned int lun_set:1; /* set, if lun field is valid */
unsigned int cmd_sn_set:1; /* set, if cmd_sn field is valid */
/* set, if scst_mgmt_affected_cmds_done was called */
unsigned int affected_cmds_done_called:1;
/*
* Number of commands to finish before sending response,
@@ -1862,18 +1900,36 @@ struct scst_mgmt_cmd {
/* completition status, one of the SCST_MGMT_STATUS_* constants */
int status;
/* Used for storage of target driver private stuff */
void *tgt_priv;
/* Used for storage of target driver private stuff or origin PR cmd */
union {
void *tgt_priv;
struct scst_cmd *origin_pr_cmd;
};
};
/*
* Persistent reservations registrant
*/
struct scst_dev_registrant {
uint8_t *transport_id;
uint16_t rel_tgt_id;
uint64_t key;
/* tgt_dev (I_T nexus) for this registrant, if any */
struct scst_tgt_dev *tgt_dev;
/* List entry for dev_registrants_list */
struct list_head dev_registrants_list_entry;
/* 2 auxiliary fields used to rollback changes for errors, etc. */
struct list_head aux_list_entry;
uint64_t rollback_key;
};
/*
* SCST device
*/
struct scst_device {
struct scst_dev_type *handler; /* corresponding dev handler */
struct scst_mem_lim dev_mem_lim;
unsigned short type; /* SCSI type of the device */
/*************************************************************
@@ -1890,12 +1946,15 @@ struct scst_device {
/* If set, dev is read only */
unsigned short rd_only:1;
/* Set if tgt_kobj was initialized */
unsigned short dev_kobj_initialized:1;
/**************************************************************/
/*************************************************************
** Dev's control mode page related values. Updates serialized
** by scst_block_dev(). It's long to not interfere with the
** above flags.
** neighbour fields.
*************************************************************/
unsigned long queue_alg:4;
@@ -1913,6 +1972,23 @@ struct scst_device {
/**************************************************************/
/* Set if dev is persistently reserved. Protected by dev_pr_mutex. */
unsigned short pr_is_set:1;
/*
* Set if there is a thread changing or going to change PR state(s).
* Protected by dev_pr_mutex.
*/
unsigned short pr_writer_active:1;
/*
* How many threads are checking commands for PR allowance. Used to
* implement lockless read-only fast path.
*/
atomic_t pr_readers_count;
struct scst_dev_type *handler; /* corresponding dev handler */
/* Used for storage of dev handler private stuff */
void *dh_priv;
@@ -1924,16 +2000,20 @@ struct scst_device {
/* Corresponding real SCSI device, could be NULL for virtual devices */
struct scsi_device *scsi_dev;
/* Lists of commands with lock, if dedicated threads are used */
/* List of commands with lock, if dedicated threads are used */
struct scst_cmd_threads dev_cmd_threads;
/* Memory limits for this device */
struct scst_mem_lim dev_mem_lim;
/* How many cmds alive on this dev */
atomic_t dev_cmd_count;
/* How many write cmds alive on this dev. Temporary, ToDo */
atomic_t write_cmd_count;
spinlock_t dev_lock; /* device lock */
/*
* How many there are "on_dev" commands, i.e. ones those are being
* executed by the underlying SCSI/virtual device.
*/
atomic_t on_dev_count;
/*
* How many times device was blocked for new cmds execution.
@@ -1941,11 +2021,48 @@ struct scst_device {
*/
int block_count;
/* How many write cmds alive on this dev. Temporary, ToDo */
atomic_t write_cmd_count;
/*************************************************************
** Persistent reservation fields. Protected by dev_pr_mutex.
*************************************************************/
/* True if persist through power loss is activated */
unsigned short pr_aptpl:1;
/* Persistent reservation type */
uint8_t pr_type;
/* Persistent reservation scope */
uint8_t pr_scope;
/* Mutex to protect PR operations */
struct mutex dev_pr_mutex;
/* Persistent reservation generation value */
uint32_t pr_generation;
/* Reference to registrant - persistent reservation holder */
struct scst_dev_registrant *pr_holder;
/* List of dev's registrants */
struct list_head dev_registrants_list;
/*
* How many there are "on_dev" commands, i.e. ones those are being
* executed by the underlying SCSI/virtual device.
* Count of connected tgt_devs from transports, which don't support
* PRs, i.e. don't have get_initiator_port_transport_id(). Protected
* by scst_mutex.
*/
atomic_t on_dev_count;
int not_pr_supporting_tgt_devs_num;
/* Persist through power loss files */
char *pr_file_name;
char *pr_file_name1;
/**************************************************************/
spinlock_t dev_lock; /* device lock */
struct list_head blocked_cmd_list; /* protected by dev_lock */
@@ -1979,9 +2096,6 @@ struct scst_device {
/* Threads pool type of the device. Valid only if threads_num > 0. */
enum scst_dev_type_threads_pool_type threads_pool_type;
/* Set if tgt_kobj was initialized */
unsigned int dev_kobj_initialized:1;
/*
* Used to protect sysfs attributes to be called after this
* object was unregistered.
@@ -2094,6 +2208,9 @@ struct scst_tgt_dev {
struct scst_session *sess; /* corresponding session */
struct scst_acg_dev *acg_dev; /* corresponding acg_dev */
/* Reference to registrant to find quicker */
struct scst_dev_registrant *registrant;
/* List entry in dev->dev_tgt_dev_list */
struct list_head dev_tgt_dev_list_entry;
@@ -2258,12 +2375,12 @@ static inline int scst_register_target_template(struct scst_tgt_template *vtt)
void scst_unregister_target_template(struct scst_tgt_template *vtt);
struct scst_tgt *scst_register(struct scst_tgt_template *vtt,
struct scst_tgt *scst_register_target(struct scst_tgt_template *vtt,
const char *target_name);
void scst_unregister(struct scst_tgt *tgt);
void scst_unregister_target(struct scst_tgt *tgt);
struct scst_session *scst_register_session(struct scst_tgt *tgt, int atomic,
const char *initiator_name, void *data,
const char *initiator_name, void *tgt_priv, void *result_fn_data,
void (*result_fn) (struct scst_session *sess, void *data, int result));
void scst_unregister_session(struct scst_session *sess, int wait,
void (*unreg_done_fn) (struct scst_session *sess));
@@ -3194,6 +3311,7 @@ struct scst_trace_log {
};
extern struct mutex scst_mutex;
extern bool iscsi_tid_name_only;
#ifdef CONFIG_SCST_PROC
@@ -3395,6 +3513,9 @@ int scst_tape_generic_dev_done(struct scst_cmd *cmd,
int scst_obtain_device_parameters(struct scst_device *dev);
void scst_reassign_persistent_sess_states(struct scst_session *new_sess,
struct scst_session *old_sess);
int scst_get_max_lun_commands(struct scst_session *sess, uint64_t lun);
/*
+64 -24
View File
@@ -63,12 +63,12 @@
/*************************************************************
** Values for task management functions
*************************************************************/
#define SCST_ABORT_TASK 0
#define SCST_ABORT_TASK_SET 1
#define SCST_CLEAR_ACA 2
#define SCST_CLEAR_TASK_SET 3
#define SCST_LUN_RESET 4
#define SCST_TARGET_RESET 5
#define SCST_ABORT_TASK 0
#define SCST_ABORT_TASK_SET 1
#define SCST_CLEAR_ACA 2
#define SCST_CLEAR_TASK_SET 3
#define SCST_LUN_RESET 4
#define SCST_TARGET_RESET 5
/** SCST extensions **/
@@ -77,20 +77,20 @@
* Aborts all tasks there, resets the reservation, if any, and sets
* up the I_T Nexus loss UA.
*/
#define SCST_NEXUS_LOSS_SESS 6
#define SCST_NEXUS_LOSS_SESS 6
/* Aborts all tasks in the corresponding session */
#define SCST_ABORT_ALL_TASKS_SESS 7
#define SCST_ABORT_ALL_TASKS_SESS 7
/*
* Notifies about I_T nexus loss event. Aborts all tasks in all sessions
* of the tgt, resets the reservations, if any, and sets up the I_T Nexus
* loss UA.
*/
#define SCST_NEXUS_LOSS 8
#define SCST_NEXUS_LOSS 8
/* Aborts all tasks in all sessions of the tgt */
#define SCST_ABORT_ALL_TASKS 9
#define SCST_ABORT_ALL_TASKS 9
/*
* Internal TM command issued by SCST in scst_unregister_session(). It is the
@@ -99,9 +99,24 @@
* - it doesn't call task_mgmt_fn_done()
* - it doesn't queue NEXUS LOSS UA.
*
* Target driver shall NEVER use it!!
* Target drivers must NEVER use it!!
*/
#define SCST_UNREG_SESS_TM 10
#define SCST_UNREG_SESS_TM 10
/*
* Internal TM command issued by SCST in scst_pr_abort_reg(). It aborts all
* tasks from mcmd->origin_pr_cmd->tgt_dev, except mcmd->origin_pr_cmd.
* Additionally:
* - it signals pr_aborting_cmpl completion when all affected
* commands marked as aborted.
* - it doesn't call task_mgmt_affected_cmds_done()
* - it doesn't call task_mgmt_fn_done()
* - it calls mcmd->origin_pr_cmd->scst_cmd_done() when all affected
* commands aborted.
*
* Target drivers must NEVER use it!!
*/
#define SCST_PR_ABORT_ALL 11
/*************************************************************
** Values for mgmt cmd's status field. Codes taken from iSCSI
@@ -128,18 +143,23 @@ enum scst_cmd_queue_type {
** CDB flags
*************************************************************/
enum scst_cdb_flags {
SCST_TRANSFER_LEN_TYPE_FIXED = 0x001,
SCST_SMALL_TIMEOUT = 0x002,
SCST_LONG_TIMEOUT = 0x004,
SCST_UNKNOWN_LENGTH = 0x008,
SCST_INFO_VALID = 0x010, /* must be single bit */
SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED = 0x020,
SCST_IMPLICIT_HQ = 0x040,
SCST_SKIP_UA = 0x080,
SCST_WRITE_MEDIUM = 0x100,
SCST_LOCAL_CMD = 0x200,
SCST_FULLY_LOCAL_CMD = 0x400,
SCST_REG_RESERVE_ALLOWED = 0x800,
SCST_TRANSFER_LEN_TYPE_FIXED = 0x0001,
SCST_SMALL_TIMEOUT = 0x0002,
SCST_LONG_TIMEOUT = 0x0004,
SCST_UNKNOWN_LENGTH = 0x0008,
SCST_INFO_VALID = 0x0010, /* must be single bit */
SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED = 0x0020,
SCST_IMPLICIT_HQ = 0x0040,
SCST_SKIP_UA = 0x0080,
SCST_WRITE_MEDIUM = 0x0100,
SCST_LOCAL_CMD = 0x0200,
SCST_FULLY_LOCAL_CMD = 0x0400,
SCST_REG_RESERVE_ALLOWED = 0x0800,
SCST_WRITE_EXCL_ALLOWED = 0x1000,
SCST_EXCL_ACCESS_ALLOWED = 0x2000,
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
SCST_TEST_IO_IN_SIRQ_ALLOWED = 0x8000,
#endif
};
/*************************************************************
@@ -188,6 +208,9 @@ enum scst_cdb_flags {
#define scst_sense_invalid_field_in_cdb ILLEGAL_REQUEST, 0x24, 0
#define scst_sense_invalid_field_in_parm_list ILLEGAL_REQUEST, 0x26, 0
#define scst_sense_parameter_value_invalid ILLEGAL_REQUEST, 0x26, 2
#define scst_sense_invalid_release ILLEGAL_REQUEST, 0x26, 4
#define scst_sense_parameter_list_length_invalid \
ILLEGAL_REQUEST, 0x1A, 0
#define scst_sense_reset_UA UNIT_ATTENTION, 0x29, 0
#define scst_sense_nexus_loss_UA UNIT_ATTENTION, 0x29, 0x7
#define scst_sense_saving_params_unsup ILLEGAL_REQUEST, 0x39, 0
@@ -202,6 +225,9 @@ enum scst_cdb_flags {
#define scst_sense_invalid_message ILLEGAL_REQUEST, 0x49, 0
#define scst_sense_cleared_by_another_ini_UA UNIT_ATTENTION, 0x2F, 0
#define scst_sense_capacity_data_changed UNIT_ATTENTION, 0x2A, 0x9
#define scst_sense_reservation_preempted UNIT_ATTENTION, 0x2A, 0x03
#define scst_sense_reservation_released UNIT_ATTENTION, 0x2A, 0x04
#define scst_sense_registrations_preempted UNIT_ATTENTION, 0x2A, 0x05
#define scst_sense_reported_luns_data_changed UNIT_ATTENTION, 0x3F, 0xE
#define scst_sense_inquery_data_changed UNIT_ATTENTION, 0x3F, 0x3
@@ -306,6 +332,16 @@ enum scst_cdb_flags {
#define SCST_CONTR_MODE_FIXED_SENSE 0
#define SCST_CONTR_MODE_DESCR_SENSE 1
/*************************************************************
** TransportID protocol identifiers
*************************************************************/
#define SCSI_TRANSPORTID_PROTOCOLID_FCP2 0
#define SCSI_TRANSPORTID_PROTOCOLID_SPI5 1
#define SCSI_TRANSPORTID_PROTOCOLID_SRP 4
#define SCSI_TRANSPORTID_PROTOCOLID_ISCSI 5
#define SCSI_TRANSPORTID_PROTOCOLID_SAS 6
/*************************************************************
** Misc SCSI constants
*************************************************************/
@@ -366,6 +402,10 @@ enum scst_cdb_flags {
*************************************************************/
#define SCST_SYSFS_BLOCK_SIZE PAGE_SIZE
#define SCST_PR_DIR "/var/lib/scst/pr"
#define TID_COMMON_SIZE 24
#define SCST_SYSFS_KEY_MARK "[key]"
#define SCST_MIN_REL_TGT_ID 1
+5
View File
@@ -102,6 +102,7 @@
#define TRACE_SCSI 0x00001000
#define TRACE_SPECIAL 0x00002000 /* filtering debug, etc */
#define TRACE_FLOW_CONTROL 0x00004000 /* flow control in action */
#define TRACE_PRES 0x00008000
#define TRACE_ALL 0xffffffff
/* Flags 0xXXXX0000 are local for users */
@@ -204,6 +205,9 @@ do { \
#define TRACE_MGMT_DBG(args...) TRACE_DBG_FLAG(TRACE_MGMT_DEBUG, args)
#define TRACE_MGMT_DBG_SPECIAL(args...) \
TRACE_DBG_FLAG(TRACE_MGMT_DEBUG|TRACE_SPECIAL, args)
#define TRACE_PR(args...) TRACE_DBG_FLAG(TRACE_PRES, args)
const char *debug_transport_id_to_initiator_name(const uint8_t *transport_id);
#define TRACE_BUFFER(message, buff, len) \
do { \
@@ -318,6 +322,7 @@ do { \
#define TRACE_DBG_SPECIAL(format, args...) do {} while (0)
#define TRACE_MGMT_DBG(format, args...) do {} while (0)
#define TRACE_MGMT_DBG_SPECIAL(format, args...) do {} while (0)
#define TRACE_PR(format, args...) do {} while (0)
#define TRACE_BUFFER(message, buff, len) do {} while (0)
#define TRACE_BUFF_FLAG(flag, message, buff, len) do {} while (0)
+1
View File
@@ -96,6 +96,7 @@ struct scst_user_dev_desc {
int32_t sgv_purge_interval;
struct scst_user_opt opt;
uint32_t block_size;
uint8_t enable_pr_cmds_notifications;
char name[SCST_MAX_NAME];
char sgv_name[SCST_MAX_NAME];
};
+10 -12
View File
@@ -92,20 +92,18 @@ config SCST_STRICT_SECURITY
If unsure, say "N".
config SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
bool "Allow pass-through commands to be sent from soft-IRQ context"
config SCST_TEST_IO_IN_SIRQ
bool "Allow test I/O from soft-IRQ context"
depends on SCST
help
Allows SCST to submit SCSI pass-through commands to real SCSI devices
via the SCSI middle layer using scsi_execute_async() function from
soft-IRQ context (tasklets). This used to be the default, but
currently it seems the SCSI middle layer starts expecting only thread
context on the IO submit path, so it is disabled now by default.
Enabling it will decrease amount of context switches and improve
performance. It is more or less safe. In the worst case, if in your
configuration the SCSI middle layer really doesn't expect SIRQ
context in scsi_execute_async() function, you will get a warning
message in the kernel log.
Allows SCST to submit selected SCSI commands (TUR and
READ/WRITE) from soft-IRQ context (tasklets). Enabling it will
decrease amount of context switches and slightly improve
performance. The goal of this option is to be able to measure
overhead of the context switches. See more info about it in
README.scst.
WARNING! Improperly used, this option can lead you to a kernel crash!
If unsure, say "N".
+4 -2
View File
@@ -43,6 +43,7 @@ scst-y += scst_proc.o
#scst-y += scst_sysfs.o
scst-y += scst_mem.o
scst-y += scst_debug.o
scst-y += scst_pres.o
obj-$(CONFIG_SCST) += scst.o dev_handlers/
obj-$(BUILD_DEV) += $(DEV_HANDLERS_DIR)/
@@ -86,6 +87,7 @@ ifneq ($(MOD_VERS),)
install -m 644 Module.symvers $(INSTALL_DIR_H)
endif
-/sbin/depmod -a $(KVER)
mkdir -p /var/lib/scst/pr
@echo "****************************************************************"
@echo "*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*"
@echo "*!! !!*"
@@ -122,8 +124,8 @@ EXTRA_CFLAGS += -I$(SCST_INC_DIR) -Wextra -Wno-unused-parameter \
EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS
#EXTRA_CFLAGS += -DCONFIG_SCST_USE_EXPECTED_VALUES
#EXTRA_CFLAGS += -DALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
#EXTRA_CFLAGS += -DABORT_CONSIDER_FINISHED_TASKS_AS_NOT_EXISTING
#EXTRA_CFLAGS += -DCONFIG_SCST_TEST_IO_IN_SIRQ
#EXTRA_CFLAGS += -DCONFIG_SCST_ABORT_CONSIDER_FINISHED_TASKS_AS_NOT_EXISTING
#EXTRA_CFLAGS += -fno-inline
-2
View File
@@ -51,7 +51,6 @@ static struct scst_dev_type disk_devtype = {
.type = TYPE_DISK,
.parse_atomic = 1,
.dev_done_atomic = 1,
.exec_atomic = 1,
.attach = disk_attach,
.detach = disk_detach,
.parse = disk_parse,
@@ -67,7 +66,6 @@ static struct scst_dev_type disk_devtype_perf = {
.type = TYPE_DISK,
.parse_atomic = 1,
.dev_done_atomic = 1,
.exec_atomic = 1,
.attach = disk_attach,
.detach = disk_detach,
.parse = disk_parse,
-2
View File
@@ -51,7 +51,6 @@ static struct scst_dev_type modisk_devtype = {
.type = TYPE_MOD,
.parse_atomic = 1,
.dev_done_atomic = 1,
.exec_atomic = 1,
.attach = modisk_attach,
.detach = modisk_detach,
.parse = modisk_parse,
@@ -67,7 +66,6 @@ static struct scst_dev_type modisk_devtype_perf = {
.type = TYPE_MOD,
.parse_atomic = 1,
.dev_done_atomic = 1,
.exec_atomic = 1,
.attach = modisk_attach,
.detach = modisk_detach,
.parse = modisk_parse,
-2
View File
@@ -56,7 +56,6 @@ static struct scst_dev_type tape_devtype = {
.type = TYPE_TAPE,
.parse_atomic = 1,
.dev_done_atomic = 1,
.exec_atomic = 1,
.attach = tape_attach,
.detach = tape_detach,
.parse = tape_parse,
@@ -72,7 +71,6 @@ static struct scst_dev_type tape_devtype_perf = {
.type = TYPE_TAPE,
.parse_atomic = 1,
.dev_done_atomic = 1,
.exec_atomic = 1,
.attach = tape_attach,
.detach = tape_detach,
.parse = tape_parse,
+2 -15
View File
@@ -928,18 +928,6 @@ static int dev_user_exec(struct scst_cmd *cmd)
TRACE_ENTRY();
#if 0 /* We set exec_atomic in 0 to let SCST core know that we need a thread
* context to complete the necessary actions, but all we are going to
* do in this function is, in fact, atomic, so let's skip this check.
*/
if (scst_cmd_atomic(cmd)) {
TRACE_DBG("%s", "User exec() can not be called in atomic "
"context, rescheduling to the thread");
res = SCST_EXEC_NEED_THREAD;
goto out;
}
#endif
TRACE_DBG("Preparing EXEC for user space (ucmd=%p, h=%d, "
"bufflen %d, data_len %d, ubuff %lx)", ucmd, ucmd->h,
cmd->bufflen, cmd->data_len, ucmd->ubuff);
@@ -2891,7 +2879,6 @@ static int dev_user_register_dev(struct file *file,
dev->devtype.threads_num = -1;
dev->devtype.parse_atomic = 1;
dev->devtype.alloc_data_buf_atomic = 1;
dev->devtype.exec_atomic = 0; /* no point to make it 1 */
dev->devtype.dev_done_atomic = 1;
#ifdef CONFIG_SCST_PROC
dev->devtype.no_proc = 1;
@@ -2905,8 +2892,8 @@ static int dev_user_register_dev(struct file *file,
dev->devtype.exec = dev_user_exec;
dev->devtype.on_free_cmd = dev_user_on_free_cmd;
dev->devtype.task_mgmt_fn = dev_user_task_mgmt_fn;
dev->devtype.parent = &dev_user_devtype;
if (dev_desc->enable_pr_cmds_notifications)
dev->devtype.pr_cmds_notifications = 1;
init_completion(&dev->cleanup_cmpl);
dev->block = block;
+34 -17
View File
@@ -429,7 +429,6 @@ static struct scst_dev_type vdisk_file_devtype = {
.exec_sync = 1,
.threads_num = -1,
.parse_atomic = 1,
.exec_atomic = 0,
.dev_done_atomic = 1,
.attach = vdisk_attach,
.detach = vdisk_detach,
@@ -465,7 +464,6 @@ static struct scst_dev_type vdisk_blk_devtype = {
.type = TYPE_DISK,
.threads_num = 0,
.parse_atomic = 1,
.exec_atomic = 0,
.dev_done_atomic = 1,
#ifdef CONFIG_SCST_PROC
.no_proc = 1,
@@ -499,7 +497,6 @@ static struct scst_dev_type vdisk_null_devtype = {
.type = TYPE_DISK,
.threads_num = 0,
.parse_atomic = 1,
.exec_atomic = 1,
.dev_done_atomic = 1,
#ifdef CONFIG_SCST_PROC
.no_proc = 1,
@@ -533,7 +530,6 @@ static struct scst_dev_type vcdrom_devtype = {
.exec_sync = 1,
.threads_num = -1,
.parse_atomic = 1,
.exec_atomic = 0,
.dev_done_atomic = 1,
.attach = vdisk_attach,
.detach = vdisk_detach,
@@ -643,7 +639,7 @@ static int vdisk_get_file_size(const char *filename, bool blockio,
}
if (S_ISREG(inode->i_mode))
/* Nothing to do*/;
/* Nothing to do */;
else if (S_ISBLK(inode->i_mode))
inode = inode->i_bdev->bd_inode;
else {
@@ -1286,8 +1282,7 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
TRACE_ENTRY();
buf = kzalloc(INQ_BUF_SZ,
scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL);
buf = kzalloc(INQ_BUF_SZ, GFP_KERNEL);
if (buf == NULL) {
scst_set_busy(cmd);
goto out;
@@ -1357,8 +1352,25 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd)
num += 4;
/* Binary */
buf[num + 0] = 0x01;
/*
* Relative target port identifier
*/
buf[num + 0] = 0x01; /* binary */
/* Relative target port id */
buf[num + 1] = 0x10 | 0x04;
put_unaligned(cpu_to_be16(cmd->tgt->rel_tgt_id),
(__be16 *)&buf[num + 4 + 2]);
buf[num + 3] = 4;
num += buf[num + 3];
num += 4;
/*
* IEEE id
*/
buf[num + 0] = 0x01; /* binary */
/* EUI-64 */
buf[num + 1] = 0x02;
@@ -1662,8 +1674,7 @@ static void vdisk_exec_mode_sense(struct scst_cmd *cmd)
TRACE_ENTRY();
buf = kzalloc(MSENSE_BUF_SZ,
scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL);
buf = kzalloc(MSENSE_BUF_SZ, GFP_KERNEL);
if (buf == NULL) {
scst_set_busy(cmd);
goto out;
@@ -2206,12 +2217,9 @@ static void vdisk_exec_prevent_allow_medium_removal(struct scst_cmd *cmd)
TRACE_DBG("PERSIST/PREVENT 0x%02x", cmd->cdb[4]);
if (cmd->dev->type == TYPE_ROM) {
spin_lock(&virt_dev->flags_lock);
virt_dev->prevent_allow_medium_removal =
cmd->cdb[4] & 0x01 ? 1 : 0;
spin_unlock(&virt_dev->flags_lock);
}
spin_lock(&virt_dev->flags_lock);
virt_dev->prevent_allow_medium_removal = cmd->cdb[4] & 0x01 ? 1 : 0;
spin_unlock(&virt_dev->flags_lock);
return;
}
@@ -2876,7 +2884,16 @@ static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
dev->swp = DEF_SWP;
dev->tas = DEF_TAS;
spin_lock(&virt_dev->flags_lock);
virt_dev->prevent_allow_medium_removal = 0;
spin_unlock(&virt_dev->flags_lock);
} else if (mcmd->fn == SCST_PR_ABORT_ALL) {
struct scst_device *dev = tgt_dev->dev;
struct scst_vdisk_dev *virt_dev =
(struct scst_vdisk_dev *)dev->dh_priv;
spin_lock(&virt_dev->flags_lock);
virt_dev->prevent_allow_medium_removal = 0;
spin_unlock(&virt_dev->flags_lock);
}
TRACE_EXIT();
+91
View File
@@ -137,4 +137,95 @@ void debug_print_buffer(const void *data, int len)
}
EXPORT_SYMBOL(debug_print_buffer);
#ifdef CONFIG_SCST_DEBUG
/*
* This function converts transport_id in a string form into internal per-CPU
* static buffer. This buffer isn't anyhow protected, because it's acceptable
* if the name corrupted in the debug logs because of the race for this buffer.
*
* Note! You can't call this function 2 or more times in a single logging
* (printk) statement, because then each new call of this functon will override
* data written in this buffer by the previous call. You should instead split
* that logging statement on smaller statements each calling
* debug_transport_id_to_initiator_name() only once.
*/
const char *debug_transport_id_to_initiator_name(const uint8_t *transport_id)
{
/*
* No external protection, because it's acceptable if the name
* corrupted in the debug logs because of the race for this
* buffer.
*/
#define SIZEOF_NAME_BUF 256
static char name_bufs[NR_CPUS][SIZEOF_NAME_BUF];
char *name_buf;
unsigned long flags;
sBUG_ON(transport_id == NULL); /* better to catch it not under lock */
spin_lock_irqsave(&trace_buf_lock, flags);
name_buf = name_bufs[smp_processor_id()];
/*
* To prevent external racing with us users from accidentally
* missing their NULL terminator.
*/
memset(name_buf, 0, SIZEOF_NAME_BUF);
smp_mb();
switch (transport_id[0] & 0x0f) {
case SCSI_TRANSPORTID_PROTOCOLID_ISCSI:
scnprintf(name_buf, SIZEOF_NAME_BUF, "%s",
&transport_id[4]);
break;
case SCSI_TRANSPORTID_PROTOCOLID_FCP2:
scnprintf(name_buf, SIZEOF_NAME_BUF,
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
transport_id[8], transport_id[9],
transport_id[10], transport_id[11],
transport_id[12], transport_id[13],
transport_id[14], transport_id[15]);
break;
case SCSI_TRANSPORTID_PROTOCOLID_SPI5:
scnprintf(name_buf, SIZEOF_NAME_BUF,
"%x:%x", be16_to_cpu((uint16_t)transport_id[2]),
be16_to_cpu((uint16_t)transport_id[6]));
break;
case SCSI_TRANSPORTID_PROTOCOLID_SRP:
scnprintf(name_buf, SIZEOF_NAME_BUF,
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
transport_id[8], transport_id[9],
transport_id[10], transport_id[11],
transport_id[12], transport_id[13],
transport_id[14], transport_id[15],
transport_id[16], transport_id[17],
transport_id[18], transport_id[19],
transport_id[20], transport_id[21],
transport_id[22], transport_id[23]);
break;
case SCSI_TRANSPORTID_PROTOCOLID_SAS:
scnprintf(name_buf, SIZEOF_NAME_BUF,
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
transport_id[4], transport_id[5],
transport_id[6], transport_id[7],
transport_id[8], transport_id[9],
transport_id[10], transport_id[11]);
break;
default:
scnprintf(name_buf, SIZEOF_NAME_BUF,
"(Not known protocol ID %x)", transport_id[0] & 0x0f);
break;
}
spin_unlock_irqrestore(&trace_buf_lock, flags);
return name_buf;
#undef SIZEOF_NAME_BUF
}
#endif /* CONFIG_SCST_DEBUG */
#endif /* CONFIG_SCST_DEBUG || CONFIG_SCST_TRACING */
+396 -87
View File
@@ -36,6 +36,8 @@
#include "scst_priv.h"
#include "scst_mem.h"
#include "scst_pres.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
struct scsi_io_context {
unsigned int full_cdb_used:1;
@@ -160,17 +162,25 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{0x00, "MMMMMMMMMMMMMMMM", "TEST UNIT READY",
/* let's be HQ to don't look dead under high load */
SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_IMPLICIT_HQ|
SCST_REG_RESERVE_ALLOWED,
SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_EXCL_ACCESS_ALLOWED,
0, get_trans_len_none},
{0x01, " M ", "REWIND",
SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
{0x01, "O V OO OO ", "REZERO UNIT",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
SCST_DATA_NONE, SCST_WRITE_EXCL_ALLOWED,
0, get_trans_len_none},
{0x02, "VVVVVV V ", "REQUEST BLOCK ADDR",
SCST_DATA_NONE, SCST_SMALL_TIMEOUT, 0, get_trans_len_none},
{0x03, "MMMMMMMMMMMMMMMM", "REQUEST SENSE",
SCST_DATA_READ, SCST_SMALL_TIMEOUT|SCST_SKIP_UA|SCST_LOCAL_CMD|
SCST_REG_RESERVE_ALLOWED,
SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|
SCST_EXCL_ACCESS_ALLOWED,
4, get_trans_len_1},
{0x04, "M O O ", "FORMAT UNIT",
SCST_DATA_WRITE, SCST_LONG_TIMEOUT|SCST_UNKNOWN_LENGTH|SCST_WRITE_MEDIUM,
@@ -178,22 +188,36 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{0x04, " O ", "FORMAT",
SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
{0x05, "VMVVVV V ", "READ BLOCK LIMITS",
SCST_DATA_READ, SCST_SMALL_TIMEOUT|SCST_REG_RESERVE_ALLOWED,
SCST_DATA_READ, SCST_SMALL_TIMEOUT|
SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|
SCST_EXCL_ACCESS_ALLOWED,
0, get_trans_len_block_limit},
{0x07, " O ", "INITIALIZE ELEMENT STATUS",
SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
{0x07, "OVV O OV ", "REASSIGN BLOCKS",
SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
{0x08, "O ", "READ(6)",
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 4, get_trans_len_1_256},
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED|
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_WRITE_EXCL_ALLOWED,
4, get_trans_len_1_256},
{0x08, " MV OO OV ", "READ(6)",
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 2, get_trans_len_3},
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED|
SCST_WRITE_EXCL_ALLOWED,
2, get_trans_len_3},
{0x08, " M ", "GET MESSAGE(6)",
SCST_DATA_READ, FLAG_NONE, 2, get_trans_len_3},
{0x08, " O ", "RECEIVE",
SCST_DATA_READ, FLAG_NONE, 2, get_trans_len_3},
{0x0A, "O ", "WRITE(6)",
SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_WRITE_MEDIUM,
4, get_trans_len_1_256},
{0x0A, " M O OV ", "WRITE(6)",
SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
@@ -216,30 +240,41 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
SCST_DATA_NONE, SCST_LONG_TIMEOUT|SCST_WRITE_MEDIUM,
0, get_trans_len_none},
{0x0F, "VOVVVV V ", "READ REVERSE",
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 2, get_trans_len_3},
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED|
SCST_WRITE_EXCL_ALLOWED,
2, get_trans_len_3},
{0x10, "VM V V ", "WRITE FILEMARKS",
SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
{0x10, " O O ", "SYNCHRONIZE BUFFER",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
{0x11, "VMVVVV ", "SPACE",
SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
SCST_DATA_NONE, SCST_LONG_TIMEOUT|
SCST_WRITE_EXCL_ALLOWED,
0, get_trans_len_none},
{0x12, "MMMMMMMMMMMMMMMM", "INQUIRY",
SCST_DATA_READ, SCST_SMALL_TIMEOUT|SCST_IMPLICIT_HQ|SCST_SKIP_UA|
SCST_REG_RESERVE_ALLOWED,
SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED,
4, get_trans_len_1},
{0x13, "VOVVVV ", "VERIFY(6)",
SCST_DATA_NONE, SCST_TRANSFER_LEN_TYPE_FIXED|
SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED,
SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED|
SCST_WRITE_EXCL_ALLOWED,
2, get_trans_len_3},
{0x14, "VOOVVV ", "RECOVER BUFFERED DATA",
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 2, get_trans_len_3},
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED|
SCST_WRITE_EXCL_ALLOWED,
2, get_trans_len_3},
{0x15, "OMOOOOOOOOOOOOOO", "MODE SELECT(6)",
SCST_DATA_WRITE, SCST_LOCAL_CMD, 4, get_trans_len_1},
{0x16, "MMMMMMMMMMMMMMMM", "RESERVE",
SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_CMD,
SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_CMD|
SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED,
0, get_trans_len_none},
{0x17, "MMMMMMMMMMMMMMMM", "RELEASE",
SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_CMD|SCST_REG_RESERVE_ALLOWED,
SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_CMD|
SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED,
0, get_trans_len_none},
{0x18, "OOOOOOOO ", "COPY",
SCST_DATA_WRITE, SCST_LONG_TIMEOUT, 2, get_trans_len_3},
@@ -272,25 +307,39 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{0x24, "V VVM ", "SET WINDOW",
SCST_DATA_WRITE, FLAG_NONE, 6, get_trans_len_3},
{0x25, "M MM M ", "READ CAPACITY",
SCST_DATA_READ, SCST_IMPLICIT_HQ|SCST_REG_RESERVE_ALLOWED,
SCST_DATA_READ, SCST_IMPLICIT_HQ|
SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|
SCST_EXCL_ACCESS_ALLOWED,
0, get_trans_len_read_capacity},
{0x25, " O ", "GET WINDOW",
SCST_DATA_READ, FLAG_NONE, 6, get_trans_len_3},
{0x28, "M MMMM ", "READ(10)",
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 7, get_trans_len_2},
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED|
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_WRITE_EXCL_ALLOWED,
7, get_trans_len_2},
{0x28, " O ", "GET MESSAGE(10)",
SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_2},
{0x29, "V VV O ", "READ GENERATION",
SCST_DATA_READ, FLAG_NONE, 8, get_trans_len_1},
{0x2A, "O MO M ", "WRITE(10)",
SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_WRITE_MEDIUM,
7, get_trans_len_2},
{0x2A, " O ", "SEND MESSAGE(10)",
SCST_DATA_WRITE, FLAG_NONE, 7, get_trans_len_2},
{0x2A, " O ", "SEND(10)",
SCST_DATA_WRITE, FLAG_NONE, 7, get_trans_len_2},
{0x2B, " O ", "LOCATE",
SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
SCST_DATA_NONE, SCST_LONG_TIMEOUT|
SCST_WRITE_EXCL_ALLOWED,
0, get_trans_len_none},
{0x2B, " O ", "POSITION TO ELEMENT",
SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
{0x2B, "O OO O ", "SEEK(10)",
@@ -305,22 +354,27 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
7, get_trans_len_2},
{0x2F, "O OO O ", "VERIFY(10)",
SCST_DATA_NONE, SCST_TRANSFER_LEN_TYPE_FIXED|
SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED,
SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED|
SCST_WRITE_EXCL_ALLOWED,
7, get_trans_len_2},
{0x33, "O OO O ", "SET LIMITS(10)",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
{0x34, " O ", "READ POSITION",
SCST_DATA_READ, SCST_SMALL_TIMEOUT, 7, get_trans_len_read_pos},
SCST_DATA_READ, SCST_SMALL_TIMEOUT|
SCST_WRITE_EXCL_ALLOWED,
7, get_trans_len_read_pos},
{0x34, " O ", "GET DATA BUFFER STATUS",
SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_2},
{0x34, "O OO O ", "PRE-FETCH",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
SCST_DATA_NONE, SCST_WRITE_EXCL_ALLOWED,
0, get_trans_len_none},
{0x35, "O OO O ", "SYNCHRONIZE CACHE",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
{0x36, "O OO O ", "LOCK UNLOCK CACHE",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
{0x37, "O O ", "READ DEFECT DATA(10)",
SCST_DATA_READ, FLAG_NONE, 8, get_trans_len_1},
SCST_DATA_READ, SCST_WRITE_EXCL_ALLOWED,
8, get_trans_len_1},
{0x37, " O ", "INIT ELEMENT STATUS WRANGE",
SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
{0x38, " O O ", "MEDIUM SCAN",
@@ -350,7 +404,10 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{0x43, " O ", "READ TOC/PMA/ATIP",
SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_2},
{0x44, " M ", "REPORT DENSITY SUPPORT",
SCST_DATA_READ, SCST_REG_RESERVE_ALLOWED, 7, get_trans_len_2},
SCST_DATA_READ, SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|
SCST_EXCL_ACCESS_ALLOWED,
7, get_trans_len_2},
{0x44, " O ", "READ HEADER",
SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_2},
{0x45, " O ", "PLAY AUDIO(10)",
@@ -370,7 +427,10 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{0x4C, "OOOOOOOOOOOOOOOO", "LOG SELECT",
SCST_DATA_WRITE, SCST_SMALL_TIMEOUT, 7, get_trans_len_2},
{0x4D, "OOOOOOOOOOOOOOOO", "LOG SENSE",
SCST_DATA_READ, SCST_SMALL_TIMEOUT|SCST_REG_RESERVE_ALLOWED,
SCST_DATA_READ, SCST_SMALL_TIMEOUT|
SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|
SCST_EXCL_ACCESS_ALLOWED,
7, get_trans_len_2},
{0x4E, " O ", "STOP PLAY/SCAN",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
@@ -392,7 +452,8 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_CMD,
0, get_trans_len_none},
{0x57, "OOOOOOOOOOOOOOOO", "RELEASE(10)",
SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_CMD|SCST_REG_RESERVE_ALLOWED,
SCST_DATA_NONE, SCST_SMALL_TIMEOUT|SCST_LOCAL_CMD|
SCST_REG_RESERVE_ALLOWED,
0, get_trans_len_none},
{0x58, " O ", "REPAIR TRACK",
SCST_DATA_NONE, SCST_WRITE_MEDIUM, 0, get_trans_len_none},
@@ -405,9 +466,17 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{0x5D, " O ", "SEND CUE SHEET",
SCST_DATA_WRITE, FLAG_NONE, 6, get_trans_len_3},
{0x5E, "OOOOO OOOO ", "PERSISTENT RESERV IN",
SCST_DATA_READ, FLAG_NONE, 5, get_trans_len_4},
SCST_DATA_READ, SCST_SMALL_TIMEOUT|
SCST_LOCAL_CMD|
SCST_WRITE_EXCL_ALLOWED|
SCST_EXCL_ACCESS_ALLOWED,
5, get_trans_len_4},
{0x5F, "OOOOO OOOO ", "PERSISTENT RESERV OUT",
SCST_DATA_WRITE, FLAG_NONE, 5, get_trans_len_4},
SCST_DATA_WRITE, SCST_SMALL_TIMEOUT|
SCST_LOCAL_CMD|
SCST_WRITE_EXCL_ALLOWED|
SCST_EXCL_ACCESS_ALLOWED,
5, get_trans_len_4},
/* 16-bytes length CDB */
{0x80, "O OO O ", "XDWRITE EXTENDED",
@@ -423,13 +492,28 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{0x84, "OOOOOOOOOOOOOOOO", "RECEIVE COPY RESULT",
SCST_DATA_WRITE, FLAG_NONE, 10, get_trans_len_4},
{0x86, "OOOOOOOOOO ", "ACCESS CONTROL IN",
SCST_DATA_NONE, SCST_REG_RESERVE_ALLOWED, 0, get_trans_len_none},
SCST_DATA_NONE, SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|
SCST_EXCL_ACCESS_ALLOWED,
0, get_trans_len_none},
{0x87, "OOOOOOOOOO ", "ACCESS CONTROL OUT",
SCST_DATA_NONE, SCST_REG_RESERVE_ALLOWED, 0, get_trans_len_none},
SCST_DATA_NONE, SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|
SCST_EXCL_ACCESS_ALLOWED,
0, get_trans_len_none},
{0x88, "M MMMM ", "READ(16)",
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 10, get_trans_len_4},
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED|
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_WRITE_EXCL_ALLOWED,
10, get_trans_len_4},
{0x8A, "O OO O ", "WRITE(16)",
SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_WRITE_MEDIUM,
10, get_trans_len_4},
{0x8C, "OOOOOOOOOO ", "READ ATTRIBUTE",
SCST_DATA_READ, FLAG_NONE, 10, get_trans_len_4},
@@ -443,15 +527,20 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED,
10, get_trans_len_4},
{0x90, "O OO O ", "PRE-FETCH(16)",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
SCST_DATA_NONE, SCST_WRITE_EXCL_ALLOWED,
0, get_trans_len_none},
{0x91, "O OO O ", "SYNCHRONIZE CACHE(16)",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
{0x91, " M ", "SPACE(16)",
SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
SCST_DATA_NONE, SCST_LONG_TIMEOUT|
SCST_WRITE_EXCL_ALLOWED,
0, get_trans_len_none},
{0x92, "O OO O ", "LOCK UNLOCK CACHE(16)",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
{0x92, " O ", "LOCATE(16)",
SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
SCST_DATA_NONE, SCST_LONG_TIMEOUT|
SCST_WRITE_EXCL_ALLOWED,
0, get_trans_len_none},
{0x93, "O O ", "WRITE SAME(16)",
SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
10, get_trans_len_4},
@@ -465,14 +554,17 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{0xA0, "VVVVVVVVVV M ", "REPORT LUNS",
SCST_DATA_READ, SCST_SMALL_TIMEOUT|SCST_IMPLICIT_HQ|SCST_SKIP_UA|
SCST_FULLY_LOCAL_CMD|SCST_LOCAL_CMD|
SCST_REG_RESERVE_ALLOWED,
SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED,
6, get_trans_len_4},
{0xA1, " O ", "BLANK",
SCST_DATA_NONE, SCST_LONG_TIMEOUT, 0, get_trans_len_none},
{0xA3, " O ", "SEND KEY",
SCST_DATA_WRITE, FLAG_NONE, 8, get_trans_len_2},
{0xA3, "OOOOO OOOO ", "REPORT DEVICE IDENTIDIER",
SCST_DATA_READ, SCST_REG_RESERVE_ALLOWED, 6, get_trans_len_4},
SCST_DATA_READ, SCST_REG_RESERVE_ALLOWED|
SCST_WRITE_EXCL_ALLOWED|SCST_EXCL_ACCESS_ALLOWED,
6, get_trans_len_4},
{0xA3, " M ", "MAINTENANCE(IN)",
SCST_DATA_READ, FLAG_NONE, 6, get_trans_len_4},
{0xA4, " O ", "REPORT KEY",
@@ -490,11 +582,20 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{0xA8, " O ", "GET MESSAGE(12)",
SCST_DATA_READ, FLAG_NONE, 6, get_trans_len_4},
{0xA8, "O OO O ", "READ(12)",
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED, 6, get_trans_len_4},
SCST_DATA_READ, SCST_TRANSFER_LEN_TYPE_FIXED|
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_WRITE_EXCL_ALLOWED,
6, get_trans_len_4},
{0xA9, " O ", "PLAY TRACK RELATIVE(12)",
SCST_DATA_NONE, FLAG_NONE, 0, get_trans_len_none},
{0xAA, "O OO O ", "WRITE(12)",
SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM,
SCST_DATA_WRITE, SCST_TRANSFER_LEN_TYPE_FIXED|
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_WRITE_MEDIUM,
6, get_trans_len_4},
{0xAA, " O ", "SEND MESSAGE(12)",
SCST_DATA_WRITE, FLAG_NONE, 6, get_trans_len_4},
@@ -509,7 +610,8 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
6, get_trans_len_4},
{0xAF, "O OO O ", "VERIFY(12)",
SCST_DATA_NONE, SCST_TRANSFER_LEN_TYPE_FIXED|
SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED,
SCST_VERIFY_BYTCHK_MISMATCH_ALLOWED|
SCST_WRITE_EXCL_ALLOWED,
6, get_trans_len_4},
#if 0 /* No need to support at all */
{0xB0, " OO O ", "SEARCH DATA HIGH(12)",
@@ -528,7 +630,8 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
{0xB6, " M ", "SET STREAMING",
SCST_DATA_WRITE, FLAG_NONE, 9, get_trans_len_2},
{0xB7, " O ", "READ DEFECT DATA(12)",
SCST_DATA_READ, FLAG_NONE, 9, get_trans_len_1},
SCST_DATA_READ, SCST_WRITE_EXCL_ALLOWED,
9, get_trans_len_1},
{0xB8, " O ", "READ ELEMENT STATUS",
SCST_DATA_READ, FLAG_NONE, 7, get_trans_len_3_read_elem_stat},
{0xB9, " O ", "READ CD MSF",
@@ -574,8 +677,8 @@ static void scst_free_all_UA(struct scst_tgt_dev *tgt_dev);
static void scst_release_space(struct scst_cmd *cmd);
static void scst_unblock_cmds(struct scst_device *dev);
static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev);
static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
struct scst_acg_dev *acg_dev);
static int scst_alloc_add_tgt_dev(struct scst_session *sess,
struct scst_acg_dev *acg_dev, struct scst_tgt_dev **out_tgt_dev);
static void scst_tgt_retry_timer_fn(unsigned long arg);
#ifdef CONFIG_SCST_DEBUG_TM
@@ -1540,7 +1643,7 @@ static void scst_check_reassign_sess(struct scst_session *sess)
{
struct scst_acg *acg, *old_acg;
struct scst_acg_dev *acg_dev;
int i;
int i, rc;
struct list_head *shead;
struct scst_tgt_dev *tgt_dev;
bool luns_changed = false;
@@ -1592,8 +1695,10 @@ retry_add:
TRACE_MGMT_DBG("sess %p: Allocing new tgt_dev for LUN %lld",
sess, (unsigned long long)acg_dev->lun);
tgt_dev = scst_alloc_add_tgt_dev(sess, acg_dev);
if (tgt_dev == NULL) {
rc = scst_alloc_add_tgt_dev(sess, acg_dev, &tgt_dev);
if (rc == -EPERM)
continue;
else if (rc != 0) {
add_failed = true;
break;
}
@@ -2026,7 +2131,8 @@ restart:
return;
}
bool scst_is_relative_target_port_id_unique(uint16_t id, struct scst_tgt *t)
bool scst_is_relative_target_port_id_unique(uint16_t id,
const struct scst_tgt *t)
{
bool res = true;
struct scst_tgt_template *tgtt;
@@ -2165,6 +2271,15 @@ int scst_alloc_device(gfp_t gfp_mask, struct scst_device **out_dev)
dev->dev_double_ua_possible = 1;
dev->queue_alg = SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER;
mutex_init(&dev->dev_pr_mutex);
atomic_set(&dev->pr_readers_count, 0);
dev->pr_generation = 0;
dev->pr_is_set = 0;
dev->pr_holder = NULL;
dev->pr_scope = SCOPE_LU;
dev->pr_type = TYPE_UNSPECIFIED;
INIT_LIST_HEAD(&dev->dev_registrants_list);
scst_init_threads(&dev->dev_cmd_threads);
*out_dev = dev;
@@ -2802,14 +2917,15 @@ void scst_tgt_dev_stop_threads(struct scst_tgt_dev *tgt_dev)
* scst_mutex supposed to be held, there must not be parallel activity in this
* session.
*/
static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
struct scst_acg_dev *acg_dev)
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;
int ini_sg, ini_unchecked_isa_dma, ini_use_clustering;
struct scst_tgt_dev *tgt_dev;
struct scst_device *dev = acg_dev->dev;
struct list_head *sess_tgt_dev_list_head;
int rc, i, sl;
int i, sl;
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
TRACE_ENTRY();
@@ -2820,8 +2936,9 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
tgt_dev = kmem_cache_zalloc(scst_tgtd_cachep, GFP_KERNEL);
#endif
if (tgt_dev == NULL) {
TRACE(TRACE_OUT_OF_MEM, "%s",
"Allocation of scst_tgt_dev failed");
TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of scst_tgt_dev "
"failed");
res = -ENOMEM;
goto out;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
@@ -2878,18 +2995,6 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
if (sess->tgt->tgtt->rdy_to_xfer_atomic)
__set_bit(SCST_TGT_DEV_AFTER_INIT_WR_ATOMIC,
&tgt_dev->tgt_dev_flags);
if (dev->handler->exec_atomic)
__set_bit(SCST_TGT_DEV_AFTER_INIT_OTH_ATOMIC,
&tgt_dev->tgt_dev_flags);
}
if (dev->handler->exec_atomic) {
if (sess->tgt->tgtt->rdy_to_xfer_atomic)
__set_bit(SCST_TGT_DEV_AFTER_RESTART_WR_ATOMIC,
&tgt_dev->tgt_dev_flags);
__set_bit(SCST_TGT_DEV_AFTER_RESTART_OTH_ATOMIC,
&tgt_dev->tgt_dev_flags);
__set_bit(SCST_TGT_DEV_AFTER_RX_DATA_ATOMIC,
&tgt_dev->tgt_dev_flags);
}
if (dev->handler->dev_done_atomic &&
sess->tgt->tgtt->xmit_response_atomic) {
@@ -2901,17 +3006,34 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
dev->d_sense, SCST_LOAD_SENSE(scst_sense_reset_UA));
scst_alloc_set_UA(tgt_dev, sense_buffer, sl, 0);
rc = scst_tgt_dev_setup_threads(tgt_dev);
if (rc != 0)
goto out_free;
if (sess->tgt->tgtt->get_initiator_port_transport_id == NULL) {
if (!list_empty(&dev->dev_registrants_list)) {
PRINT_WARNING("Initiators from target %s can't connect "
"to device %s, because the device has PR "
"registrants and the target doesn't support "
"Persistent Reservations", sess->tgt->tgtt->name,
dev->virt_name);
res = -EPERM;
goto out_free;
}
dev->not_pr_supporting_tgt_devs_num++;
}
res = scst_pr_init_tgt_dev(tgt_dev);
if (res != 0)
goto out_dec_free;
res = scst_tgt_dev_setup_threads(tgt_dev);
if (res != 0)
goto out_pr_clear;
if (dev->handler && dev->handler->attach_tgt) {
TRACE_DBG("Calling dev handler's attach_tgt(%p)", tgt_dev);
rc = dev->handler->attach_tgt(tgt_dev);
res = dev->handler->attach_tgt(tgt_dev);
TRACE_DBG("%s", "Dev handler's attach_tgt() returned");
if (rc != 0) {
if (res != 0) {
PRINT_ERROR("Device handler's %s attach_tgt() "
"failed: %d", dev->handler->name, rc);
"failed: %d", dev->handler->name, res);
goto out_stop_threads;
}
}
@@ -2927,18 +3049,25 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
list_add_tail(&tgt_dev->sess_tgt_dev_list_entry,
sess_tgt_dev_list_head);
*out_tgt_dev = tgt_dev;
out:
TRACE_EXIT();
return tgt_dev;
TRACE_EXIT_RES(res);
return res;
out_stop_threads:
scst_tgt_dev_stop_threads(tgt_dev);
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)
dev->not_pr_supporting_tgt_devs_num--;
out_free:
scst_free_all_UA(tgt_dev);
kmem_cache_free(scst_tgtd_cachep, tgt_dev);
tgt_dev = NULL;
goto out;
}
@@ -2983,7 +3112,11 @@ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev)
list_del(&tgt_dev->sess_tgt_dev_list_entry);
if (tgt_dev->sess->tgt->tgtt->get_initiator_port_transport_id == NULL)
dev->not_pr_supporting_tgt_devs_num--;
scst_clear_reservation(tgt_dev);
scst_pr_clear_tgt_dev(tgt_dev);
scst_free_all_UA(tgt_dev);
if (dev->handler && dev->handler->detach_tgt) {
@@ -3014,11 +3147,11 @@ int scst_sess_alloc_tgt_devs(struct scst_session *sess)
list_for_each_entry(acg_dev, &sess->acg->acg_dev_list,
acg_dev_list_entry) {
tgt_dev = scst_alloc_add_tgt_dev(sess, acg_dev);
if (tgt_dev == NULL) {
res = -ENOMEM;
res = scst_alloc_add_tgt_dev(sess, acg_dev, &tgt_dev);
if (res == -EPERM)
continue;
else if (res != 0)
goto out_free;
}
}
out:
@@ -3083,11 +3216,12 @@ int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev,
list_add_tail(&acg_dev->dev_acg_dev_list_entry, &dev->dev_acg_dev_list);
list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
tgt_dev = scst_alloc_add_tgt_dev(sess, acg_dev);
if (tgt_dev == NULL) {
res = -ENOMEM;
res = scst_alloc_add_tgt_dev(sess, acg_dev, &tgt_dev);
if (res == -EPERM)
continue;
else if (res != 0)
goto out_free;
}
list_add_tail(&tgt_dev->extra_tgt_dev_list_entry,
&tmp_tgt_dev_list);
}
@@ -3646,6 +3780,8 @@ void scst_free_session(struct scst_session *sess)
mutex_unlock(&scst_mutex);
kfree(sess->transport_id);
scst_sess_sysfs_put(sess); /* must not be called under scst_mutex */
TRACE_EXIT();
@@ -3984,7 +4120,7 @@ int scst_alloc_request(struct scst_cmd *cmd)
{
int res = 0;
struct scsi_request *req;
int gm = scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL;
int gm = GFP_KERNEL;
TRACE_ENTRY();
@@ -4315,7 +4451,7 @@ int scst_scsi_exec_async(struct scst_cmd *cmd,
struct request *rq;
struct scsi_io_context *sioc;
int write = (cmd->data_direction & SCST_DATA_WRITE) ? WRITE : READ;
gfp_t gfp = scst_cmd_atomic(cmd) ? GFP_ATOMIC : GFP_KERNEL;
gfp_t gfp = GFP_KERNEL;
int cmd_len = cmd->cdb_len;
if (cmd->ext_cdb_len == 0) {
@@ -4477,6 +4613,95 @@ out:
}
EXPORT_SYMBOL(scst_copy_sg);
int scst_get_full_buf(struct scst_cmd *cmd, uint8_t **buf)
{
int res = 0;
TRACE_ENTRY();
EXTRACHECKS_BUG_ON(cmd->sg_buff_vmallocated);
if (scst_get_buf_count(cmd) > 1) {
int len;
uint8_t *tmp_buf;
int full_size;
full_size = 0;
len = scst_get_buf_first(cmd, &tmp_buf);
while (len > 0) {
full_size += len;
scst_put_buf(cmd, tmp_buf);
len = scst_get_buf_next(cmd, &tmp_buf);
}
*buf = vmalloc(full_size);
if (*buf == NULL) {
TRACE(TRACE_OUT_OF_MEM, "vmalloc() failed for opcode "
"%x", cmd->cdb[0]);
res = -ENOMEM;
goto out;
}
cmd->sg_buff_vmallocated = 1;
if (scst_cmd_get_data_direction(cmd) == SCST_DATA_WRITE) {
uint8_t *buf_ptr;
buf_ptr = *buf;
len = scst_get_buf_first(cmd, &tmp_buf);
while (len > 0) {
memcpy(buf_ptr, tmp_buf, len);
buf_ptr += len;
scst_put_buf(cmd, tmp_buf);
len = scst_get_buf_next(cmd, &tmp_buf);
}
}
res = full_size;
} else
res = scst_get_buf_first(cmd, buf);
out:
TRACE_EXIT_RES(res);
return res;
}
void scst_put_full_buf(struct scst_cmd *cmd, uint8_t *buf)
{
TRACE_ENTRY();
if (buf == NULL)
goto out;
if (cmd->sg_buff_vmallocated) {
if (scst_cmd_get_data_direction(cmd) == SCST_DATA_READ) {
int len;
uint8_t *tmp_buf, *buf_p;
buf_p = buf;
len = scst_get_buf_first(cmd, &tmp_buf);
while (len > 0) {
memcpy(tmp_buf, buf_p, len);
buf_p += len;
scst_put_buf(cmd, tmp_buf);
len = scst_get_buf_next(cmd, &tmp_buf);
}
}
cmd->sg_buff_vmallocated = 0;
vfree(buf);
} else
scst_put_buf(cmd, buf);
out:
TRACE_EXIT();
return;
}
static const int SCST_CDB_LENGTH[8] = { 6, 10, 10, -1, 16, 12, -1, -1 };
#define SCST_CDB_GROUP(opcode) ((opcode >> 5) & 0x7)
@@ -4584,14 +4809,16 @@ static int get_trans_len_prevent_allow_medium_removal(struct scst_cmd *cmd,
uint8_t off)
{
if ((cmd->cdb[4] & 3) == 0)
cmd->op_flags |= SCST_REG_RESERVE_ALLOWED;
cmd->op_flags |= SCST_REG_RESERVE_ALLOWED |
SCST_WRITE_EXCL_ALLOWED | SCST_EXCL_ACCESS_ALLOWED;
return 0;
}
static int get_trans_len_start_stop(struct scst_cmd *cmd, uint8_t off)
{
if ((cmd->cdb[4] & 0xF1) == 0x1)
cmd->op_flags |= SCST_REG_RESERVE_ALLOWED;
cmd->op_flags |= SCST_REG_RESERVE_ALLOWED |
SCST_WRITE_EXCL_ALLOWED | SCST_EXCL_ACCESS_ALLOWED;
return 0;
}
@@ -4605,8 +4832,8 @@ static int get_trans_len_3_read_elem_stat(struct scst_cmd *cmd, uint8_t off)
cmd->bufflen |= ((u32)p[2]);
if ((cmd->cdb[6] & 0x2) == 0x2)
cmd->op_flags |= SCST_REG_RESERVE_ALLOWED;
cmd->op_flags |= SCST_REG_RESERVE_ALLOWED |
SCST_WRITE_EXCL_ALLOWED | SCST_EXCL_ACCESS_ALLOWED;
return 0;
}
@@ -6414,6 +6641,88 @@ int scst_get_max_lun_commands(struct scst_session *sess, uint64_t lun)
}
EXPORT_SYMBOL(scst_get_max_lun_commands);
/**
* scst_reassign_persistent_sess_states() - reassigns persistent states
*
* Reassigns persistent states from old_sess to new_sess.
*/
void scst_reassign_persistent_sess_states(struct scst_session *new_sess,
struct scst_session *old_sess)
{
struct scst_device *dev;
TRACE_ENTRY();
TRACE_DBG("Reassigning persistent states from old_sess %p to "
"new_sess %p", old_sess, new_sess);
if ((new_sess == NULL) || (old_sess == NULL)) {
TRACE_DBG("%s", "new_sess or old_sess is NULL");
goto out;
}
if ((new_sess->transport_id == NULL) ||
(old_sess->transport_id == NULL)) {
TRACE_DBG("%s", "new_sess or old_sess doesn't support PRs");
goto out;
}
mutex_lock(&scst_mutex);
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
struct scst_tgt_dev *tgt_dev;
struct scst_tgt_dev *new_tgt_dev = NULL, *old_tgt_dev = NULL;
TRACE_DBG("Processing dev %s", dev->virt_name);
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry) {
if (tgt_dev->sess == new_sess) {
new_tgt_dev = tgt_dev;
if (old_tgt_dev != NULL)
break;
}
if (tgt_dev->sess == old_sess) {
old_tgt_dev = tgt_dev;
if (new_tgt_dev != NULL)
break;
}
}
if ((new_tgt_dev == NULL) || (old_tgt_dev == NULL)) {
TRACE_DBG("new_tgt_dev %p or old_sess %p is NULL, "
"skipping (dev %s)", new_tgt_dev, old_tgt_dev,
dev->virt_name);
continue;
}
scst_pr_write_lock(dev);
if (old_tgt_dev->registrant != NULL) {
TRACE_PR("Reassigning reg %p from tgt_dev %p to %p",
old_tgt_dev->registrant, old_tgt_dev,
new_tgt_dev);
if (new_tgt_dev->registrant != NULL)
new_tgt_dev->registrant->tgt_dev = NULL;
new_tgt_dev->registrant = old_tgt_dev->registrant;
new_tgt_dev->registrant->tgt_dev = new_tgt_dev;
old_tgt_dev->registrant = NULL;
}
scst_pr_write_unlock(dev);
}
mutex_unlock(&scst_mutex);
out:
TRACE_EXIT();
return;
}
EXPORT_SYMBOL(scst_reassign_persistent_sess_states);
/**
* scst_get_next_lexem() - parse and return next lexem in the string
*
+40 -27
View File
@@ -33,6 +33,7 @@
#include "scst.h"
#include "scst_priv.h"
#include "scst_mem.h"
#include "scst_pres.h"
#if defined(CONFIG_HIGHMEM4G) || defined(CONFIG_HIGHMEM64G)
#warning "HIGHMEM kernel configurations are fully supported, but not\
@@ -214,6 +215,10 @@ int __scst_register_target_template(struct scst_tgt_template *vtt,
goto out_err;
}
if (vtt->get_initiator_port_transport_id == NULL)
PRINT_WARNING("Target driver %s doesn't support Persistent "
"Reservations", vtt->name);
if (vtt->threads_num < 0) {
PRINT_ERROR("Wrong threads_num value %d for "
"target \"%s\"", vtt->threads_num,
@@ -223,13 +228,12 @@ int __scst_register_target_template(struct scst_tgt_template *vtt,
}
#ifndef CONFIG_SCST_PROC
if (!vtt->enable_target || !vtt->is_target_enabled) {
if (!vtt->enable_target || !vtt->is_target_enabled)
PRINT_WARNING("Target driver %s doesn't have enable_target() "
"and/or is_target_enabled() method(s). This is unsafe "
"and can lead that initiators connected on the "
"initialization time can see an unexpected set of "
"devices or no devices at all!", vtt->name);
}
if (((vtt->add_target != NULL) && (vtt->del_target == NULL)) ||
((vtt->add_target == NULL) && (vtt->del_target != NULL))) {
@@ -333,7 +337,7 @@ void scst_unregister_target_template(struct scst_tgt_template *vtt)
restart:
list_for_each_entry(tgt, &vtt->tgt_list, tgt_list_entry) {
mutex_unlock(&scst_mutex);
scst_unregister(tgt);
scst_unregister_target(tgt);
mutex_lock(&scst_mutex);
goto restart;
}
@@ -365,7 +369,7 @@ EXPORT_SYMBOL(scst_unregister_target_template);
* Registers a target for template vtt and returns new target structure on
* success or NULL otherwise.
*/
struct scst_tgt *scst_register(struct scst_tgt_template *vtt,
struct scst_tgt *scst_register_target(struct scst_tgt_template *vtt,
const char *target_name)
{
struct scst_tgt *tgt;
@@ -391,6 +395,7 @@ struct scst_tgt *scst_register(struct scst_tgt_template *vtt,
int len = strlen(target_name) +
strlen(SCST_DEFAULT_ACG_NAME) + 1 + 1;
tgt->default_group_name = kmalloc(len, GFP_KERNEL);
if (tgt->default_group_name == NULL) {
TRACE(TRACE_OUT_OF_MEM, "Allocation of default "
@@ -505,7 +510,7 @@ out_err:
vtt->name, rc);
goto out;
}
EXPORT_SYMBOL(scst_register);
EXPORT_SYMBOL(scst_register_target);
static inline int test_sess_list(struct scst_tgt *tgt)
{
@@ -519,7 +524,7 @@ static inline int test_sess_list(struct scst_tgt *tgt)
/**
* scst_unregister_target() - unregister target
*/
void scst_unregister(struct scst_tgt *tgt)
void scst_unregister_target(struct scst_tgt *tgt)
{
struct scst_session *sess;
struct scst_tgt_template *vtt = tgt->tgtt;
@@ -585,7 +590,7 @@ again:
TRACE_EXIT();
return;
}
EXPORT_SYMBOL(scst_unregister);
EXPORT_SYMBOL(scst_unregister_target);
static int scst_susp_wait(bool interruptible)
{
@@ -956,14 +961,6 @@ static int scst_dev_handler_check(struct scst_dev_type *dev_handler)
}
#endif
if (dev_handler->exec == NULL) {
#ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
dev_handler->exec_atomic = 1;
#else
dev_handler->exec_atomic = 0;
#endif
}
if (dev_handler->alloc_data_buf == NULL)
dev_handler->alloc_data_buf_atomic = 1;
@@ -1009,14 +1006,6 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
if (res != 0)
goto out;
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
if (strcmp(dev->virt_name, dev_name) == 0) {
PRINT_ERROR("Device %s already exists", dev_name);
res = -EEXIST;
goto out;
}
}
res = scst_suspend_activity(true);
if (res != 0)
goto out;
@@ -1026,6 +1015,14 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
goto out_resume;
}
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
if (strcmp(dev->virt_name, dev_name) == 0) {
PRINT_ERROR("Device %s already exists", dev_name);
res = -EEXIST;
goto out_up;
}
}
res = scst_alloc_device(GFP_KERNEL, &dev);
if (res != 0)
goto out_up;
@@ -1051,12 +1048,18 @@ int scst_register_virtual_device(struct scst_dev_type *dev_handler,
goto out_free_del;
}
rc = scst_assign_dev_handler(dev, dev_handler);
rc = scst_pr_init_dev(dev);
if (rc != 0) {
res = rc;
goto out_free_del;
}
rc = scst_assign_dev_handler(dev, dev_handler);
if (rc != 0) {
res = rc;
goto out_pr_clear_dev;
}
out_up:
mutex_unlock(&scst_mutex);
@@ -1073,6 +1076,9 @@ out:
TRACE_EXIT_RES(res);
return res;
out_pr_clear_dev:
scst_pr_clear_dev(dev);
out_free_del:
list_del(&dev->dev_list_entry);
@@ -1117,6 +1123,8 @@ void scst_unregister_virtual_device(int id)
scst_acg_remove_dev(acg_dev->acg, dev, true);
}
scst_pr_clear_dev(dev);
scst_assign_dev_handler(dev, &scst_null_devtype);
PRINT_INFO("Detached from virtual device %s (id %d)",
@@ -1773,6 +1781,7 @@ static void scst_stop_all_threads(void)
return;
}
/* It does NOT stop ran threads on error! */
static int scst_start_all_threads(int num)
{
int res;
@@ -1969,14 +1978,14 @@ static void __init scst_print_config(void)
(j == i) ? "" : ", ");
#endif
#ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
i += snprintf(&buf[i], sizeof(buf) - i,
"%sALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ",
"%sTEST_IO_IN_SIRQ",
(j == i) ? "" : ", ");
#endif
#ifdef CONFIG_SCST_STRICT_SECURITY
i += snprintf(&buf[i], sizeof(buf) - i, "%sSCST_STRICT_SECURITY",
i += snprintf(&buf[i], sizeof(buf) - i, "%sSTRICT_SECURITY",
(j == i) ? "" : ", ");
#endif
@@ -2190,6 +2199,10 @@ static int __init init_scst(void)
res = scst_proc_init_module();
if (res != 0)
goto out_thread_free;
#else
res = scst_pr_check_pr_path();
if (res != 0)
goto out_thread_free;
#endif
PRINT_INFO("SCST version %s loaded successfully (max mem for "
+2581
View File
File diff suppressed because it is too large Load Diff
+168
View File
@@ -0,0 +1,168 @@
/*
* scst_pres.c
*
* Copyright (C) 2009 - 2010 Alexey Obitotskiy <alexeyo1@open-e.com>
* Copyright (C) 2009 - 2010 Open-E, Inc.
* Copyright (C) 2009 - 2010 Vladislav Bolkhovitin <vst@vlnb.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2
* of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef SCST_PRES_H_
#define SCST_PRES_H_
#define PR_REGISTER 0x00
#define PR_RESERVE 0x01
#define PR_RELEASE 0x02
#define PR_CLEAR 0x03
#define PR_PREEMPT 0x04
#define PR_PREEMPT_AND_ABORT 0x05
#define PR_REGISTER_AND_IGNORE 0x06
#define PR_REGISTER_AND_MOVE 0x07
#define PR_READ_KEYS 0x00
#define PR_READ_RESERVATION 0x01
#define PR_REPORT_CAPS 0x02
#define PR_READ_FULL_STATUS 0x03
#define TYPE_UNSPECIFIED (-1)
#define TYPE_WRITE_EXCLUSIVE 0x01
#define TYPE_EXCLUSIVE_ACCESS 0x03
#define TYPE_WRITE_EXCLUSIVE_REGONLY 0x05
#define TYPE_EXCLUSIVE_ACCESS_REGONLY 0x06
#define TYPE_WRITE_EXCLUSIVE_ALL_REG 0x07
#define TYPE_EXCLUSIVE_ACCESS_ALL_REG 0x08
#define SCOPE_LU 0x00
static inline bool scst_pr_type_valid(uint8_t type)
{
switch (type) {
case TYPE_WRITE_EXCLUSIVE:
case TYPE_EXCLUSIVE_ACCESS:
case TYPE_WRITE_EXCLUSIVE_REGONLY:
case TYPE_EXCLUSIVE_ACCESS_REGONLY:
case TYPE_WRITE_EXCLUSIVE_ALL_REG:
case TYPE_EXCLUSIVE_ACCESS_ALL_REG:
return true;
default:
return false;
}
}
#ifndef CONFIG_SCST_PROC
int scst_pr_check_pr_path(void);
#endif
static inline bool scst_pr_read_lock(struct scst_device *dev)
{
bool unlock = false;
TRACE_ENTRY();
atomic_inc(&dev->pr_readers_count);
smp_mb__after_atomic_inc(); /* to sync with scst_pr_write_lock() */
if (unlikely(dev->pr_writer_active)) {
unlock = true;
atomic_dec(&dev->pr_readers_count);
mutex_lock(&dev->dev_pr_mutex);
}
TRACE_EXIT_RES(unlock);
return unlock;
}
static inline void scst_pr_read_unlock(struct scst_device *dev, bool unlock)
{
TRACE_ENTRY();
if (unlikely(unlock))
mutex_unlock(&dev->dev_pr_mutex);
else {
/*
* To sync with scst_pr_write_lock(). We need it to ensure
* order of our reads with the writer's writes.
*/
smp_mb__before_atomic_dec();
atomic_dec(&dev->pr_readers_count);
}
TRACE_EXIT();
return;
}
static inline void scst_pr_write_lock(struct scst_device *dev)
{
TRACE_ENTRY();
mutex_lock(&dev->dev_pr_mutex);
dev->pr_writer_active = 1;
/* to sync with scst_pr_read_lock() and unlock() */
smp_mb();
while (atomic_read(&dev->pr_readers_count) != 0) {
TRACE_DBG("Waiting for %d readers (dev %p)",
atomic_read(&dev->pr_readers_count), dev);
msleep(1);
}
TRACE_EXIT();
return;
}
static inline void scst_pr_write_unlock(struct scst_device *dev)
{
TRACE_ENTRY();
dev->pr_writer_active = 0;
mutex_unlock(&dev->dev_pr_mutex);
TRACE_EXIT();
return;
}
int scst_pr_init_dev(struct scst_device *dev);
void scst_pr_clear_dev(struct scst_device *dev);
int scst_pr_init_tgt_dev(struct scst_tgt_dev *tgt_dev);
void scst_pr_clear_tgt_dev(struct scst_tgt_dev *tgt_dev);
bool scst_pr_crh_case(struct scst_cmd *cmd);
bool scst_pr_is_cmd_allowed(struct scst_cmd *cmd);
void scst_pr_register(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size);
void scst_pr_register_and_ignore(struct scst_cmd *cmd, uint8_t *buffer,
int buffer_size);
void scst_pr_register_and_move(struct scst_cmd *cmd, uint8_t *buffer,
int buffer_size);
void scst_pr_reserve(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size);
void scst_pr_release(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size);
void scst_pr_clear(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size);
void scst_pr_preempt(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size);
void scst_pr_preempt_and_abort(struct scst_cmd *cmd, uint8_t *buffer,
int buffer_size);
void scst_pr_read_keys(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size);
void scst_pr_read_reservation(struct scst_cmd *cmd, uint8_t *buffer,
int buffer_size);
void scst_pr_report_caps(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size);
void scst_pr_read_full_status(struct scst_cmd *cmd, uint8_t *buffer,
int buffer_size);
#ifndef CONFIG_SCST_PROC
void scst_pr_sync_device_file(struct scst_tgt_dev *tgt_dev, struct scst_cmd *cmd);
#endif
#endif /* SCST_PRES_H_ */
+11 -3
View File
@@ -108,7 +108,7 @@ extern unsigned long scst_trace_flag;
**/
#define SCST_CMD_STATE_RES_CONT_NEXT SCST_EXEC_COMPLETED
#define SCST_CMD_STATE_RES_CONT_SAME SCST_EXEC_NOT_COMPLETED
#define SCST_CMD_STATE_RES_NEED_THREAD SCST_EXEC_NEED_THREAD
#define SCST_CMD_STATE_RES_NEED_THREAD (SCST_EXEC_NOT_COMPLETED+1)
/**
** Maximum count of uncompleted commands that an initiator could
@@ -197,6 +197,10 @@ static inline bool scst_set_io_context(struct scst_cmd *cmd,
{
bool res;
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
return false;
#endif
if (cmd->cmd_threads == &scst_main_cmd_threads) {
EXTRACHECKS_BUG_ON(in_interrupt());
/*
@@ -414,6 +418,9 @@ int scst_alloc_space(struct scst_cmd *cmd);
int scst_lib_init(void);
void scst_lib_exit(void);
int scst_get_full_buf(struct scst_cmd *cmd, uint8_t **buf);
void scst_put_full_buf(struct scst_cmd *cmd, uint8_t *buf);
uint64_t scst_pack_lun(const uint64_t lun, unsigned int addr_method);
uint64_t scst_unpack_lun(const uint8_t *lun, int len);
@@ -567,7 +574,7 @@ int scst_set_pending_UA(struct scst_cmd *cmd);
void scst_report_luns_changed(struct scst_acg *acg);
void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
int other_ini, int call_dev_task_mgmt_fn);
bool other_ini, bool call_dev_task_mgmt_fn);
void scst_process_reset(struct scst_device *dev,
struct scst_session *originator, struct scst_cmd *exclude_cmd,
struct scst_mgmt_cmd *mcmd, bool setUA);
@@ -732,8 +739,9 @@ static inline int scst_sn_before(uint32_t seq1, uint32_t seq2)
return (int32_t)(seq1-seq2) < 0;
}
bool scst_is_relative_target_port_id_unique(uint16_t id, struct scst_tgt *t);
int gen_relative_target_port_id(uint16_t *id);
bool scst_is_relative_target_port_id_unique(uint16_t id,
const struct scst_tgt *t);
#ifdef CONFIG_SCST_MEASURE_LATENCY
+4 -3
View File
@@ -112,6 +112,7 @@ static struct scst_trace_log scst_proc_trace_tbl[] = {
{ TRACE_MGMT, "mgmt" },
{ TRACE_MGMT_DEBUG, "mgmt_dbg" },
{ TRACE_FLOW_CONTROL, "flow_control" },
{ TRACE_PRES, "pr" },
{ 0, NULL }
};
@@ -2311,12 +2312,12 @@ static int scst_version_info_show(struct seq_file *seq, void *v)
seq_printf(seq, "USE_EXPECTED_VALUES\n");
#endif
#ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
seq_printf(seq, "ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ\n");
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
seq_printf(seq, "TEST_IO_IN_SIRQ\n");
#endif
#ifdef CONFIG_SCST_STRICT_SECURITY
seq_printf(seq, "SCST_STRICT_SECURITY\n");
seq_printf(seq, "STRICT_SECURITY\n");
#endif
TRACE_EXIT();
+8 -7
View File
@@ -85,6 +85,7 @@ static struct scst_trace_log scst_trace_tbl[] = {
{ TRACE_MGMT, "mgmt" },
{ TRACE_MGMT_DEBUG, "mgmt_dbg" },
{ TRACE_FLOW_CONTROL, "flow_control" },
{ TRACE_PRES, "pr" },
{ 0, NULL }
};
@@ -694,7 +695,7 @@ int scst_create_tgt_sysfs(struct scst_tgt *tgt)
retval = sysfs_create_file(tgt->tgt_luns_kobj, &scst_luns_mgmt.attr);
if (retval != 0) {
PRINT_ERROR("Can't add tgt attr %s for tgt %s",
PRINT_ERROR("Can't add attribute %s for tgt %s",
scst_luns_mgmt.attr.name, tgt->tgt_name);
goto out;
}
@@ -710,7 +711,7 @@ int scst_create_tgt_sysfs(struct scst_tgt *tgt)
retval = sysfs_create_file(tgt->tgt_ini_grp_kobj,
&scst_ini_group_mgmt.attr);
if (retval != 0) {
PRINT_ERROR("Can't add tgt attr %s for tgt %s",
PRINT_ERROR("Can't add attribute %s for tgt %s",
scst_ini_group_mgmt.attr.name, tgt->tgt_name);
goto out;
}
@@ -2445,7 +2446,7 @@ static ssize_t scst_rel_tgt_id_store(struct kobject *kobj,
if (res != 0)
goto out_err;
TRACE_DBG("Try to set relative target port id %d",
TRACE_DBG("Trying to set relative target port id %d",
(uint16_t)rel_tgt_id);
if (rel_tgt_id < SCST_MIN_REL_TGT_ID ||
@@ -3051,7 +3052,7 @@ static ssize_t scst_trace_level_show(const struct scst_trace_log *local_tbl,
#endif
" special, scsi, mgmt, minor,\n"
" mgmt_dbg, scsi_serializing,\n"
" retry, recv_bot, send_bot, recv_top,\n"
" retry, recv_bot, send_bot, recv_top, pr\n"
" send_top%s]", help != NULL ? help : "");
return pos;
@@ -3288,12 +3289,12 @@ static ssize_t scst_version_show(struct kobject *kobj,
strcat(buf, "USE_EXPECTED_VALUES\n");
#endif
#ifdef CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ
strcat(buf, "ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ\n");
#ifdef CONFIG_SCST_TEST_IO_IN_SIRQ
strcat(buf, "TEST_IO_IN_SIRQ\n");
#endif
#ifdef CONFIG_SCST_STRICT_SECURITY
strcat(buf, "SCST_STRICT_SECURITY\n");
strcat(buf, "STRICT_SECURITY\n");
#endif
TRACE_EXIT();
+606 -244
View File
File diff suppressed because it is too large Load Diff
+5 -4
View File
@@ -644,7 +644,7 @@ static void scst_local_release_adapter(struct device *dev)
if (scst_lcl_host->session[i])
scst_unregister_session(
scst_lcl_host->session[i], TRUE, NULL);
scst_unregister(scst_lcl_host->target);
scst_unregister_target(scst_lcl_host->target);
kfree(scst_lcl_host);
}
@@ -683,7 +683,8 @@ static int scst_local_add_adapter(void)
* Register a target with SCST and add a session
*/
sprintf(name, "scstlcltgt%d", scst_local_add_host);
scst_lcl_host->target = scst_register(&scst_local_targ_tmpl, name);
scst_lcl_host->target = scst_register_target(&scst_local_targ_tmpl,
name);
if (!scst_lcl_host) {
printk(KERN_WARNING "scst_register_target failed:\n");
error = -1;
@@ -697,7 +698,7 @@ static int scst_local_add_adapter(void)
sprintf(name, "scstlclhst%d:%d", scst_local_add_host, i);
scst_lcl_host->session[i] = scst_register_session(
scst_lcl_host->target,
0, name, NULL, NULL);
0, name, NULL, NULL, NULL);
if (!scst_lcl_host->session[i]) {
printk(KERN_WARNING "scst_register_session failed:\n");
error = -1;
@@ -732,7 +733,7 @@ unregister_session:
TRUE, NULL);
}
unregister_target:
scst_unregister(scst_lcl_host->target);
scst_unregister_target(scst_lcl_host->target);
cleanup:
kfree(scst_lcl_host);
TRACE_EXIT();
+7 -13
View File
@@ -2137,7 +2137,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
BUG_ON(!sdev->scst_tgt);
ch->scst_sess = scst_register_session(sdev->scst_tgt, 0, ch->sess_name,
NULL, NULL);
ch, NULL, NULL);
if (!ch->scst_sess) {
rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
TRACE_DBG("%s", "Failed to create scst sess");
@@ -2147,8 +2147,6 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id,
TRACE_DBG("Establish connection sess=%p name=%s cm_id=%p",
ch->scst_sess, ch->sess_name, ch->cm_id);
scst_sess_set_tgt_priv(ch->scst_sess, ch);
/* create srp_login_response */
rsp->opcode = SRP_LOGIN_RSP;
rsp->tag = req->tag;
@@ -2775,11 +2773,7 @@ static int srpt_xmit_response(struct scst_cmd *scmnd)
int resp_len;
enum srpt_command_state prev_state;
if (unlikely(scst_cmd_atomic(scmnd))) {
TRACE_DBG("%s", "Switching to thread context.");
ret = SCST_TGT_RES_NEED_THREAD_CTX;
goto out;
}
EXTRACHECKS_BUG_ON(scst_cmd_atomic(scst_cmd));
ioctx = scst_cmd_get_tgt_priv(scmnd);
BUG_ON(!ioctx);
@@ -2971,8 +2965,8 @@ static int srpt_detect(struct scst_tgt_template *tp)
/**
* srpt_release() - SCST release callback function.
*
* Callback function called by the SCST core from scst_unregister() to free up
* the resources associated with device scst_tgt.
* Callback function called by the SCST core from scst_unregister_target() to
* free up the resources associated with device scst_tgt.
*/
static int srpt_release(struct scst_tgt *scst_tgt)
{
@@ -3157,7 +3151,7 @@ static void srpt_add_one(struct ib_device *device)
if (!sdev)
return;
sdev->scst_tgt = scst_register(&srpt_template, NULL);
sdev->scst_tgt = scst_register_target(&srpt_template, NULL);
if (!sdev->scst_tgt) {
PRINT_ERROR("SCST registration failed for %s.",
sdev->device->name);
@@ -3306,7 +3300,7 @@ err_dev:
device_unregister(&sdev->dev);
#endif
unregister_tgt:
scst_unregister(sdev->scst_tgt);
scst_unregister_target(sdev->scst_tgt);
free_dev:
kfree(sdev);
@@ -3366,7 +3360,7 @@ static void srpt_remove_one(struct ib_device *device)
* such that no new SRP_LOGIN_REQ information units can arrive while
* destroying the SCST target.
*/
scst_unregister(sdev->scst_tgt);
scst_unregister_target(sdev->scst_tgt);
sdev->scst_tgt = NULL;
srpt_free_ioctx_ring(sdev, sdev->ioctx_ring,
+12 -9
View File
@@ -646,6 +646,7 @@ static int do_tm(struct vdisk_cmd *vcmd)
{
struct scst_user_get_cmd *cmd = vcmd->cmd;
struct scst_user_reply_cmd *reply = vcmd->reply;
struct vdisk_dev *dev = vcmd->dev;
int res = 0;
TRACE_ENTRY();
@@ -659,6 +660,16 @@ static int do_tm(struct vdisk_cmd *vcmd)
cmd->tm_cmd.fn, cmd->tm_cmd.sess_h,
cmd->tm_cmd.cmd_h_to_abort);
switch (cmd->tm_cmd.fn) {
case SCST_LUN_RESET:
case SCST_TARGET_RESET:
case SCST_PR_ABORT_ALL:
pthread_mutex_lock(&dev->dev_mutex);
dev->prevent_allow_medium_removal = 0;
pthread_mutex_unlock(&dev->dev_mutex);
break;
}
memset(reply, 0, sizeof(*reply));
reply->cmd_h = cmd->cmd_h;
reply->subcode = cmd->subcode;
@@ -1618,15 +1629,7 @@ static void exec_prevent_allow_medium_removal(struct vdisk_cmd *vcmd)
TRACE_DBG("PERSIST/PREVENT 0x%02x", cmd->cdb[4]);
pthread_mutex_lock(&dev->dev_mutex);
if (dev->type == TYPE_ROM)
dev->prevent_allow_medium_removal =
cmd->cdb[4] & 0x01 ? 1 : 0;
else {
PRINT_ERROR("%s", "Prevent allow medium removal for "
"non-CDROM device");
set_cmd_error(vcmd,
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
}
dev->prevent_allow_medium_removal = cmd->cdb[4] & 0x01 ? 1 : 0;
pthread_mutex_unlock(&dev->dev_mutex);
return;