mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-22 13:11:27 +00:00
an external module. When applying the SCST kernel patch to the mainstream kernel tree with debugging and/or tracing enabled however, the resulting code triggers a compiler error. This is because the symbols DEBUG and TRACING conflict with symbols with the same named defined in unrelated kernel headers. The patch below resolves these conflicts by renaming the following preprocessor symbols: - DEBUG into CONFIG_SCST_DEBUG. - DEBUG_DIGEST_FAILURES into CONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES. - DEBUG_OOM into CONFIG_SCST_DEBUG_OOM. - DEBUG_RETRY into CONFIG_SCST_DEBUG_RETRY. - DEBUG_SN into CONFIG_SCST_DEBUG_SN. - DEBUG_TM into CONFIG_SCST_DEBUG_TM. - EXTRACHECKS into CONFIG_SCST_EXTRACHECKS. - SCST_HIGHMEM into CONFIG_SCST_HIGHMEM. - STRICT_SERIALIZING into CONFIG_SCST_STRICT_SERIALIZING. - TM_DBG_GO_OFFLINE into CONFIG_SCST_TM_DBG_GO_OFFLINE. Mapped 0/1 values into macro undefined / macro defined. - TRACING into CONFIG_SCST_TRACING. - USE_EXPECTED_VALUES into CONFIG_SCST_USE_EXPECTED_VALUES. - In qla_isp/linux/isp_scst.c, renamed DEBUG into DEBUG_ISP_SCST. - In qla_isp/..., renamed SCSI_TARGET in SCST_SCSI_TARGET. - In qla_isp/..., renamed SCSI_TARGET_DEV in SCST_SCSI_TARGET_DEV. Additionally, all CONFIG_SCSI_TARGET* macro's are renamed into CONFIG_SCST* in order to avoid confusion between the STGT CONFIG-symbols and the SCST CONFIG- symbols. The following additional options are now configurable through Kconfig: - CONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES - CONFIG_SCST_STRICT_SERIALIZING - CONFIG_SCST_STRICT_SECURITY - CONFIG_SCST_ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ - CONFIG_SCST_ABORT_CONSIDER_FINISHED_TASKS_AS_NOT_EXISTING - CONFIG_SCST_USE_EXPECTED_VALUES - CONFIG_SCST_DEBUG_OOM - CONFIG_SCST_DEBUG_RETRY - CONFIG_SCST_DEBUG_SN - CONFIG_SCST_DEBUG_TM - CONFIG_SCST_TM_DBG_GO_OFFLINE The patch below has been verified as follows: - Verified that the following command does not print any new warning messages: make -s clean && make -C srpt -s clean && make -s scst iscsi-scst && make -C srpt -s - Verified as follows that the internal SCST patches still apply cleanly: for p in *patch; do patch -p0 --dry-run -f -s <$p; done - Checked that the patch generated by generate-kernel-patch still applies cleanly to the 2.6.25.7 kernel, and that the patched kernel tree still compiles, installs and boots fine, that the iscsi-scst, ib_srpt, scst_disk and scst_vdisk modules still load, and that iSCSI communication still works fine. All SCST kernel configuration options that could be enabled have been enabled during this test. Signed-off-by: Bart Van Assche <bart.vanassche@gmail.com> git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@453 d57e44dd-8a1f-0410-8b47-8ef2f437770f
608 lines
12 KiB
C
608 lines
12 KiB
C
/*
|
|
* Copyright (C) 2004 - 2005 FUJITA Tomonori <tomof@acm.org>
|
|
* Copyright (C) 2007 - 2008 Vladislav Bolkhovitin
|
|
* Copyright (C) 2007 - 2008 CMS Distribution Limited
|
|
*
|
|
* 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.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
#include "iscsi.h"
|
|
|
|
#define ISCSI_PROC_VERSION_NAME "version"
|
|
|
|
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
|
|
|
#define ISCSI_PROC_LOG_ENTRY_NAME "trace_level"
|
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
static struct scst_proc_log iscsi_proc_local_trace_tbl[] =
|
|
{
|
|
{ TRACE_D_READ, "d_read" },
|
|
{ TRACE_D_WRITE, "d_write" },
|
|
{ TRACE_CONN_OC, "conn" },
|
|
{ TRACE_CONN_OC_DBG, "conn_dbg" },
|
|
{ TRACE_D_IOV, "iov" },
|
|
{ TRACE_D_DUMP_PDU, "pdu" },
|
|
{ TRACE_NET_PG, "net_page" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static int iscsi_log_info_show(struct seq_file *seq, void *v)
|
|
{
|
|
int res = 0;
|
|
|
|
TRACE_ENTRY();
|
|
|
|
res = scst_proc_log_entry_read(seq, trace_flag,
|
|
iscsi_proc_local_trace_tbl);
|
|
|
|
TRACE_EXIT_RES(res);
|
|
return res;
|
|
}
|
|
|
|
static ssize_t iscsi_proc_log_entry_write(struct file *file,
|
|
const char __user *buf, size_t length, loff_t *off)
|
|
{
|
|
int res = 0;
|
|
|
|
TRACE_ENTRY();
|
|
|
|
res = scst_proc_log_entry_write(file, buf, length, &trace_flag,
|
|
ISCSI_DEFAULT_LOG_FLAGS, iscsi_proc_local_trace_tbl);
|
|
|
|
TRACE_EXIT_RES(res);
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
static int iscsi_version_info_show(struct seq_file *seq, void *v)
|
|
{
|
|
TRACE_ENTRY();
|
|
|
|
seq_printf(seq, "%s\n", ISCSI_VERSION_STRING);
|
|
|
|
#ifdef CONFIG_SCST_EXTRACHECKS
|
|
seq_printf(seq, "EXTRACHECKS\n");
|
|
#endif
|
|
|
|
#ifdef CONFIG_SCST_TRACING
|
|
seq_printf(seq, "TRACING\n");
|
|
#endif
|
|
|
|
#ifdef CONFIG_SCST_DEBUG
|
|
seq_printf(seq, "DEBUG\n");
|
|
#endif
|
|
|
|
#ifdef CONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES
|
|
seq_printf(seq, "DEBUG_DIGEST_FAILURES\n");
|
|
#endif
|
|
|
|
TRACE_EXIT();
|
|
return 0;
|
|
}
|
|
|
|
static struct scst_proc_data iscsi_version_proc_data = {
|
|
SCST_DEF_RW_SEQ_OP(NULL)
|
|
.show = iscsi_version_info_show,
|
|
};
|
|
|
|
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
|
static struct scst_proc_data iscsi_log_proc_data = {
|
|
SCST_DEF_RW_SEQ_OP(iscsi_proc_log_entry_write)
|
|
.show = iscsi_log_info_show,
|
|
};
|
|
#endif
|
|
|
|
static __init int iscsi_proc_log_entry_build(struct scst_tgt_template *templ)
|
|
{
|
|
int res = 0;
|
|
struct proc_dir_entry *p, *root;
|
|
|
|
TRACE_ENTRY();
|
|
|
|
root = scst_proc_get_tgt_root(templ);
|
|
if (root) {
|
|
p = scst_create_proc_entry(root, ISCSI_PROC_VERSION_NAME,
|
|
&iscsi_version_proc_data);
|
|
if (p == NULL) {
|
|
PRINT_ERROR("Not enough memory to register "
|
|
"target driver %s entry %s in /proc",
|
|
templ->name, ISCSI_PROC_VERSION_NAME);
|
|
res = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
|
/* create the proc file entry for the device */
|
|
iscsi_log_proc_data.data = (void *)templ->name;
|
|
p = scst_create_proc_entry(root, ISCSI_PROC_LOG_ENTRY_NAME,
|
|
&iscsi_log_proc_data);
|
|
if (p == NULL) {
|
|
PRINT_ERROR("Not enough memory to register "
|
|
"target driver %s entry %s in /proc",
|
|
templ->name, ISCSI_PROC_LOG_ENTRY_NAME);
|
|
res = -ENOMEM;
|
|
goto out_remove_ver;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
out:
|
|
TRACE_EXIT_RES(res);
|
|
return res;
|
|
|
|
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
|
out_remove_ver:
|
|
remove_proc_entry(ISCSI_PROC_VERSION_NAME, root);
|
|
goto out;
|
|
#endif
|
|
}
|
|
|
|
static void iscsi_proc_log_entry_clean(struct scst_tgt_template *templ)
|
|
{
|
|
struct proc_dir_entry *root;
|
|
|
|
TRACE_ENTRY();
|
|
|
|
root = scst_proc_get_tgt_root(templ);
|
|
if (root) {
|
|
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
|
remove_proc_entry(ISCSI_PROC_LOG_ENTRY_NAME, root);
|
|
#endif
|
|
remove_proc_entry(ISCSI_PROC_VERSION_NAME, root);
|
|
}
|
|
|
|
TRACE_EXIT();
|
|
return;
|
|
}
|
|
|
|
struct proc_entries {
|
|
const char *name;
|
|
struct file_operations *fops;
|
|
};
|
|
|
|
static struct proc_entries iscsi_proc_entries[] =
|
|
{
|
|
{"session", &session_seq_fops},
|
|
};
|
|
|
|
static struct proc_dir_entry *proc_iscsi_dir;
|
|
|
|
void iscsi_procfs_exit(void)
|
|
{
|
|
int i;
|
|
|
|
if (!proc_iscsi_dir)
|
|
return;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(iscsi_proc_entries); i++)
|
|
remove_proc_entry(iscsi_proc_entries[i].name, proc_iscsi_dir);
|
|
|
|
iscsi_proc_log_entry_clean(&iscsi_template);
|
|
}
|
|
|
|
int __init iscsi_procfs_init(void)
|
|
{
|
|
int i, err = 0;
|
|
struct proc_dir_entry *ent;
|
|
|
|
proc_iscsi_dir = scst_proc_get_tgt_root(&iscsi_template);
|
|
if (proc_iscsi_dir == NULL) {
|
|
err = -ESRCH;
|
|
goto out;
|
|
}
|
|
|
|
proc_iscsi_dir->owner = THIS_MODULE;
|
|
|
|
err = iscsi_proc_log_entry_build(&iscsi_template);
|
|
if (err < 0)
|
|
goto out;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(iscsi_proc_entries); i++) {
|
|
ent = create_proc_entry(iscsi_proc_entries[i].name, 0, proc_iscsi_dir);
|
|
if (ent)
|
|
ent->proc_fops = iscsi_proc_entries[i].fops;
|
|
else {
|
|
err = -ENOMEM;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
out:
|
|
return err;
|
|
|
|
err:
|
|
if (proc_iscsi_dir)
|
|
iscsi_procfs_exit();
|
|
goto out;
|
|
}
|
|
|
|
/* target_mutex supposed to be locked */
|
|
static int get_conn_info(struct iscsi_target *target, unsigned long ptr)
|
|
{
|
|
int err;
|
|
struct iscsi_session *session;
|
|
struct conn_info info;
|
|
struct iscsi_conn *conn;
|
|
|
|
err = copy_from_user(&info, (void *) ptr, sizeof(info));
|
|
if (err < 0)
|
|
return err;
|
|
|
|
session = session_lookup(target, info.sid);
|
|
if (!session)
|
|
return -ENOENT;
|
|
conn = conn_lookup(session, info.cid);
|
|
|
|
info.cid = conn->cid;
|
|
info.stat_sn = conn->stat_sn;
|
|
info.exp_stat_sn = conn->exp_stat_sn;
|
|
|
|
if (copy_to_user((void *) ptr, &info, sizeof(info)))
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* target_mutex supposed to be locked */
|
|
static int add_conn(struct iscsi_target *target, unsigned long ptr)
|
|
{
|
|
int err;
|
|
struct iscsi_session *session;
|
|
struct conn_info info;
|
|
|
|
err = copy_from_user(&info, (void *) ptr, sizeof(info));
|
|
if (err < 0)
|
|
return err;
|
|
|
|
session = session_lookup(target, info.sid);
|
|
if (!session)
|
|
return -ENOENT;
|
|
|
|
return conn_add(session, &info);
|
|
}
|
|
|
|
/* target_mutex supposed to be locked */
|
|
static int del_conn(struct iscsi_target *target, unsigned long ptr)
|
|
{
|
|
int err;
|
|
struct iscsi_session *session;
|
|
struct conn_info info;
|
|
|
|
err = copy_from_user(&info, (void *) ptr, sizeof(info));
|
|
if (err < 0)
|
|
return err;
|
|
|
|
session = session_lookup(target, info.sid);
|
|
if (!session)
|
|
return -ENOENT;
|
|
|
|
return conn_del(session, &info);
|
|
}
|
|
|
|
/* target_mutex supposed to be locked */
|
|
static int get_session_info(struct iscsi_target *target, unsigned long ptr)
|
|
{
|
|
int err;
|
|
struct iscsi_session *session;
|
|
struct session_info info;
|
|
|
|
err = copy_from_user(&info, (void *) ptr, sizeof(info));
|
|
if (err < 0)
|
|
return err;
|
|
|
|
session = session_lookup(target, info.sid);
|
|
|
|
if (!session)
|
|
return -ENOENT;
|
|
|
|
info.exp_cmd_sn = session->exp_cmd_sn;
|
|
|
|
if (copy_to_user((void *) ptr, &info, sizeof(info)))
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* target_mutex supposed to be locked */
|
|
static int add_session(struct iscsi_target *target, unsigned long ptr)
|
|
{
|
|
int err;
|
|
struct session_info info;
|
|
|
|
err = copy_from_user(&info, (void *) ptr, sizeof(info));
|
|
if (err < 0)
|
|
return err;
|
|
|
|
info.initiator_name[ISCSI_NAME_LEN-1] = '\0';
|
|
info.user_name[ISCSI_NAME_LEN-1] = '\0';
|
|
|
|
return session_add(target, &info);
|
|
}
|
|
|
|
/* target_mutex supposed to be locked */
|
|
static int del_session(struct iscsi_target *target, unsigned long ptr)
|
|
{
|
|
int err;
|
|
struct session_info info;
|
|
|
|
err = copy_from_user(&info, (void *) ptr, sizeof(info));
|
|
if (err < 0)
|
|
return err;
|
|
|
|
return session_del(target, info.sid);
|
|
}
|
|
|
|
/* target_mutex supposed to be locked */
|
|
static int iscsi_param_config(struct iscsi_target *target, unsigned long ptr, int set)
|
|
{
|
|
int err;
|
|
struct iscsi_param_info info;
|
|
|
|
err = copy_from_user(&info, (void *) ptr, sizeof(info));
|
|
if (err < 0)
|
|
goto out;
|
|
|
|
err = iscsi_param_set(target, &info, set);
|
|
if (err < 0)
|
|
goto out;
|
|
|
|
if (!set)
|
|
err = copy_to_user((void *) ptr, &info, sizeof(info));
|
|
|
|
out:
|
|
return err;
|
|
}
|
|
|
|
/* target_mgmt_mutex supposed to be locked */
|
|
static int add_target(unsigned long ptr)
|
|
{
|
|
int err;
|
|
struct target_info info;
|
|
|
|
err = copy_from_user(&info, (void *) ptr, sizeof(info));
|
|
if (err < 0)
|
|
return err;
|
|
|
|
err = target_add(&info);
|
|
if (!err)
|
|
err = copy_to_user((void *) ptr, &info, sizeof(info));
|
|
|
|
return err;
|
|
}
|
|
|
|
static int iscsi_check_version(unsigned long arg)
|
|
{
|
|
struct iscsi_register_info reg;
|
|
char ver[sizeof(ISCSI_SCST_INTERFACE_VERSION)+1];
|
|
int res;
|
|
|
|
res = copy_from_user(®, (void *)arg, sizeof(reg));
|
|
if (res < 0) {
|
|
PRINT_ERROR("%s", "Unable to get register info");
|
|
goto out;
|
|
}
|
|
|
|
res = copy_from_user(ver, (void *)(unsigned long)reg.version,
|
|
sizeof(ver));
|
|
if (res < 0) {
|
|
PRINT_ERROR("%s", "Unable to get version string");
|
|
goto out;
|
|
}
|
|
ver[sizeof(ver)-1] = '\0';
|
|
|
|
if (strcmp(ver, ISCSI_SCST_INTERFACE_VERSION) != 0) {
|
|
PRINT_ERROR("Incorrect version of user space %s (expected %s)",
|
|
ver, ISCSI_SCST_INTERFACE_VERSION);
|
|
res = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
res = ISCSI_CONN_IOV_MAX << PAGE_SHIFT;
|
|
|
|
out:
|
|
return res;
|
|
}
|
|
|
|
static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
{
|
|
struct iscsi_target *target = NULL;
|
|
long err;
|
|
u32 id;
|
|
|
|
switch (cmd) {
|
|
case ADD_TARGET:
|
|
case DEL_TARGET:
|
|
case ADD_SESSION:
|
|
case DEL_SESSION:
|
|
case GET_SESSION_INFO:
|
|
case ISCSI_PARAM_SET:
|
|
case ISCSI_PARAM_GET:
|
|
case ADD_CONN:
|
|
case DEL_CONN:
|
|
case GET_CONN_INFO:
|
|
break;
|
|
|
|
case REGISTER_USERD:
|
|
err = iscsi_check_version(arg);
|
|
goto out;
|
|
|
|
default:
|
|
PRINT_ERROR("Invalid ioctl cmd %x", cmd);
|
|
err = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
err = get_user(id, (u32 *) arg);
|
|
if (err != 0)
|
|
goto out;
|
|
|
|
err = mutex_lock_interruptible(&target_mgmt_mutex);
|
|
if (err < 0)
|
|
goto out;
|
|
|
|
if (cmd == DEL_TARGET) {
|
|
err = target_del(id);
|
|
goto out_unlock;
|
|
}
|
|
|
|
target = target_lookup_by_id(id);
|
|
|
|
if (cmd == ADD_TARGET)
|
|
if (target) {
|
|
err = -EEXIST;
|
|
PRINT_ERROR("Target %u already exist!", id);
|
|
goto out_unlock;
|
|
}
|
|
|
|
switch (cmd) {
|
|
case ADD_TARGET:
|
|
err = add_target(arg);
|
|
goto out_unlock;
|
|
}
|
|
|
|
if (!target) {
|
|
PRINT_ERROR("Can't find the target %u", id);
|
|
err = -EINVAL;
|
|
goto out_unlock;
|
|
}
|
|
|
|
mutex_lock(&target->target_mutex);
|
|
|
|
switch (cmd) {
|
|
case ADD_SESSION:
|
|
err = add_session(target, arg);
|
|
break;
|
|
|
|
case DEL_SESSION:
|
|
err = del_session(target, arg);
|
|
break;
|
|
|
|
case GET_SESSION_INFO:
|
|
err = get_session_info(target, arg);
|
|
break;
|
|
|
|
case ISCSI_PARAM_SET:
|
|
err = iscsi_param_config(target, arg, 1);
|
|
break;
|
|
|
|
case ISCSI_PARAM_GET:
|
|
err = iscsi_param_config(target, arg, 0);
|
|
break;
|
|
|
|
case ADD_CONN:
|
|
err = add_conn(target, arg);
|
|
break;
|
|
|
|
case DEL_CONN:
|
|
err = del_conn(target, arg);
|
|
break;
|
|
|
|
case GET_CONN_INFO:
|
|
err = get_conn_info(target, arg);
|
|
break;
|
|
|
|
default:
|
|
sBUG();
|
|
break;
|
|
}
|
|
|
|
mutex_unlock(&target->target_mutex);
|
|
|
|
out_unlock:
|
|
mutex_unlock(&target_mgmt_mutex);
|
|
|
|
out:
|
|
return err;
|
|
}
|
|
|
|
static int release(struct inode *inode, struct file *filp)
|
|
{
|
|
TRACE(TRACE_MGMT, "%s", "Releasing allocated resources");
|
|
target_del_all();
|
|
return 0;
|
|
}
|
|
|
|
struct file_operations ctr_fops = {
|
|
.owner = THIS_MODULE,
|
|
.unlocked_ioctl = ioctl,
|
|
.compat_ioctl = ioctl,
|
|
.release = release,
|
|
};
|
|
|
|
#ifdef CONFIG_SCST_DEBUG
|
|
void iscsi_dump_iov(struct msghdr *msg)
|
|
{
|
|
if (trace_flag & TRACE_D_IOV) {
|
|
int i;
|
|
printk("%p, %zd\n", msg->msg_iov, msg->msg_iovlen);
|
|
for (i = 0; i < min_t(size_t, msg->msg_iovlen,
|
|
ISCSI_CONN_IOV_MAX); i++) {
|
|
printk("%d: %p,%zd\n", i, msg->msg_iov[i].iov_base,
|
|
msg->msg_iov[i].iov_len);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void iscsi_dump_char(int ch)
|
|
{
|
|
static unsigned char text[16];
|
|
static int i;
|
|
|
|
if (ch < 0) {
|
|
while ((i % 16) != 0) {
|
|
printk(" ");
|
|
text[i] = ' ';
|
|
i++;
|
|
if ((i % 16) == 0)
|
|
printk(" | %.16s |\n", text);
|
|
else if ((i % 4) == 0)
|
|
printk(" |");
|
|
}
|
|
i = 0;
|
|
return;
|
|
}
|
|
|
|
text[i] = (ch < 0x20 || (ch >= 0x80 && ch <= 0xa0)) ? ' ' : ch;
|
|
printk(" %02x", ch);
|
|
i++;
|
|
if ((i % 16) == 0) {
|
|
printk(" | %.16s |\n", text);
|
|
i = 0;
|
|
} else if ((i % 4) == 0)
|
|
printk(" |");
|
|
}
|
|
|
|
void iscsi_dump_pdu(struct iscsi_pdu *pdu)
|
|
{
|
|
if (trace_flag & TRACE_D_DUMP_PDU) {
|
|
unsigned char *buf;
|
|
int i;
|
|
|
|
buf = (void *)&pdu->bhs;
|
|
printk("BHS: (%p,%zd)\n", buf, sizeof(pdu->bhs));
|
|
for (i = 0; i < sizeof(pdu->bhs); i++)
|
|
iscsi_dump_char(*buf++);
|
|
iscsi_dump_char(-1);
|
|
|
|
buf = (void *)pdu->ahs;
|
|
printk("AHS: (%p,%d)\n", buf, pdu->ahssize);
|
|
for (i = 0; i < pdu->ahssize; i++)
|
|
iscsi_dump_char(*buf++);
|
|
iscsi_dump_char(-1);
|
|
|
|
printk("Data: (%d)\n", pdu->datasize);
|
|
}
|
|
}
|
|
#endif /* CONFIG_SCST_DEBUG */
|