+++ /dev/null
-Summary of changes from v0.4.15 to v0.4.16
-=================================
-
-Arne Redlich
- o fix overzealous assert() in digest_data()
- o add checking on return value of ISCSI_PARAM_GET
- o 2.6.22, 2.6.23 and 2.6.24 compile fixes
- o add conn->rwsize check
- o avoid potential NULL-ptr dereferences in rx and tx buffer
- o fix the shell syntax in init scripts
-
-Dave Jiang
- o fix digest endieness on LE archs
-
-FUJITA Tomonori
- o fix SPARC alignment issues (based on a patch from joel.bertrand@systella.fr)
-
-Ross S. W. Walker
- o fix DISTDIR in Makefile for /etc install
- o add support to nullio for volumes > 2TB
- o remove init.d memory size adjustment
- o add error code reporting to blockio_open_path
- o blockio gen_scsiid bug fix
- o add verbosity to kernel output and task management
-
-
-Summary of changes from v0.4.14 to v0.4.15
-=================================
-
-Juhani Rautiainen
- o Add RELEASE/RESERVE support
-
-Ross S. W. Walker
- o Improve the build system to support several kernel versions
- o Add block-io support
-
-
-Summary of changes from v0.4.13 to v0.4.14
-=================================
-
-Arne Redlich
- o Kill unused "state" in struct iscsi_cmnd.
- o Fixed fileio_sync() to propagate error to the caller (and initiator).
- o Don't attempt to show target/session params if communication with ietd
- fails.
- o Fixes to ietadm parameters handling.
-
-FUJITA Tomonori
- o rewritten iSNS code, many iSNS fixes.
- o added iSNS SCN support.
- o IPv6 fixes to userspace.
-
-Ming Zhang
- o Fix the READ_* commands error handling bug.
- o fix the mode sense response.
- o wrong #endif sequence in misc.h
-
-Richard Bollinger
- o add a patch to ietd.c that allows defunct sessions to go away.
- o add write-back cache and read-only support.
-
-Frederic Temporelli
- o Fix for the combination of 32-bit userland and 64-bit kernel on mips.
-
-Henry Liu
- o corrected many task management functions, prevent crashing on
- LUN RESET, TARGET WARM RESET.
-
-K Chapman
- o Fixed a typo in check_segment_length().
-
-Emmanuel Florac
- o Add ietadm manpage.
-
-
-Summary of changes from v0.4.12 to v0.4.13
-=================================
-Arne Redlich
- o patch to avoid digest calculation for PDUs whose data has been skipped
- already for various reasons.
- o Correct a bug managing non-default MaxRxDSL.
- o added to ietadm ability to show target parameters.
- o add on the workaround to AIX initiator MaxCmdSN bug.
-
-FUJITA Tomonori
- o added to ietadm ability to show the iSCSI parameters for an established
- session.
-
-Ming Zhang
- o Fixed this bug : ietd should manage the iscsi name in a case insensitive
- way to conform to the RFC.
- o workaround to AIX initiator MaxCmdSN bug.
- o Fixed socket() return value judgment.
-
-Bastiaan Bakker
- o add 'condrestart' command to the RedHat initscript.
-
-Robert Whitehead
- o correct the bug that prevents iet to start if there isn't
- an /etc/ietd.conf file.
-
-Summary of changes from v0.4.11 to v0.4.12
-=================================
-
-Arne Redlich
- o Fix MaxRecvDataSegmentLength handling.
- o Fix login parameter handling.
- o Update man pages.
-
-Bastiaan Bakker
- o Add features to specify the listen address and port.
- o Fix setuid and setgid bugs in ietd daemon.
-
-FUJITA Tomonori
- o Add IPv6 support.
-
-Junjiro Okajima
- o Fix a bug about getting parameters from kernel space.
-
-Krzysztof Blaszkowski
- o Fix for requests with unaligned to 4 length.
-
-
-Summary of changes from v0.4.10 to v0.4.11
-=================================
-
-FUJITA Tomonori
- o Fix Task Management Function bugs.
-
-Ming Zhang
- o Update man pages.
-
-
-Summary of changes from v0.4.9 to v0.4.10
-=================================
-
-Arne Redlich
- o Fix 0x83 inquiry output.
- o Fix iSCSI parameter handling bugs.
-
-FUJITA Tomonori
- o Add the access control based on initiator address
- and target name patterns.
-
-Junjiro Okajima
- o Fix parameter checking bugs.
-
-Ming Zhang
- o Add the nullio mode (only useful for performance evaluation).
-
-
-Summary of changes from v0.4.8 to v0.4.9
-=================================
-
-FUJITA Tomonori
- o Fix parameter negotiation handling bugs.
-
-Wang Zhenyu
- o Fix digest negotiation handling bugs.
-
-
-Summary of changes from v0.4.7 to v0.4.8
-=================================
-
-FUJITA Tomonori
- o Fix unsolicited data handling bugs.
- o Rewrite parameter handling code.
- o Rewrite ietadm tool.
- o Improve dynamic configuration support.
- o Cleanups on the kernel-user interface.
- o Improve wrong PDU handling.
- o Implement a framework to handle multiple configuration methods.
- o Implement basic access control support.
-
-
-Summary of changes from v0.4.6 to v0.4.7
-=================================
-
-Florian Zierer
- o Add the startup script for Gentoo.
-
-FUJITA Tomonori
- o Rewrite parameter handling code.
- o Fix task management code bug.
- o Fix 0x83 inquiry output (Thanks to Christophe Varoqui).
-
-Ming Zhang
- o Acquire T10 ID.
- o Fix parameter handling bugs.
- o Some user-space cleanups.
-
-Philipp Hug
- o Fix ietd.8 man typo.
-
-
-Summary of changes from v0.4.5 to v0.4.6
-=================================
-
-FUJITA Tomonori
- o Replace the makeshift event notification code with netlink.
- o Add task management code except for ACA and reassign stuff.
- o Fix r2t lun bug (Thanks to Ming Zhang).
-
-
-Summary of changes from v0.4.4 to v0.4.5
-=================================
-
-FUJITA Tomonori
- o Rewrite the iSCSI command handling code.
- o Rewrite the I/O data handling code.
- o Fix worker thread.
- o Several cleanups.
-
-
-Summary of changes from v0.4.3 to v0.4.4
-=================================
-
-Krzysztof Blaszkowski
- o Fix an out-of-memory bug.
-
-
-Summary of changes from v0.4.2 to v0.4.3
-=================================
-
-Arne Redlich
- o Fix header digest bug.
- o Fix unexpected closed connection bug.
- o Fix iSCSI parameter bug.
-
-FUJITA Tomonori
- o Fix network thread.
-
-
-Summary of changes from v0.4.1 to v0.4.2
-=================================
-
-FUJITA Tomonori
- o Fix network thread.
- o Fix MaxOutstandingR2T handling.
-
-Ming Zhang
- o Add large volume support (over 2TB).
-
-
-Summary of changes from v0.4.0 to v0.4.1
-=================================
-
-Arne Redlich
- o Add mutual CHAP support. Note that you need to replace "User"
- with "IncomingUser" in ietd.conf.
-
-FUJITA Tomonori
- o Fix InitialR2T=No support.
- o Fix INQUIRY command handling.
- o Fix network and worker thread.
- o Start to split SCSI stuff.
- o Rewrite the R2T handling code.
- o Several cleanups.
-
-
-Summary of changes from v0.3.8 to v0.4.0
-=================================
-
-Arne Redlich
- o iSNS bug fix.
-
-FUJITA Tomonori
- o Move to 2.6 kernels.
- o Rewrite the kernel thread performing network I/O.
- o Add header and data digests (Thanks to Arne Redlich).
-
-Ming Zhang
- o Add mode sense page 0x3 and 0x4 support (Thanks to K Chapman).
- o iSNS bug fix.
-
-
-Summary of changes from v0.3.7 to v0.3.8
-=================================
-
-Arne Redlich
- o Fix ietadm global option bug.
-
-FUJITA Tomonori
- o Fix TCP option bugs (Thanks to Chuck Berg).
- o Fix REPORT LUN (handling lots of LUs).
-
-
-Summary of changes from v0.3.6 to v0.3.7
-=================================
-
-Arne Redlich
- o Fix target_alloc_pages().
-
-FUJITA Tomonori
- o Fix REPORT LUN bug.
-
-
-Summary of changes from v0.3.5 to v0.3.6
-=================================
-
-Arne Redlich
- o Fix bugs about rejecting PDUs.
-
-FUJITA Tomonori
- o Cleanups on target_cmnd structure.
- o Kill highmem stuff.
- o Fix REPORT LUN (handling lots of LUs).
-
-
-Summary of changes from v0.3.4 to v0.3.5
-=================================
-
-Arne Redlich
- o Fix ietd security hole.
- o Fix REPORT LUN bug.
- o FIX NOOP_OUT padding bug.
-
-FUJITA Tomonori
- o Rewrite event notification code.
-
-Libor Vanek
- o Add max_sessions option.
- o Fix command parsing bug.
-
-Ming Zhang
- o Cleanups for 64-bit architectures.
-
-
-Summary of changes from v0.3.3 to v0.3.4
-=================================
-
-FUJITA Tomonori
- o Improve dynamic configuration support (adding targets and users).
-
-
-Summary of changes from v0.3.2 to v0.3.3
-=================================
-
-FUJITA Tomonori
- o Fix Makefile for the startup script.
-
-
-Summary of changes from v0.3.1 to v0.3.2
-=================================
-
-Ali Lehmann
- o Add a new startup script for Debian.
-
-FUJITA Tomonori
- o Fix the istd's handling of connections in out-of-memory situations.
- o Fix bugs in regular file support.
- o Fix `ietadm --mode del all`.
-
-Libor Vanek
- o Add a new startup script for RedHat.
-
-Ming Zhang
- o Add uid/gid option to ietd daemon.
- o Fix a access freed-memory bug in kernel/daemon.c.
-
-
-Summary of changes from v0.3.0 to v0.3.1
-=================================
-
-FUJITA Tomonori
- o Fix memory leaks in ietd daemon (Thanks to Ming).
- o Fix bugs about REPORT_LUNS commands (Thanks to Ming).
- o Fix a bug about Target Task Tag.
- o Add regular file support to fileio mode.
-
-
-Summary of changes from v0.2.6 to v0.3.0
-=================================
-
-Ali Lehmann
- o Update ietd.8 man page.
-
-FUJITA Tomonori
- o Fix shutdown code.
- o Fix istd kernel thread bugs.
- o Replace procfs interface with ioctl.
- o Add dynamic configuration support.
- o Update README and the boot script.
-
-Ming Zhang
- o Add config option to ietd daemon.
-
-
-Summary of changes from v0.2.5 to v0.2.6
-=================================
-
-Ali Lehmann
- o Add ietd.8 and ietd.conf.5 man pages.
-
-FUJITA Tomonori
- o Update README, Makefile, and the boot script.
-
-
-Summary of changes from v0.2.4 to v0.2.5
-=================================
-
-FUJITA Tomonori
- o Update README.
-
-
-Summary of changes from v0.2.3 to v0.2.4
-=================================
-
-Ming Zhang
- o Add a preliminary iSNS support.
- o Fix merge mistakes that I made at the previous release.
-
-
-Summary of changes from v0.2.2 to v0.2.3
-=================================
-
-Ming Zhang
- o Improve INQUIRY, REQUEST_SENSE, and MODE_SENSE command supports
- o Add fake RESERVE* and RELEASE* command supports
-
-
-Summary of changes from v0.2.1 to v0.2.2
-=================================
-
-FUJITA Tomonori
- o Improve the write performance of the file IO mode
-
-Ming Zhang
- o Fix unupdated pg_cnt when allocating a new tcmnd
- o Several cleanups
-
-
-Summary of changes from v0.2.0 to v0.2.1
-=================================
-
-FUJITA Tomonori
- o Fix a bug that makes the target use CPU unnecessarily
- o Add a feature that enable you to pass options to an IO mode
-
-
-Summary of changes from v0.1.0 to v0.2.0
-=================================
-
-FUJITA Tomonori
- o Rewrite read and write kernel threads which perform network IO
- o Fix race issues in the proc interface
- o Fix shutdown code
-
-Ming Zhang
- o Fix memory leaks in file and block IO modes
-
-
-Summary of changes from the ardis v20040211 to v0.1.0
-=================================
-
-FUJITA Tomonori
- o Remove a kernel patch. Multiple threads execute I/O operations
- o Replace IO functions with the kernel standard functions
- o Add multiple IO modes feature
- o Fix several race issues
- o Fix several out-of-memory situation bugs
iSCSI SCST target driver
========================
-Version 1.0.2, XX XXXXX 2009
+Version 2.0.0, XX XXXXX 2010
----------------------------
ISCSI-SCST is a deeply reworked fork of iSCSI Enterprise Target (IET)
See more info at http://scst.sourceforge.net/target_iscsi.html.
-This version is compatible with SCST version 1.0.2 and higher.
+This version is compatible with SCST version 2.0.0 and higher.
Installation if your Linux kernel already has iSCSI-SCST built-in
Installation out of Linux kernel tree
-------------------------------------
-Basically as in README-IET, where file names are changed as specified
-above.
+See HOWTOs in the doc/ subdirectory.
Only vanilla kernels from kernel.org and RHEL/CentOS 5.2 kernels are
supported, but it should work on other (vendors') kernels, if you manage
To use full power of TCP zero-copy transmit functions, especially
dealing with user space supplied via scst_user module memory, iSCSI-SCST
needs to be notified when Linux networking finished data transmission.
-Patch put_page_callback-<kernel-version>.patch provides such
-functionality. The corresponding version of it should be applied on your
-kernel. Then you should enable CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
-kernel config option. This is highly recommended, but not required. Basically,
-you should consider using of this patch as some optimization, which IET
-doesn't have, so if you don't use it, you will just revert to the
-original IET behavior, when for data transmission:
+For that you should enable CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
+kernel config option. This is highly recommended, but not required.
+Basically, iSCSI-SCST works fine with an unpatched Linux kernel with the
+same or better speed as other open source iSCSI targets, including IET,
+but if you want even better performance you have to patch and rebuild
+the kernel. Without CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
+enabled you will just revert to the original behavior of other open
+source iSCSI targets, when for data transmission:
- For in-kernel allocated memory (scst_vdisk and pass-through
handlers) usage of SGV cache on transmit path (READ-type commands)
will be disabled, but data will still be sent in zero-copy manner.
- The performance hit will be not big, but performance will still
- remain better, than for IET, because SGV cache will remain used on
- receive path while IET doesn't have such feature.
- For user space allocated memory (scst_user handler) all transmitted
data will be additionally copied into temporary TCP buffers. The
Usage
-----
-See in doc/iscsi-scst-howto.txt examples how to configure iSCSI-SCST.
+See HOWTOs in the doc/ subdirectory.
-ISCSI parameters like iSNS, CHAP and target parameters are configured in
-iscsi-scstd.conf. All LUN information is configured using the
-corresponding SCST interface. See in SCST README file section "Access
-and devices visibility management (LUN masking)" to find out how to do
-it. It is highly recommended to use scstadmin utility for that purpose.
-The LUN information in iscsi-scstd.conf will be ignored. This is because
-now responsibilities are divided between the target driver (iSCSI-SCST)
-and the SCST core as it logically should be: the target driver is
-responsible for handling targets and their parameters, SCST core is
-responsible for handling backstorage.
+In 2.0.0 usage of iscsi-scstd.conf as well as iscsi-scst-adm is
+obsolete. Use the sysfs interface facilities instead.
It is recommended to use TEST UNIT READY ("tur") command to check if
iSCSI-SCST target is alive.
-IMPORTANT: All LUN information (access control) MUST be configured
-========= BEFORE iscsi-scstd started!
+IMPORTANT: In the procfs build all LUN information (access control)
+========= MUST be configured BEFORE iscsi-scstd started!
Also see SCST README file how to tune for the best performance.
======= supported. See SCST README file for details.
+Sysfs interface
+---------------
+
+Starting from 2.0.0 iSCSI-SCST has sysfs interface. You can switch to it
+by running "make disable_proc". To switch back to the procfs interface
+you should run "make enable_proc". The procfs interface from version
+2.0.0 is obsolete and will be removed in one of the next versions.
+
+Root of SCST sysfs interface is /sys/kernel/scst_tgt. Root of iSCSI-SCST
+is /sys/kernel/scst_tgt/targets/iscsi. It has the following entries:
+
+ - None, one or more subdirectories for targets with name equal to names
+ of the corresponding targets.
+
+ - IncomingUser[num] - optional one or more attributes containing user
+ name and password for incoming discovery user name. Not exist by
+ default and can be added through "mgmt" entry, see below.
+
+ - OutgoingUser - optional attribute containing user name and password
+ for outgoing discovery user name. Not exist by default and can be
+ added through "mgmt" entry, see below.
+
+ - iSNSServer - contains name or IP address of iSNS server with optional
+ "AccessControl" attribute, which allows to enable iSNS access
+ control. Empty by default.
+
+ - enabled - using this attribute you can enable or disable iSCSI-SCST
+ accept new connections. It allows to finish configuring global
+ iSCSI-SCST attributes before it starts accepting new connections. 0
+ by default.
+
+ - open_state - read-only attribute, which allows to see if the user
+ space part of iSCSI-SCST connected to the kernel part.
+
+ - trace_level - allows to enable and disable various tracing
+ facilities. See content of this file for help how to use it.
+
+ - version - read-only attribute, which allows to see version of
+ iSCSI-SCST and enabled optional features.
+
+ - mgmt - main management entry, which allows to configure iSCSI-SCST.
+ Namely, add/delete targets as well as add/delete optional global and
+ per-target attributes. See content of this file for help how to use
+ it.
+
+Each iSCSI-SCST attribute can contain in the last line mark "[key]". It
+is automatically added mark used to allow scstadmin to see which
+attributes it should save in the config file. You can ignore it.
+
+Each target subdirectory contains the following entries:
+
+ - ini_group - subdirectory defining initiator groups for this target,
+ used to define per-initiator access control. See SCST core README for
+ more details.
+
+ - luns - subdirectory defining LUNs of this target. See SCST core
+ README for more details.
+
+ - sessions - subdirectory containing connected to this target sessions.
+
+ - IncomingUser[num] - optional one or more attributes containing user
+ name and password for incoming user name. Not exist by default and can
+ be added through the "mgmt" entry, see above.
+
+ - OutgoingUser - optional attribute containing user name and password
+ for outgoing user name. Not exist by default and can be added through
+ the "mgmt" entry, see above.
+
+ - Entries defining default iSCSI parameters values used during iSCSI
+ parameters negotiation.
+
+ - QueuedCommands - defines maximum number of commands queued to any
+ session of this target.
+
+ - enabled - using this attribute you can enable or disable iSCSI-SCST
+ accept new connections to this target. It allows to finish
+ configuring it before it starts accepting new connections. 0 by
+ default.
+
+ - tid - TID of this target.
+
+Subdirectory "sessions" contains one subdirectory for each connected
+session with name equal to name of the connected initiator.
+
+Each session subdirectory contains the following entries:
+
+ - One subdirectory for each TCP connection in this session. ISCSI-SCST
+ supports 1 connection per session, but the session subdirectory can
+ contain several connections: one active and other being closed.
+
+ - Entries defining negotiated iSCSI parameters.
+
+ - initiator_name - contains initiator name
+
+ - sid - contains SID of this session
+
+ - reinstating - contains reinstatement state of this session
+
+ - force_close - write-only attribute, which allows to force close this
+ session. This is the only writable session attribute.
+
+ - active_commands - contains number of active, i.e. not yet or being
+ executed, SCSI commands in this session.
+
+ - commands - contains overall number of SCSI commands in this session.
+
+Each connection subdirectory contains the following entries:
+
+ - cid - contains CID of this connection.
+
+ - ip - contains IP address of the connected initiator.
+
+ - state - contains processing state of this connection.
+
+Below is a sample script, which configures 1 virtual disk "disk1" using
+/disk1 image and one target iqn.2006-10.net.vlnb:tgt with all default
+parameters:
+
+#!/bin/bash
+
+modprobe scst
+modprobe scst_vdisk
+
+echo "open disk1 /disk1 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
+
+service iscsi-scst start
+
+echo "add_target iqn.2006-10.net.vlnb:tgt" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
+
+echo "add disk1 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
+
+echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
+echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled
+
+
+Below is more advanced sample script, which configures more virtual
+devices of various types, including virtual CDROM and 2 targets, one
+with all default parameters, another one with some not default
+parameters, incoming and outgoing user names for CHAP authentification,
+and special permissions for initiator iqn.2005-03.org.open-iscsi:cacdcd2520,
+which will see another set of devices. Also this sample configures CHAP
+authentication for discovery sessions and iSNS server with access control.
+
+#!/bin/bash
+
+modprobe scst
+modprobe scst_vdisk
+
+echo "open disk1 /disk1 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
+echo "open disk2 /disk2 4096 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
+echo "open blockio /dev/sda5" >/sys/kernel/scst_tgt/handlers/vdisk_blockio/mgmt
+echo "open nullio none" >/sys/kernel/scst_tgt/handlers/vdisk_nullio/mgmt
+echo "open cdrom" >/sys/kernel/scst_tgt/handlers/vcdrom/mgmt
+
+service iscsi-scst start
+
+echo "192.168.1.16 AccessControl" >/sys/kernel/scst_tgt/targets/iscsi/iSNSServer
+echo "add_attribute IncomingUser joeD 12charsecret" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
+echo "add_attribute OutgoingUser jackD 12charsecret1" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
+
+echo "add_target iqn.2006-10.net.vlnb:tgt" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
+
+echo "add disk1 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
+echo "add cdrom 1" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
+
+echo "add_target iqn.2006-10.net.vlnb:tgt1 \
+ IncomingUser1 joe2 12charsecret2; \
+ IncomingUser joe 12charsecret; \
+ OutgoingUser jim1 12charpasswd; \
+ InitialR2T No; \
+ ImmediateData Yes; \
+ MaxRecvDataSegmentLength 8192; \
+ MaxXmitDataSegmentLength 8192; \
+ MaxBurstLength 131072; \
+ FirstBurstLength 32768; \
+ MaxOutstandingR2T 1; \
+ HeaderDigest CRC32C,None; \
+ DataDigest CRC32C,None; \
+ QueuedCommands 8; \
+ " >/sys/kernel/scst_tgt/targets/iscsi/mgmt
+
+echo "add disk2 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/mgmt
+echo "add nullio 26" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/mgmt
+
+echo "create special_ini" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/mgmt
+echo "add blockio 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/luns/mgmt
+echo "add iqn.2005-03.org.open-iscsi:cacdcd2520" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/initiators/mgmt
+
+echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
+echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/enabled
+
+echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled
+
+The resulting overall SCST sysfs hierarchy with an initiator connected to
+both iSCSI-SCST targets will look like:
+
+/sys/kernel/scst_tgt
+|-- devices
+| |-- blockio
+| | |-- block_size
+| | |-- exported
+| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/luns/0
+| | |-- filename
+| | |-- handler -> ../../handlers/vdisk_blockio
+| | |-- read_only
+| | |-- removable
+| | |-- resync_size
+| | |-- size
+| | |-- t10_dev_id
+| | `-- type
+| |-- cdrom
+| | |-- exported
+| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/1
+| | |-- filename
+| | |-- handler -> ../../handlers/vcdrom
+| | |-- removable
+| | |-- size
+| | |-- t10_dev_id
+| | `-- type
+| |-- disk1
+| | |-- block_size
+| | |-- exported
+| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/0
+| | |-- filename
+| | |-- handler -> ../../handlers/vdisk_fileio
+| | |-- nv_cache
+| | |-- o_direct
+| | |-- read_only
+| | |-- removable
+| | |-- resync_size
+| | |-- size
+| | |-- t10_dev_id
+| | |-- type
+| | `-- write_through
+| |-- disk2
+| | |-- block_size
+| | |-- exported
+| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/0
+| | |-- filename
+| | |-- handler -> ../../handlers/vdisk_fileio
+| | |-- nv_cache
+| | |-- o_direct
+| | |-- read_only
+| | |-- removable
+| | |-- resync_size
+| | |-- size
+| | |-- t10_dev_id
+| | |-- type
+| | `-- write_through
+| `-- nullio
+| |-- block_size
+| |-- exported
+| | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/26
+| |-- handler -> ../../handlers/vdisk_nullio
+| |-- read_only
+| |-- removable
+| |-- size
+| |-- t10_dev_id
+| `-- type
+|-- handlers
+| |-- vcdrom
+| | |-- mgmt
+| | |-- trace_level
+| | `-- type
+| |-- vdisk_blockio
+| | |-- mgmt
+| | |-- trace_level
+| | `-- type
+| |-- vdisk_fileio
+| | |-- mgmt
+| | |-- trace_level
+| | `-- type
+| `-- vdisk_nullio
+| |-- mgmt
+| |-- trace_level
+| `-- type
+|-- sgv
+| |-- global_stats
+| |-- sgv
+| | `-- stats
+| |-- sgv-clust
+| | `-- stats
+| `-- sgv-dma
+| `-- stats
+|-- targets
+| `-- iscsi
+| |-- IncomingUser
+| |-- OutgoingUser
+| |-- enabled
+| |-- iSNSServer
+| |-- iqn.2006-10.net.vlnb:tgt
+| | |-- DataDigest
+| | |-- FirstBurstLength
+| | |-- HeaderDigest
+| | |-- ImmediateData
+| | |-- InitialR2T
+| | |-- MaxBurstLength
+| | |-- MaxOutstandingR2T
+| | |-- MaxRecvDataSegmentLength
+| | |-- MaxXmitDataSegmentLength
+| | |-- QueuedCommands
+| | |-- enabled
+| | |-- ini_group
+| | | `-- mgmt
+| | |-- luns
+| | | |-- 0
+| | | | |-- device -> ../../../../../devices/disk1
+| | | | `-- read_only
+| | | |-- 1
+| | | | |-- device -> ../../../../../devices/cdrom
+| | | | `-- read_only
+| | | `-- mgmt
+| | |-- sessions
+| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
+| | | |-- 10.170.75.2
+| | | | |-- cid
+| | | | |-- ip
+| | | | `-- state
+| | | |-- DataDigest
+| | | |-- FirstBurstLength
+| | | |-- HeaderDigest
+| | | |-- ImmediateData
+| | | |-- InitialR2T
+| | | |-- MaxBurstLength
+| | | |-- MaxOutstandingR2T
+| | | |-- MaxRecvDataSegmentLength
+| | | |-- MaxXmitDataSegmentLength
+| | | |-- active_commands
+| | | |-- commands
+| | | |-- force_close
+| | | |-- initiator_name
+| | | |-- reinstating
+| | | `-- sid
+| | `-- tid
+| |-- iqn.2006-10.net.vlnb:tgt1
+| | |-- DataDigest
+| | |-- FirstBurstLength
+| | |-- HeaderDigest
+| | |-- ImmediateData
+| | |-- IncomingUser
+| | |-- IncomingUser1
+| | |-- InitialR2T
+| | |-- MaxBurstLength
+| | |-- MaxOutstandingR2T
+| | |-- MaxRecvDataSegmentLength
+| | |-- MaxXmitDataSegmentLength
+| | |-- OutgoingUser
+| | |-- QueuedCommands
+| | |-- enabled
+| | |-- ini_group
+| | | |-- mgmt
+| | | `-- special_ini
+| | | |-- initiators
+| | | | |-- iqn.2005-03.org.open-iscsi:cacdcd2520
+| | | | `-- mgmt
+| | | `-- luns
+| | | |-- 0
+| | | | |-- device -> ../../../../../../../devices/blockio
+| | | | `-- read_only
+| | | `-- mgmt
+| | |-- luns
+| | | |-- 0
+| | | | |-- device -> ../../../../../devices/disk2
+| | | | `-- read_only
+| | | |-- 26
+| | | | |-- device -> ../../../../../devices/nullio
+| | | | `-- read_only
+| | | `-- mgmt
+| | |-- sessions
+| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
+| | | |-- 10.170.75.2
+| | | | |-- cid
+| | | | |-- ip
+| | | | `-- state
+| | | |-- DataDigest
+| | | |-- FirstBurstLength
+| | | |-- HeaderDigest
+| | | |-- ImmediateData
+| | | |-- InitialR2T
+| | | |-- MaxBurstLength
+| | | |-- MaxOutstandingR2T
+| | | |-- MaxRecvDataSegmentLength
+| | | |-- MaxXmitDataSegmentLength
+| | | |-- active_commands
+| | | |-- commands
+| | | |-- force_close
+| | | |-- initiator_name
+| | | |-- reinstating
+| | | `-- sid
+| | `-- tid
+| |-- mgmt
+| |-- open_state
+| |-- trace_level
+| `-- version
+|-- threads
+|-- trace_level
+`-- version
+
+
Troubleshooting
---------------
target's backstorage gets overloaded, or working over a slow link, when
the link can't serve all the queued commands on time,
-To workaround it you can reduce QueuedCommands parameter in
-iscsi-scstd.conf file for the corresponding target to some lower value,
-like 8 (default is 32).
+To workaround it you can reduce QueuedCommands parameter for the
+corresponding target to some lower value, like 8 (default is 32).
Also see SCST README file for more details about that issue and ways to
prevent it.
Thanks to:
- * IET developers for IET
-
* Ming Zhang <blackmagic02881@gmail.com> for fixes
* Krzysztof Blaszkowski <kb@sysmikro.com.pl> for many fixes
+++ /dev/null
-Introduction
--------------
-iSCSI Enterprise Target is for building an iSCSI storage system on
-Linux. It is aimed at developing an iSCSI target satisfying enterprise
-requirements.
-
-We borrow code from an Ardis iSCSI target (with respect to the GPL).
-
-
-Installation
--------------
-The iSCSI target requires a host running the Linux operating system
-with a kernel version of 2.6.19 (2.6.14 - 2.6.18 kernels using
-backward compatibility patches, see below) or newer. You need to
-enable "Cryptographic API" under "Cryptographic options" in the kernel
-config. You also need to enable "CRC32c CRC algorithm" if you use
-header or data digests. They are the kernel options, CONFIG_CRYPTO and
-CONFIG_CRYPTO_CRC32C, respectively. The user-space code requires
-OpenSSL library (http://www.openssl.org/).
-
-The iSCSI target consists of kernel modules and a daemon. Since IET
-is generally targeted at the latest stable mainline kernel, you might
-need to apply a backward compatibility patch to compile it against
-older kernel versions:
-
- patch -p0 < patches/compat-2.6.14-2.6.18.patch
-
-Compilation of the kernel modules require the path to the kernel
-sources:
-
- make KSRC=<kernel-src>
-
-The path can also be set by editing the main Makefile. If KSRC is
-omitted, make program will try to locate the kernel sources for
-current running kernel. Be sure to check whether it finds the right
-kernel sources.
-
-This will build the modules, the daemon, and the control tool. To
-install both, use:
-
- make KSRC=<kernel-src> install
-
-The kernel modules will be install in the module directory of the
-kernel. The daemon and the control tool will be installed as ietd and
-ietadm under /usr/sbin. The boot script will be installed as
-iscsi-targt under /etc/init.d.
-
-If you use Linux distribution that does not have /etc/init.d, the
-boot script will not be installed. So you need to install it to an
-appropriate directory manually.
-
-
-Configuration
--------------
-The daemon is configured via the configuration file /etc/ietd.conf.
-See the man page and the example file for the current syntax.
-
-The ietadm utility is for managing IET software dynamically. You can
-change the configurations of running targets. See the help message.
-
-The access control based on initiator address and target name patterns
-is configured via two configuration files (/etc/initiators.allow and
-/etc/initiators.deny). These files work like tcpd files
-(/etc/hosts.allow and /etc/hosts.deny). This feature enables you to
-hide a particular targets from some initiators. See the example files
-for the supported expressions. You can change the configuration
-dynamically. The modifications to the files become effective
-immediately.
-
-
-Starting
--------------
-The target is not started automatically. So execute:
-
- /etc/init.d/iscsi-target start
-
-Note that you must edit the configuration file before starting the
-target.
-
-
-Stopping
--------------
-Execute:
-
- /etc/init.d/iscsi-target stop
-
-Contact
--------------
-Please send bug reports, comments, feature requests etc. to our
-mailing list <iscsitarget-devel@lists.sourceforge.net>.
-
-
-Developer Notes
-----------------
-The central resource for IET development is the
-<iscsitarget-devel@lists.sourceforge.net> mailing list.
-
-Our subversion repository can be found at: svn://svn.berlios.de/iscsitarget
-
-When submitting patches, please diff against the code in our repository's
-trunk and adhere otherwise to the same rules that apply to Linux kernel
-development, in particular the Linux kernel coding style
-($KSRC/Documentation/CodingStyle) and the rules for submitting patches
-($KSRC/Documentation/SubmittingPatches), i.e. please send patches inline as
-plain text.
iSCSI SCST target driver
========================
-Version 1.0.2, XX XXXXX 2009
-----------------------------
-
-This driver is a forked with all respects version of iSCSI Enterprise
-Target (IET) (http://iscsitarget.sourceforge.net/) with updates to work
-over SCST as well as with many improvements and bugfixes (see ChangeLog
-file). The reason of fork is that the necessary changes are intrusive
-and with the current IET merge policy, where only simple bugfix-like
-patches, which doesn't touch the core code, could be merged, it is very
-unlikely that they will be merged in the main IET trunk.
-
-To let it be installed and work at the same host together with IET
-simultaneously all the driver's modules and files were renamed:
-
- * ietd.conf -> iscsi-scstd.conf
- * ietadm -> iscsi-scst-adm
- * ietd -> iscsi-scstd
- * iscsi-target -> iscsi-scst
- * iscsi-target.ko -> iscsi-scst.ko
-
-To use full power of TCP zero-copy transmit functions, especially
-dealing with user space supplied via scst_user module memory, iSCSI-SCST
-needs to be notified when Linux networking finished data transmission.
-For that you should enable CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
-kernel config option. This is highly recommended, but not required. Basically,
-you should consider usage of this option as some optimization, which IET
-doesn't have, so if you don't use it, you will just revert to the
-original IET behavior, when for data transmission:
-
- - For in-kernel allocated memory (scst_vdisk and pass-through
- handlers) usage of SGV cache on transmit path (READ-type commands)
- will be disabled, but data will still be sent in zero-copy manner.
- The performance hit will be not big, but performance will still
- remain better, than for IET, because SGV cache will remain used on
- receive path while IET doesn't have such feature.
-
- - For user space allocated memory (scst_user handler) all transmitted
- data will be additionally copied into temporary TCP buffers. The
- performance hit will be quite noticeable.
-
-Note, that if your network hardware does not support TX offload
-functions or has them disabled, then TCP zero-copy transmit functions on
-your system will not be used by Linux networking in any case, so
-put_page_callback patch will not be able to improve performance for you.
-You can check your network hardware offload capabilities by command
-"ethtool -k ethX", where X is the network device number. At least
-"tx-checksumming" and "scatter-gather" should be enabled.
+ISCSI-SCST is a deeply reworked fork of iSCSI Enterprise Target (IET)
+(http://iscsitarget.sourceforge.net). Reasons of the fork were:
+ - To be able to use full power of SCST core.
+
+ - To fix all the problems, corner cases issues and iSCSI standard
+ violations which IET has.
+
+See more info at http://scst.sourceforge.net/target_iscsi.html.
Usage
-----
See in http://scst.sourceforge.net/iscsi-scst-howto.txt how to configure
iSCSI-SCST.
-ISCSI parameters like iSNS, CHAP and target parameters are configured in
-iscsi-scstd.conf. All LUN information is configured using the
-corresponding SCST interface. See in SCST README file section "Access
-and devices visibility management (LUN masking)" to find out how to do
-it. It is highly recommended to use scstadmin utility for that purpose.
-The LUN information in iscsi-scstd.conf will be ignored. This is because
-now responsibilities are divided between the target driver (iSCSI-SCST)
-and the SCST core as it logically should be: the target driver is
-responsible for handling targets and their parameters, SCST core is
-responsible for handling backstorage.
+In 2.0.0 usage of iscsi-scstd.conf as well as iscsi-scst-adm is
+obsolete. Use the sysfs interface facilities instead.
It is recommended to use TEST UNIT READY ("tur") command to check if
iSCSI-SCST target is alive.
-IMPORTANT: All LUN information (access control) MUST be configured
-========= BEFORE iscsi-scstd started!
+IMPORTANT: In the procfs build all LUN information (access control)
+========= MUST be configured BEFORE iscsi-scstd started!
Also see SCST README file how to tune for the best performance.
======= supported. See SCST README file for details.
+Sysfs interface
+---------------
+
+Starting from 2.0.0 iSCSI-SCST has sysfs interface. You can switch to it
+by running "make disable_proc". To switch back to the procfs interface
+you should run "make enable_proc". The procfs interface from version
+2.0.0 is obsolete and will be removed in one of the next versions.
+
+Root of SCST sysfs interface is /sys/kernel/scst_tgt. Root of iSCSI-SCST
+is /sys/kernel/scst_tgt/targets/iscsi. It has the following entries:
+
+ - None, one or more subdirectories for targets with name equal to names
+ of the corresponding targets.
+
+ - IncomingUser[num] - optional one or more attributes containing user
+ name and password for incoming discovery user name. Not exist by
+ default and can be added through "mgmt" entry, see below.
+
+ - OutgoingUser - optional attribute containing user name and password
+ for outgoing discovery user name. Not exist by default and can be
+ added through "mgmt" entry, see below.
+
+ - iSNSServer - contains name or IP address of iSNS server with optional
+ "AccessControl" attribute, which allows to enable iSNS access
+ control. Empty by default.
+
+ - enabled - using this attribute you can enable or disable iSCSI-SCST
+ accept new connections. It allows to finish configuring global
+ iSCSI-SCST attributes before it starts accepting new connections. 0
+ by default.
+
+ - open_state - read-only attribute, which allows to see if the user
+ space part of iSCSI-SCST connected to the kernel part.
+
+ - trace_level - allows to enable and disable various tracing
+ facilities. See content of this file for help how to use it.
+
+ - version - read-only attribute, which allows to see version of
+ iSCSI-SCST and enabled optional features.
+
+ - mgmt - main management entry, which allows to configure iSCSI-SCST.
+ Namely, add/delete targets as well as add/delete optional global and
+ per-target attributes. See content of this file for help how to use
+ it.
+
+Each iSCSI-SCST attribute can contain in the last line mark "[key]". It
+is automatically added mark used to allow scstadmin to see which
+attributes it should save in the config file. You can ignore it.
+
+Each target subdirectory contains the following entries:
+
+ - ini_group - subdirectory defining initiator groups for this target,
+ used to define per-initiator access control. See SCST core README for
+ more details.
+
+ - luns - subdirectory defining LUNs of this target. See SCST core
+ README for more details.
+
+ - sessions - subdirectory containing connected to this target sessions.
+
+ - IncomingUser[num] - optional one or more attributes containing user
+ name and password for incoming user name. Not exist by default and can
+ be added through the "mgmt" entry, see above.
+
+ - OutgoingUser - optional attribute containing user name and password
+ for outgoing user name. Not exist by default and can be added through
+ the "mgmt" entry, see above.
+
+ - Entries defining default iSCSI parameters values used during iSCSI
+ parameters negotiation.
+
+ - QueuedCommands - defines maximum number of commands queued to any
+ session of this target.
+
+ - enabled - using this attribute you can enable or disable iSCSI-SCST
+ accept new connections to this target. It allows to finish
+ configuring it before it starts accepting new connections. 0 by
+ default.
+
+ - tid - TID of this target.
+
+Subdirectory "sessions" contains one subdirectory for each connected
+session with name equal to name of the connected initiator.
+
+Each session subdirectory contains the following entries:
+
+ - One subdirectory for each TCP connection in this session. ISCSI-SCST
+ supports 1 connection per session, but the session subdirectory can
+ contain several connections: one active and other being closed.
+
+ - Entries defining negotiated iSCSI parameters.
+
+ - initiator_name - contains initiator name
+
+ - sid - contains SID of this session
+
+ - reinstating - contains reinstatement state of this session
+
+ - force_close - write-only attribute, which allows to force close this
+ session. This is the only writable session attribute.
+
+ - active_commands - contains number of active, i.e. not yet or being
+ executed, SCSI commands in this session.
+
+ - commands - contains overall number of SCSI commands in this session.
+
+Each connection subdirectory contains the following entries:
+
+ - cid - contains CID of this connection.
+
+ - ip - contains IP address of the connected initiator.
+
+ - state - contains processing state of this connection.
+
+Below is a sample script, which configures 1 virtual disk "disk1" using
+/disk1 image and one target iqn.2006-10.net.vlnb:tgt with all default
+parameters:
+
+#!/bin/bash
+
+modprobe scst
+modprobe scst_vdisk
+
+echo "open disk1 /disk1 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
+
+service iscsi-scst start
+
+echo "add_target iqn.2006-10.net.vlnb:tgt" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
+
+echo "add disk1 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
+
+echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
+echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled
+
+
+Below is more advanced sample script, which configures more virtual
+devices of various types, including virtual CDROM and 2 targets, one
+with all default parameters, another one with some not default
+parameters, incoming and outgoing user names for CHAP authentification,
+and special permissions for initiator iqn.2005-03.org.open-iscsi:cacdcd2520,
+which will see another set of devices. Also this sample configures CHAP
+authentication for discovery sessions and iSNS server with access control.
+
+#!/bin/bash
+
+modprobe scst
+modprobe scst_vdisk
+
+echo "open disk1 /disk1 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
+echo "open disk2 /disk2 4096 NV_CACHE" >/sys/kernel/scst_tgt/handlers/vdisk_fileio/mgmt
+echo "open blockio /dev/sda5" >/sys/kernel/scst_tgt/handlers/vdisk_blockio/mgmt
+echo "open nullio none" >/sys/kernel/scst_tgt/handlers/vdisk_nullio/mgmt
+echo "open cdrom" >/sys/kernel/scst_tgt/handlers/vcdrom/mgmt
+
+service iscsi-scst start
+
+echo "192.168.1.16 AccessControl" >/sys/kernel/scst_tgt/targets/iscsi/iSNSServer
+echo "add_attribute IncomingUser joeD 12charsecret" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
+echo "add_attribute OutgoingUser jackD 12charsecret1" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
+
+echo "add_target iqn.2006-10.net.vlnb:tgt" >/sys/kernel/scst_tgt/targets/iscsi/mgmt
+
+echo "add disk1 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
+echo "add cdrom 1" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/mgmt
+
+echo "add_target iqn.2006-10.net.vlnb:tgt1 \
+ IncomingUser1 joe2 12charsecret2; \
+ IncomingUser joe 12charsecret; \
+ OutgoingUser jim1 12charpasswd; \
+ InitialR2T No; \
+ ImmediateData Yes; \
+ MaxRecvDataSegmentLength 8192; \
+ MaxXmitDataSegmentLength 8192; \
+ MaxBurstLength 131072; \
+ FirstBurstLength 32768; \
+ MaxOutstandingR2T 1; \
+ HeaderDigest CRC32C,None; \
+ DataDigest CRC32C,None; \
+ QueuedCommands 8; \
+ " >/sys/kernel/scst_tgt/targets/iscsi/mgmt
+
+echo "add disk2 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/mgmt
+echo "add nullio 26" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/mgmt
+
+echo "create special_ini" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/mgmt
+echo "add blockio 0" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/luns/mgmt
+echo "add iqn.2005-03.org.open-iscsi:cacdcd2520" >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/initiators/mgmt
+
+echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt/enabled
+echo 1 >/sys/kernel/scst_tgt/targets/iscsi/iqn.2006-10.net.vlnb:tgt1/enabled
+
+echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled
+
+The resulting overall SCST sysfs hierarchy with an initiator connected to
+both iSCSI-SCST targets will look like:
+
+/sys/kernel/scst_tgt
+|-- devices
+| |-- blockio
+| | |-- block_size
+| | |-- exported
+| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/ini_group/special_ini/luns/0
+| | |-- filename
+| | |-- handler -> ../../handlers/vdisk_blockio
+| | |-- read_only
+| | |-- removable
+| | |-- resync_size
+| | |-- size
+| | |-- t10_dev_id
+| | `-- type
+| |-- cdrom
+| | |-- exported
+| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/1
+| | |-- filename
+| | |-- handler -> ../../handlers/vcdrom
+| | |-- removable
+| | |-- size
+| | |-- t10_dev_id
+| | `-- type
+| |-- disk1
+| | |-- block_size
+| | |-- exported
+| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt/luns/0
+| | |-- filename
+| | |-- handler -> ../../handlers/vdisk_fileio
+| | |-- nv_cache
+| | |-- o_direct
+| | |-- read_only
+| | |-- removable
+| | |-- resync_size
+| | |-- size
+| | |-- t10_dev_id
+| | |-- type
+| | `-- write_through
+| |-- disk2
+| | |-- block_size
+| | |-- exported
+| | | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/0
+| | |-- filename
+| | |-- handler -> ../../handlers/vdisk_fileio
+| | |-- nv_cache
+| | |-- o_direct
+| | |-- read_only
+| | |-- removable
+| | |-- resync_size
+| | |-- size
+| | |-- t10_dev_id
+| | |-- type
+| | `-- write_through
+| `-- nullio
+| |-- block_size
+| |-- exported
+| | `-- export0 -> ../../../targets/iscsi/iqn.2006-10.net.vlnb:tgt1/luns/26
+| |-- handler -> ../../handlers/vdisk_nullio
+| |-- read_only
+| |-- removable
+| |-- size
+| |-- t10_dev_id
+| `-- type
+|-- handlers
+| |-- vcdrom
+| | |-- mgmt
+| | |-- trace_level
+| | `-- type
+| |-- vdisk_blockio
+| | |-- mgmt
+| | |-- trace_level
+| | `-- type
+| |-- vdisk_fileio
+| | |-- mgmt
+| | |-- trace_level
+| | `-- type
+| `-- vdisk_nullio
+| |-- mgmt
+| |-- trace_level
+| `-- type
+|-- sgv
+| |-- global_stats
+| |-- sgv
+| | `-- stats
+| |-- sgv-clust
+| | `-- stats
+| `-- sgv-dma
+| `-- stats
+|-- targets
+| `-- iscsi
+| |-- IncomingUser
+| |-- OutgoingUser
+| |-- enabled
+| |-- iSNSServer
+| |-- iqn.2006-10.net.vlnb:tgt
+| | |-- DataDigest
+| | |-- FirstBurstLength
+| | |-- HeaderDigest
+| | |-- ImmediateData
+| | |-- InitialR2T
+| | |-- MaxBurstLength
+| | |-- MaxOutstandingR2T
+| | |-- MaxRecvDataSegmentLength
+| | |-- MaxXmitDataSegmentLength
+| | |-- QueuedCommands
+| | |-- enabled
+| | |-- ini_group
+| | | `-- mgmt
+| | |-- luns
+| | | |-- 0
+| | | | |-- device -> ../../../../../devices/disk1
+| | | | `-- read_only
+| | | |-- 1
+| | | | |-- device -> ../../../../../devices/cdrom
+| | | | `-- read_only
+| | | `-- mgmt
+| | |-- sessions
+| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
+| | | |-- 10.170.75.2
+| | | | |-- cid
+| | | | |-- ip
+| | | | `-- state
+| | | |-- DataDigest
+| | | |-- FirstBurstLength
+| | | |-- HeaderDigest
+| | | |-- ImmediateData
+| | | |-- InitialR2T
+| | | |-- MaxBurstLength
+| | | |-- MaxOutstandingR2T
+| | | |-- MaxRecvDataSegmentLength
+| | | |-- MaxXmitDataSegmentLength
+| | | |-- active_commands
+| | | |-- commands
+| | | |-- force_close
+| | | |-- initiator_name
+| | | |-- reinstating
+| | | `-- sid
+| | `-- tid
+| |-- iqn.2006-10.net.vlnb:tgt1
+| | |-- DataDigest
+| | |-- FirstBurstLength
+| | |-- HeaderDigest
+| | |-- ImmediateData
+| | |-- IncomingUser
+| | |-- IncomingUser1
+| | |-- InitialR2T
+| | |-- MaxBurstLength
+| | |-- MaxOutstandingR2T
+| | |-- MaxRecvDataSegmentLength
+| | |-- MaxXmitDataSegmentLength
+| | |-- OutgoingUser
+| | |-- QueuedCommands
+| | |-- enabled
+| | |-- ini_group
+| | | |-- mgmt
+| | | `-- special_ini
+| | | |-- initiators
+| | | | |-- iqn.2005-03.org.open-iscsi:cacdcd2520
+| | | | `-- mgmt
+| | | `-- luns
+| | | |-- 0
+| | | | |-- device -> ../../../../../../../devices/blockio
+| | | | `-- read_only
+| | | `-- mgmt
+| | |-- luns
+| | | |-- 0
+| | | | |-- device -> ../../../../../devices/disk2
+| | | | `-- read_only
+| | | |-- 26
+| | | | |-- device -> ../../../../../devices/nullio
+| | | | `-- read_only
+| | | `-- mgmt
+| | |-- sessions
+| | | `-- iqn.2005-03.org.open-iscsi:cacdcd2520
+| | | |-- 10.170.75.2
+| | | | |-- cid
+| | | | |-- ip
+| | | | `-- state
+| | | |-- DataDigest
+| | | |-- FirstBurstLength
+| | | |-- HeaderDigest
+| | | |-- ImmediateData
+| | | |-- InitialR2T
+| | | |-- MaxBurstLength
+| | | |-- MaxOutstandingR2T
+| | | |-- MaxRecvDataSegmentLength
+| | | |-- MaxXmitDataSegmentLength
+| | | |-- active_commands
+| | | |-- commands
+| | | |-- force_close
+| | | |-- initiator_name
+| | | |-- reinstating
+| | | `-- sid
+| | `-- tid
+| |-- mgmt
+| |-- open_state
+| |-- trace_level
+| `-- version
+|-- threads
+|-- trace_level
+`-- version
+
+
Troubleshooting
---------------
target's backstorage gets overloaded, or working over a slow link, when
the link can't serve all the queued commands on time,
-To workaround it you can reduce QueuedCommands parameter in
-iscsi-scstd.conf file for the corresponding target to some lower value,
-like 8 (default is 32).
+To workaround it you can reduce QueuedCommands parameter for the
+corresponding target to some lower value, like 8 (default is 32).
Also see SCST README file for more details about that issue and ways to
prevent it.
Thanks to:
- * IET developers for IET
-
* Ming Zhang <blackmagic02881@gmail.com> for fixes
* Krzysztof Blaszkowski <kb@sysmikro.com.pl> for many fixes
- - Fix support of ranges in parameters negotiation.
+ - __cmnd_abort() must be called by SCST core through new callback
+ instead of the driver itself.
+
+ - Remove the "poor man solution" suspending. Instead, immediate/unsolicited
+ data for suspended commands should be received in the dummy_page and
+ then, when they are resumed, aborted with BUSY status. All other
+ commands should proceed normally.
+
+ - Separate iSCSI request and response structures. Currently they share the
+ same structure. This architecture decision derived from IET and makes
+ the code a lot less readable, maintainable and effective as well as more
+ errors prone, so it must be corrected.
+
+ - Code beautifying, i.e. make it be written in the same nice looking style.
+ Particularly, all functions and variables names should share the same style.
+
+ - Fix support of ranges in parameters negotiation. Are there any initiators who
+ use ranges and, hence, can be used for testing?
- Minor "ToDo"'s spread in the code.
#define aligned_u64 uint64_t __attribute__((aligned(8)))
#endif
-struct iscsi_kern_target_info {
- u32 tid;
- char name[ISCSI_NAME_LEN];
-};
-
-struct iscsi_kern_session_info {
- u32 tid;
-
- aligned_u64 sid;
- char initiator_name[ISCSI_NAME_LEN];
- char user_name[ISCSI_NAME_LEN];
- u32 exp_cmd_sn;
-};
-
-#define DIGEST_ALL (DIGEST_NONE | DIGEST_CRC32C)
-#define DIGEST_NONE (1 << 0)
-#define DIGEST_CRC32C (1 << 1)
-
-struct iscsi_kern_conn_info {
- u32 tid;
- aligned_u64 sid;
-
- u32 cid;
- u32 stat_sn;
- u32 exp_stat_sn;
- int fd;
-};
+#define ISCSI_MAX_ATTR_NAME_LEN 50
+#define ISCSI_MAX_ATTR_VALUE_LEN 512
enum {
key_initial_r2t,
key_target,
};
-struct iscsi_kern_param_info {
+struct iscsi_kern_target_info {
+ u32 tid;
+ u32 cookie;
+ char name[ISCSI_NAME_LEN];
+ u32 attrs_num;
+ aligned_u64 attrs_ptr;
+};
+
+struct iscsi_kern_session_info {
+ u32 tid;
+ aligned_u64 sid;
+ char initiator_name[ISCSI_NAME_LEN];
+#ifdef CONFIG_SCST_PROC
+ char user_name[ISCSI_NAME_LEN];
+#endif
+ u32 exp_cmd_sn;
+ s32 session_params[session_key_last];
+ s32 target_params[target_key_last];
+};
+
+#define DIGEST_ALL (DIGEST_NONE | DIGEST_CRC32C)
+#define DIGEST_NONE (1 << 0)
+#define DIGEST_CRC32C (1 << 1)
+
+struct iscsi_kern_conn_info {
u32 tid;
aligned_u64 sid;
- u32 param_type;
+ u32 cid;
+ u32 stat_sn;
+ u32 exp_stat_sn;
+ int fd;
+};
+
+struct iscsi_kern_attr {
+ u32 mode;
+ char name[ISCSI_MAX_ATTR_NAME_LEN];
+};
+
+struct iscsi_kern_mgmt_cmd_res_info {
+ u32 tid;
+ u32 cookie;
+ u32 req_cmd;
+ u32 result;
+ char value[ISCSI_MAX_ATTR_VALUE_LEN];
+};
+
+struct iscsi_kern_params_info {
+ u32 tid;
+ aligned_u64 sid;
+
+ u32 params_type;
u32 partial;
- s32 session_param[session_key_last];
- s32 target_param[target_key_last];
+ s32 session_params[session_key_last];
+ s32 target_params[target_key_last];
};
enum iscsi_kern_event_code {
+#ifndef CONFIG_SCST_PROC
+ E_ADD_TARGET,
+ E_DEL_TARGET,
+ E_MGMT_CMD,
E_ENABLE_TARGET,
E_DISABLE_TARGET,
+ E_GET_ATTR_VALUE,
+ E_SET_ATTR_VALUE,
+#endif
E_CONN_CLOSE,
};
aligned_u64 sid;
u32 cid;
u32 code;
+ u32 cookie;
+ char target_name[ISCSI_NAME_LEN];
+ u32 param1_size;
+ u32 param2_size;
};
struct iscsi_kern_register_info {
- aligned_u64 version;
+ union {
+ aligned_u64 version;
+ struct {
+ int max_data_seg_len;
+ int max_queued_cmds;
+ };
+ };
+};
+
+struct iscsi_kern_attr_info {
+ u32 tid;
+ u32 cookie;
+ struct iscsi_kern_attr attr;
};
#define DEFAULT_NR_QUEUED_CMNDS 32
#define NETLINK_ISCSI_SCST 25
-/* On success returns MAX_DATA_SEG_LEN */
-#define REGISTER_USERD _IOW('s', 0, struct iscsi_kern_register_info)
-
+#define REGISTER_USERD _IOWR('s', 0, struct iscsi_kern_register_info)
#define ADD_TARGET _IOW('s', 1, struct iscsi_kern_target_info)
#define DEL_TARGET _IOW('s', 2, struct iscsi_kern_target_info)
-#define ENABLE_TARGET _IOW('s', 3, struct iscsi_kern_target_info)
-#define DISABLE_TARGET _IOW('s', 4, struct iscsi_kern_target_info)
-#define ADD_SESSION _IOW('s', 5, struct iscsi_kern_session_info)
-#define DEL_SESSION _IOW('s', 6, struct iscsi_kern_session_info)
-#define ADD_CONN _IOW('s', 7, struct iscsi_kern_conn_info)
-#define DEL_CONN _IOW('s', 8, struct iscsi_kern_conn_info)
-#define ISCSI_PARAM_SET _IOW('s', 9, struct iscsi_kern_param_info)
-#define ISCSI_PARAM_GET _IOWR('s', 10, struct iscsi_kern_param_info)
+#define ADD_SESSION _IOW('s', 3, struct iscsi_kern_session_info)
+#define DEL_SESSION _IOW('s', 4, struct iscsi_kern_session_info)
+#define ADD_CONN _IOW('s', 5, struct iscsi_kern_conn_info)
+#define DEL_CONN _IOW('s', 6, struct iscsi_kern_conn_info)
+#define ISCSI_PARAM_SET _IOW('s', 7, struct iscsi_kern_params_info)
+#define ISCSI_PARAM_GET _IOWR('s', 8, struct iscsi_kern_params_info)
+
+#ifndef CONFIG_SCST_PROC
+#define ISCSI_ATTR_ADD _IOW('s', 9, struct iscsi_kern_attr_info)
+#define ISCSI_ATTR_DEL _IOW('s', 10, struct iscsi_kern_attr_info)
+#define MGMT_CMD_CALLBACK _IOW('s', 11, struct iscsi_kern_mgmt_cmd_res_info)
+#endif
static inline int iscsi_is_key_internal(int key)
{
#define ISCSI_VERSION_STRING_SUFFIX
#endif
-#define ISCSI_VERSION_STRING "1.0.2/0.4.17r214" ISCSI_VERSION_STRING_SUFFIX
+#define ISCSI_VERSION_STRING "2.0.0/0.4.17r214" ISCSI_VERSION_STRING_SUFFIX
#include "iscsi.h"
+/* Protected by target_mgmt_mutex */
+int ctr_open_state;
+
#ifdef CONFIG_SCST_PROC
#include <linux/proc_fs.h>
TRACE_EXIT_RES(res);
return res;
}
-#endif
+
+#endif /* DEBUG or TRACE */
static int iscsi_version_info_show(struct seq_file *seq, void *v)
{
#else /* CONFIG_SCST_PROC */
+/* Protected by target_mgmt_mutex */
+static LIST_HEAD(iscsi_attrs_list);
+
static ssize_t iscsi_version_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
static struct kobj_attribute iscsi_version_attr =
__ATTR(version, S_IRUGO, iscsi_version_show, NULL);
+static ssize_t iscsi_open_state_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ switch (ctr_open_state) {
+ case ISCSI_CTR_OPEN_STATE_CLOSED:
+ sprintf(buf, "%s\n", "closed");
+ break;
+ case ISCSI_CTR_OPEN_STATE_OPEN:
+ sprintf(buf, "%s\n", "open");
+ break;
+ case ISCSI_CTR_OPEN_STATE_CLOSING:
+ sprintf(buf, "%s\n", "closing");
+ break;
+ default:
+ sprintf(buf, "%s\n", "unknown");
+ break;
+ }
+
+ return strlen(buf);
+}
+
+static struct kobj_attribute iscsi_open_state_attr =
+ __ATTR(open_state, S_IRUGO, iscsi_open_state_show, NULL);
+
const struct attribute *iscsi_attrs[] = {
&iscsi_version_attr.attr,
+ &iscsi_open_state_attr.attr,
NULL,
};
#endif /* CONFIG_SCST_PROC */
-/* target_mutex supposed to be locked */
-static int add_conn(struct iscsi_target *target, void __user *ptr)
+/* target_mgmt_mutex supposed to be locked */
+static int add_conn(void __user *ptr)
{
int err;
struct iscsi_session *session;
struct iscsi_kern_conn_info info;
+ struct iscsi_target *target;
+
+ TRACE_ENTRY();
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
- return err;
+ goto out;
+
+ target = target_lookup_by_id(info.tid);
+ if (target == NULL) {
+ PRINT_ERROR("Target %d not found", info.tid);
+ err = -ENOENT;
+ goto out;
+ }
+
+ mutex_lock(&target->target_mutex);
session = session_lookup(target, info.sid);
- if (!session)
- return -ENOENT;
+ if (!session) {
+ PRINT_ERROR("Session %lld not found",
+ (long long unsigned int)info.tid);
+ err = -ENOENT;
+ goto out_unlock;
+ }
- return conn_add(session, &info);
+ err = __add_conn(session, &info);
+
+out_unlock:
+ mutex_unlock(&target->target_mutex);
+
+out:
+ TRACE_EXIT_RES(err);
+ return err;
}
-/* target_mutex supposed to be locked */
-static int del_conn(struct iscsi_target *target, void __user *ptr)
+/* target_mgmt_mutex supposed to be locked */
+static int del_conn(void __user *ptr)
{
int err;
struct iscsi_session *session;
struct iscsi_kern_conn_info info;
+ struct iscsi_target *target;
+
+ TRACE_ENTRY();
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
- return err;
+ goto out;
+
+ target = target_lookup_by_id(info.tid);
+ if (target == NULL) {
+ PRINT_ERROR("Target %d not found", info.tid);
+ err = -ENOENT;
+ goto out;
+ }
+
+ mutex_lock(&target->target_mutex);
session = session_lookup(target, info.sid);
if (!session) {
PRINT_ERROR("Session %llx not found",
(long long unsigned int)info.sid);
- return -ENOENT;
+ err = -ENOENT;
+ goto out_unlock;
}
- return conn_del(session, &info);
+ err = __del_conn(session, &info);
+
+out_unlock:
+ mutex_unlock(&target->target_mutex);
+
+out:
+ TRACE_EXIT_RES(err);
+ return err;
}
/* target_mgmt_mutex supposed to be locked */
-static int add_session(struct iscsi_target *target, void __user *ptr)
+static int add_session(void __user *ptr)
{
int err;
- struct iscsi_kern_session_info info;
+ struct iscsi_kern_session_info *info;
+ struct iscsi_target *target;
- err = copy_from_user(&info, ptr, sizeof(info));
- if (err < 0)
- return err;
+ TRACE_ENTRY();
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ PRINT_ERROR("Can't alloc info (size %d)", sizeof(*info));
+ err = -ENOMEM;
+ goto out;
+ }
- info.initiator_name[ISCSI_NAME_LEN-1] = '\0';
- info.user_name[ISCSI_NAME_LEN-1] = '\0';
+ err = copy_from_user(info, ptr, sizeof(*info));
+ if (err != 0) {
+ PRINT_ERROR("copy_from_user() didn't copy %d bytes", err);
+ err = -EFAULT;
+ goto out_free;
+ }
- return session_add(target, &info);
+ info->initiator_name[sizeof(info->initiator_name)-1] = '\0';
+#ifdef CONFIG_SCST_PROC
+ info->user_name[sizeof(info->user_name)-1] = '\0';
+#endif
+
+ target = target_lookup_by_id(info->tid);
+ if (target == NULL) {
+ PRINT_ERROR("Target %d not found", info->tid);
+ err = -ENOENT;
+ goto out_free;
+ }
+
+ err = __add_session(target, info);
+
+out_free:
+ kfree(info);
+
+out:
+ TRACE_EXIT_RES(err);
+ return err;
}
-/* target_mutex supposed to be locked */
-static int del_session(struct iscsi_target *target, void __user *ptr)
+/* target_mgmt_mutex supposed to be locked */
+static int del_session(void __user *ptr)
{
int err;
- struct iscsi_kern_session_info info;
+ struct iscsi_kern_session_info *info;
+ struct iscsi_target *target;
- err = copy_from_user(&info, ptr, sizeof(info));
- if (err < 0)
- return err;
+ TRACE_ENTRY();
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ PRINT_ERROR("Can't alloc info (size %d)", sizeof(*info));
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = copy_from_user(info, ptr, sizeof(*info));
+ if (err != 0) {
+ PRINT_ERROR("copy_from_user() didn't copy %d bytes", err);
+ err = -EFAULT;
+ goto out_free;
+ }
+
+ info->initiator_name[sizeof(info->initiator_name)-1] = '\0';
+#ifdef CONFIG_SCST_PROC
+ info->user_name[sizeof(info->user_name)-1] = '\0';
+#endif
+
+ target = target_lookup_by_id(info->tid);
+ if (target == NULL) {
+ PRINT_ERROR("Target %d not found", info->tid);
+ err = -ENOENT;
+ goto out_free;
+ }
- return session_del(target, info.sid);
+ mutex_lock(&target->target_mutex);
+ err = __del_session(target, info->sid);
+ mutex_unlock(&target->target_mutex);
+
+out_free:
+ kfree(info);
+
+out:
+ TRACE_EXIT_RES(err);
+ return err;
}
-/* target_mutex supposed to be locked */
-static int iscsi_param_config(struct iscsi_target *target, void __user *ptr,
- int set)
+/* target_mgmt_mutex supposed to be locked */
+static int iscsi_params_config(void __user *ptr, int set)
{
int err;
- struct iscsi_kern_param_info info;
+ struct iscsi_kern_params_info info;
+ struct iscsi_target *target;
+
+ TRACE_ENTRY();
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
goto out;
- err = iscsi_param_set(target, &info, set);
+ target = target_lookup_by_id(info.tid);
+ if (target == NULL) {
+ PRINT_ERROR("Target %d not found", info.tid);
+ err = -ENOENT;
+ goto out;
+ }
+
+ mutex_lock(&target->target_mutex);
+ err = iscsi_params_set(target, &info, set);
+ mutex_unlock(&target->target_mutex);
+
if (err < 0)
goto out;
err = copy_to_user(ptr, &info, sizeof(info));
out:
+ TRACE_EXIT_RES(err);
return err;
}
+#ifndef CONFIG_SCST_PROC
+
/* target_mgmt_mutex supposed to be locked */
-static int enable_target(void __user *ptr)
+static int mgmt_cmd_callback(void __user *ptr)
{
- int err;
- struct iscsi_kern_target_info info;
+ int err = 0, rc;
+ struct iscsi_kern_mgmt_cmd_res_info cinfo;
+ struct scst_sysfs_user_info *info;
- err = copy_from_user(&info, ptr, sizeof(info));
- if (err < 0)
- return err;
+ TRACE_ENTRY();
+
+ rc = copy_from_user(&cinfo, ptr, sizeof(cinfo));
+ if (rc != 0) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ cinfo.value[sizeof(cinfo.value)-1] = '\0';
+
+ info = scst_sysfs_user_get_info(cinfo.cookie);
+ TRACE_DBG("cookie %u, info %p, result %d", cinfo.cookie, info,
+ cinfo.result);
+ if (info == NULL) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ info->info_status = 0;
+
+ if (cinfo.result != 0) {
+ info->info_status = cinfo.result;
+ goto out_complete;
+ }
+
+ switch (cinfo.req_cmd) {
+ case E_ENABLE_TARGET:
+ case E_DISABLE_TARGET:
+ {
+ struct iscsi_target *target;
+
+ target = target_lookup_by_id(cinfo.tid);
+ if (target == NULL) {
+ PRINT_ERROR("Target %d not found", cinfo.tid);
+ err = -ENOENT;
+ goto out_status;
+ }
- err = target_enable(&info);
+ target->tgt_enabled = (cinfo.req_cmd == E_ENABLE_TARGET) ? 1 : 0;
+ break;
+ }
+
+ case E_GET_ATTR_VALUE:
+ info->data = kstrdup(cinfo.value, GFP_KERNEL);
+ if (info->data == NULL) {
+ PRINT_ERROR("Can't dublicate value %s", cinfo.value);
+ info->info_status = -ENOMEM;
+ goto out_complete;
+ }
+ break;
+ }
+out_complete:
+ complete(&info->info_completion);
+
+out:
+ TRACE_EXIT_RES(err);
return err;
+
+out_status:
+ info->info_status = err;
+ goto out_complete;
+}
+
+static ssize_t iscsi_attr_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ int pos;
+ struct iscsi_attr *tgt_attr;
+ void *value;
+
+ TRACE_ENTRY();
+
+ tgt_attr = container_of(attr, struct iscsi_attr, attr);
+
+ pos = iscsi_sysfs_send_event(
+ (tgt_attr->target != NULL) ? tgt_attr->target->tid : 0,
+ E_GET_ATTR_VALUE, tgt_attr->name, NULL, &value);
+
+ if (pos != 0)
+ goto out;
+
+ pos = scnprintf(buf, SCST_SYSFS_BLOCK_SIZE, "%s\n", (char *)value);
+
+ kfree(value);
+
+out:
+ TRACE_EXIT_RES(pos);
+ return pos;
+}
+
+static ssize_t iscsi_attr_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ int res;
+ char *buffer;
+ struct iscsi_attr *tgt_attr;
+
+ TRACE_ENTRY();
+
+ buffer = kzalloc(count+1, GFP_KERNEL);
+ if (buffer == NULL) {
+ res = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(buffer, buf, count);
+ buffer[count] = '\0';
+
+ tgt_attr = container_of(attr, struct iscsi_attr, attr);
+
+ res = iscsi_sysfs_send_event(
+ (tgt_attr->target != NULL) ? tgt_attr->target->tid : 0,
+ E_SET_ATTR_VALUE, tgt_attr->name, buffer, NULL);
+
+ kfree(buffer);
+
+ if (res == 0)
+ res = count;
+
+out:
+ TRACE_EXIT_RES(res);
+ return res;
+}
+
+/*
+ * target_mgmt_mutex supposed to be locked. If target != 0, target_mutex
+ * supposed to be locked as well.
+ */
+int iscsi_add_attr(struct iscsi_target *target,
+ const struct iscsi_kern_attr *attr_info)
+{
+ int res = 0;
+ struct iscsi_attr *tgt_attr;
+ struct list_head *attrs_list;
+ const char *name;
+
+ TRACE_ENTRY();
+
+ if (target != NULL) {
+ attrs_list = &target->attrs_list;
+ name = target->name;
+ } else {
+ attrs_list = &iscsi_attrs_list;
+ name = "global";
+ }
+
+ list_for_each_entry(tgt_attr, attrs_list, attrs_list_entry) {
+ if (strncmp(tgt_attr->name, attr_info->name,
+ sizeof(tgt_attr->name) == 0)) {
+ PRINT_ERROR("Attribute %s for %s already exist",
+ attr_info->name, name);
+ res = -EEXIST;
+ goto out;
+ }
+ }
+
+ TRACE_DBG("Adding %s's attr %s with mode %x", name,
+ attr_info->name, attr_info->mode);
+
+ tgt_attr = kzalloc(sizeof(*tgt_attr), GFP_KERNEL);
+ if (tgt_attr == NULL) {
+ PRINT_ERROR("Unable to allocate user (size %d)",
+ sizeof(*tgt_attr));
+ res = -ENOMEM;
+ goto out;
+ }
+
+ tgt_attr->target = target;
+
+ tgt_attr->name = kstrdup(attr_info->name, GFP_KERNEL);
+ if (tgt_attr->name == NULL) {
+ PRINT_ERROR("Unable to allocate attr %s name/value (target %s)",
+ attr_info->name, name);
+ res = -ENOMEM;
+ goto out_free;
+ }
+
+ list_add(&tgt_attr->attrs_list_entry, attrs_list);
+
+ tgt_attr->attr.attr.name = tgt_attr->name;
+ tgt_attr->attr.attr.owner = THIS_MODULE;
+ tgt_attr->attr.attr.mode = attr_info->mode & (S_IRUGO | S_IWUGO);
+ tgt_attr->attr.show = iscsi_attr_show;
+ tgt_attr->attr.store = iscsi_attr_store;
+
+ res = sysfs_create_file(
+ (target != NULL) ? scst_sysfs_get_tgt_kobj(target->scst_tgt) :
+ scst_sysfs_get_tgtt_kobj(&iscsi_template),
+ &tgt_attr->attr.attr);
+ if (res != 0) {
+ PRINT_ERROR("Unable to create file '%s' for target '%s'",
+ tgt_attr->attr.attr.name, name);
+ goto out_del;
+ }
+
+out:
+ TRACE_EXIT_RES(res);
+ return res;
+
+out_del:
+ list_del(&tgt_attr->attrs_list_entry);
+
+out_free:
+ kfree(tgt_attr->name);
+ kfree(tgt_attr);
+ goto out;
+}
+
+void __iscsi_del_attr(struct iscsi_target *target,
+ struct iscsi_attr *tgt_attr)
+{
+ TRACE_ENTRY();
+
+ TRACE_DBG("Deleting %s's attr %s",
+ (target != NULL) ? target->name : "global", tgt_attr->name);
+
+ list_del(&tgt_attr->attrs_list_entry);
+
+ sysfs_remove_file((target != NULL) ?
+ scst_sysfs_get_tgt_kobj(target->scst_tgt) :
+ scst_sysfs_get_tgtt_kobj(&iscsi_template),
+ &tgt_attr->attr.attr);
+
+ kfree(tgt_attr->name);
+ kfree(tgt_attr);
+
+ TRACE_EXIT();
+ return;
+}
+
+/*
+ * target_mgmt_mutex supposed to be locked. If target != 0, target_mutex
+ * supposed to be locked as well.
+ */
+static int iscsi_del_attr(struct iscsi_target *target,
+ const char *attr_name)
+{
+ int res = 0;
+ struct iscsi_attr *tgt_attr, *a;
+ struct list_head *attrs_list;
+
+ TRACE_ENTRY();
+
+ if (target != NULL)
+ attrs_list = &target->attrs_list;
+ else
+ attrs_list = &iscsi_attrs_list;
+
+ tgt_attr = NULL;
+ list_for_each_entry(a, attrs_list, attrs_list_entry) {
+ if (strncmp(a->name, attr_name, sizeof(a->name)) == 0) {
+ tgt_attr = a;
+ break;
+ }
+ }
+
+ if (tgt_attr == NULL) {
+ PRINT_ERROR("attr %s not found (target %s)", attr_name,
+ (target != NULL) ? target->name : "global");
+ res = -ENOENT;
+ goto out;
+ }
+
+ __iscsi_del_attr(target, tgt_attr);
+
+out:
+ TRACE_EXIT_RES(res);
+ return res;
}
/* target_mgmt_mutex supposed to be locked */
-static int disable_target(void __user *ptr)
+static int iscsi_attr_cmd(void __user *ptr, unsigned int cmd)
{
- int err;
- struct iscsi_kern_target_info info;
+ int rc, err = 0;
+ struct iscsi_kern_attr_info info;
+ struct iscsi_target *target;
+ struct scst_sysfs_user_info *i = NULL;
- err = copy_from_user(&info, ptr, sizeof(info));
- if (err < 0)
- return err;
+ TRACE_ENTRY();
- err = target_disable(&info);
+ rc = copy_from_user(&info, ptr, sizeof(info));
+ if (rc != 0) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ info.attr.name[sizeof(info.attr.name)-1] = '\0';
+ if (info.cookie != 0) {
+ i = scst_sysfs_user_get_info(info.cookie);
+ TRACE_DBG("cookie %u, uinfo %p", info.cookie, i);
+ if (i == NULL) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ target = target_lookup_by_id(info.tid);
+
+ if (target != NULL)
+ mutex_lock(&target->target_mutex);
+
+ switch (cmd) {
+ case ISCSI_ATTR_ADD:
+ err = iscsi_add_attr(target, &info.attr);
+ break;
+ case ISCSI_ATTR_DEL:
+ err = iscsi_del_attr(target, info.attr.name);
+ break;
+ default:
+ sBUG();
+ }
+
+ if (target != NULL)
+ mutex_unlock(&target->target_mutex);
+
+ if (i != NULL) {
+ i->info_status = err;
+ complete(&i->info_completion);
+ }
+
+out:
+ TRACE_EXIT_RES(err);
return err;
}
+#endif /* CONFIG_SCST_PROC */
+
/* target_mgmt_mutex supposed to be locked */
static int add_target(void __user *ptr)
+{
+ int err;
+ struct iscsi_kern_target_info *info;
+#ifndef CONFIG_SCST_PROC
+ struct scst_sysfs_user_info *uinfo;
+#endif
+
+ TRACE_ENTRY();
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ PRINT_ERROR("Can't alloc info (size %d)", sizeof(*info));
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = copy_from_user(info, ptr, sizeof(*info));
+ if (err != 0) {
+ PRINT_ERROR("copy_from_user() didn't copy %d bytes", err);
+ err = -EFAULT;
+ goto out_free;
+ }
+
+ if (target_lookup_by_id(info->tid) != NULL) {
+ PRINT_ERROR("Target %u already exist!", info->tid);
+ err = -EEXIST;
+ goto out_free;
+ }
+
+ info->name[sizeof(info->name)-1] = '\0';
+
+#ifndef CONFIG_SCST_PROC
+ if (info->cookie != 0) {
+ uinfo = scst_sysfs_user_get_info(info->cookie);
+ TRACE_DBG("cookie %u, uinfo %p", info->cookie, uinfo);
+ if (uinfo == NULL) {
+ err = -EINVAL;
+ goto out_free;
+ }
+ } else
+ uinfo = NULL;
+#endif
+
+ err = __add_target(info);
+
+#ifndef CONFIG_SCST_PROC
+ if (uinfo != NULL) {
+ uinfo->info_status = err;
+ complete(&uinfo->info_completion);
+ }
+#endif
+
+out_free:
+ kfree(info);
+
+out:
+ TRACE_EXIT_RES(err);
+ return err;
+}
+
+/* target_mgmt_mutex supposed to be locked */
+static int del_target(void __user *ptr)
{
int err;
struct iscsi_kern_target_info info;
+#ifndef CONFIG_SCST_PROC
+ struct scst_sysfs_user_info *uinfo;
+#endif
+
+ TRACE_ENTRY();
err = copy_from_user(&info, ptr, sizeof(info));
if (err < 0)
- return err;
+ goto out;
- err = target_add(&info);
- if (!err)
- err = copy_to_user(ptr, &info, sizeof(info));
+ info.name[sizeof(info.name)-1] = '\0';
+
+#ifndef CONFIG_SCST_PROC
+ if (info.cookie != 0) {
+ uinfo = scst_sysfs_user_get_info(info.cookie);
+ TRACE_DBG("cookie %u, uinfo %p", info.cookie, uinfo);
+ if (uinfo == NULL) {
+ err = -EINVAL;
+ goto out;
+ }
+ } else
+ uinfo = NULL;
+#endif
+
+ err = __del_target(info.tid);
+
+#ifndef CONFIG_SCST_PROC
+ if (uinfo != NULL) {
+ uinfo->info_status = err;
+ complete(&uinfo->info_completion);
+ }
+#endif
+out:
+ TRACE_EXIT_RES(err);
return err;
}
-static int iscsi_check_version(void __user *arg)
+static int iscsi_register(void __user *arg)
{
struct iscsi_kern_register_info reg;
char ver[sizeof(ISCSI_SCST_INTERFACE_VERSION)+1];
- int res;
+ int res, rc;
+
+ TRACE_ENTRY();
- res = copy_from_user(®, arg, sizeof(reg));
- if (res < 0) {
+ rc = copy_from_user(®, arg, sizeof(reg));
+ if (rc != 0) {
PRINT_ERROR("%s", "Unable to get register info");
+ res = -EFAULT;
goto out;
}
- res = copy_from_user(ver, (void __user *)(unsigned long)reg.version,
+ rc = copy_from_user(ver, (void __user *)(unsigned long)reg.version,
sizeof(ver));
- if (res < 0) {
+ if (rc < 0) {
PRINT_ERROR("%s", "Unable to get version string");
+ res = -EFAULT;
goto out;
}
ver[sizeof(ver)-1] = '\0';
goto out;
}
- res = ISCSI_CONN_IOV_MAX << PAGE_SHIFT;
+ memset(®, 0, sizeof(reg));
+ reg.max_data_seg_len = ISCSI_CONN_IOV_MAX << PAGE_SHIFT;
+
+ res = 0;
+
+ rc = copy_to_user(arg, ®, sizeof(reg));
+ if (rc != 0) {
+ PRINT_ERROR("copy_to_user() failed to copy %d bytes", res);
+ res = -EFAULT;
+ goto out;
+ }
out:
+ TRACE_EXIT_RES(res);
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 ENABLE_TARGET:
- case DISABLE_TARGET:
- case ADD_SESSION:
- case DEL_SESSION:
- case ISCSI_PARAM_SET:
- case ISCSI_PARAM_GET:
- case ADD_CONN:
- case DEL_CONN:
- break;
- case REGISTER_USERD:
- err = iscsi_check_version((void __user *) arg);
- goto out;
+ TRACE_ENTRY();
- default:
- PRINT_ERROR("Invalid ioctl cmd %x", cmd);
- err = -EINVAL;
+ if (cmd == REGISTER_USERD) {
+ err = iscsi_register((void __user *)arg);
goto out;
}
- err = get_user(id, (u32 __user *) 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((void __user *) arg);
- goto out_unlock;
- case ENABLE_TARGET:
- err = enable_target((void __user *) arg);
- goto out_unlock;
- case DISABLE_TARGET:
- err = disable_target((void __user *) arg);
- goto out_unlock;
- case ADD_SESSION:
- err = add_session(target, (void __user *) arg);
- goto out_unlock;
- }
+ err = add_target((void __user *)arg);
+ break;
- if (!target) {
- PRINT_ERROR("Can't find the target %u", id);
- err = -EINVAL;
- goto out_unlock;
- }
+ case DEL_TARGET:
+ err = del_target((void __user *)arg);
+ break;
- mutex_lock(&target->target_mutex);
+#ifndef CONFIG_SCST_PROC
+ case ISCSI_ATTR_ADD:
+ case ISCSI_ATTR_DEL:
+ err = iscsi_attr_cmd((void __user *)arg, cmd);
+ break;
+
+ case MGMT_CMD_CALLBACK:
+ err = mgmt_cmd_callback((void __user *)arg);
+ break;
+#endif
+
+ case ADD_SESSION:
+ err = add_session((void __user *)arg);
+ break;
- switch (cmd) {
case DEL_SESSION:
- err = del_session(target, (void __user *) arg);
+ err = del_session((void __user *)arg);
break;
case ISCSI_PARAM_SET:
- err = iscsi_param_config(target, (void __user *) arg, 1);
+ err = iscsi_params_config((void __user *)arg, 1);
break;
case ISCSI_PARAM_GET:
- err = iscsi_param_config(target, (void __user *) arg, 0);
+ err = iscsi_params_config((void __user *)arg, 0);
break;
case ADD_CONN:
- err = add_conn(target, (void __user *) arg);
+ err = add_conn((void __user *)arg);
break;
case DEL_CONN:
- err = del_conn(target, (void __user *) arg);
+ err = del_conn((void __user *)arg);
break;
default:
- sBUG();
- break;
+ PRINT_ERROR("Invalid ioctl cmd %x", cmd);
+ err = -EINVAL;
+ goto out_unlock;
}
- mutex_unlock(&target->target_mutex);
-
out_unlock:
mutex_unlock(&target_mgmt_mutex);
out:
+ TRACE_EXIT_RES(err);
return err;
}
+int open(struct inode *inode, struct file *file)
+{
+ bool already;
+
+ mutex_lock(&target_mgmt_mutex);
+ already = (ctr_open_state != ISCSI_CTR_OPEN_STATE_CLOSED);
+ if (!already)
+ ctr_open_state = ISCSI_CTR_OPEN_STATE_OPEN;
+ mutex_unlock(&target_mgmt_mutex);
+
+ if (already) {
+ PRINT_WARNING("%s", "Attempt to second open the control "
+ "device!");
+ return -EBUSY;
+ } else
+ return 0;
+}
+
static int release(struct inode *inode, struct file *filp)
{
+#ifndef CONFIG_SCST_PROC
+ struct iscsi_attr *attr, *t;
+#endif
+
TRACE(TRACE_MGMT, "%s", "Releasing allocated resources");
+
+ mutex_lock(&target_mgmt_mutex);
+ ctr_open_state = ISCSI_CTR_OPEN_STATE_CLOSING;
+ mutex_unlock(&target_mgmt_mutex);
+
target_del_all();
+
+ mutex_lock(&target_mgmt_mutex);
+
+#ifndef CONFIG_SCST_PROC
+ list_for_each_entry_safe(attr, t, &iscsi_attrs_list,
+ attrs_list_entry) {
+ __iscsi_del_attr(NULL, attr);
+ }
+#endif
+
+ ctr_open_state = ISCSI_CTR_OPEN_STATE_CLOSED;
+
+ mutex_unlock(&target_mgmt_mutex);
+
return 0;
}
.owner = THIS_MODULE,
.unlocked_ioctl = ioctl,
.compat_ioctl = ioctl,
+ .open = open,
.release = release,
};
#ifdef CONFIG_SCST_PROC
+static int print_digest_state(char *p, size_t size, unsigned long flags)
+{
+ int pos;
+
+ if (DIGEST_NONE & flags)
+ pos = scnprintf(p, size, "%s", "none");
+ else if (DIGEST_CRC32C & flags)
+ pos = scnprintf(p, size, "%s", "crc32c");
+ else
+ pos = scnprintf(p, size, "%s", "unknown");
+
+ return pos;
+}
+
/* target_mutex supposed to be locked */
void conn_info_show(struct seq_file *seq, struct iscsi_session *session)
{
conn->rd_state = ISCSI_CONN_RD_STATE_IDLE;
conn->wr_state = ISCSI_CONN_WR_STATE_IDLE;
- conn->hdigest_type = session->sess_param.header_digest;
- conn->ddigest_type = session->sess_param.data_digest;
+ conn->hdigest_type = session->sess_params.header_digest;
+ conn->ddigest_type = session->sess_params.data_digest;
res = digest_init(conn);
if (res != 0)
goto out_err_free1;
}
/* target_mutex supposed to be locked */
-int conn_add(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
+int __add_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
{
struct iscsi_conn *conn, *new_conn = NULL;
int err;
}
/* target_mutex supposed to be locked */
-int conn_del(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
+int __del_conn(struct iscsi_session *session, struct iscsi_kern_conn_info *info)
{
struct iscsi_conn *conn;
int err = -EEXIST;
}
#endif
-static int notify(void *data, int len)
+/* event_mutex supposed to be held */
+static int __event_send(const void *buf, int buf_len)
{
+ int res = 0, len;
struct sk_buff *skb;
struct nlmsghdr *nlh;
- static u32 seq;
+ static u32 seq; /* protected by event_mutex */
+
+ TRACE_ENTRY();
+
+ if (ctr_open_state != ISCSI_CTR_OPEN_STATE_OPEN)
+ goto out;
+
+ len = NLMSG_SPACE(buf_len);
skb = alloc_skb(NLMSG_SPACE(len), GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
+ if (skb == NULL) {
+ PRINT_ERROR("alloc_skb() failed (len %d)", len);
+ res = -ENOMEM;
+ goto out;
+ }
nlh = __nlmsg_put(skb, iscsid_pid, seq++, NLMSG_DONE,
len - sizeof(*nlh), 0);
- memcpy(NLMSG_DATA(nlh), data, len);
+ memcpy(NLMSG_DATA(nlh), buf, buf_len);
+ res = netlink_unicast(nl, skb, iscsid_pid, 0);
+ if (res <= 0) {
+ if (res != -ECONNREFUSED)
+ PRINT_ERROR("netlink_unicast() failed: %d", res);
+ else
+ TRACE(TRACE_MINOR, "netlink_unicast() failed: %s. "
+ "Not functioning user space?",
+ "Connection refused");
+ goto out;
+ }
- return netlink_unicast(nl, skb, iscsid_pid, 0);
+out:
+ TRACE_EXIT_RES(res);
+ return res;
}
-int event_send(u32 tid, u64 sid, u32 cid, enum iscsi_kern_event_code code)
+int event_send(u32 tid, u64 sid, u32 cid, u32 cookie,
+ enum iscsi_kern_event_code code,
+ const char *param1, const char *param2)
{
int err;
+ static DEFINE_MUTEX(event_mutex);
struct iscsi_kern_event event;
+ int param1_size, param2_size;
+
+ param1_size = (param1 != NULL) ? strlen(param1) : 0;
+ param2_size = (param2 != NULL) ? strlen(param2) : 0;
event.tid = tid;
event.sid = sid;
event.cid = cid;
event.code = code;
+ event.cookie = cookie;
+ event.param1_size = param1_size;
+ event.param2_size = param2_size;
+
+ mutex_lock(&event_mutex);
+
+ err = __event_send(&event, sizeof(event));
+ if (err <= 0)
+ goto out_unlock;
- err = notify(&event, NLMSG_SPACE(sizeof(struct iscsi_kern_event)));
+ if (param1_size > 0) {
+ err = __event_send(param1, param1_size);
+ if (err <= 0)
+ goto out_unlock;
+ }
+
+ if (param2_size > 0) {
+ err = __event_send(param2, param2_size);
+ if (err <= 0)
+ goto out_unlock;
+ }
+out_unlock:
+ mutex_unlock(&event_mutex);
return err;
}
static int ctr_major;
static char ctr_name[] = "iscsi-scst-ctl";
-static int iscsi_template_registered;
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
unsigned long iscsi_trace_flag = ISCSI_DEFAULT_LOG_FLAGS;
TRACE_DBG("req %p", req);
- pdusize = req->conn->session->sess_param.max_xmit_data_length;
+ pdusize = req->conn->session->sess_params.max_xmit_data_length;
expsize = req->read_size;
size = min(expsize, (u32)req->bufflen);
offset = 0;
static inline int iscsi_get_allowed_cmds(struct iscsi_session *sess)
{
- int res = max(-1, (int)sess->max_queued_cmnds -
+ int res = max(-1, (int)sess->tgt_params.queued_cmnds -
atomic_read(&sess->active_cmds)-1);
TRACE_DBG("allowed cmds %d (sess %p, active_cmds %d)", res,
sess, atomic_read(&sess->active_cmds));
*/
EXTRACHECKS_BUG_ON(req->outstanding_r2t >
- sess->sess_param.max_outstanding_r2t);
+ sess->sess_params.max_outstanding_r2t);
- if (req->outstanding_r2t == sess->sess_param.max_outstanding_r2t)
+ if (req->outstanding_r2t == sess->sess_params.max_outstanding_r2t)
goto out;
- burst = sess->sess_param.max_burst_length;
+ burst = sess->sess_params.max_burst_length;
offset = be32_to_cpu(cmnd_hdr(req)->data_length) -
req->r2t_len_to_send;
list_add_tail(&rsp->write_list_entry, &send);
req->outstanding_r2t++;
- } while ((req->outstanding_r2t < sess->sess_param.max_outstanding_r2t) &&
+ } while ((req->outstanding_r2t < sess->sess_params.max_outstanding_r2t) &&
(req->r2t_len_to_send != 0));
iscsi_cmnds_init_write(&send, ISCSI_INIT_WRITE_WAKE);
if (dir & SCST_DATA_WRITE) {
unsolicited_data_expected = !(req_hdr->flags & ISCSI_CMD_FINAL);
- if (unlikely(session->sess_param.initial_r2t &&
+ if (unlikely(session->sess_params.initial_r2t &&
unsolicited_data_expected)) {
PRINT_ERROR("Initiator %s violated negotiated "
"parameters: initial R2T is required (ITT %x, "
goto out_close;
}
- if (unlikely(!session->sess_param.immediate_data &&
+ if (unlikely(!session->sess_params.immediate_data &&
req->pdu.datasize)) {
PRINT_ERROR("Initiator %s violated negotiated "
"parameters: forbidden immediate data sent "
goto out_close;
}
- if (unlikely(session->sess_param.first_burst_length < req->pdu.datasize)) {
+ if (unlikely(session->sess_params.first_burst_length < req->pdu.datasize)) {
PRINT_ERROR("Initiator %s violated negotiated "
"parameters: immediate data len (%d) > "
"first_burst_length (%d) (ITT %x, op %x)",
session->initiator_name,
req->pdu.datasize,
- session->sess_param.first_burst_length,
+ session->sess_params.first_burst_length,
cmnd_itt(req), req_hdr->scb[0]);
goto out_close;
}
req->outstanding_r2t = 1;
req->r2t_len_to_send = req->r2t_len_to_receive -
min_t(unsigned int,
- session->sess_param.first_burst_length -
+ session->sess_params.first_burst_length -
req->pdu.datasize,
req->r2t_len_to_receive);
} else
struct iscsi_conn *conn = cmnd->conn;
struct iscsi_session *session = conn->session;
- if (unlikely(cmnd->pdu.datasize > session->sess_param.max_recv_data_length)) {
+ if (unlikely(cmnd->pdu.datasize > session->sess_params.max_recv_data_length)) {
PRINT_ERROR("Initiator %s violated negotiated parameters: "
"data too long (ITT %x, datasize %u, "
"max_recv_data_length %u", session->initiator_name,
cmnd_itt(cmnd), cmnd->pdu.datasize,
- session->sess_param.max_recv_data_length);
+ session->sess_params.max_recv_data_length);
mark_conn_closed(conn);
return -EINVAL;
}
#define ISCSI_TRACE_TLB_HELP ", d_read, d_write, conn, conn_dbg, iov, pdu, net_page"
#endif
+#define ISCSI_MGMT_CMD_HELP \
+ " echo \"add_attribute IncomingUser name password\" >mgmt\n" \
+ " echo \"del_attribute IncomingUser name\" >mgmt\n" \
+ " echo \"add_attribute OutgoingUser name password\" >mgmt\n" \
+ " echo \"del_attribute OutgoingUser name\" >mgmt\n" \
+ " echo \"add_target_attribute target_name IncomingUser name password\" >mgmt\n" \
+ " echo \"del_target_attribute target_name IncomingUser name\" >mgmt\n" \
+ " echo \"add_target_attribute target_name OutgoingUser name password\" >mgmt\n" \
+ " echo \"del_target_attribute target_name OutgoingUser name\" >mgmt\n"
+
struct scst_tgt_template iscsi_template = {
.name = "iscsi",
.sg_tablesize = 0xFFFF /* no limit */,
.tgtt_attrs = iscsi_attrs,
.tgt_attrs = iscsi_tgt_attrs,
.sess_attrs = iscsi_sess_attrs,
- .enable_tgt = iscsi_enable_target,
- .is_tgt_enabled = iscsi_is_target_enabled,
+ .enable_target = iscsi_enable_target,
+ .is_target_enabled = iscsi_is_target_enabled,
+ .add_target = iscsi_sysfs_add_target,
+ .del_target = iscsi_sysfs_del_target,
+ .mgmt_cmd = iscsi_sysfs_mgmt_cmd,
+ .mgmt_cmd_help = ISCSI_MGMT_CMD_HELP,
#endif
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
.default_trace_flags = ISCSI_DEFAULT_LOG_FLAGS,
if (err < 0)
goto out_kmem;
- iscsi_template_registered = 1;
-
#ifdef CONFIG_SCST_PROC
err = iscsi_procfs_init();
if (err < 0)
#define iscsi_sense_unexpected_unsolicited_data ABORTED_COMMAND, 0x0C, 0x0C
#define iscsi_sense_incorrect_amount_of_data ABORTED_COMMAND, 0x0C, 0x0D
-struct iscsi_sess_param {
+/*
+ * All members must have int type to match expectations of iscsi_tgt_store_*()
+ * functions!
+ */
+struct iscsi_sess_params {
int initial_r2t;
int immediate_data;
int max_connections;
int ifmarkint;
};
-struct iscsi_trgt_param {
+/*
+ * All members must have int type to match expectations of iscsi_tgt_store_*()
+ * functions!
+ */
+struct iscsi_tgt_params {
int queued_cmnds;
};
unsigned int ready;
};
+struct iscsi_target;
struct iscsi_cmnd;
+#ifndef CONFIG_SCST_PROC
+struct iscsi_attr {
+ struct list_head attrs_list_entry;
+ struct kobj_attribute attr;
+ struct iscsi_target *target;
+ const char *name;
+};
+#endif
+
struct iscsi_target {
struct scst_tgt *scst_tgt;
struct list_head session_list; /* protected by target_mutex */
- /* Both protected by target_mgmt_mutex */
- struct iscsi_trgt_param trgt_param;
- /*
- * Put here to have uniform parameters checking and assigning
- * from various places, including iscsi-scst-adm.
- */
- struct iscsi_sess_param trgt_sess_param;
-
struct list_head target_list_entry;
u32 tid;
- /* All protected by target_sysfs_mutex */
+ /* Protected by iscsi_sysfs_mutex */
unsigned int tgt_enabled:1;
- unsigned int expected_ioctl;
- int ioctl_res;
- struct completion *target_enabling_cmpl;
- struct mutex target_sysfs_mutex;
+#ifndef CONFIG_SCST_PROC
+ /* Protected by target_mutex */
+ struct list_head attrs_list;
+#endif
char name[ISCSI_NAME_LEN];
};
/* Unprotected, since accessed only from a single read thread */
u32 next_ttt;
- u32 max_queued_cmnds; /* unprotected, since read-only */
+ /* Read only, if there are connection(s) */
+ struct iscsi_tgt_params tgt_params;
atomic_t active_cmds;
spinlock_t sn_lock;
struct iscsi_cmnd *tm_rsp;
/* Read only, if there are connection(s) */
- struct iscsi_sess_param sess_param;
+ struct iscsi_sess_params sess_params;
/*
* In some corner cases commands can be deleted from the hash
#define ISCSI_TM_DATA_WAIT_TIMEOUT (10 * HZ)
#define ISCSI_TM_DATA_WAIT_SCHED_TIMEOUT (ISCSI_TM_DATA_WAIT_TIMEOUT + HZ)
+#define ISCSI_CTR_OPEN_STATE_CLOSED 0
+#define ISCSI_CTR_OPEN_STATE_OPEN 1
+#define ISCSI_CTR_OPEN_STATE_CLOSING 2
+
extern struct mutex target_mgmt_mutex;
+extern int ctr_open_state;
extern const struct file_operations ctr_fops;
extern spinlock_t iscsi_rd_lock;
/* conn.c */
extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
extern void conn_reinst_finished(struct iscsi_conn *);
-extern int conn_add(struct iscsi_session *, struct iscsi_kern_conn_info *);
-extern int conn_del(struct iscsi_session *, struct iscsi_kern_conn_info *);
+extern int __add_conn(struct iscsi_session *, struct iscsi_kern_conn_info *);
+extern int __del_conn(struct iscsi_session *, struct iscsi_kern_conn_info *);
#ifdef CONFIG_SCST_PROC
extern int conn_free(struct iscsi_conn *);
#endif
extern void req_add_to_write_timeout_list(struct iscsi_cmnd *req);
/* target.c */
-#ifndef CONFIG_SCST_PROC
+#ifdef CONFIG_SCST_PROC
+extern const struct seq_operations iscsi_seq_op;
+#else
extern const struct attribute *iscsi_tgt_attrs[];
extern ssize_t iscsi_enable_target(struct scst_tgt *scst_tgt, const char *buf,
size_t size);
extern bool iscsi_is_target_enabled(struct scst_tgt *scst_tgt);
+extern ssize_t iscsi_sysfs_send_event(uint32_t tid,
+ enum iscsi_kern_event_code code,
+ const char *param1, const char *param2, void **data);
#endif
-struct iscsi_target *target_lookup_by_id(u32);
-extern int target_add(struct iscsi_kern_target_info *);
-extern int target_enable(struct iscsi_kern_target_info *);
-extern int target_disable(struct iscsi_kern_target_info *);
-extern int target_del(u32 id);
+extern struct iscsi_target *target_lookup_by_id(u32);
+extern int __add_target(struct iscsi_kern_target_info *);
+extern int __del_target(u32 id);
+extern ssize_t iscsi_sysfs_add_target(const char *target_name,
+ const char *params);
+extern ssize_t iscsi_sysfs_del_target(const char *target_name);
+extern ssize_t iscsi_sysfs_mgmt_cmd(const char *cmd);
extern void target_del_session(struct iscsi_target *target,
struct iscsi_session *session, int flags);
extern void target_del_all_sess(struct iscsi_target *target, int flags);
extern void target_del_all(void);
-extern const struct seq_operations iscsi_seq_op;
-
/* config.c */
#ifdef CONFIG_SCST_PROC
extern int iscsi_procfs_init(void);
extern void iscsi_procfs_exit(void);
#else
extern const struct attribute *iscsi_attrs[];
+extern int iscsi_add_attr(struct iscsi_target *target,
+ const struct iscsi_kern_attr *user_info);
+extern void __iscsi_del_attr(struct iscsi_target *target,
+ struct iscsi_attr *tgt_attr);
#endif
/* session.c */
-#ifdef CONFIG_SCST_PROC
-int print_digest_state(char *p, size_t size, unsigned long flags);
-#else
+#ifndef CONFIG_SCST_PROC
extern const struct attribute *iscsi_sess_attrs[];
#endif
extern const struct file_operations session_seq_fops;
extern struct iscsi_session *session_lookup(struct iscsi_target *, u64);
extern void sess_reinst_finished(struct iscsi_session *);
-extern int session_add(struct iscsi_target *, struct iscsi_kern_session_info *);
-extern int session_del(struct iscsi_target *, u64);
+extern int __add_session(struct iscsi_target *,
+ struct iscsi_kern_session_info *);
+extern int __del_session(struct iscsi_target *, u64);
extern int session_free(struct iscsi_session *session, bool del);
/* params.c */
-extern int iscsi_param_set(struct iscsi_target *,
- struct iscsi_kern_param_info *, int);
+extern const char *iscsi_get_digest_name(int val, char *res);
+extern const char *iscsi_get_bool_value(int val);
+extern int iscsi_params_set(struct iscsi_target *,
+ struct iscsi_kern_params_info *, int);
/* event.c */
-extern int event_send(u32, u64, u32, enum iscsi_kern_event_code);
+extern int event_send(u32, u64, u32, u32, enum iscsi_kern_event_code,
+ const char *param1, const char *param2);
extern int event_init(void);
extern void event_exit(void);
TRACE_ENTRY();
- TRACE_CONN_CLOSE("Closing connection %p (conn_ref_cnt=%d)", conn,
+ TRACE_MGMT_DBG("Closing connection %p (conn_ref_cnt=%d)", conn,
atomic_read(&conn->conn_ref_cnt));
iscsi_extracheck_is_rd_thread(conn);
TRACE_CONN_CLOSE("Notifying user space about closing connection %p",
conn);
- event_send(target->tid, session->sid, conn->cid, E_CONN_CLOSE);
+ event_send(target->tid, session->sid, conn->cid, 0, E_CONN_CLOSE,
+ NULL, NULL);
#ifdef CONFIG_SCST_PROC
mutex_lock(&target->target_mutex);
#include "iscsi.h"
#include "digest.h"
-#define CHECK_PARAM(info, iparam, word, min, max) \
-do { \
- if (!(info)->partial || ((info)->partial & 1 << key_##word)) \
- if ((iparam)[key_##word] < (min) || \
- (iparam)[key_##word] > (max)) { \
- PRINT_ERROR("%s: %u is out of range (%u %u)", \
- #word, (iparam)[key_##word], (min), (max)); \
- if ((iparam)[key_##word] < (min)) \
- (iparam)[key_##word] = (min); \
- else \
- (iparam)[key_##word] = (max); \
- } \
+#define CHECK_PARAM(info, iparams, word, min, max) \
+do { \
+ if (!(info)->partial || ((info)->partial & 1 << key_##word)) { \
+ TRACE_DBG("%s: %u", #word, (iparams)[key_##word]); \
+ if ((iparams)[key_##word] < (min) || \
+ (iparams)[key_##word] > (max)) { \
+ PRINT_ERROR("%s: %u is out of range (%u %u)", \
+ #word, (iparams)[key_##word], (min), (max)); \
+ if ((iparams)[key_##word] < (min)) \
+ (iparams)[key_##word] = (min); \
+ else \
+ (iparams)[key_##word] = (max); \
+ } \
+ } \
} while (0)
-#define SET_PARAM(param, info, iparam, word) \
-({ \
- int changed = 0; \
- if (!(info)->partial || ((info)->partial & 1 << key_##word)) { \
- if ((param)->word != (iparam)[key_##word]) \
- changed = 1; \
- (param)->word = (iparam)[key_##word]; \
- } \
- changed; \
+#define SET_PARAM(params, info, iparams, word) \
+({ \
+ int changed = 0; \
+ if (!(info)->partial || ((info)->partial & 1 << key_##word)) { \
+ if ((params)->word != (iparams)[key_##word]) \
+ changed = 1; \
+ (params)->word = (iparams)[key_##word]; \
+ TRACE_DBG("%s set to %u", #word, (iparams)[key_##word]); \
+ } \
+ changed; \
})
-#define GET_PARAM(param, info, iparam, word) \
-do { \
- (iparam)[key_##word] = (param)->word; \
+#define GET_PARAM(params, info, iparams, word) \
+do { \
+ (iparams)[key_##word] = (params)->word; \
} while (0)
-static const char *get_bool_name(int val)
+const char *iscsi_get_bool_value(int val)
{
if (val)
return "Yes";
return "No";
}
-static const char *get_digest_name(int val)
+const char *iscsi_get_digest_name(int val, char *res)
{
- if (val == DIGEST_NONE)
- return "None";
- else if (val == DIGEST_CRC32C)
- return "CRC32C";
- else
- return "Unknown";
+ int pos = 0;
+
+ if (val & DIGEST_NONE)
+ pos = sprintf(&res[pos], "%s", "None");
+
+ if (val & DIGEST_CRC32C)
+ pos += sprintf(&res[pos], "%s%s", (pos != 0) ? ", " : "",
+ "CRC32C");
+
+ if (pos == 0)
+ sprintf(&res[pos], "%s", "Unknown");
+
+ return res;
}
-static void log_params(struct iscsi_sess_param *param)
+static void log_params(struct iscsi_sess_params *params)
{
+ char digest_name[64];
+
PRINT_INFO("Negotiated parameters: InitialR2T %s, ImmediateData %s, "
"MaxConnections %d, MaxRecvDataSegmentLength %d, "
"MaxXmitDataSegmentLength %d, ",
- get_bool_name(param->initial_r2t),
- get_bool_name(param->immediate_data), param->max_connections,
- param->max_recv_data_length, param->max_xmit_data_length);
+ iscsi_get_bool_value(params->initial_r2t),
+ iscsi_get_bool_value(params->immediate_data), params->max_connections,
+ params->max_recv_data_length, params->max_xmit_data_length);
PRINT_INFO(" MaxBurstLength %d, FirstBurstLength %d, "
"DefaultTime2Wait %d, DefaultTime2Retain %d, ",
- param->max_burst_length, param->first_burst_length,
- param->default_wait_time, param->default_retain_time);
+ params->max_burst_length, params->first_burst_length,
+ params->default_wait_time, params->default_retain_time);
PRINT_INFO(" MaxOutstandingR2T %d, DataPDUInOrder %s, "
"DataSequenceInOrder %s, ErrorRecoveryLevel %d, ",
- param->max_outstanding_r2t,
- get_bool_name(param->data_pdu_inorder),
- get_bool_name(param->data_sequence_inorder),
- param->error_recovery_level);
+ params->max_outstanding_r2t,
+ iscsi_get_bool_value(params->data_pdu_inorder),
+ iscsi_get_bool_value(params->data_sequence_inorder),
+ params->error_recovery_level);
PRINT_INFO(" HeaderDigest %s, DataDigest %s, OFMarker %s, "
"IFMarker %s, OFMarkInt %d, IFMarkInt %d",
- get_digest_name(param->header_digest),
- get_digest_name(param->data_digest),
- get_bool_name(param->ofmarker),
- get_bool_name(param->ifmarker),
- param->ofmarkint, param->ifmarkint);
+ iscsi_get_digest_name(params->header_digest, digest_name),
+ iscsi_get_digest_name(params->data_digest, digest_name),
+ iscsi_get_bool_value(params->ofmarker),
+ iscsi_get_bool_value(params->ifmarker),
+ params->ofmarkint, params->ifmarkint);
}
/* target_mutex supposed to be locked */
-static void sess_param_check(struct iscsi_kern_param_info *info)
+static void sess_params_check(struct iscsi_kern_params_info *info)
{
- int32_t *iparam = info->session_param;
-
- CHECK_PARAM(info, iparam, max_connections, 1, 1);
- CHECK_PARAM(info, iparam, max_recv_data_length, 512,
- (int32_t) (ISCSI_CONN_IOV_MAX * PAGE_SIZE));
- CHECK_PARAM(info, iparam, max_xmit_data_length, 512,
- (int32_t) (ISCSI_CONN_IOV_MAX * PAGE_SIZE));
- CHECK_PARAM(info, iparam, error_recovery_level, 0, 0);
- CHECK_PARAM(info, iparam, data_pdu_inorder, 0, 1);
- CHECK_PARAM(info, iparam, data_sequence_inorder, 0, 1);
-
- digest_alg_available(&iparam[key_header_digest]);
- digest_alg_available(&iparam[key_data_digest]);
-
- CHECK_PARAM(info, iparam, ofmarker, 0, 0);
- CHECK_PARAM(info, iparam, ifmarker, 0, 0);
+ int32_t *iparams = info->session_params;
+ const int max_len = ISCSI_CONN_IOV_MAX * PAGE_SIZE;
+
+ CHECK_PARAM(info, iparams, initial_r2t, 0, 1);
+ CHECK_PARAM(info, iparams, immediate_data, 0, 1);
+ CHECK_PARAM(info, iparams, max_connections, 1, 1);
+ CHECK_PARAM(info, iparams, max_recv_data_length, 512, max_len);
+ CHECK_PARAM(info, iparams, max_xmit_data_length, 512, max_len);
+ CHECK_PARAM(info, iparams, max_burst_length, 512, max_len);
+ CHECK_PARAM(info, iparams, first_burst_length, 512, max_len);
+ CHECK_PARAM(info, iparams, max_outstanding_r2t, 1, 65535);
+ CHECK_PARAM(info, iparams, error_recovery_level, 0, 0);
+ CHECK_PARAM(info, iparams, data_pdu_inorder, 0, 1);
+ CHECK_PARAM(info, iparams, data_sequence_inorder, 0, 1);
+
+ digest_alg_available(&iparams[key_header_digest]);
+ digest_alg_available(&iparams[key_data_digest]);
+
+ CHECK_PARAM(info, iparams, ofmarker, 0, 0);
+ CHECK_PARAM(info, iparams, ifmarker, 0, 0);
+
+ return;
}
/* target_mutex supposed to be locked */
-static void sess_param_set(struct iscsi_sess_param *param,
- struct iscsi_kern_param_info *info)
+static void sess_params_set(struct iscsi_sess_params *params,
+ struct iscsi_kern_params_info *info)
{
- int32_t *iparam = info->session_param;
-
- SET_PARAM(param, info, iparam, initial_r2t);
- SET_PARAM(param, info, iparam, immediate_data);
- SET_PARAM(param, info, iparam, max_connections);
- SET_PARAM(param, info, iparam, max_recv_data_length);
- SET_PARAM(param, info, iparam, max_xmit_data_length);
- SET_PARAM(param, info, iparam, max_burst_length);
- SET_PARAM(param, info, iparam, first_burst_length);
- SET_PARAM(param, info, iparam, default_wait_time);
- SET_PARAM(param, info, iparam, default_retain_time);
- SET_PARAM(param, info, iparam, max_outstanding_r2t);
- SET_PARAM(param, info, iparam, data_pdu_inorder);
- SET_PARAM(param, info, iparam, data_sequence_inorder);
- SET_PARAM(param, info, iparam, error_recovery_level);
- SET_PARAM(param, info, iparam, header_digest);
- SET_PARAM(param, info, iparam, data_digest);
- SET_PARAM(param, info, iparam, ofmarker);
- SET_PARAM(param, info, iparam, ifmarker);
- SET_PARAM(param, info, iparam, ofmarkint);
- SET_PARAM(param, info, iparam, ifmarkint);
+ int32_t *iparams = info->session_params;
+
+ SET_PARAM(params, info, iparams, initial_r2t);
+ SET_PARAM(params, info, iparams, immediate_data);
+ SET_PARAM(params, info, iparams, max_connections);
+ SET_PARAM(params, info, iparams, max_recv_data_length);
+ SET_PARAM(params, info, iparams, max_xmit_data_length);
+ SET_PARAM(params, info, iparams, max_burst_length);
+ SET_PARAM(params, info, iparams, first_burst_length);
+ SET_PARAM(params, info, iparams, default_wait_time);
+ SET_PARAM(params, info, iparams, default_retain_time);
+ SET_PARAM(params, info, iparams, max_outstanding_r2t);
+ SET_PARAM(params, info, iparams, data_pdu_inorder);
+ SET_PARAM(params, info, iparams, data_sequence_inorder);
+ SET_PARAM(params, info, iparams, error_recovery_level);
+ SET_PARAM(params, info, iparams, header_digest);
+ SET_PARAM(params, info, iparams, data_digest);
+ SET_PARAM(params, info, iparams, ofmarker);
+ SET_PARAM(params, info, iparams, ifmarker);
+ SET_PARAM(params, info, iparams, ofmarkint);
+ SET_PARAM(params, info, iparams, ifmarkint);
+ return;
}
-static void sess_param_get(struct iscsi_sess_param *param,
- struct iscsi_kern_param_info *info)
+static void sess_params_get(struct iscsi_sess_params *params,
+ struct iscsi_kern_params_info *info)
{
- int32_t *iparam = info->session_param;
-
- GET_PARAM(param, info, iparam, initial_r2t);
- GET_PARAM(param, info, iparam, immediate_data);
- GET_PARAM(param, info, iparam, max_connections);
- GET_PARAM(param, info, iparam, max_recv_data_length);
- GET_PARAM(param, info, iparam, max_xmit_data_length);
- GET_PARAM(param, info, iparam, max_burst_length);
- GET_PARAM(param, info, iparam, first_burst_length);
- GET_PARAM(param, info, iparam, default_wait_time);
- GET_PARAM(param, info, iparam, default_retain_time);
- GET_PARAM(param, info, iparam, max_outstanding_r2t);
- GET_PARAM(param, info, iparam, data_pdu_inorder);
- GET_PARAM(param, info, iparam, data_sequence_inorder);
- GET_PARAM(param, info, iparam, error_recovery_level);
- GET_PARAM(param, info, iparam, header_digest);
- GET_PARAM(param, info, iparam, data_digest);
- GET_PARAM(param, info, iparam, ofmarker);
- GET_PARAM(param, info, iparam, ifmarker);
- GET_PARAM(param, info, iparam, ofmarkint);
- GET_PARAM(param, info, iparam, ifmarkint);
+ int32_t *iparams = info->session_params;
+
+ GET_PARAM(params, info, iparams, initial_r2t);
+ GET_PARAM(params, info, iparams, immediate_data);
+ GET_PARAM(params, info, iparams, max_connections);
+ GET_PARAM(params, info, iparams, max_recv_data_length);
+ GET_PARAM(params, info, iparams, max_xmit_data_length);
+ GET_PARAM(params, info, iparams, max_burst_length);
+ GET_PARAM(params, info, iparams, first_burst_length);
+ GET_PARAM(params, info, iparams, default_wait_time);
+ GET_PARAM(params, info, iparams, default_retain_time);
+ GET_PARAM(params, info, iparams, max_outstanding_r2t);
+ GET_PARAM(params, info, iparams, data_pdu_inorder);
+ GET_PARAM(params, info, iparams, data_sequence_inorder);
+ GET_PARAM(params, info, iparams, error_recovery_level);
+ GET_PARAM(params, info, iparams, header_digest);
+ GET_PARAM(params, info, iparams, data_digest);
+ GET_PARAM(params, info, iparams, ofmarker);
+ GET_PARAM(params, info, iparams, ifmarker);
+ GET_PARAM(params, info, iparams, ofmarkint);
+ GET_PARAM(params, info, iparams, ifmarkint);
+ return;
}
/* target_mutex supposed to be locked */
-static void trgt_param_check(struct iscsi_kern_param_info *info)
+static void tgt_params_check(struct iscsi_kern_params_info *info)
{
- int32_t *iparam = info->target_param;
+ int32_t *iparams = info->target_params;
- CHECK_PARAM(info, iparam, queued_cmnds, MIN_NR_QUEUED_CMNDS,
+ CHECK_PARAM(info, iparams, queued_cmnds, MIN_NR_QUEUED_CMNDS,
MAX_NR_QUEUED_CMNDS);
+ return;
}
/* target_mutex supposed to be locked */
-static void trgt_param_set(struct iscsi_target *target,
- struct iscsi_kern_param_info *info)
+static void tgt_params_set(struct iscsi_tgt_params *params,
+ struct iscsi_kern_params_info *info)
{
- struct iscsi_trgt_param *param = &target->trgt_param;
- int32_t *iparam = info->target_param;
+ int32_t *iparams = info->target_params;
- SET_PARAM(param, info, iparam, queued_cmnds);
+ SET_PARAM(params, info, iparams, queued_cmnds);
+ return;
}
/* target_mutex supposed to be locked */
-static void trgt_param_get(struct iscsi_trgt_param *param,
- struct iscsi_kern_param_info *info)
+static void tgt_params_get(struct iscsi_tgt_params *params,
+ struct iscsi_kern_params_info *info)
{
- int32_t *iparam = info->target_param;
+ int32_t *iparams = info->target_params;
- GET_PARAM(param, info, iparam, queued_cmnds);
+ GET_PARAM(params, info, iparams, queued_cmnds);
+ return;
}
/* target_mutex supposed to be locked */
-static int trgt_param(struct iscsi_target *target,
- struct iscsi_kern_param_info *info, int set)
+static int iscsi_tgt_params_set(struct iscsi_session *session,
+ struct iscsi_kern_params_info *info, int set)
{
- if (set) {
- struct iscsi_trgt_param *prm;
- trgt_param_check(info);
- trgt_param_set(target, info);
+ struct iscsi_tgt_params *params = &session->tgt_params;
- prm = &target->trgt_param;
- PRINT_INFO("Target parameter changed: QueuedCommands %d",
- prm->queued_cmnds);
+ if (set) {
+ tgt_params_check(info);
+ tgt_params_set(params, info);
+ PRINT_INFO("Target parameters set for session %llx: "
+ "QueuedCommands %d", session->sid,
+ params->queued_cmnds);
} else
- trgt_param_get(&target->trgt_param, info);
+ tgt_params_get(params, info);
return 0;
}
/* target_mutex supposed to be locked */
-static int sess_param(struct iscsi_target *target,
- struct iscsi_kern_param_info *info, int set)
+static int iscsi_sess_params_set(struct iscsi_session *session,
+ struct iscsi_kern_params_info *info, int set)
{
- struct iscsi_session *session = NULL;
- struct iscsi_sess_param *param;
- int err = -ENOENT;
+ struct iscsi_sess_params *params;
if (set)
- sess_param_check(info);
-
- if (info->sid) {
- session = session_lookup(target, info->sid);
- if (!session)
- goto out;
- if (set && !list_empty(&session->conn_list)) {
- err = -EBUSY;
- goto out;
- }
- param = &session->sess_param;
- } else
- param = &target->trgt_sess_param;
+ sess_params_check(info);
+
+ params = &session->sess_params;
if (set) {
- sess_param_set(param, info);
- if (session != NULL)
- log_params(param);
+ sess_params_set(params, info);
+ log_params(params);
} else
- sess_param_get(param, info);
+ sess_params_get(params, info);
- err = 0;
-out:
- return err;
+ return 0;
}
/* target_mutex supposed to be locked */
-int iscsi_param_set(struct iscsi_target *target,
- struct iscsi_kern_param_info *info, int set)
+int iscsi_params_set(struct iscsi_target *target,
+ struct iscsi_kern_params_info *info, int set)
{
int err;
+ struct iscsi_session *session;
- if (info->param_type == key_session)
- err = sess_param(target, info, set);
- else if (info->param_type == key_target)
- err = trgt_param(target, info, set);
+ if (info->sid == 0) {
+ PRINT_ERROR("sid must not be %d", 0);
+ err = -EINVAL;
+ goto out;
+ }
+
+ session = session_lookup(target, info->sid);
+ if (session == NULL) {
+ PRINT_ERROR("Session for sid %llx not found", info->sid);
+ err = -ENOENT;
+ goto out;
+ }
+
+ if (set && !list_empty(&session->conn_list)) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (info->params_type == key_session)
+ err = iscsi_sess_params_set(session, info, set);
+ else if (info->params_type == key_target)
+ err = iscsi_tgt_params_set(session, info, set);
else
err = -EINVAL;
+out:
return err;
}
#include "iscsi.h"
-#ifdef CONFIG_SCST_PROC
-int print_digest_state(char *p, size_t size, unsigned long flags)
-#else
-static int print_digest_state(char *p, size_t size, unsigned long flags)
-#endif
-{
- int pos;
-
- if (DIGEST_NONE & flags)
- pos = scnprintf(p, size, "%s", "none");
- else if (DIGEST_CRC32C & flags)
- pos = scnprintf(p, size, "%s", "crc32c");
- else
- pos = scnprintf(p, size, "%s", "unknown");
-
- return pos;
-}
-
/* target_mutex supposed to be locked */
struct iscsi_session *session_lookup(struct iscsi_target *target, u64 sid)
{
session->target = target;
session->sid = info->sid;
- session->sess_param = target->trgt_sess_param;
- session->max_queued_cmnds = target->trgt_param.queued_cmnds;
atomic_set(&session->active_cmds, 0);
-
session->exp_cmd_sn = info->exp_cmd_sn;
session->initiator_name = kstrdup(info->initiator_name, GFP_KERNEL);
goto err;
}
+#ifdef CONFIG_SCST_PROC
name = kmalloc(strlen(info->user_name) + strlen(info->initiator_name) +
1, GFP_KERNEL);
if (name == NULL) {
sprintf(name, "%s@%s", info->user_name, info->initiator_name);
else
sprintf(name, "%s", info->initiator_name);
+#else
+ name = info->initiator_name;
+#endif
INIT_LIST_HEAD(&session->conn_list);
INIT_LIST_HEAD(&session->pending_list);
goto err;
}
+#ifdef CONFIG_SCST_PROC
kfree(name);
+#endif
scst_sess_set_tgt_priv(session->scst_sess, session);
if (session) {
kfree(session->initiator_name);
kfree(session);
+#ifdef CONFIG_SCST_PROC
kfree(name);
+#endif
}
return err;
}
}
/* target_mgmt_mutex supposed to be locked */
-int session_add(struct iscsi_target *target,
+int __add_session(struct iscsi_target *target,
struct iscsi_kern_session_info *info)
{
struct iscsi_session *new_sess = NULL, *sess, *old_sess;
- int err = 0;
+ int err = 0, i;
union iscsi_sid sid;
bool reinstatement = false;
+ struct iscsi_kern_params_info *params_info;
TRACE_MGMT_DBG("Adding session SID %llx", info->sid);
goto out_err_unlock;
}
+ params_info = kmalloc(sizeof(*params_info), GFP_KERNEL);
+ if (params_info == NULL) {
+ PRINT_ERROR("Unable to allocate params info (size %d)",
+ sizeof(*params_info));
+ err = -ENOMEM;
+ goto out_err_unlock;
+ }
+
sid = *(union iscsi_sid *)&info->sid;
sid.id.tsih = 0;
old_sess = NULL;
list_add_tail(&new_sess->session_list_entry, &target->session_list);
+ memset(params_info, 0, sizeof(*params_info));
+ params_info->tid = target->tid;
+ params_info->sid = info->sid;
+ params_info->params_type = key_session;
+ for (i = 0; i < session_key_last; i++)
+ params_info->session_params[i] = info->session_params[i];
+
+ err = iscsi_params_set(target, params_info, 1);
+ if (err != 0)
+ goto out_del;
+
+ memset(params_info, 0, sizeof(*params_info));
+ params_info->tid = target->tid;
+ params_info->sid = info->sid;
+ params_info->params_type = key_target;
+ for (i = 0; i < target_key_last; i++)
+ params_info->target_params[i] = info->target_params[i];
+
+ err = iscsi_params_set(target, params_info, 1);
+ if (err != 0)
+ goto out_del;
+
+ kfree(params_info);
+ params_info = NULL;
+
if (old_sess != NULL) {
reinstatement = true;
out:
return err;
+out_del:
+ list_del(&new_sess->session_list_entry);
+ kfree(params_info);
+
out_err_unlock:
mutex_unlock(&target->target_mutex);
}
/* target_mutex supposed to be locked */
-int session_del(struct iscsi_target *target, u64 sid)
+int __del_session(struct iscsi_target *target, u64 sid)
{
struct iscsi_session *session;
#else /* CONFIG_SCST_PROC */
+#define ISCSI_SESS_BOOL_PARAM_ATTR(name, exported_name) \
+static ssize_t iscsi_sess_show_##name(struct kobject *kobj, \
+ struct kobj_attribute *attr, char *buf) \
+{ \
+ int pos; \
+ struct scst_session *scst_sess; \
+ struct iscsi_session *sess; \
+ \
+ scst_sess = container_of(kobj, struct scst_session, sess_kobj); \
+ sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess); \
+ \
+ pos = sprintf(buf, "%s\n", \
+ iscsi_get_bool_value(sess->sess_params.name)); \
+ \
+ return pos; \
+} \
+ \
+static struct kobj_attribute iscsi_sess_attr_##name = \
+ __ATTR(exported_name, S_IRUGO, iscsi_sess_show_##name, NULL);
+
+#define ISCSI_SESS_INT_PARAM_ATTR(name, exported_name) \
+static ssize_t iscsi_sess_show_##name(struct kobject *kobj, \
+ struct kobj_attribute *attr, char *buf) \
+{ \
+ int pos; \
+ struct scst_session *scst_sess; \
+ struct iscsi_session *sess; \
+ \
+ scst_sess = container_of(kobj, struct scst_session, sess_kobj); \
+ sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess); \
+ \
+ pos = sprintf(buf, "%d\n", sess->sess_params.name); \
+ \
+ return pos; \
+} \
+ \
+static struct kobj_attribute iscsi_sess_attr_##name = \
+ __ATTR(exported_name, S_IRUGO, iscsi_sess_show_##name, NULL);
+
+#define ISCSI_SESS_DIGEST_PARAM_ATTR(name, exported_name) \
+static ssize_t iscsi_sess_show_##name(struct kobject *kobj, \
+ struct kobj_attribute *attr, char *buf) \
+{ \
+ int pos; \
+ struct scst_session *scst_sess; \
+ struct iscsi_session *sess; \
+ char digest_name[64]; \
+ \
+ scst_sess = container_of(kobj, struct scst_session, sess_kobj); \
+ sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess); \
+ \
+ pos = sprintf(buf, "%s\n", iscsi_get_digest_name( \
+ sess->sess_params.name, digest_name)); \
+ \
+ return pos; \
+} \
+ \
+static struct kobj_attribute iscsi_sess_attr_##name = \
+ __ATTR(exported_name, S_IRUGO, iscsi_sess_show_##name, NULL);
+
+ISCSI_SESS_BOOL_PARAM_ATTR(initial_r2t, InitialR2T);
+ISCSI_SESS_BOOL_PARAM_ATTR(immediate_data, ImmediateData);
+ISCSI_SESS_INT_PARAM_ATTR(max_recv_data_length, MaxRecvDataSegmentLength);
+ISCSI_SESS_INT_PARAM_ATTR(max_xmit_data_length, MaxXmitDataSegmentLength);
+ISCSI_SESS_INT_PARAM_ATTR(max_burst_length, MaxBurstLength);
+ISCSI_SESS_INT_PARAM_ATTR(first_burst_length, FirstBurstLength);
+ISCSI_SESS_INT_PARAM_ATTR(max_outstanding_r2t, MaxOutstandingR2T);
+ISCSI_SESS_DIGEST_PARAM_ATTR(header_digest, HeaderDigest);
+ISCSI_SESS_DIGEST_PARAM_ATTR(data_digest, DataDigest);
+
static ssize_t iscsi_sess_sid_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return pos;
}
-static struct kobj_attribute iscsi_sess_sid_attr =
+static struct kobj_attribute iscsi_attr_sess_sid =
__ATTR(sid, S_IRUGO, iscsi_sess_sid_show, NULL);
static ssize_t iscsi_sess_reinstating_show(struct kobject *kobj,
return pos;
}
-static struct kobj_attribute iscsi_sess_reinstating_attr =
+static struct kobj_attribute iscsi_sess_attr_reinstating =
__ATTR(reinstating, S_IRUGO, iscsi_sess_reinstating_show, NULL);
-static ssize_t iscsi_sess_hdigest_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
+static ssize_t iscsi_sess_force_close_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
{
- int pos;
+ int res;
struct scst_session *scst_sess;
struct iscsi_session *sess;
+ struct iscsi_conn *conn;
TRACE_ENTRY();
scst_sess = container_of(kobj, struct scst_session, sess_kobj);
sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
- pos = print_digest_state(buf, SCST_SYSFS_BLOCK_SIZE,
- sess->sess_param.header_digest);
-
- TRACE_EXIT_RES(pos);
- return pos;
-}
+ if (mutex_lock_interruptible(&sess->target->target_mutex) != 0) {
+ res = -EINTR;
+ goto out;
+ }
-static struct kobj_attribute iscsi_sess_hdigest_attr =
- __ATTR(hdigest, S_IRUGO, iscsi_sess_hdigest_show, NULL);
+ PRINT_INFO("Deleting session %llu with initiator %s (%p)",
+ (long long unsigned int)sess->sid, sess->initiator_name, sess);
-static ssize_t iscsi_sess_ddigest_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- int pos;
- struct scst_session *scst_sess;
- struct iscsi_session *sess;
+ list_for_each_entry(conn, &sess->conn_list, conn_list_entry) {
+ TRACE_MGMT_DBG("Deleting connection with initiator %p", conn);
+ __mark_conn_closed(conn, ISCSI_CONN_ACTIVE_CLOSE|ISCSI_CONN_DELETING);
+ }
- TRACE_ENTRY();
+ mutex_unlock(&sess->target->target_mutex);
- scst_sess = container_of(kobj, struct scst_session, sess_kobj);
- sess = (struct iscsi_session *)scst_sess_get_tgt_priv(scst_sess);
-
- pos = print_digest_state(buf, SCST_SYSFS_BLOCK_SIZE,
- sess->sess_param.data_digest);
+ res = count;
- TRACE_EXIT_RES(pos);
- return pos;
+out:
+ TRACE_EXIT_RES(res);
+ return res;
}
-static struct kobj_attribute iscsi_sess_ddigest_attr =
- __ATTR(ddigest, S_IRUGO, iscsi_sess_ddigest_show, NULL);
+static struct kobj_attribute iscsi_sess_attr_force_close =
+ __ATTR(force_close, S_IWUSR, NULL, iscsi_sess_force_close_store);
const struct attribute *iscsi_sess_attrs[] = {
- &iscsi_sess_sid_attr.attr,
- &iscsi_sess_reinstating_attr.attr,
- &iscsi_sess_hdigest_attr.attr,
- &iscsi_sess_ddigest_attr.attr,
+ &iscsi_sess_attr_initial_r2t.attr,
+ &iscsi_sess_attr_immediate_data.attr,
+ &iscsi_sess_attr_max_recv_data_length.attr,
+ &iscsi_sess_attr_max_xmit_data_length.attr,
+ &iscsi_sess_attr_max_burst_length.attr,
+ &iscsi_sess_attr_first_burst_length.attr,
+ &iscsi_sess_attr_max_outstanding_r2t.attr,
+ &iscsi_sess_attr_header_digest.attr,
+ &iscsi_sess_attr_data_digest.attr,
+ &iscsi_attr_sess_sid.attr,
+ &iscsi_sess_attr_reinstating.attr,
+ &iscsi_sess_attr_force_close.attr,
NULL,
};
#include "digest.h"
#define MAX_NR_TARGETS (1UL << 30)
-#define SYSFS_WAIT_TIMEOUT (15 * HZ)
DEFINE_MUTEX(target_mgmt_mutex);
}
/* target_mgmt_mutex supposed to be locked */
-static struct iscsi_target *target_lookup_by_name(char *name)
+static struct iscsi_target *target_lookup_by_name(const char *name)
{
struct iscsi_target *target;
}
/* target_mgmt_mutex supposed to be locked */
-static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid)
+static int iscsi_target_create(struct iscsi_kern_target_info *info, u32 tid,
+ struct iscsi_target **out_target)
{
int err = -EINVAL, len;
char *name = info->name;
target->tid = info->tid = tid;
- strncpy(target->name, name, sizeof(target->name) - 1);
+ strlcpy(target->name, name, sizeof(target->name));
mutex_init(&target->target_mutex);
- mutex_init(&target->target_sysfs_mutex);
INIT_LIST_HEAD(&target->session_list);
+#ifndef CONFIG_SCST_PROC
+ INIT_LIST_HEAD(&target->attrs_list);
+#endif
target->scst_tgt = scst_register(&iscsi_template, target->name);
if (!target->scst_tgt) {
list_add_tail(&target->target_list_entry, &target_list);
+ *out_target = target;
+
return 0;
out_free:
}
/* target_mgmt_mutex supposed to be locked */
-int target_add(struct iscsi_kern_target_info *info)
+int __add_target(struct iscsi_kern_target_info *info)
{
- int err = -EEXIST;
+ int err;
u32 tid = info->tid;
+ struct iscsi_target *target;
+ struct iscsi_kern_params_info *params_info;
+ struct iscsi_kern_attr *attr_info;
+ union add_info_union {
+ struct iscsi_kern_params_info params_info;
+ struct iscsi_kern_attr attr_info;
+ } *add_info;
+#ifndef CONFIG_SCST_PROC
+ int i, rc;
+ unsigned long attrs_ptr_long;
+ struct iscsi_kern_attr __user *attrs_ptr;
+#endif
if (nr_targets > MAX_NR_TARGETS) {
err = -EBUSY;
goto out;
}
- if (target_lookup_by_name(info->name))
+ if (target_lookup_by_name(info->name)) {
+ PRINT_ERROR("Target %s already exist!", info->name);
+ err = -EEXIST;
goto out;
+ }
- if (tid && target_lookup_by_id(tid))
+ if (tid && target_lookup_by_id(tid)) {
+ PRINT_ERROR("Target %u already exist!", tid);
+ err = -EEXIST;
+ goto out;
+ }
+
+ add_info = kmalloc(sizeof(*add_info), GFP_KERNEL);
+ if (add_info == NULL) {
+ PRINT_ERROR("Unable to allocate additional info (size %d)",
+ sizeof(*add_info));
+ err = -ENOMEM;
goto out;
+ }
+ params_info = (struct iscsi_kern_params_info *)add_info;
+ attr_info = (struct iscsi_kern_attr *)add_info;
- if (!tid) {
+ if (tid == 0) {
do {
if (!++next_target_id)
++next_target_id;
tid = next_target_id;
}
- err = iscsi_target_create(info, tid);
- if (!err)
- nr_targets++;
-out:
- return err;
-}
-
-static void target_destroy(struct iscsi_target *target)
-{
- TRACE_MGMT_DBG("Destroying target tid %u", target->tid);
-
- scst_unregister(target->scst_tgt);
-
- kfree(target);
+ err = iscsi_target_create(info, tid, &target);
+ if (err != 0)
+ goto out_free;
- module_put(THIS_MODULE);
-}
+ nr_targets++;
-/* target_mgmt_mutex supposed to be locked */
-int target_enable(struct iscsi_kern_target_info *info)
-{
- int res = 0;
- struct iscsi_target *tgt;
+#ifndef CONFIG_SCST_PROC
+ mutex_lock(&target->target_mutex);
- TRACE_ENTRY();
+ attrs_ptr_long = info->attrs_ptr;
+ attrs_ptr = (struct iscsi_kern_attr __user *)attrs_ptr_long;
+ for (i = 0; i < info->attrs_num; i++) {
+ memset(attr_info, 0, sizeof(*attr_info));
+
+ rc = copy_from_user(attr_info, attrs_ptr, sizeof(*attr_info));
+ if (rc != 0) {
+ PRINT_ERROR("copy_from_user() of users of target %s "
+ "failed", info->name);
+ err = -EFAULT;
+ goto out_del_unlock;
+ }
- tgt = target_lookup_by_id(info->tid);
- if (tgt == NULL) {
- PRINT_ERROR("Target %d not found", info->tid);
- res = -EINVAL;
- goto out;
- }
+ attr_info->name[sizeof(attr_info->name)-1] = '\0';
- mutex_lock(&tgt->target_sysfs_mutex);
+ err = iscsi_add_attr(target, attr_info);
+ if (err != 0)
+ goto out_del_unlock;
- if (tgt->expected_ioctl != ENABLE_TARGET) {
- PRINT_ERROR("Unexpected ENABLE_TARGET IOCTL for target %d",
- tgt->tid);
- res = -EINVAL;
- goto out_unlock;
+ attrs_ptr++;
}
- tgt->expected_ioctl = 0;
-
- WARN_ON(tgt->tgt_enabled);
- tgt->tgt_enabled = 1;
-
- tgt->ioctl_res = 0;
+ mutex_unlock(&target->target_mutex);
+#endif
- complete_all(tgt->target_enabling_cmpl);
+ err = tid;
-out_unlock:
- mutex_unlock(&tgt->target_sysfs_mutex);
+out_free:
+ kfree(add_info);
out:
- TRACE_EXIT_RES(res);
- return res;
+ return err;
+
+#ifndef CONFIG_SCST_PROC
+out_del_unlock:
+ mutex_unlock(&target->target_mutex);
+ __del_target(tid);
+ goto out_free;
+#endif
}
-/* target_mgmt_mutex supposed to be locked */
-int target_disable(struct iscsi_kern_target_info *info)
+static void target_destroy(struct iscsi_target *target)
{
- int res = 0;
- struct iscsi_target *tgt;
-
- TRACE_ENTRY();
-
- tgt = target_lookup_by_id(info->tid);
- if (tgt == NULL) {
- PRINT_ERROR("Target %d not found", info->tid);
- res = -EINVAL;
- goto out;
- }
+#ifndef CONFIG_SCST_PROC
+ struct iscsi_attr *attr, *t;
+#endif
- mutex_lock(&tgt->target_sysfs_mutex);
+ TRACE_MGMT_DBG("Destroying target tid %u", target->tid);
- if (tgt->expected_ioctl != DISABLE_TARGET) {
- PRINT_ERROR("Unexpected DISABLE_TARGET IOCTL for target %d",
- tgt->tid);
- res = -EINVAL;
- goto out_unlock;
+#ifndef CONFIG_SCST_PROC
+ list_for_each_entry_safe(attr, t, &target->attrs_list,
+ attrs_list_entry) {
+ __iscsi_del_attr(target, attr);
}
+#endif
- mutex_unlock(&tgt->target_sysfs_mutex);
-
- mutex_lock(&tgt->target_mutex);
- target_del_all_sess(tgt, ISCSI_CONN_ACTIVE_CLOSE | ISCSI_CONN_DELETING);
- mutex_unlock(&tgt->target_mutex);
-
- mutex_lock(&tgt->target_sysfs_mutex);
-
- tgt->expected_ioctl = 0;
-
- WARN_ON(!tgt->tgt_enabled);
- tgt->tgt_enabled = 0;
-
- tgt->ioctl_res = 0;
-
- complete_all(tgt->target_enabling_cmpl);
+ scst_unregister(target->scst_tgt);
-out_unlock:
- mutex_unlock(&tgt->target_sysfs_mutex);
+ kfree(target);
-out:
- TRACE_EXIT_RES(res);
- return res;
+ module_put(THIS_MODULE);
+ return;
}
/* target_mgmt_mutex supposed to be locked */
-int target_del(u32 id)
+int __del_target(u32 id)
{
struct iscsi_target *target;
int err;
} else {
TRACE_MGMT_DBG("Freeing session %p without connections",
session);
- session_del(target, session->sid);
+ __del_session(target, session->sid);
}
TRACE_EXIT();
return pos;
}
-static struct kobj_attribute iscsi_tgt_tid_attr =
+static struct kobj_attribute iscsi_tgt_attr_tid =
__ATTR(tid, S_IRUGO, iscsi_tgt_tid_show, NULL);
const struct attribute *iscsi_tgt_attrs[] = {
- &iscsi_tgt_tid_attr.attr,
+ &iscsi_tgt_attr_tid.attr,
NULL,
};
+ssize_t iscsi_sysfs_send_event(uint32_t tid, enum iscsi_kern_event_code code,
+ const char *param1, const char *param2, void **data)
+{
+ int res;
+ struct scst_sysfs_user_info *info;
+
+ TRACE_ENTRY();
+
+ if (ctr_open_state != ISCSI_CTR_OPEN_STATE_OPEN) {
+ PRINT_ERROR("%s", "User space process not connected");
+ res = -EPERM;
+ goto out;
+ }
+
+ res = scst_sysfs_user_add_info(&info);
+ if (res != 0)
+ goto out;
+
+ TRACE_DBG("Sending event %d (tid %d, param1 %s, param2 %s, cookie %d, "
+ "info %p)", tid, code, param1, param2, info->info_cookie, info);
+
+ res = event_send(tid, 0, 0, info->info_cookie, code, param1, param2);
+ if (res <= 0) {
+ PRINT_ERROR("event_send() failed: %d", res);
+ goto out_free;
+ }
+
+ /*
+ * It may wait 30 secs in blocking connect to an unreacheable
+ * iSNS server. It must be fixed, but not now. ToDo.
+ */
+ res = scst_wait_info_completion(info, 31 * HZ);
+
+ if (data != NULL)
+ *data = info->data;
+
+out_free:
+ scst_sysfs_user_del_info(info);
+
+out:
+ TRACE_EXIT_RES(res);
+ return res;
+}
+
ssize_t iscsi_enable_target(struct scst_tgt *scst_tgt, const char *buf,
size_t size)
{
struct iscsi_target *tgt =
(struct iscsi_target *)scst_tgt_get_tgt_priv(scst_tgt);
- DECLARE_COMPLETION_ONSTACK(enabling_cmpl);
- int res = 0, rc, ioctl_res = 0;
+ int res;
bool enable;
+ uint32_t type;
TRACE_ENTRY();
- mutex_lock(&tgt->target_sysfs_mutex);
-
- if (tgt->target_enabling_cmpl != NULL) {
- TRACE_DBG("A sysfs command is being processed for target %d",
- tgt->tid);
- res = -ETXTBSY;
- goto out_unlock;
- }
-
- tgt->target_enabling_cmpl = &enabling_cmpl;
-
switch (buf[0]) {
case '0':
- if (!tgt->tgt_enabled) {
- TRACE_DBG("Target %d already disabled", tgt->tid);
- goto out_null_unlock;
- }
- enable = true;
- tgt->expected_ioctl = DISABLE_TARGET;
- res = event_send(tgt->tid, 0, 0, E_DISABLE_TARGET);
- if (res <= 0) {
- PRINT_ERROR("event_send() failed: %d", res);
- goto out_null_unlock;
- }
+ type = E_DISABLE_TARGET;
+ enable = false;
break;
case '1':
- if (tgt->tgt_enabled) {
- TRACE_DBG("Target %d already enabled", tgt->tid);
- goto out_null_unlock;
- }
- enable = false;
- tgt->expected_ioctl = ENABLE_TARGET;
- res = event_send(tgt->tid, 0, 0, E_ENABLE_TARGET);
- if (res <= 0) {
- PRINT_ERROR("event_send() failed: %d", res);
- goto out_null_unlock;
- }
+ type = E_ENABLE_TARGET;
+ enable = true;
break;
default:
PRINT_ERROR("%s: Requested action not understood: %s",
__func__, buf);
res = -EINVAL;
- goto out_null_unlock;
+ goto out;
}
- mutex_unlock(&tgt->target_sysfs_mutex);
-
- TRACE_DBG("Waiting for completion of enable/disable (%d) "
- "target %d", enable, tgt->tid);
-
- rc = wait_for_completion_interruptible_timeout(&enabling_cmpl,
- SYSFS_WAIT_TIMEOUT);
- if (res == 0) {
- PRINT_ERROR("Timeout attempting to %s target %d",
- enable ? "enable" : "disable", tgt->tid);
- res = -EBUSY;
- /* go through */
- } else if (res < 0) {
- if (res != -ERESTARTSYS)
- PRINT_ERROR("wait_for_completion() failed: %d", res);
- /* go through */
- }
+ TRACE_DBG("%s target %d", enable ? "Enabling" : "Disabling", tgt->tid);
+
+ res = iscsi_sysfs_send_event(tgt->tid, type, NULL, NULL, NULL);
+
+out:
+ TRACE_EXIT_RES(res);
+ return res;
+}
- TRACE_DBG("Waiting for completion of enable/disable (%d) "
- "target %d finished with res %d", enable, tgt->tid, res);
+bool iscsi_is_target_enabled(struct scst_tgt *scst_tgt)
+{
+ struct iscsi_target *tgt =
+ (struct iscsi_target *)scst_tgt_get_tgt_priv(scst_tgt);
- mutex_lock(&tgt->target_sysfs_mutex);
+ return tgt->tgt_enabled;
+}
- ioctl_res = tgt->ioctl_res;
+ssize_t iscsi_sysfs_add_target(const char *target_name, const char *params)
+{
+ int res;
-out_null_unlock:
- tgt->target_enabling_cmpl = NULL;
+ TRACE_ENTRY();
-out_unlock:
- mutex_unlock(&tgt->target_sysfs_mutex);
+ res = iscsi_sysfs_send_event(0, E_ADD_TARGET, target_name,
+ params, NULL);
+ if (res > 0) {
+ /* It's tid */
+ res = 0;
+ }
+
+ TRACE_EXIT_RES(res);
+ return res;
+}
+
+ssize_t iscsi_sysfs_del_target(const char *target_name)
+{
+ int res = 0, tid;
+
+ TRACE_ENTRY();
- if (res == 0) {
- res = ioctl_res;
- if (res == 0)
- res = size;
+ /* We don't want to have tgt visible after the mutex unlock */
+ {
+ struct iscsi_target *tgt;
+ mutex_lock(&target_mgmt_mutex);
+ tgt = target_lookup_by_name(target_name);
+ if (tgt == NULL) {
+ PRINT_ERROR("Target %s not found", target_name);
+ mutex_unlock(&target_mgmt_mutex);
+ res = -ENOENT;
+ goto out;
+ }
+ tid = tgt->tid;
+ mutex_unlock(&target_mgmt_mutex);
}
+ TRACE_DBG("Deleting target %s (tid %d)", target_name, tid);
+
+ res = iscsi_sysfs_send_event(tid, E_DEL_TARGET, NULL, NULL, NULL);
+
+out:
TRACE_EXIT_RES(res);
return res;
}
-bool iscsi_is_target_enabled(struct scst_tgt *scst_tgt)
+ssize_t iscsi_sysfs_mgmt_cmd(const char *cmd)
{
- struct iscsi_target *tgt =
- (struct iscsi_target *)scst_tgt_get_tgt_priv(scst_tgt);
+ int res;
- return tgt->tgt_enabled;
+ TRACE_ENTRY();
+
+ TRACE_DBG("Sending mgmt cmd %s", cmd);
+
+ res = iscsi_sysfs_send_event(0, E_MGMT_CMD, cmd, NULL, NULL);
+
+ TRACE_EXIT_RES(res);
+ return res;
}
#endif /* CONFIG_SCST_PROC */
SRCS_ADM = iscsi_adm.c param.c
OBJS_ADM = $(SRCS_ADM:.c=.o)
+SCST_INC_DIR := ../../scst/include
+#SCST_INC_DIR := /usr/local/include/scst
+
CFLAGS += -O2 -fno-inline -Wall -Wextra -Wstrict-prototypes -Wno-sign-compare \
-Wimplicit-function-declaration -Wno-unused-parameter \
- -Wno-missing-field-initializers -g -I../include
+ -Wno-missing-field-initializers -g -I../include -I$(SCST_INC_DIR)
CFLAGS += -D_GNU_SOURCE # required for glibc >= 2.8
PROGRAMS = iscsi-scstd iscsi-scst-adm
}
}
-static inline void chap_calc_digest_md5(char chap_id, char *secret, int secret_len, u8 *challenge, int challenge_len, u8 *digest)
+static inline void chap_calc_digest_md5(char chap_id, const char *secret, int secret_len,
+ const u8 *challenge, int challenge_len, u8 *digest)
{
MD5_CTX ctx;
MD5_Final(digest, &ctx);
}
-static inline void chap_calc_digest_sha1(char chap_id, char *secret, int secret_len, u8 *challenge, int challenge_len, u8 *digest)
+static inline void chap_calc_digest_sha1(char chap_id, const char *secret, int secret_len,
+ const u8 *challenge, int challenge_len, u8 *digest)
{
SHA_CTX ctx;
int digest_len = 0, retval = 0, encoding_format;
char pass[ISCSI_NAME_LEN];
- memset(pass, 0, sizeof(pass));
- if (config_account_query(conn->tid, AUTH_DIR_INCOMING, pass, pass) < 0) {
+ if (accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING)) {
log_warning("CHAP initiator auth.: "
"No CHAP credentials configured");
retval = CHAP_TARGET_ERROR;
}
memset(pass, 0, sizeof(pass));
- if (config_account_query(conn->tid, AUTH_DIR_INCOMING, value, pass) < 0) {
+ if (config_account_query(conn->tid, ISCSI_USER_DIR_INCOMING, value, pass) < 0) {
log_warning("CHAP initiator auth.: "
"No valid user/pass combination for initiator %s "
"found", conn->initiator);
u8 *challenge = NULL, *digest = NULL;
int encoding_format, response_len;
int challenge_len = 0, digest_len = 0, retval = 0;
- char pass[ISCSI_NAME_LEN], name[ISCSI_NAME_LEN];
+ struct iscsi_user *user;
if (!(value = text_key_find(conn, "CHAP_I"))) {
- /* initiator doesn't want target auth!? */
+ /* Initiator doesn't want target auth!? */
conn->state = STATE_SECURITY_DONE;
retval = 0;
goto out;
}
chap_id = strtol(value, &value, 10);
- memset(pass, 0, sizeof(pass));
- memset(name, 0, sizeof(name));
- if (config_account_query(conn->tid, AUTH_DIR_OUTGOING, name, pass) < 0) {
+ user = account_get_first(conn->tid, ISCSI_USER_DIR_OUTGOING);
+ if (user == NULL) {
log_warning("CHAP target auth.: "
"no outgoing credentials configured%s",
conn->tid ? "." : " for discovery.");
switch (conn->auth.chap.digest_alg) {
case CHAP_DIGEST_ALG_MD5:
- chap_calc_digest_md5(chap_id, pass, strlen(pass),
+ chap_calc_digest_md5(chap_id, user->password, strlen(user->password),
challenge, challenge_len, digest);
break;
case CHAP_DIGEST_ALG_SHA1:
- chap_calc_digest_sha1(chap_id, pass, strlen(pass),
+ chap_calc_digest_sha1(chap_id, user->password, strlen(user->password),
challenge, challenge_len, digest);
break;
default:
memset(response, 0x0, response_len);
chap_encode_string(digest, digest_len, response, encoding_format);
- text_key_add(conn, "CHAP_N", name);
+ text_key_add(conn, "CHAP_N", user->name);
text_key_add(conn, "CHAP_R", response);
conn->state = STATE_SECURITY_DONE;
#include <dirent.h>
#include <errno.h>
#include <netdb.h>
+#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#define BUFSIZE 4096
#define CONFIG_FILE "/etc/iscsi-scstd.conf"
-#define ACCT_CONFIG_FILE CONFIG_FILE
-/*
- * Account configuration code
- */
+/* Index must match ISCSI_USER_DIR_*!! */
+struct iscsi_key user_keys[] = {
+ {"IncomingUser",},
+ {"OutgoingUser",},
+ {NULL,},
+};
-struct user {
- struct __qelem ulist;
+static struct __qelem discovery_users_in = LIST_HEAD_INIT(discovery_users_in);
+static struct __qelem discovery_users_out = LIST_HEAD_INIT(discovery_users_out);
- u32 tid;
- char *name;
- char *password;
-};
+static struct __qelem *account_list_get(struct target *target, int dir)
+{
+ struct __qelem *list = NULL;
+
+ if (target != NULL) {
+ list = (dir == ISCSI_USER_DIR_INCOMING) ?
+ &target->target_in_accounts : &target->target_out_accounts;
+ } else
+ list = (dir == ISCSI_USER_DIR_INCOMING) ?
+ &discovery_users_in : &discovery_users_out;
-/* this is the orignal Ardis code. */
-static char *target_sep_string(char **pp)
+ return list;
+}
+
+char *config_sep_string(char **pp)
{
char *p = *pp;
char *q;
+ static char blank = '\0';
+
+ if ((pp == NULL) || (*pp == NULL))
+ return ␣
- for (p = *pp; isspace(*p); p++)
+ for (p = *pp; isspace(*p) || (*p == '='); p++)
;
- for (q = p; *q && !isspace(*q); q++)
+
+ for (q = p; (*q != '\0') && !isspace(*q) && (*q != '='); q++)
;
- if (*q)
- *q++ = 0;
- else
- p = NULL;
+
+ if (*q != '\0')
+ *q++ = '\0';
+
*pp = q;
return p;
}
-static struct iscsi_key user_keys[] = {
- {"IncomingUser",},
- {"OutgoingUser",},
- {NULL,},
-};
+static char *config_gets(char *buf, int size, const char *data, int *offset)
+{
+ int offs = *offset, i = 0;
-static struct __qelem discovery_users_in = LIST_HEAD_INIT(discovery_users_in);
-static struct __qelem discovery_users_out = LIST_HEAD_INIT(discovery_users_out);
+ while ((i < size-1) && (data[offs] != '\n') && (data[offs] != ';') && (data[offs] != '\0'))
+ buf[i++] = data[offs++];
-#define HASH_ORDER 4
-#define acct_hash(x) ((x) & ((1 << HASH_ORDER) - 1))
+ if ((i == 0) && (data[offs] == '\0'))
+ return NULL;
-static struct __qelem trgt_acct_in[1 << HASH_ORDER];
-static struct __qelem trgt_acct_out[1 << HASH_ORDER];
+ if (data[offs] != '\0')
+ offs++;
-static struct __qelem *account_list_get(u32 tid, int dir)
+ *offset = offs;
+ buf[i] = '\0';
+
+ return buf;
+}
+
+int accounts_empty(u32 tid, int dir)
{
- struct __qelem *list = NULL;
+ struct target *target;
+ struct __qelem *list;
if (tid) {
- list = (dir == AUTH_DIR_INCOMING) ?
- &trgt_acct_in[acct_hash(tid)] : &trgt_acct_out[acct_hash(tid)];
+ target = target_find_by_id(tid);
+ if (target == NULL)
+ return 0;
} else
- list = (dir == AUTH_DIR_INCOMING) ?
- &discovery_users_in : &discovery_users_out;
+ target = NULL;
- return list;
+ list = account_list_get(target, dir);
+
+ return list_empty(list);
}
-static int config_account_init(char *filename)
+static struct iscsi_user *__account_lookup_by_name(struct target *target,
+ int dir, const char *name)
{
- FILE *fp;
- char buf[BUFSIZE], *p, *q;
- u32 tid;
- int idx, res = 0;
+ struct __qelem *list;
+ struct iscsi_user *user = NULL;
- if (!(fp = fopen(filename, "r"))) {
- return errno == ENOENT ? 0 : -errno;
+ list = account_list_get(target, dir);
+
+ list_for_each_entry(user, list, ulist) {
+ if (!strcmp(user->name, name))
+ return user;
}
- tid = 0;
- while (fgets(buf, sizeof(buf), fp)) {
- q = buf;
- p = target_sep_string(&q);
- if (!p || *p == '#')
- continue;
+ return NULL;
+}
- if (!strcasecmp(p, "Target")) {
- tid = 0;
- if (!(p = target_sep_string(&q)))
- continue;
- tid = target_find_id_by_name(p);
- } else if (!((idx = param_index_by_name(p, user_keys)) < 0)) {
- char *name, *pass;
- name = target_sep_string(&q);
- pass = target_sep_string(&q);
- res = config_account_add(tid, idx, name, pass);
- if (res < 0) {
- log_error("%s %s\n", name, pass);
- break;
- }
- }
- }
+static struct iscsi_user *account_lookup_by_name(u32 tid, int dir, const char *name)
+{
+ struct target *target;
- fclose(fp);
+ if (tid) {
+ target = target_find_by_id(tid);
+ if (target == NULL)
+ return NULL;
+ } else
+ target = NULL;
- return res;
+ return __account_lookup_by_name(target, dir, name);
}
-/* Return the first account if the length of name is zero */
-static struct user *account_lookup_by_name(u32 tid, int dir, char *name)
+struct iscsi_user *account_get_first(u32 tid, int dir)
{
- struct __qelem *list = account_list_get(tid, dir);
- struct user *user = NULL;
+ struct target *target;
+ struct __qelem *list;
+ struct iscsi_user *user = NULL;
+
+ if (tid) {
+ target = target_find_by_id(tid);
+ if (target == NULL)
+ return NULL;
+ } else
+ target = NULL;
+
+ list = account_list_get(target, dir);
list_for_each_entry(user, list, ulist) {
- if (user->tid != tid)
- continue;
- if (!strlen(name))
- return user;
- if (!strcmp(user->name, name))
+ return user;
+ }
+
+ return NULL;
+}
+
+struct iscsi_user *account_lookup_by_sysfs_name(struct target *target,
+ int dir, const char *sysfs_name)
+{
+ struct __qelem *list;
+ struct iscsi_user *user = NULL;
+
+ list = account_list_get(target, dir);
+
+ list_for_each_entry(user, list, ulist) {
+ if (!strcmp(user->sysfs_name, sysfs_name))
return user;
}
return NULL;
}
-int config_account_query(u32 tid, int dir, char *name, char *pass)
+int config_account_query(u32 tid, int dir, const char *name, char *pass)
{
- struct user *user;
+ struct iscsi_user *user;
if (!(user = account_lookup_by_name(tid, dir, name)))
return -ENOENT;
- if (!strlen(name))
- strncpy(name, user->name, ISCSI_NAME_LEN);
-
- strncpy(pass, user->password, ISCSI_NAME_LEN);
+ strlcpy(pass, user->password, ISCSI_NAME_LEN);
return 0;
}
int config_account_list(u32 tid, int dir, u32 *cnt, u32 *overflow,
char *buf, size_t buf_sz)
{
- struct __qelem *list = account_list_get(tid, dir);
- struct user *user;
+ struct target *target;
+ struct __qelem *list;
+ struct iscsi_user *user;
*cnt = *overflow = 0;
+ if (tid) {
+ target = target_find_by_id(tid);
+ if (target == NULL)
+ return -ENOENT;
+ } else
+ target = NULL;
+
+ list = account_list_get(target, dir);
+
if (!list)
return -ENOENT;
list_for_each_entry(user, list, ulist) {
- if (user->tid != tid)
- continue;
if (buf_sz >= ISCSI_NAME_LEN) {
- strncpy(buf, user->name, ISCSI_NAME_LEN);
+ strlcpy(buf, user->name, ISCSI_NAME_LEN);
buf_sz -= ISCSI_NAME_LEN;
buf += ISCSI_NAME_LEN;
*cnt += 1;
return 0;
}
-static void account_destroy(struct user *user)
+static void account_destroy(struct iscsi_user *user, int del)
{
if (!user)
return;
- remque(&user->ulist);
- free(user->name);
- free(user->password);
+ if (del)
+ list_del(&user->ulist);
+ free((void *)user->name);
+ free((void *)user->password);
free(user);
+ return;
}
-int config_account_del(u32 tid, int dir, char *name)
+void accounts_free(struct __qelem *accounts_list)
{
- struct user *user;
+ struct iscsi_user *user, *t;
- if (!name || !(user = account_lookup_by_name(tid, dir, name)))
- return -ENOENT;
+ list_for_each_entry_safe(user, t, accounts_list, ulist) {
+ account_destroy(user, 1);
+ }
- account_destroy(user);
+ return;
+}
- /* update the file here. */
- return 0;
+int config_account_del(u32 tid, int dir, char *name, u32 cookie)
+{
+ struct iscsi_user *user;
+ int res = 0;
+
+ if (!name) {
+ log_error("%s", "Name expected");
+ res = -EINVAL;
+ goto out;
+ }
+
+ user = account_lookup_by_name(tid, dir, name);
+ if (user == NULL) {
+ log_error("User %s not found", name);
+ res = -ENOENT;
+ goto out;
+ }
+
+#ifndef CONFIG_SCST_PROC
+ res = kernel_user_del(user, cookie);
+ if (res != 0)
+ goto out;
+#endif
+
+ account_destroy(user, 1);
+
+out:
+ return res;
}
-static struct user *account_create(void)
+static struct iscsi_user *account_create(struct target *target, int direction,
+ const char *sysfs_name, const char *name, const char *pass)
{
- struct user *user;
+ struct iscsi_user *user;
if (!(user = malloc(sizeof(*user))))
return NULL;
memset(user, 0, sizeof(*user));
INIT_LIST_HEAD(&user->ulist);
+ user->target = target;
+ user->direction = direction;
+
+ if (!(user->name = strdup(name)) ||
+ !(user->password = strdup(pass))) {
+ log_error("Unable to duplicate name (%s) or password (%s)",
+ name, pass);
+ goto out_destroy;
+ }
+
+ if (direction == ISCSI_USER_DIR_INCOMING) {
+ int inc_user_num = 0;
+ if (sysfs_name != NULL) {
+ strlcpy(user->sysfs_name, sysfs_name, sizeof(user->sysfs_name));
+ if (account_lookup_by_sysfs_name(target, direction, sysfs_name) == NULL)
+ goto out;
+ }
+
+ while (1) {
+ if (inc_user_num == 0)
+ snprintf(user->sysfs_name, sizeof(user->sysfs_name),
+ "IncomingUser");
+ else
+ snprintf(user->sysfs_name, sizeof(user->sysfs_name),
+ "IncomingUser%d", inc_user_num);
+ if (account_lookup_by_sysfs_name(target, direction, user->sysfs_name) == NULL)
+ break;
+ inc_user_num++;
+ }
+ } else
+ snprintf(user->sysfs_name, sizeof(user->sysfs_name),
+ "OutgoingUser");
+
+out:
return user;
+
+out_destroy:
+ account_destroy(user, 0);
+ user = NULL;
+ goto out;
}
-int config_account_add(u32 tid, int dir, char *name, char *pass)
+int account_replace(struct target *target, int direction,
+ const char *sysfs_name, char *value)
{
- int err = -ENOMEM;
- struct user *user;
+ int res = 0;
+ struct iscsi_user *user, *user1;
+ char *name, *pass, *n;
struct __qelem *list;
- if (!name || !pass)
- return -EINVAL;
+ name = config_sep_string(&value);
+ pass = config_sep_string(&value);
- if (tid) {
- /* check here */
- /* return -ENOENT; */
+ n = config_sep_string(&value);
+ if (*n != '\0') {
+ log_error("Unexpected parameter value %s\n", n);
+ res = -EINVAL;
+ goto out;
+ }
+
+ user = account_lookup_by_sysfs_name(target, direction, sysfs_name);
+ if (user == NULL) {
+ log_error("Unknown parameter %s\n", sysfs_name);
+ res = -EINVAL;
+ goto out;
+ }
+
+ user1 = __account_lookup_by_name(target, direction, name);
+ if ((user1 != NULL) && (user1 != user)) {
+ log_error("User %s already exists\n", name);
+ res = -EEXIST;
+ goto out;
+ }
+
+ list = account_list_get(target, direction);
+
+ list_del(&user->ulist);
+
+ user1 = account_create(target, direction, sysfs_name, name, pass);
+ if (user1 == NULL) {
+ res = -ENOMEM;
+ goto out_add;
+ }
+
+ list_add_tail(user1, list);
+
+ account_destroy(user, 0);
+
+out:
+ return res;
+
+out_add:
+ list_add_tail(user, list);
+ goto out;
+}
+
+int __config_account_add(struct target *target, int dir, char *name,
+ char *pass, char *sysfs_name, int send_to_kern, u32 cookie)
+{
+ int err = 0;
+ struct iscsi_user *user;
+ struct __qelem *list;
+ int del = 0;
+
+ if (!name || !pass) {
+ log_error("%s", "Name or password is NULL");
+ err = -EINVAL;
+ goto out;
}
/* Check for minimum RFC defined value */
if (strlen(pass) < 12) {
log_error("Secret for user %s is too short. At least 12 bytes "
"are required\n", name);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
- if (!(user = account_create()) ||
- !(user->name = strdup(name)) ||
- !(user->password = strdup(pass)))
+ user = account_create(target, dir, sysfs_name, name, pass);
+ if (user == NULL) {
+ err = -ENOMEM;
goto out;
+ }
- user->tid = tid;
- list = account_list_get(tid, dir);
- if (dir == AUTH_DIR_OUTGOING) {
- struct user *old, *tmp;
- list_for_each_entry_safe(old, tmp, list, ulist) {
- if (tid != old->tid)
- continue;
- log_warning("Only one outgoing %s account is supported."
- " Replacing the old one.\n",
- tid ? "target" : "discovery");
- account_destroy(old);
+ if (__account_lookup_by_name(target, dir, name) != NULL) {
+ log_error("User %s already exists for target %s (direction %s)",
+ name, target ? target->name : "discovery",
+ (dir == ISCSI_USER_DIR_OUTGOING) ? "outgoing" : "incoming");
+ err = -EEXIST;
+ goto out_destroy;
+ }
+
+ list = account_list_get(target, dir);
+ if (dir == ISCSI_USER_DIR_OUTGOING) {
+ struct iscsi_user *old;
+ list_for_each_entry(old, list, ulist) {
+ log_warning("Only one outgoing %s account is "
+ "supported. Replacing the old one.\n",
+ target ? "target" : "discovery");
+ account_destroy(old, 1);
+ break;
}
}
- insque(user, list);
+ log_debug(1, "User %s added to target %s (direction %s)", user->name,
+ target ? target->name : "discovery",
+ (dir == ISCSI_USER_DIR_OUTGOING) ? "outgoing" : "incoming");
+
+ list_add_tail(user, list);
+ del = 1;
+
+#ifndef CONFIG_SCST_PROC
+ if (send_to_kern) {
+ err = kernel_user_add(user, cookie);
+ if (err != 0)
+ goto out_destroy;
+ }
+#endif
- /* update the file here. */
- return 0;
out:
- account_destroy(user);
+ return err;
+
+out_destroy:
+ account_destroy(user, del);
+ goto out;
+}
+
+int config_account_add(u32 tid, int dir, char *name, char *pass, char *sysfs_name,
+ u32 cookie)
+{
+ int err = 0;
+ struct target *target;
+ if (tid) {
+ target = target_find_by_id(tid);
+ if (target == NULL) {
+ err = -ENOENT;
+ goto out;
+ }
+ } else
+ target = NULL;
+
+ err = __config_account_add(target, dir, name, pass, sysfs_name, 1, cookie);
+
+out:
return err;
}
* Main configuration code
*/
-static int __config_target_create(u32 *tid, char *name, int update)
+int config_target_create(u32 *tid, char *name)
{
int err;
+ struct target *target;
- if (target_find_by_name(name)) {
- log_error("duplicated target %s", name);
- return -EINVAL;
- }
- if ((err = target_add(tid, name)) < 0)
- return err;
+ err = target_create(name, &target);
+ if (err != 0)
+ goto out;
+
+ err = target_add(target, tid, 0);
+ if (err != 0)
+ goto out_free;
+out:
return err;
-}
-int config_target_create(u32 *tid, char *name)
-{
- return __config_target_create(tid, name, 1);
+out_free:
+ target_free(target);
+ goto out;
}
int config_target_destroy(u32 tid)
{
int err;
- if ((err = target_del(tid)) < 0)
+ if ((err = target_del(tid, 0)) < 0)
return err;
return err;
}
-int config_param_set(u32 tid, u64 sid, int type, u32 partial,
- struct iscsi_param *param)
+int config_params_get(u32 tid, u64 sid, int type, struct iscsi_param *params)
{
- int err;
+ int err, i;
+ struct target *target;
- err = kernel_param_set(tid, sid, type, partial, param);
+ if (sid != 0) {
+ err = kernel_params_get(tid, sid, type, params);
+ goto out;
+ }
+ err = 0;
+
+ target = target_find_by_id(tid);
+ if (target == NULL) {
+ log_error("target %d not found", tid);
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (type == key_session) {
+ for (i = 0; i < session_key_last; i++)
+ params[i].val = target->session_params[i];
+ } else {
+ for (i = 0; i < target_key_last; i++)
+ params[i].val = target->target_params[i];
+ }
+
+out:
return err;
}
-static int iscsi_param_partial_set(u32 tid, u64 sid, int type, int key, u32 val)
+int config_params_set(u32 tid, u64 sid, int type, u32 partial,
+ struct iscsi_param *params)
{
- struct iscsi_param *param;
- struct iscsi_param session_param[session_key_last];
- struct iscsi_param target_param[target_key_last];
+ int err, i;
+ struct target *target;
- if (type == key_session)
- param = session_param;
- else
- param = target_param;
+ if (sid != 0) {
+ err = kernel_params_set(tid, sid, type, partial, params);
+ goto out;
+ }
- param[key].val = val;
+ err = 0;
- return config_param_set(tid, sid, type, 1 << key, param);
+ target = target_find_by_id(tid);
+ if (target == 0) {
+ log_error("target %d not found", tid);
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (partial == 0)
+ partial = (typeof(partial))-1;
+
+ if (type == key_session) {
+ for (i = 0; i < session_key_last; i++) {
+ if (partial & (1 << i)) {
+ err = params_check_val(session_keys, i, ¶ms[i].val);
+ if (err < 0) {
+ log_error("Wrong value %u for parameter %s\n",
+ params[i].val, session_keys[i].name);
+ goto out;
+ }
+ }
+ }
+ for (i = 0; i < session_key_last; i++) {
+ if (partial & (1 << i))
+ target->session_params[i] = params[i].val;
+ }
+ } else {
+ for (i = 0; i < target_key_last; i++) {
+ if (partial & (1 << i)) {
+ err = params_check_val(target_keys, i, ¶ms[i].val);
+ if (err < 0) {
+ log_error("Wrong value %u for parameter %s\n",
+ params[i].val, target_keys[i].name);
+ goto out;
+ }
+ }
+ }
+ for (i = 0; i < target_key_last; i++) {
+ if (partial & (1 << i))
+ target->target_params[i] = params[i].val;
+ }
+ }
+
+out:
+ return err;
}
-static int config_main_init(char *filename)
+int config_parse_main(const char *data, u32 cookie)
{
- FILE *config;
char buf[BUFSIZE];
- char *p, *q;
- int idx;
- u32 tid, val;
+ char *p, *q, *n;
+ int idx, offset = 0;
+ u32 val;
int res = 0;
+ struct target *target = NULL;
+ int global_section = 1; /* supposed to be bool and true */
+ int parsed_something = 0; /* supposed to be bool and false */
+ int stop_on_errors = (cookie != 0);
+
+ while (config_gets(buf, sizeof(buf), data, &offset)) {
+ parsed_something = 1;
+ /*
+ * If stop_on_errors is false, let's always continue parsing
+ * and only report errors.
+ */
+ if (stop_on_errors && (res != 0))
+ goto out_target_free;
- if (!(config = fopen(filename, "r"))) {
- return errno == ENOENT ? 0 : -errno;
- }
-
- tid = 0;
- while (fgets(buf, BUFSIZE, config)) {
q = buf;
- p = target_sep_string(&q);
- if (!p || *p == '#')
+ p = config_sep_string(&q);
+ if ((*p == '#') || (*p == '\0'))
continue;
+
if (!strcasecmp(p, "Target")) {
- tid = 0;
- if (!(p = target_sep_string(&q)))
+ global_section = 0;
+
+ if (target != NULL) {
+ res = target_add(target, NULL, cookie);
+ if (res != 0)
+ target_free(target);
+ }
+
+ target = NULL;
+ p = config_sep_string(&q);
+ if (p == '\0') {
+ log_error("Target name required on %s\n", q);
continue;
- if (__config_target_create(&tid, p, 0))
- log_debug(1, "creating target %s", p);
- } else if (!strcasecmp(p, "Alias") && tid) {
+ }
+
+ n = config_sep_string(&q);
+ if (*n != '\0') {
+ log_error("Unexpected parameter value %s\n", n);
+ res = -EINVAL;
+ continue;
+ }
+
+ log_debug(1, "Creating target %s", p);
+ res = target_create(p, &target);
+ if (res != 0)
+ goto out;
+ } else if (!strcasecmp(p, "Alias") && target) {
;
- } else if (!((idx = param_index_by_name(p, target_keys)) < 0) && tid) {
- val = strtol(q, &q, 0);
- if (param_check_val(target_keys, idx, &val) < 0) {
+ } else if (!((idx = params_index_by_name(p, target_keys)) < 0) && (target != NULL)) {
+ char *str = config_sep_string(&q);
+
+ n = config_sep_string(&q);
+ if (*n != '\0') {
+ log_error("Unexpected parameter value %s\n", n);
+ res = -EINVAL;
+ continue;
+ }
+
+ res = params_str_to_val(target_keys, idx, str, &val);
+ if (res < 0) {
+ log_error("Wrong value %s for parameter %s\n",
+ str, target_keys[idx].name);
+ continue;
+ }
+
+ res = params_check_val(target_keys, idx, &val);
+ if (res < 0) {
log_error("Wrong value %u for parameter %s\n",
val, target_keys[idx].name);
- res = -1;
- break;
+ continue;
}
- iscsi_param_partial_set(tid, 0, key_target, idx, val);
- } else if (!((idx = param_index_by_name(p, session_keys)) < 0) && tid) {
- char *str = target_sep_string(&q);
- if (param_str_to_val(session_keys, idx, str, &val) < 0) {
+ target->target_params[idx] = val;
+ } else if (!((idx = params_index_by_name(p, session_keys)) < 0) && (target != NULL)) {
+ char *str = config_sep_string(&q);
+
+ n = config_sep_string(&q);
+ if (*n != '\0') {
+ log_error("Unexpected parameter value %s\n", n);
+ res = -EINVAL;
+ continue;
+ }
+
+ res = params_str_to_val(session_keys, idx, str, &val);
+ if (res < 0) {
log_error("Wrong value %s for parameter %s\n",
str, session_keys[idx].name);
- res = -1;
- break;
+ continue;
}
- if (param_check_val(session_keys, idx, &val) < 0) {
+
+ res = params_check_val(session_keys, idx, &val);
+ if (res < 0) {
log_error("Wrong value %u for parameter %s\n",
val, session_keys[idx].name);
- res = -1;
- break;
+ continue;
}
- iscsi_param_partial_set(tid, 0, key_session, idx, val);
- } else if (param_index_by_name(p, user_keys) < 0) {
- log_warning("Unknown iscsi-scstd.conf param: %s\n", p);
- res = -1;
- break;
- }
- }
+ target->session_params[idx] = val;
+ } else if (!((idx = params_index_by_name_numwild(p, user_keys)) < 0) &&
+ ((target != NULL) || global_section)) {
+ char *name, *pass;
- fclose(config);
- return res;
-}
+ name = config_sep_string(&q);
+ pass = config_sep_string(&q);
-int config_load(char *params)
-{
- int i, err;
+ n = config_sep_string(&q);
+ if (*n != '\0') {
+ log_error("Unexpected parameter value %s\n", n);
+ res = -EINVAL;
+ continue;
+ }
- for (i = 0; i < 1 << HASH_ORDER; i++) {
- INIT_LIST_HEAD(&trgt_acct_in[i]);
- INIT_LIST_HEAD(&trgt_acct_out[i]);
+ res = __config_account_add(target, idx, name, pass, p,
+ (target == 0), 0);
+ if (res < 0)
+ continue;
+ } else if (global_section &&
+ (!strcasecmp(p, ISCSI_ISNS_SERVER_PARAM_NAME) ||
+ !strcasecmp(p, ISCSI_ISNS_ACCESS_CONTROL_PARAM_NAME)))
+ continue;
+ else {
+ log_error("Unknown or unexpected param: %s\n", p);
+ res = -EINVAL;
+ continue;
+ }
}
- /* First, we must finish the main configuration. */
- if ((err = config_main_init(params ? params : CONFIG_FILE)))
- return err;
+ if (stop_on_errors && (res != 0))
+ goto out_target_free;
- if ((err = config_account_init(ACCT_CONFIG_FILE)) < 0)
- return err;
+ if (target != NULL) {
+ res = target_add(target, NULL, cookie);
+ if (res != 0)
+ goto out_target_free;
+ }
- /* TODO: error handling */
+out:
+ if (stop_on_errors) {
+ if ((res == 0) && !parsed_something)
+ res = -ENOENT;
+ } else
+ res = 0;
- return err;
+ return res;
+
+out_target_free:
+ if (target != NULL)
+ target_free(target);
+ goto out;
}
-int config_isns_load(char *params, char **isns, int *isns_ac)
+static int config_isns_load(const char *config)
{
- FILE *config;
char buf[BUFSIZE];
+ int offset = 0;
char *p, *q;
- if (!(config = fopen(params ? : CONFIG_FILE, "r")))
- return -errno;
-
- while (fgets(buf, BUFSIZE, config)) {
+ while (config_gets(buf, sizeof(buf), config, &offset)) {
q = buf;
- p = target_sep_string(&q);
- if (!p || *p == '#')
+ p = config_sep_string(&q);
+ if ((*p == '\0') || (*p == '#'))
continue;
- if (!strcasecmp(p, "iSNSServer")) {
- *isns = strdup(target_sep_string(&q));
- } else if (!strcasecmp(p, "iSNSAccessControl")) {
- char *str = target_sep_string(&q);
- if (!strcasecmp(str, "Yes"))
- *isns_ac = 1;
+ if (!strcasecmp(p, ISCSI_ISNS_SERVER_PARAM_NAME)) {
+ isns_server = strdup(config_sep_string(&q));
+ } else if (!strcasecmp(p, ISCSI_ISNS_ACCESS_CONTROL_PARAM_NAME)) {
+ char *str = config_sep_string(&q);
+ if (!strcasecmp(str, "No"))
+ isns_access_control = 0;
+ else
+ isns_access_control = 1;
}
}
- fclose(config);
return 0;
}
+
+int config_load(const char *config_name)
+{
+ int i, err = 0, rc;
+ int config;
+ const char *cname;
+ int size;
+ char *buf;
+
+ if (config_name != NULL)
+ cname = config_name;
+ else
+ cname = CONFIG_FILE;
+
+ config = open(cname, O_RDONLY);
+ if (config == -1) {
+ if ((errno == ENOENT) && (config_name == NULL)) {
+#ifdef CONFIG_SCST_PROC
+ log_debug(3, "Default config file %s not found",
+ CONFIG_FILE);
+#endif
+ goto out;
+ } else {
+ err = -errno;
+ log_error("Open config file %s failed: %s", cname,
+ strerror(err));
+ goto out;
+ }
+ }
+
+ size = lseek(config, 0, SEEK_END);
+ if (size < 0) {
+ err = -errno;
+ log_error("lseek() failed: %s", strerror(err));
+ goto out_close;
+ }
+
+ buf = malloc(size+1);
+ if (buf == NULL) {
+ err = -ENOMEM;
+ log_error("malloc() failed: %s", strerror(err));
+ goto out_close;
+ }
+
+ rc = lseek(config, 0, SEEK_SET);
+ if (rc < 0) {
+ err = -errno;
+ log_error("lseek() failed: %s", strerror(err));
+ goto out_free;
+ }
+
+ i = 0;
+ do {
+ rc = read(config, &buf[i], size - i);
+ if (rc < 0) {
+ err = -errno;
+ log_error("read() failed: %s", strerror(err));
+ goto out_free;
+ } else if (rc == 0)
+ break;
+ i += rc;
+ } while (i < size);
+
+ size = i;
+ buf[size+1] = '\0';
+
+ config_parse_main(buf, 0);
+
+ err = config_isns_load(buf);
+ if ((err == 0) && (isns_server != NULL)) {
+ int rc = isns_init();
+ if (rc != 0) {
+ log_error("iSNS server %s init failed: %d", isns_server, rc);
+ isns_exit();
+ }
+ }
+
+out_free:
+ free(buf);
+
+out_close:
+ close(config);
+
+out:
+ return err;
+}
struct connection *conn_alloc(void)
{
struct connection *conn;
+ unsigned int session_params[session_key_last];
+ int i;
conn = malloc(sizeof(*conn));
if (conn == NULL)
memset(conn, 0, sizeof(*conn));
conn->state = STATE_FREE;
- param_set_defaults(conn->session_param, session_keys);
INIT_LIST_HEAD(&conn->rsp_buf_list);
+ params_set_defaults(session_params, session_keys);
+
+ for (i = 0; i < session_key_last; i++)
+ conn->session_params[i].val = session_params[i];
+
out:
return conn;
}
void conn_free(struct connection *conn)
{
- remque(&conn->clist);
+ list_del(&conn->clist);
free(conn->initiator);
free(conn->user);
free(conn);
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int devn;
int ctlfd = -1;
int err;
- struct iscsi_kern_register_info reg = { 0 };
+ struct iscsi_kern_register_info reg;
if (!(f = fopen("/proc/devices", "r"))) {
err = -errno;
goto out_err;
}
+ memset(®, 0, sizeof(reg));
reg.version = (uintptr_t)ISCSI_SCST_INTERFACE_VERSION;
err = ioctl(ctlfd, REGISTER_USERD, ®);
- if (err < 0) {
+ if (err != 0) {
err = -errno;
log_error("Unable to register: %s. Incompatible version of the "
"kernel module?\n", strerror(errno));
goto out_close;
} else {
log_debug(0, "MAX_DATA_SEG_LEN %d", err);
- *max_data_seg_len = err;
+ *max_data_seg_len = reg.max_data_seg_len;
}
out:
goto out;
}
-int kernel_target_create(u32 *tid, char *name)
+int kernel_target_create(struct target *target, u32 *tid, u32 cookie)
{
- int err;
+ int err, i, j;
struct iscsi_kern_target_info info;
+ struct iscsi_user *user;
+ struct iscsi_kern_attr *kern_attrs;
memset(&info, 0, sizeof(info));
+ strlcpy(info.name, target->name, sizeof(info.name));
+ info.tid = (tid != NULL) ? *tid : 0;
+ info.cookie = cookie;
+
+ for (j = 0; j < session_key_last; j++) {
+ if (session_keys[j].show_in_sysfs)
+ info.attrs_num++;;
+ }
+ for (j = 0; j < target_key_last; j++) {
+ if (target_keys[j].show_in_sysfs)
+ info.attrs_num++;;
+ }
+ list_for_each_entry(user, &target->target_in_accounts, ulist) {
+ info.attrs_num++;
+ }
+ list_for_each_entry(user, &target->target_out_accounts, ulist) {
+ info.attrs_num++;
+ }
+
+ kern_attrs = calloc(info.attrs_num, sizeof(*kern_attrs));
+ if (kern_attrs == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
+ info.attrs_ptr = (unsigned long)kern_attrs;
+
+ i = 0;
+ for (j = 0; j < session_key_last; j++) {
+ if (!session_keys[j].show_in_sysfs)
+ continue;
+ kern_attrs[i].mode = 0644;
+ strlcpy(kern_attrs[i].name, session_keys[j].name,
+ sizeof(kern_attrs[i].name));
+ i++;
+ }
+ for (j = 0; j < target_key_last; j++) {
+ if (!target_keys[j].show_in_sysfs)
+ continue;
+ kern_attrs[i].mode = 0644;
+ strlcpy(kern_attrs[i].name, target_keys[j].name,
+ sizeof(kern_attrs[i].name));
+ i++;
+ }
+ list_for_each_entry(user, &target->target_in_accounts, ulist) {
+ kern_attrs[i].mode = 0600;
+ strlcpy(kern_attrs[i].name, user->sysfs_name,
+ sizeof(kern_attrs[i].name));
+ i++;
+ }
+ list_for_each_entry(user, &target->target_out_accounts, ulist) {
+ kern_attrs[i].mode = 0600;
+ strlcpy(kern_attrs[i].name, user->sysfs_name,
+ sizeof(kern_attrs[i].name));
+ i++;
+ }
+
+ log_debug(1, "Adding target %s (attrs_num %d)", target->name,
+ info.attrs_num);
- memcpy(info.name, name, sizeof(info.name) - 1);
- info.tid = *tid;
if ((err = ioctl(ctrl_fd, ADD_TARGET, &info)) < 0) {
err = -errno;
- log_error("Can't create target %u: %s\n", *tid,
+ log_error("Can't create target %s: %s\n", target->name,
strerror(errno));
- } else
- *tid = info.tid;
+ } else {
+ target->tid = err;
+ if (tid != NULL)
+ *tid = err;
+ err = 0;
+ }
+ free(kern_attrs);
+
+out:
return err;
}
-int kernel_target_destroy(u32 tid)
+int kernel_target_destroy(u32 tid, u32 cookie)
{
struct iscsi_kern_target_info info;
int res;
memset(&info, 0, sizeof(info));
info.tid = tid;
+ info.cookie = cookie;
res = ioctl(ctrl_fd, DEL_TARGET, &info);
if (res < 0) {
return res;
}
+#ifndef CONFIG_SCST_PROC
+
+int kernel_attr_add(struct target *target, const char *name, u32 mode,
+ u32 cookie)
+{
+ struct iscsi_kern_attr_info info;
+ int res;
+
+ memset(&info, 0, sizeof(info));
+ if (target != NULL)
+ info.tid = target->tid;
+ info.cookie = cookie;
+
+ info.attr.mode = mode;
+ strlcpy(info.attr.name, name, sizeof(info.attr.name));
+
+ res = ioctl(ctrl_fd, ISCSI_ATTR_ADD, &info);
+ if (res < 0)
+ res = -errno;
+
+ return res;
+}
+
+int kernel_attr_del(struct target *target, const char *name, u32 cookie)
+{
+ struct iscsi_kern_attr_info info;
+ int res;
+
+ memset(&info, 0, sizeof(info));
+ if (target != NULL)
+ info.tid = target->tid;
+ info.cookie = cookie;
+
+ strlcpy(info.attr.name, name, sizeof(info.attr.name));
+
+ res = ioctl(ctrl_fd, ISCSI_ATTR_DEL, &info);
+ if (res < 0)
+ res = -errno;
+
+ return res;
+}
+
+static int __kernel_user_cmd(struct iscsi_user *user, u32 cookie, unsigned int cmd)
+{
+ struct iscsi_kern_attr_info info;
+ int res;
+
+ memset(&info, 0, sizeof(info));
+ if (user->target != NULL)
+ info.tid = user->target->tid;
+ info.cookie = cookie;
+
+ info.attr.mode = 0600;
+ strlcpy(info.attr.name, user->sysfs_name, sizeof(info.attr.name));
+
+ res = ioctl(ctrl_fd, cmd, &info);
+ if (res < 0)
+ res = -errno;
+
+ return res;
+}
+
+int kernel_user_add(struct iscsi_user *user, u32 cookie)
+{
+ int res;
+ res = __kernel_user_cmd(user, cookie, ISCSI_ATTR_ADD);
+ if (res != 0)
+ log_error("Can't add user %s (%d)\n", user->name, res);
+ return res;
+}
+
+int kernel_user_del(struct iscsi_user *user, u32 cookie)
+{
+ int res;
+ res = __kernel_user_cmd(user, cookie, ISCSI_ATTR_DEL);
+ if (res != 0)
+ log_error("Can't del user %s (%d)\n", user->name, res);
+ return res;
+}
+
+#endif /* CONFIG_SCST_PROC */
+
int kernel_conn_destroy(u32 tid, u64 sid, u32 cid)
{
int err;
return err;
}
-int kernel_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param)
+int kernel_params_get(u32 tid, u64 sid, int type, struct iscsi_param *params)
{
int err, i;
- struct iscsi_kern_param_info info;
+ struct iscsi_kern_params_info info;
+
+ if (sid == 0) {
+ log_error("kernel_params_get(): sid must be not %d", 0);
+ err = -EINVAL;
+ goto out;
+ }
memset(&info, 0, sizeof(info));
info.tid = tid;
info.sid = sid;
- info.param_type = type;
+ info.params_type = type;
if ((err = ioctl(ctrl_fd, ISCSI_PARAM_GET, &info)) < 0) {
err = -errno;
- log_debug(1, "Can't get session param for session 0x%" PRIu64
+ log_debug(1, "Can't get session params for session 0x%" PRIu64
" (tid %u, err %d): %s\n", sid, tid, err, strerror(errno));
}
if (type == key_session)
for (i = 0; i < session_key_last; i++)
- param[i].val = info.session_param[i];
+ params[i].val = info.session_params[i];
else
for (i = 0; i < target_key_last; i++)
- param[i].val = info.target_param[i];
+ params[i].val = info.target_params[i];
+out:
return err;
}
-int kernel_param_set(u32 tid, u64 sid, int type, u32 partial,
- struct iscsi_param *param)
+int kernel_params_set(u32 tid, u64 sid, int type, u32 partial,
+ const struct iscsi_param *params)
{
int i, err;
- struct iscsi_kern_param_info info;
+ struct iscsi_kern_params_info info;
+
+ if (sid == 0) {
+ log_error("kernel_params_set(): sid must be not %d", 0);
+ err = -EINVAL;
+ goto out;
+ }
memset(&info, 0, sizeof(info));
info.tid = tid;
info.sid = sid;
- info.param_type = type;
+ info.params_type = type;
info.partial = partial;
- if (info.param_type == key_session)
+ if (info.params_type == key_session)
for (i = 0; i < session_key_last; i++)
- info.session_param[i] = param[i].val;
+ info.session_params[i] = params[i].val;
else
for (i = 0; i < target_key_last; i++)
- info.target_param[i] = param[i].val;
+ info.target_params[i] = params[i].val;
if ((err = ioctl(ctrl_fd, ISCSI_PARAM_SET, &info)) < 0) {
err = -errno;
- log_error("Can't set session param for session 0x%" PRIu64
+ log_error("Can't set session params for session 0x%" PRIu64
" (tid %u, type %d, partial %d, err %d): %s\n", sid,
tid, type, partial, err, strerror(errno));
}
+out:
return err;
}
-int kernel_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
- char *name, char *user)
+int kernel_session_create(struct connection *conn)
{
struct iscsi_kern_session_info info;
- int res;
+ int res, i;
+ struct target *target;
memset(&info, 0, sizeof(info));
- info.tid = tid;
- info.sid = sid;
- info.exp_cmd_sn = exp_cmd_sn;
- strncpy(info.initiator_name, name, sizeof(info.initiator_name) - 1);
- strncpy(info.user_name, user, sizeof(info.user_name) - 1);
+ info.tid = conn->tid;
+ info.sid = conn->sess->sid.id64;
+ info.exp_cmd_sn = conn->exp_cmd_sn;
+ strlcpy(info.initiator_name, conn->sess->initiator, sizeof(info.initiator_name));
+
+#ifdef CONFIG_SCST_PROC
+ if (conn->user != NULL)
+ strlcpy(info.user_name, conn->user, sizeof(info.user_name));
+ else
+ info.user_name[0] = '\0';
+#endif
+
+ target = target_find_by_id(conn->tid);
+ if (target == NULL) {
+ log_error("Target %d not found", conn->tid);
+ res = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < session_key_last; i++)
+ info.session_params[i] = conn->session_params[i].val;
+
+ for (i = 0; i < target_key_last; i++)
+ info.target_params[i] = target->target_params[i];
res = ioctl(ctrl_fd, ADD_SESSION, &info);
if (res < 0) {
res = -errno;
log_error("Can't create sess 0x%" PRIu64 " (tid %d, "
- "initiator %s): %s\n", sid, tid, name, strerror(errno));
+ "initiator %s): %s\n", conn->sess->sid.id64, conn->tid,
+ conn->sess->initiator, strerror(errno));
}
+out:
return res;
}
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
+#include <ctype.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
+#include <scst_const.h>
+
#include "iscsid.h"
+#define ISCSI_ISNS_SYSFS_ACCESS_CONTROL_ENABLED "AccessControl"
+
static struct sockaddr_nl src_addr, dest_addr;
static int nl_write(int fd, void *data, int len)
struct iovec iov[2];
struct msghdr msg;
struct nlmsghdr nlh;
+ int res;
iov[0].iov_base = &nlh;
iov[0].iov_len = sizeof(nlh);
msg.msg_iov = iov;
msg.msg_iovlen = 2;
- return recvmsg(fd, &msg, MSG_DONTWAIT);
+ res = recvmsg(fd, &msg, iscsi_enabled ? MSG_DONTWAIT : 0);
+ if (res > 0) {
+ res -= sizeof(nlh);
+ if (res < 0)
+ res = -EPIPE;
+ }
+
+ return res;
+}
+
+#ifndef CONFIG_SCST_PROC
+
+static int send_mgmt_cmd_res(u32 tid, u32 cookie, u32 req_cmd, int result,
+ const char *res_str)
+{
+ struct iscsi_kern_mgmt_cmd_res_info cinfo;
+ int res;
+
+ memset(&cinfo, 0, sizeof(cinfo));
+ cinfo.tid = tid;
+ cinfo.cookie = cookie;
+ cinfo.req_cmd = req_cmd;
+ cinfo.result = result;
+
+ if (res_str != NULL)
+ strlcpy(cinfo.value, res_str, sizeof(cinfo.value));
+
+ log_debug(1, "Sending result %d (cookie %d)", result, cookie);
+
+ res = ioctl(ctrl_fd, MGMT_CMD_CALLBACK, &cinfo);
+ if (res != 0) {
+ log_error("Can't send mgmt reply (cookie %d, result %d, "
+ "res %d): %s\n", cookie, result, res, strerror(errno));
+ }
+
+ return res;
+}
+
+static int handle_e_add_target(int fd, const struct iscsi_kern_event *event)
+{
+ int res, rc;
+ char *buf;
+ int size, offs;
+
+ if (event->param1_size == 0) {
+ log_error("Incorrect E_ADD_TARGET: %s", "Target name expected");
+ res = -EINVAL;
+ goto out;
+ }
+
+ /* Params are not 0-terminated */
+
+ size = strlen("Target ") + event->param1_size + 2 + event->param2_size + 1;
+
+ buf = malloc(size);
+ if (buf == NULL) {
+ log_error("Unable to allocate tmp buffer (size %d)", size);
+ res = -ENOMEM;
+ goto out;
+ }
+
+ offs = sprintf(buf, "Target ");
+
+ while (1) {
+ if ((rc = nl_read(fd, &buf[offs], event->param1_size)) < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ log_error("read netlink fd (%d) failed: %s", fd,
+ strerror(errno));
+ send_mgmt_cmd_res(0, event->cookie, E_ADD_TARGET, -errno, NULL);
+ exit(1);
+ }
+ break;
+ }
+
+ offs += rc;
+ offs += sprintf(&buf[offs], "; ");
+
+ if (event->param2_size > 0) {
+ while (1) {
+ if ((rc = nl_read(fd, &buf[offs], event->param2_size)) < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ log_error("read netlink fd (%d) failed: %s", fd,
+ strerror(errno));
+ send_mgmt_cmd_res(0, event->cookie, E_ADD_TARGET, -errno, NULL);
+ exit(1);
+ }
+ break;
+ }
+ offs += rc;
+ }
+
+ buf[offs] = '\0';
+
+ log_debug(1, "Going to parse %s", buf);
+
+ res = config_parse_main(buf, event->cookie);
+ if (res != 0)
+ goto out_free;
+
+out_free:
+ free(buf);
+
+out:
+ return res;
+}
+
+static int handle_e_del_target(int fd, const struct iscsi_kern_event *event)
+{
+ int res;
+
+ log_debug(2, "Going to delete target %d", event->tid);
+
+ res = target_del(event->tid, event->cookie);
+ return res;
+}
+
+static int handle_add_user(struct target *target, int dir, char *sysfs_name,
+ char *p, u32 cookie)
+{
+ int res;
+ char *name, *pass;
+
+ name = config_sep_string(&p);
+ pass = config_sep_string(&p);
+
+ res = __config_account_add(target, dir, name, pass, sysfs_name, 1, cookie);
+
+ return res;
+}
+
+static int handle_add_param(struct target *target, char *p, u32 cookie)
+{
+ int res, dir;
+ char *pp;
+
+ pp = config_sep_string(&p);
+ dir = params_index_by_name_numwild(pp, user_keys);
+ if (dir >= 0)
+ res = handle_add_user(target, dir, pp, p, cookie);
+ else {
+ log_error("Syntax error at %s", pp);
+ res = -EINVAL;
+ goto out;
+ }
+
+out:
+ return res;
+}
+
+static int handle_del_user(struct target *target, int dir, char *p, u32 cookie)
+{
+ int res;
+ char *name;
+
+ name = config_sep_string(&p);
+
+ res = config_account_del((target != NULL) ? target->tid : 0, dir,
+ name, cookie);
+
+ return res;
+}
+
+static int handle_del_param(struct target *target, char *p, u32 cookie)
+{
+ int res, dir;
+ char *pp;
+
+ pp = config_sep_string(&p);
+ dir = params_index_by_name_numwild(pp, user_keys);
+ if (dir >= 0)
+ res = handle_del_user(target, dir, p, cookie);
+ else {
+ log_error("Syntax error at %s", pp);
+ res = -EINVAL;
+ goto out;
+ }
+
+out:
+ return res;
+}
+
+static int handle_e_mgmt_cmd(int fd, const struct iscsi_kern_event *event)
+{
+ int res, rc;
+ char *buf, *p, *pp;
+ int size;
+
+ if (event->param1_size == 0) {
+ log_error("Incorrect E_MGMT_CMD: %s", "command expected");
+ res = -EINVAL;
+ goto out;
+ }
+
+ /* Params are not 0-terminated */
+
+ size = event->param1_size + 1;
+
+ buf = malloc(size);
+ if (buf == NULL) {
+ log_error("Unable to allocate tmp buffer (size %d)", size);
+ res = -ENOMEM;
+ goto out;
+ }
+
+ while (1) {
+ if ((rc = nl_read(fd, buf, event->param1_size)) < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ log_error("read netlink fd (%d) failed: %s", fd,
+ strerror(errno));
+ send_mgmt_cmd_res(0, event->cookie, E_MGMT_CMD, -errno, NULL);
+ exit(1);
+ }
+ break;
+ }
+
+ buf[rc] = '\0';
+
+ log_debug(1, "Going to parse %s", buf);
+
+ p = buf;
+ pp = config_sep_string(&p);
+ if (strcasecmp("add_attribute", pp) == 0) {
+ res = handle_add_param(NULL, p, event->cookie);
+ } else if (strcasecmp("add_target_attribute", pp) == 0) {
+ struct target *target;
+ pp = config_sep_string(&p);
+ target = target_find_by_name(pp);
+ if (target == NULL) {
+ log_error("Target %s not found", pp);
+ res = -ENOENT;
+ goto out_free;
+ }
+ res = handle_add_param(target, p, event->cookie);
+ } else if (strcasecmp("del_attribute", pp) == 0) {
+ res = handle_del_param(NULL, p, event->cookie);
+ } else if (strcasecmp("del_target_parameter", pp) == 0) {
+ struct target *target;
+ pp = config_sep_string(&p);
+ target = target_find_by_name(pp);
+ if (target == NULL) {
+ log_error("Target %s not found", pp);
+ res = -ENOENT;
+ goto out_free;
+ }
+ res = handle_del_param(target, p, event->cookie);
+ } else {
+ log_error("Syntax error at %s", p);
+ res = -EINVAL;
+ }
+
+out_free:
+ free(buf);
+
+out:
+ return res;
+}
+
+static void add_key_mark(char *res_str, int res_str_len, int new_line)
+{
+ int offs = strlen(res_str);
+ snprintf(&res_str[offs], res_str_len - offs, "%s%s\n",
+ new_line ? "\n" : "", SCST_SYSFS_KEY_MARK);
+ return;
+}
+
+static int handle_e_get_attr_value(int fd, const struct iscsi_kern_event *event)
+{
+ int res = 0, rc, idx;
+ char *buf, *p, *pp;
+ int size;
+ struct target *target;
+ char res_str[ISCSI_MAX_ATTR_VALUE_LEN];
+
+ memset(res_str, 0, sizeof(res_str));
+
+ if (event->param1_size == 0) {
+ log_error("Incorrect E_GET_ATTR_VALUE: %s", "attr name expected");
+ res = -EINVAL;
+ goto out;
+ }
+
+ /* Params are not 0-terminated */
+
+ size = event->param1_size + 1;
+
+ buf = malloc(size);
+ if (buf == NULL) {
+ log_error("Unable to allocate tmp buffer (size %d)", size);
+ res = -ENOMEM;
+ goto out;
+ }
+
+ while (1) {
+ if ((rc = nl_read(fd, buf, event->param1_size)) < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ log_error("read netlink fd (%d) failed: %s", fd,
+ strerror(errno));
+ send_mgmt_cmd_res(0, event->cookie, E_GET_ATTR_VALUE, -errno, NULL);
+ exit(1);
+ }
+ break;
+ }
+
+ buf[rc] = '\0';
+
+ log_debug(1, "Going to parse name %s", buf);
+
+ target = target_find_by_id(event->tid);
+
+ p = buf;
+ pp = config_sep_string(&p);
+ if (!((idx = params_index_by_name(pp, target_keys)) < 0)) {
+ if (target == NULL) {
+ log_error("Target expected for attr %s", pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ params_val_to_str(target_keys, idx, target->target_params[idx],
+ res_str, sizeof(res_str));
+
+ if (target->target_params[idx] != target_keys[idx].local_def)
+ add_key_mark(res_str, sizeof(res_str), 1);
+ } else if (!((idx = params_index_by_name(pp, session_keys)) < 0)) {
+ if (target == NULL) {
+ log_error("Target expected for attr %s", pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ params_val_to_str(session_keys, idx, target->session_params[idx],
+ res_str, sizeof(res_str));
+
+ if (target->session_params[idx] != session_keys[idx].local_def)
+ add_key_mark(res_str, sizeof(res_str), 1);
+ } else if (!((idx = params_index_by_name_numwild(pp, user_keys)) < 0)) {
+ struct iscsi_user *user;
+
+ user = account_lookup_by_sysfs_name(target, idx, pp);
+ if (user == NULL) {
+ log_error("Unknown user attribute %s", pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ snprintf(res_str, sizeof(res_str), "%s %s\n", user->name,
+ user->password);
+ add_key_mark(res_str, sizeof(res_str), 0);
+ } else if (strcasecmp(ISCSI_ENABLED_ATTR_NAME, pp) == 0) {
+ if (target != NULL) {
+ log_error("Not NULL target %s for global attribute %s",
+ target->name, pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ snprintf(res_str, sizeof(res_str), "%d\n", iscsi_enabled);
+ } else if (strcasecmp(ISCSI_ISNS_SERVER_PARAM_NAME, pp) == 0) {
+ if (target != NULL) {
+ log_error("Not NULL target %s for global attribute %s",
+ target->name, pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ if (isns_server != NULL) {
+ snprintf(res_str, sizeof(res_str), "%s %s\n", isns_server,
+ isns_access_control ? ISCSI_ISNS_SYSFS_ACCESS_CONTROL_ENABLED : "");
+ add_key_mark(res_str, sizeof(res_str), 0);
+ } else
+ snprintf(res_str, sizeof(res_str), "%s\n", "");
+ } else {
+ log_error("Unknown attribute %s", pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ send_mgmt_cmd_res(event->tid, event->cookie, E_GET_ATTR_VALUE, 0, res_str);
+
+out_free:
+ free(buf);
+
+out:
+ return res;
}
+static int handle_e_set_attr_value(int fd, const struct iscsi_kern_event *event)
+{
+ int res = 0, rc, idx;
+ char *buf, *p, *pp, *n;
+ struct target *target;
+ int size, offs;
+ u32 val;
+
+ if (event->param1_size == 0) {
+ log_error("Incorrect E_SET_ATTR_VALUE: %s", "attr name expected");
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (event->param2_size == 0) {
+ log_error("Incorrect E_SET_ATTR_VALUE: %s", "attr value expected");
+ res = -EINVAL;
+ goto out;
+ }
+
+ /* Params are not 0-terminated */
+ size = event->param1_size + 1 + 1 + event->param2_size + 1;
+
+ buf = malloc(size);
+ if (buf == NULL) {
+ log_error("Unable to allocate tmp buffer (size %d)", size);
+ res = -ENOMEM;
+ goto out;
+ }
+
+ while (1) {
+ if ((rc = nl_read(fd, buf, event->param1_size)) < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ log_error("read netlink fd (%d) failed: %s", fd,
+ strerror(errno));
+ send_mgmt_cmd_res(0, event->cookie, E_SET_ATTR_VALUE, -errno, NULL);
+ exit(1);
+ }
+ break;
+ }
+
+ offs = rc;
+ offs += sprintf(&buf[offs], " ");
+
+ while (1) {
+ if ((rc = nl_read(fd, &buf[offs], event->param2_size)) < 0) {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+ log_error("read netlink fd (%d) failed: %s", fd,
+ strerror(errno));
+ send_mgmt_cmd_res(0, event->cookie, E_SET_ATTR_VALUE, -errno, NULL);
+ exit(1);
+ }
+ break;
+ }
+
+ offs += rc;
+ buf[offs] = '\0';
+
+ log_debug(1, "Going to parse %s", buf);
+
+ target = target_find_by_id(event->tid);
+
+ p = buf;
+ pp = config_sep_string(&p);
+ if (!((idx = params_index_by_name(pp, target_keys)) < 0)) {
+ if (target == NULL) {
+ log_error("Target expected for attr %s", pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ pp = config_sep_string(&p);
+
+ n = config_sep_string(&p);
+ if (*n != '\0') {
+ log_error("Unexpected parameter value %s\n", n);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ res = params_str_to_val(target_keys, idx, pp, &val);
+ if (res < 0) {
+ log_error("Wrong value %s for parameter %s\n",
+ pp, target_keys[idx].name);
+ goto out_free;
+ }
+
+ res = params_check_val(target_keys, idx, &val);
+ if (res < 0) {
+ log_error("Wrong value %u for parameter %s\n",
+ val, target_keys[idx].name);
+ goto out_free;
+ }
+
+ target->target_params[idx] = val;
+ } else if (!((idx = params_index_by_name(pp, session_keys)) < 0)) {
+ if (target == NULL) {
+ log_error("Target expected for attr %s", pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ pp = config_sep_string(&p);
+
+ n = config_sep_string(&p);
+ if (*n != '\0') {
+ log_error("Unexpected parameter value %s\n", n);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ res = params_str_to_val(session_keys, idx, pp, &val);
+ if (res < 0) {
+ log_error("Wrong value %s for parameter %s\n",
+ pp, session_keys[idx].name);
+ goto out_free;
+ }
+
+ res = params_check_val(session_keys, idx, &val);
+ if (res < 0) {
+ log_error("Wrong value %u for parameter %s\n",
+ val, session_keys[idx].name);
+ goto out_free;
+ }
+
+ target->session_params[idx] = val;
+ } else if (!((idx = params_index_by_name_numwild(pp, user_keys)) < 0)) {
+ struct iscsi_user *user;
+
+ user = account_lookup_by_sysfs_name(target, idx, pp);
+ if (user == NULL) {
+ log_error("Unknown user attribute %s", pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ res = account_replace(target, idx, pp, p);
+ if (res != 0)
+ goto out_free;
+ } else if (strcasecmp(ISCSI_ENABLED_ATTR_NAME, pp) == 0) {
+ if (target != NULL) {
+ log_error("Not NULL target %s for global attribute %s",
+ target->name, pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ pp = config_sep_string(&p);
+ if (strcmp(pp, "1") == 0)
+ iscsi_enabled = 1;
+ else if (strcmp(pp, "0") == 0)
+ iscsi_enabled = 0;
+ else {
+ log_error("Unknown value %s", pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+ } else if (strcasecmp(ISCSI_ISNS_SERVER_PARAM_NAME, pp) == 0) {
+ if (target != NULL) {
+ log_error("Not NULL target %s for global attribute %s",
+ target->name, pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+ if (isns_server != NULL)
+ isns_exit();
+
+ pp = config_sep_string(&p);
+ if (*pp == '\0') {
+ goto done;
+ }
+
+ isns_access_control = 0;
+ isns_server = strdup(pp);
+ if (isns_server == NULL) {
+ log_error("Unable to dublicate iSNS server name %s", pp);
+ res = -ENOMEM;
+ goto out_free;
+ }
+
+ pp = config_sep_string(&p);
+ if (strcasecmp(ISCSI_ISNS_SYSFS_ACCESS_CONTROL_ENABLED, pp) == 0) {
+ pp = config_sep_string(&p);
+ if (strcasecmp(pp, "No") == 0)
+ isns_access_control = 0;
+ else
+ isns_access_control = 1;
+ } else if (*pp != '\0') {
+ log_error("Unknown parameter %s", pp);
+ res = -EINVAL;
+ goto out_free_server;
+ }
+
+ res = isns_init();
+ if (res == 0) {
+ struct target *t;
+ int rc;
+
+ list_for_each_entry(t, &targets_list, tlist) {
+ rc = isns_target_register(t->name);
+ if (rc < 0) {
+ /*
+ * iSNS server can be temporary not
+ * available.
+ */
+ goto out_free_isns_exit;
+ }
+ }
+ } else
+ goto out_free_server;
+ } else {
+ log_error("Unknown attribute %s", pp);
+ res = -EINVAL;
+ goto out_free;
+ }
+
+done:
+ send_mgmt_cmd_res(event->tid, event->cookie, E_SET_ATTR_VALUE, 0, NULL);
+
+out_free:
+ free(buf);
+
+out:
+ return res;
+
+out_free_isns_exit:
+ isns_exit();
+
+out_free_server:
+ free(isns_server);
+ isns_server = NULL;
+ goto out;
+}
+
+#endif /* CONFIG_SCST_PROC */
+
void handle_iscsi_events(int fd)
{
struct session *session;
struct connection *conn;
struct iscsi_kern_event event;
+#ifndef CONFIG_SCST_PROC
+ struct target *target;
+#endif
int rc;
retry:
return;
if (errno == EINTR)
goto retry;
- log_error("read netlink fd (%d)", errno);
+ log_error("read netlink fd (%d) failed: %s", fd, strerror(errno));
exit(1);
}
- log_debug(1, "conn %u session %#" PRIx64 " target %u, code %u",
- event.cid, event.sid, event.tid, event.code);
+ log_debug(1, "target %u, session %#" PRIx64 ", conn %u, code %u, cookie %d",
+ event.tid, event.sid, event.cid, event.code, event.cookie);
+
+ /*
+ * Let's always report errors through send_mgmt_cmd_res(). If the error
+ * was returned by the corresponding ioctl(), it will lead to blank
+ * MGMT_CMD_CALLBACK ioctl()'s, but that's OK, because kernel will
+ * not reuse the cookie. Better to have extra return call, than no call
+ * at all.
+ */
switch (event.code) {
- case E_ENABLE_TARGET:
- {
- struct target *target;
- struct iscsi_kern_target_info info;
+#ifndef CONFIG_SCST_PROC
+ case E_ADD_TARGET:
+ rc = handle_e_add_target(fd, &event);
+ if (rc != 0)
+ send_mgmt_cmd_res(event.tid, event.cookie, E_ADD_TARGET, rc, NULL);
+ break;
+
+ case E_DEL_TARGET:
+ rc = handle_e_del_target(fd, &event);
+ if (rc != 0)
+ send_mgmt_cmd_res(event.tid, event.cookie, E_DEL_TARGET, rc, NULL);
+ break;
+
+ case E_MGMT_CMD:
+ rc = handle_e_mgmt_cmd(fd, &event);
+ if (rc != 0)
+ send_mgmt_cmd_res(event.tid, event.cookie, E_MGMT_CMD, rc, NULL);
+ break;
+ case E_ENABLE_TARGET:
target = target_find_by_id(event.tid);
if (target == NULL) {
log_error("Target %d not found", event.tid);
- goto out;
- }
-
- target->tgt_enabled = 1;
-
- memset(&info, 0, sizeof(info));
-
- info.tid = event.tid;
- rc = ioctl(ctrl_fd, ENABLE_TARGET, &info);
- if (rc < 0) {
- log_error("Can't enable target %u: %s\n", event.tid,
- strerror(errno));
- goto out;
- }
+ rc = -ENOENT;
+ } else
+ rc = 0;
+ rc |= send_mgmt_cmd_res(event.tid, event.cookie, E_ENABLE_TARGET, rc, NULL);
+ if (rc == 0)
+ target->tgt_enabled = 1;
break;
- }
case E_DISABLE_TARGET:
- {
- struct target *target;
- struct iscsi_kern_target_info info;
-
target = target_find_by_id(event.tid);
if (target == NULL) {
log_error("Target %d not found", event.tid);
- goto out;
- }
-
- target->tgt_enabled = 0;
+ rc = -ENOENT;
+ } else
+ rc = 0;
+ rc |= send_mgmt_cmd_res(event.tid, event.cookie, E_DISABLE_TARGET, rc, NULL);
+ if (rc == 0)
+ target->tgt_enabled = 0;
+ break;
- memset(&info, 0, sizeof(info));
+ case E_GET_ATTR_VALUE:
+ rc = handle_e_get_attr_value(fd, &event);
+ if (rc != 0)
+ send_mgmt_cmd_res(event.tid, event.cookie, E_GET_ATTR_VALUE, rc, NULL);
+ break;
- info.tid = event.tid;
- rc = ioctl(ctrl_fd, DISABLE_TARGET, &info);
- if (rc < 0) {
- log_error("Can't disable target %u: %s\n", event.tid,
- strerror(errno));
- goto out;
- }
+ case E_SET_ATTR_VALUE:
+ rc = handle_e_set_attr_value(fd, &event);
+ if (rc != 0)
+ send_mgmt_cmd_res(event.tid, event.cookie, E_SET_ATTR_VALUE, rc, NULL);
break;
- }
+#endif /* CONFIG_SCST_PROC */
case E_CONN_CLOSE:
session = session_find_id(event.tid, event.sid);
break;
}
-out:
return;
}
return err;
}
-static void show_iscsi_param(int type, struct iscsi_param *param)
+static void show_iscsi_params(int type, struct iscsi_param *param)
{
- int i, nr;
+ int i, nr, len;
char buf[1024], *p;
struct iscsi_key *keys;
for (i = 0; i < nr; i++) {
memset(buf, 0, sizeof(buf));
- strcpy(buf, keys[i].name);
- p = buf + strlen(buf);
+ strlcpy(buf, keys[i].name, sizeof(buf));
+ len = strlen(buf);
+ p = buf + len;
*p++ = '=';
- param_val_to_str(keys, i, param[i].val, p);
+ params_val_to_str(keys, i, param[i].val, p, sizeof(buf) - (len + 1));
printf("%s\n", buf);
}
}
continue;
*q++ = '\0';
- if (!((idx = param_index_by_name(p, target_keys)) < 0)) {
- if (param_str_to_val(target_keys, idx, q, &val)) {
+ if (!((idx = params_index_by_name(p, target_keys)) < 0)) {
+ if (params_str_to_val(target_keys, idx, q, &val)) {
fprintf(stderr,
"Invalid %s value \"%s\".\n",
target_keys[idx].name, q);
return -EINVAL;
}
- if (!param_check_val(target_keys, idx, &val))
+ if (!params_check_val(target_keys, idx, &val))
msg->target_partial |= (1 << idx);
- msg->target_param[idx].val = val;
+ msg->target_params[idx].val = val;
msg->type |= 1 << key_target;
continue;
}
- if (!((idx = param_index_by_name(p, session_keys)) < 0)) {
- if (param_str_to_val(session_keys, idx, q, &val)) {
+ if (!((idx = params_index_by_name(p, session_keys)) < 0)) {
+ if (params_str_to_val(session_keys, idx, q, &val)) {
fprintf(stderr,
"Invalid %s value \"%s\".\n",
session_keys[idx].name, q);
return -EINVAL;
}
- if (!param_check_val(session_keys, idx, &val))
+ if (!params_check_val(session_keys, idx, &val))
msg->session_partial |= (1 << idx);
- msg->session_param[idx].val = val;
+ msg->session_params[idx].val = val;
msg->type |= 1 << key_session;
continue;
goto out;
}
req.rcmnd = C_TRGT_NEW;
- strncpy(req.u.trgt.name, p, sizeof(req.u.trgt.name) - 1);
+ strlcpy(req.u.trgt.name, p, sizeof(req.u.trgt.name));
break;
}
case OP_DELETE:
err = iscsid_request(&req, NULL, 0);
if (!err && req.rcmnd == C_TRGT_SHOW)
- show_iscsi_param(key_target, req.u.trgt.target_param);
+ show_iscsi_params(key_target, req.u.trgt.target_params);
out:
return err;
req.rcmnd = C_SESS_SHOW;
err = iscsid_request(&req, NULL, 0);
if (!err)
- show_iscsi_param(key_session, req.u.trgt.session_param);
+ show_iscsi_params(key_session, req.u.trgt.session_params);
break;
}
"Already specified IncomingUser %s\n",
q);
*user = q;
- *auth_dir = AUTH_DIR_INCOMING;
+ *auth_dir = ISCSI_USER_DIR_INCOMING;
} else if (!strcasecmp(p, "OutgoingUser")) {
if (*user)
fprintf(stderr,
"Already specified OutgoingUser %s\n",
q);
*user = q;
- *auth_dir = AUTH_DIR_OUTGOING;
+ *auth_dir = ISCSI_USER_DIR_OUTGOING;
} else if (!strcasecmp(p, "Password")) {
if (*pass)
fprintf(stderr,
if (pass)
snprintf(buf + strlen(buf), ISCSI_NAME_LEN, " %s", pass);
- printf("%sUser %s\n", (auth_dir == AUTH_DIR_INCOMING) ?
+ printf("%sUser %s\n", (auth_dir == ISCSI_USER_DIR_INCOMING) ?
"Incoming" : "Outgoing", buf);
}
int err;
req->rcmnd = C_ACCT_SHOW;
- strncpy(req->u.acnt.u.user.name, user,
- sizeof(req->u.acnt.u.user.name) - 1);
+ strlcpy(req->u.acnt.u.user.name, user, sizeof(req->u.acnt.u.user.name));
err = iscsid_request(req, NULL, 0);
if (!err)
size_t buf_sz = 0;
char *buf;
- req->u.acnt.auth_dir = AUTH_DIR_INCOMING;
+ req->u.acnt.auth_dir = ISCSI_USER_DIR_INCOMING;
req->rcmnd = C_ACCT_LIST;
do {
show_account(req->u.acnt.auth_dir,
&buf[i * ISCSI_NAME_LEN], NULL);
- if (req->u.acnt.auth_dir == AUTH_DIR_INCOMING) {
- req->u.acnt.auth_dir = AUTH_DIR_OUTGOING;
+ if (req->u.acnt.auth_dir == ISCSI_USER_DIR_INCOMING) {
+ req->u.acnt.auth_dir = ISCSI_USER_DIR_OUTGOING;
buf_sz = 0;
retry = 1;
}
req->rcmnd = C_ACCT_NEW;
- strncpy(req->u.acnt.u.user.name, user,
- sizeof(req->u.acnt.u.user.name) - 1);
- strncpy(req->u.acnt.u.user.pass, pass,
- sizeof(req->u.acnt.u.user.pass) - 1);
+ strlcpy(req->u.acnt.u.user.name, user, sizeof(req->u.acnt.u.user.name));
+ strlcpy(req->u.acnt.u.user.pass, pass, sizeof(req->u.acnt.u.user.pass));
return iscsid_request(req, NULL, 0);
}
req->rcmnd = C_ACCT_DEL;
- strncpy(req->u.acnt.u.user.name, user,
- sizeof(req->u.acnt.u.user.name) - 1);
+ strlcpy(req->u.acnt.u.user.name, user, sizeof(req->u.acnt.u.user.name));
return iscsid_request(req, NULL, 0);
}
u32 type;
u32 session_partial;
u32 target_partial;
- struct iscsi_param session_param[session_key_last];
- struct iscsi_param target_param[target_key_last];
+ struct iscsi_param session_params[session_key_last];
+ struct iscsi_param target_params[target_key_last];
};
struct msg_acnt {
return;
}
-static void event_loop(int timeout)
+static void event_loop(void)
{
int res, i;
close(init_report_pipe[1]);
while (1) {
- res = poll(poll_array, POLL_MAX, timeout);
+ if (!iscsi_enabled) {
+ handle_iscsi_events(nl_fd);
+ continue;
+ }
+ res = poll(poll_array, POLL_MAX, isns_timeout);
if (res == 0) {
- isns_handle(1, &timeout);
+ isns_handle(1);
continue;
} else if (res < 0) {
if (errno == EINTR)
iscsi_adm_request_handle(ipc_fd);
if (poll_array[POLL_ISNS].revents)
- isns_handle(0, &timeout);
+ isns_handle(0);
if (poll_array[POLL_SCN_LISTEN].revents)
isns_scn_handle(1);
}
}
-void init_max_data_seg_len(int max_data_seg_len)
+static void init_max_data_seg_len(int max_data_seg_len)
{
if ((session_keys[key_max_recv_data_length].local_def != -1) ||
(session_keys[key_max_recv_data_length].max != -1) ||
int main(int argc, char **argv)
{
- int ch, longindex, timeout = -1;
+ int ch, longindex;
char *config = NULL;
uid_t uid = 0;
gid_t gid = 0;
- char *isns = NULL;
- int isns_ac = 0;
int max_data_seg_len = -1;
+ int err;
+
+#ifdef CONFIG_SCST_PROC
+ iscsi_enabled = 1;
+#endif
if (pipe(init_report_pipe) == -1) {
perror("pipe failed");
init_max_data_seg_len(max_data_seg_len);
+#ifndef CONFIG_SCST_PROC
+ err = kernel_attr_add(NULL, ISCSI_ISNS_SERVER_PARAM_NAME,
+ S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR, 0);
+ if (err != 0)
+ exit(err);
+
+ err = kernel_attr_add(NULL, ISCSI_ENABLED_ATTR_NAME,
+ S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR, 0);
+ if (err != 0)
+ exit(err);
+#endif
+
if ((ipc_fd = iscsi_adm_request_listen()) < 0) {
perror("ipc failed\n");
exit(-1);
setsid();
}
- config_isns_load(config, &isns, &isns_ac);
- if (isns)
- timeout = isns_init(isns, isns_ac);
-
- if (config_load(config) != 0)
+ err = config_load(config);
+ if (err != 0)
exit(1);
if (gid && setgid(gid) < 0)
if (uid && setuid(uid) < 0)
perror("setuid failed");
- event_loop(timeout);
+ event_loop();
return 0;
}
#include "iscsid.h"
+int iscsi_enabled;
+
static u32 ttt;
static u32 get_next_ttt(struct connection *conn __attribute__((unused)))
{"InitiatorAlias",},
{"SessionType",},
{"TargetName",},
- {NULL, 0, 0, 0, 0, NULL},
+ {NULL,},
};
char *text_key_find(struct connection *conn, char *searchKey)
datasize--;
if (keylen == value - key - 1
- && !strncmp(key, searchKey, keylen))
+ && !strncasecmp(key, searchKey, keylen))
return value;
}
}
return seg;
}
-void text_key_add(struct connection *conn, char *key, char *value)
+void text_key_add(struct connection *conn, char *key, const char *value)
{
struct buf_segment *seg;
int keylen = strlen(key);
size_t data_sz;
data_sz = (conn->state == STATE_FULL) ?
- conn->session_param[key_max_xmit_data_length].val :
+ conn->session_params[key_max_xmit_data_length].val :
INCOMING_BUFSIZE;
seg = list_empty(&conn->rsp_buf_list) ? NULL :
text_key_add(conn, key, "Reject");
}
-static int account_empty(u32 tid, int dir)
-{
- char pass[ISCSI_NAME_LEN];
-
- memset(pass, 0, sizeof(pass));
- return config_account_query(tid, dir, pass, pass) < 0 ? 1 : 0;
-}
-
static void text_scan_security(struct connection *conn)
{
struct iscsi_login_rsp_hdr *rsp = (struct iscsi_login_rsp_hdr *)&conn->rsp.bhs;
datasize = conn->req.datasize;
while ((key = next_key(&data, &datasize, &value))) {
- if (!(param_index_by_name(key, login_keys) < 0))
+ if (!(params_index_by_name(key, login_keys) < 0))
;
else if (!strcmp(key, "AuthMethod")) {
do {
*nextValue++ = 0;
if (!strcmp(value, "None")) {
- if (!account_empty(conn->tid, AUTH_DIR_INCOMING))
+ if (!accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING))
continue;
conn->auth_method = AUTH_NONE;
text_key_add(conn, key, "None");
break;
} else if (!strcmp(value, "CHAP")) {
- if (account_empty(conn->tid, AUTH_DIR_INCOMING))
+ if (accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING))
continue;
conn->auth_method = AUTH_CHAP;
text_key_add(conn, key, "CHAP");
"initiator %s)", conn->cid, conn->tid,
req->sid.id64, conn->initiator);
conn->sess = session;
- insque(&conn->clist, &session->conn_list);
+ list_add_tail(&conn->clist, &session->conn_list);
} else {
log_error("Only a single connection supported "
"(initiator %s)", conn->initiator);
datasize = conn->req.datasize;
while ((key = next_key(&data, &datasize, &value))) {
- if (!(param_index_by_name(key, login_keys) < 0))
+ if (!(params_index_by_name(key, login_keys) < 0))
;
else if (!strcmp(key, "AuthMethod"))
;
- else if (!((idx = param_index_by_name(key, session_keys)) < 0)) {
+ else if (!((idx = params_index_by_name(key, session_keys)) < 0)) {
unsigned int val;
char buf[32];
continue;
}
if (idx == key_max_recv_data_length) {
- conn->session_param[idx].key_state = KEY_STATE_DONE;
+ conn->session_params[idx].key_state = KEY_STATE_DONE;
idx = key_max_xmit_data_length;
};
- if (param_str_to_val(session_keys, idx, value, &val) < 0) {
- if (conn->session_param[idx].key_state == KEY_STATE_START) {
+ if (params_str_to_val(session_keys, idx, value, &val) < 0) {
+ if (conn->session_params[idx].key_state == KEY_STATE_START) {
text_key_add_reject(conn, key);
continue;
} else {
}
}
- param_check_val(session_keys, idx, &val);
- param_set_val(session_keys, conn->session_param, idx, &val);
+ params_check_val(session_keys, idx, &val);
+ params_set_val(session_keys, conn->session_params, idx, &val);
- switch (conn->session_param[idx].key_state) {
+ switch (conn->session_params[idx].key_state) {
case KEY_STATE_START:
if (iscsi_is_key_internal(idx)) {
- conn->session_param[idx].key_state = KEY_STATE_DONE;
+ conn->session_params[idx].key_state = KEY_STATE_DONE;
break;
}
memset(buf, 0, sizeof(buf));
- param_val_to_str(session_keys, idx, val, buf);
+ params_val_to_str(session_keys, idx, val, buf, sizeof(buf));
text_key_add(conn, key, buf);
- conn->session_param[idx].key_state = KEY_STATE_DONE_ADDED;
+ conn->session_params[idx].key_state = KEY_STATE_DONE_ADDED;
break;
case KEY_STATE_REQUEST:
- if (val != conn->session_param[idx].val) {
+ if (val != conn->session_params[idx].val) {
rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
rsp->status_detail = ISCSI_STATUS_INIT_ERR;
conn->state = STATE_EXIT;
log_warning("%s %u %u\n", key,
- val, conn->session_param[idx].val);
+ val, conn->session_params[idx].val);
goto out;
}
- conn->session_param[idx].key_state = KEY_STATE_DONE;
+ conn->session_params[idx].key_state = KEY_STATE_DONE;
break;
case KEY_STATE_DONE_ADDED:
case KEY_STATE_DONE:
return;
}
-static int text_check_param(struct connection *conn)
+static int text_check_params(struct connection *conn)
{
- struct iscsi_param *p = conn->session_param;
+ struct iscsi_param *p = conn->session_params;
char buf[32];
int i, cnt;
if (iscsi_is_key_internal(i))
continue;
memset(buf, 0, sizeof(buf));
- param_val_to_str(session_keys, i, p[i].val, buf);
+ params_val_to_str(session_keys, i, p[i].val, buf, sizeof(buf));
text_key_add(conn, session_keys[i].name, buf);
if (i == key_max_recv_data_length) {
p[i].key_state = KEY_STATE_DONE;
return cnt;
}
+static int init_conn_session_params(struct connection *conn)
+{
+ int res = 0, i;
+ struct target *target;
+
+ target = target_find_by_id(conn->tid);
+ if (target == NULL) {
+ log_error("target %d not found", conn->tid);
+ res = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < session_key_last; i++)
+ conn->session_params[i].val = target->session_params[i];
+
+out:
+ return res;
+}
+
static void login_start(struct connection *conn)
{
struct iscsi_login_req_hdr *req = (struct iscsi_login_req_hdr *)&conn->req.bhs;
conn->session_type = SESSION_NORMAL;
if (session_type) {
- if (!strcmp(session_type, "Discovery"))
+ if (!strcmp(session_type, "Discovery")) {
conn->session_type = SESSION_DISCOVERY;
- else if (strcmp(session_type, "Normal")) {
+ } else if (strcmp(session_type, "Normal")) {
rsp->status_class = ISCSI_STATUS_INITIATOR_ERR;
rsp->status_detail = ISCSI_STATUS_INV_SESSION_TYPE;
conn->state = STATE_EXIT;
}
if (!target->tgt_enabled) {
- log_debug(1, "Connect from %s to disabled target %s",
+ log_info("Connect from %s to disabled target %s refused",
name, target_name);
rsp->status_class = ISCSI_STATUS_TARGET_ERR;
conn->state = STATE_CLOSE;
return;
}
- err = kernel_param_get(conn->tid, conn->sid.id64, key_session,
- conn->session_param);
- if (err == -ENOENT) {
- err = kernel_param_get(conn->tid, 0, key_session,
- conn->session_param);
- }
-
+ err = init_conn_session_params(conn);
if (err != 0) {
- log_error("Can't get session param for session 0x%" PRIu64
+ log_error("Can't get session params for session 0x%" PRIu64
" (err %d): %s\n", conn->sid.id64, err,
strerror(-err));
rsp->status_class = ISCSI_STATUS_TARGET_ERR;
conn->state = STATE_LOGIN;
login_start(conn);
- if (!account_empty(conn->tid, AUTH_DIR_INCOMING))
+ if (!accounts_empty(conn->tid, ISCSI_USER_DIR_INCOMING))
goto auth_err;
if (rsp->status_class)
return;
text_scan_login(conn);
if (rsp->status_class)
return;
- stay = text_check_param(conn);
+ stay = text_check_params(conn);
break;
case STATE_LOGIN:
text_scan_login(conn);
if (rsp->status_class)
return;
- stay = text_check_param(conn);
+ stay = text_check_params(conn);
break;
default:
goto init_err;
switch (conn->state) {
case STATE_SECURITY:
case STATE_SECURITY_DONE:
- if ((nsg_disagree = text_check_param(conn))) {
+ if ((nsg_disagree = text_check_params(conn))) {
conn->state = STATE_LOGIN;
nsg = ISCSI_FLG_NSG_LOGIN;
break;
}
if (!stay && !nsg_disagree) {
int err;
- text_check_param(conn);
+ text_check_params(conn);
err = login_finish(conn);
if (err != 0) {
log_debug(1, "login_finish() failed: %d", err);
struct session *sess;
u32 tid;
- struct iscsi_param session_param[session_key_last];
+
+ /* Put here, because negotiations is done before session created */
+ struct iscsi_param session_params[session_key_last];
char *initiator;
char *user;
#define AUTH_STATE_START 0
#define AUTH_STATE_CHALLENGE 1
-/* don't touch these */
-#define AUTH_DIR_INCOMING 0
-#define AUTH_DIR_OUTGOING 1
-
#define SESSION_NORMAL 0
#define SESSION_DISCOVERY 1
#define AUTH_UNKNOWN -1
*/
#define INCOMING_BUFSIZE 8192
+struct iscsi_user {
+ struct __qelem ulist;
+
+ struct target *target;
+
+#define ISCSI_USER_DIR_INCOMING 0
+#define ISCSI_USER_DIR_OUTGOING 1
+ int direction;
+
+ const char *name;
+ const char *password;
+
+ char sysfs_name[64];
+};
+
struct target {
struct __qelem tlist;
unsigned int tgt_enabled:1;
+ unsigned int target_params[target_key_last];
+ unsigned int session_params[session_key_last];
+
u32 tid;
char name[ISCSI_NAME_LEN];
char *alias;
+ struct __qelem target_in_accounts;
+ struct __qelem target_out_accounts;
+
struct __qelem isns_head;
};
extern void isns_set_fd(int isns, int scn_listen, int scn);
/* iscsid.c */
-extern int iscsi_debug;
+extern int iscsi_enabled;
extern int cmnd_execute(struct connection *conn);
extern void cmnd_finish(struct connection *conn);
extern char *text_key_find(struct connection *conn, char *searchKey);
-extern void text_key_add(struct connection *conn, char *key, char *value);
+extern void text_key_add(struct connection *conn, char *key, const char *value);
/* log.c */
extern int log_daemon;
/* target.c */
extern struct __qelem targets_list;
-extern int target_add(u32 *, char *);
-extern int target_del(u32);
+extern int target_create(const char *name, struct target **out_target);
+extern void target_free(struct target *target);
+extern int target_add(struct target *target, u32 *tid, u32 cookie);
+extern int target_del(u32 tid, u32 cookie);
extern u32 target_find_id_by_name(const char *name);
extern struct target *target_find_by_name(const char *name);
struct target *target_find_by_id(u32);
/* ctldev.c */
extern int kernel_open(int *max_data_seg_len);
-extern int kernel_param_get(u32 tid, u64 sid, int type, struct iscsi_param *param);
-extern int kernel_param_set(u32 tid, u64 sid, int type, u32 partial,
- struct iscsi_param *param);
-extern int kernel_target_create(u32 *tid, char *name);
-extern int kernel_target_destroy(u32 tid);
-extern int kernel_session_create(u32 tid, u64 sid, u32 exp_cmd_sn,
- char *name, char *user);
+extern int kernel_params_get(u32 tid, u64 sid, int type, struct iscsi_param *params);
+extern int kernel_params_set(u32 tid, u64 sid, int type, u32 partial,
+ const struct iscsi_param *params);
+extern int kernel_target_create(struct target *target, u32 *tid, u32 cookie);
+extern int kernel_target_destroy(u32 tid, u32 cookie);
+#ifndef CONFIG_SCST_PROC
+extern int kernel_user_add(struct iscsi_user *user, u32 cookie);
+extern int kernel_user_del(struct iscsi_user *user, u32 cookie);
+extern int kernel_attr_add(struct target *target, const char *name,
+ u32 mode, u32 cookie);
+extern int kernel_attr_del(struct target *target, const char *name, u32 cookie);
+#endif
+extern int kernel_session_create(struct connection *conn);
extern int kernel_session_destroy(u32 tid, u64 sid);
extern int kernel_conn_create(u32 tid, u64 sid, u32 cid, u32 stat_sn, u32 exp_stat_sn,
int fd);
extern void handle_iscsi_events(int fd);
extern int nl_open(void);
-/* param.c */
-extern int param_index_by_name(char *name, struct iscsi_key *keys);
-
/* config.c */
-extern int config_isns_load(char *params, char **isns, int *isns_ac);
-extern int config_load(char *params);
+extern char *config_sep_string(char **pp);
+extern int config_parse_main(const char *data, u32 cookie);
+extern int config_load(const char *config_name);
extern int config_target_create(u32 *tid, char *name);
extern int config_target_destroy(u32 tid);
-int config_account_add(u32 tid, int dir, char *name, char *pass);
-extern int config_account_query(u32 tid, int dir, char *name, char *pass);
+extern int config_account_add(u32 tid, int dir, char *name, char *pass,
+ char *sysfs_name, u32 cookie);
+extern int __config_account_add(struct target *target, int dir, char *name,
+ char *pass, char *sysfs_name, int send_to_kern, u32 cookie);
+extern int config_account_query(u32 tid, int dir, const char *name, char *pass);
extern int config_account_list(u32 tid, int dir, u32 *cnt, u32 *overflow,
char *buf, size_t buf_sz);
-extern int config_account_del(u32 tid, int dir, char *name);
-extern int config_param_set(u32 tid, u64 sid, int type, u32 partial,
- struct iscsi_param *param);
+extern int config_account_del(u32 tid, int dir, char *name, u32 cookie);
+extern int config_params_get(u32 tid, u64 sid, int type, struct iscsi_param *params);
+extern int config_params_set(u32 tid, u64 sid, int type, u32 partial,
+ struct iscsi_param *params);
extern int config_initiator_access(u32 tid, int fd);
+extern int accounts_empty(u32 tid, int dir);
+extern struct iscsi_user *account_get_first(u32 tid, int dir);
+extern struct iscsi_user *account_lookup_by_sysfs_name(struct target *target,
+ int dir, const char *sysfs_name);
+extern int account_replace(struct target *target, int direction,
+ const char *sysfs_name, char *value);
+extern void accounts_free(struct __qelem *accounts_list);
/* isns.c */
-extern int isns_init(char *addr, int isns_ac);
-extern int isns_handle(int is_timeout, int *timeout);
+extern char *isns_server;
+extern int isns_access_control;
+extern int isns_timeout;
+extern int isns_init(void);
+extern int isns_handle(int is_timeout);
extern int isns_scn_handle(int accept);
extern int isns_scn_access(u32 tid, int fd, char *name);
extern int isns_target_register(char *name);
struct __qelem ilist;
};
+char *isns_server;
+int isns_access_control;
+int isns_timeout = -1;
+
static LIST_HEAD(qry_list);
static uint16_t scn_listen_port;
-static int use_isns, use_isns_ac, isns_fd, scn_listen_fd, scn_fd;
+static int isns_fd, scn_listen_fd, scn_fd;
static struct isns_io isns_rx, scn_rx;
static char *rxbuf;
static uint16_t transaction;
struct isns_initiator *ini;
struct target *target = target_find_by_id(tid);
- if (!use_isns || !use_isns_ac)
+ if ((isns_server == NULL) || !isns_access_control)
return 0;
if (!target)
- return -EPERM;
+ return -ENOENT;
list_for_each_entry(ini, &target->isns_head, ilist) {
if (!strcmp(ini->name, name))
{
int fd, err;
+ log_debug(1, "Going to connect to iSNS server %s", isns_server);
+
fd = socket(ss.ss_family, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0) {
log_error("unable to create (%s) %d!", strerror(errno),
ss.ss_family);
- return -1;
+ return -errno;
}
+ /*
+ * ToDo: must be made non-blocking, otherwise for an unreacheable
+ * server it blocks all other events processing until timeout (30 secs).
+ */
err = connect(fd, (struct sockaddr *) &ss, sizeof(ss));
if (err < 0) {
log_error("unable to connect (%s) %d!", strerror(errno),
ss.ss_family);
close(fd);
- return -1;
+ return -errno;
}
log_error("%s %d: new connection %d", __func__, __LINE__, fd);
err = isns_get_ip(fd);
if (err) {
close(fd);
- return -1;
+&n