提交 c3351dfa 编写于 作者: L Linus Torvalds

Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending

Pull SCSI target updates from Nicholas Bellinger:
 "Here are the target updates for v3.18-rc2 code.  These where
  originally destined for -rc1, but due to the combination of travel
  last week for KVM Forum and my mistake of taking the three week merge
  window literally, the pull request slipped..  Apologies for that.

  Things where reasonably quiet this round.  The highlights include:

   - New userspace backend driver (target_core_user.ko) by Shaohua Li
     and Andy Grover
   - A number of cleanups in target, iscsi-taret and qla_target code
     from Joern Engel
   - Fix an OOPs related to queue full handling with CHECK_CONDITION
     status from Quinn Tran
   - Fix to disable TX completion interrupt coalescing in iser-target,
     that was causing problems on some hardware
   - Fix for PR APTPL metadata handling with demo-mode ACLs

  I'm most excited about the new backend driver that uses UIO + shared
  memory ring to dispatch I/O and control commands into user-space.
  This was probably the most requested feature by users over the last
  couple of years, and opens up a new area of development + porting of
  existing user-space storage applications to LIO.  Thanks to Shaohua +
  Andy for making this happen.

  Also another honorable mention, a new Xen PV SCSI driver was merged
  via the xen/tip.git tree recently, which puts us now at 10 target
  drivers in upstream! Thanks to David Vrabel + Juergen Gross for their
  work to get this code merged"

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (40 commits)
  target/file: fix inclusive vfs_fsync_range() end
  iser-target: Disable TX completion interrupt coalescing
  target: Add force_pr_aptpl device attribute
  target: Fix APTPL metadata handling for dynamic MappedLUNs
  qla_target: don't delete changed nacls
  target/user: Recalculate pad size inside is_ring_space_avail()
  tcm_loop: Fixup tag handling
  iser-target: Fix smatch warning
  target/user: Fix up smatch warnings in tcmu_netlink_event
  target: Add a user-passthrough backstore
  target: Add documentation on the target userspace pass-through driver
  uio: Export definition of struct uio_device
  target: Remove unneeded check in sbc_parse_cdb
  target: Fix queue full status NULL pointer for SCF_TRANSPORT_TASK_SENSE
  qla_target: rearrange struct qla_tgt_prm
  qla_target: improve qlt_unmap_sg()
  qla_target: make some global functions static
  qla_target: remove unused parameter
  target: simplify core_tmr_abort_task
  target: encapsulate smp_mb__after_atomic()
  ...
Contents:
1) TCM Userspace Design
a) Background
b) Benefits
c) Design constraints
d) Implementation overview
i. Mailbox
ii. Command ring
iii. Data Area
e) Device discovery
f) Device events
g) Other contingencies
2) Writing a user pass-through handler
a) Discovering and configuring TCMU uio devices
b) Waiting for events on the device(s)
c) Managing the command ring
3) Command filtering and pass_level
4) A final note
TCM Userspace Design
--------------------
TCM is another name for LIO, an in-kernel iSCSI target (server).
Existing TCM targets run in the kernel. TCMU (TCM in Userspace)
allows userspace programs to be written which act as iSCSI targets.
This document describes the design.
The existing kernel provides modules for different SCSI transport
protocols. TCM also modularizes the data storage. There are existing
modules for file, block device, RAM or using another SCSI device as
storage. These are called "backstores" or "storage engines". These
built-in modules are implemented entirely as kernel code.
Background:
In addition to modularizing the transport protocol used for carrying
SCSI commands ("fabrics"), the Linux kernel target, LIO, also modularizes
the actual data storage as well. These are referred to as "backstores"
or "storage engines". The target comes with backstores that allow a
file, a block device, RAM, or another SCSI device to be used for the
local storage needed for the exported SCSI LUN. Like the rest of LIO,
these are implemented entirely as kernel code.
These backstores cover the most common use cases, but not all. One new
use case that other non-kernel target solutions, such as tgt, are able
to support is using Gluster's GLFS or Ceph's RBD as a backstore. The
target then serves as a translator, allowing initiators to store data
in these non-traditional networked storage systems, while still only
using standard protocols themselves.
If the target is a userspace process, supporting these is easy. tgt,
for example, needs only a small adapter module for each, because the
modules just use the available userspace libraries for RBD and GLFS.
Adding support for these backstores in LIO is considerably more
difficult, because LIO is entirely kernel code. Instead of undertaking
the significant work to port the GLFS or RBD APIs and protocols to the
kernel, another approach is to create a userspace pass-through
backstore for LIO, "TCMU".
Benefits:
In addition to allowing relatively easy support for RBD and GLFS, TCMU
will also allow easier development of new backstores. TCMU combines
with the LIO loopback fabric to become something similar to FUSE
(Filesystem in Userspace), but at the SCSI layer instead of the
filesystem layer. A SUSE, if you will.
The disadvantage is there are more distinct components to configure, and
potentially to malfunction. This is unavoidable, but hopefully not
fatal if we're careful to keep things as simple as possible.
Design constraints:
- Good performance: high throughput, low latency
- Cleanly handle if userspace:
1) never attaches
2) hangs
3) dies
4) misbehaves
- Allow future flexibility in user & kernel implementations
- Be reasonably memory-efficient
- Simple to configure & run
- Simple to write a userspace backend
Implementation overview:
The core of the TCMU interface is a memory region that is shared
between kernel and userspace. Within this region is: a control area
(mailbox); a lockless producer/consumer circular buffer for commands
to be passed up, and status returned; and an in/out data buffer area.
TCMU uses the pre-existing UIO subsystem. UIO allows device driver
development in userspace, and this is conceptually very close to the
TCMU use case, except instead of a physical device, TCMU implements a
memory-mapped layout designed for SCSI commands. Using UIO also
benefits TCMU by handling device introspection (e.g. a way for
userspace to determine how large the shared region is) and signaling
mechanisms in both directions.
There are no embedded pointers in the memory region. Everything is
expressed as an offset from the region's starting address. This allows
the ring to still work if the user process dies and is restarted with
the region mapped at a different virtual address.
See target_core_user.h for the struct definitions.
The Mailbox:
The mailbox is always at the start of the shared memory region, and
contains a version, details about the starting offset and size of the
command ring, and head and tail pointers to be used by the kernel and
userspace (respectively) to put commands on the ring, and indicate
when the commands are completed.
version - 1 (userspace should abort if otherwise)
flags - none yet defined.
cmdr_off - The offset of the start of the command ring from the start
of the memory region, to account for the mailbox size.
cmdr_size - The size of the command ring. This does *not* need to be a
power of two.
cmd_head - Modified by the kernel to indicate when a command has been
placed on the ring.
cmd_tail - Modified by userspace to indicate when it has completed
processing of a command.
The Command Ring:
Commands are placed on the ring by the kernel incrementing
mailbox.cmd_head by the size of the command, modulo cmdr_size, and
then signaling userspace via uio_event_notify(). Once the command is
completed, userspace updates mailbox.cmd_tail in the same way and
signals the kernel via a 4-byte write(). When cmd_head equals
cmd_tail, the ring is empty -- no commands are currently waiting to be
processed by userspace.
TCMU commands start with a common header containing "len_op", a 32-bit
value that stores the length, as well as the opcode in the lowest
unused bits. Currently only two opcodes are defined, TCMU_OP_PAD and
TCMU_OP_CMD. When userspace encounters a command with PAD opcode, it
should skip ahead by the bytes in "length". (The kernel inserts PAD
entries to ensure each CMD entry fits contigously into the circular
buffer.)
When userspace handles a CMD, it finds the SCSI CDB (Command Data
Block) via tcmu_cmd_entry.req.cdb_off. This is an offset from the
start of the overall shared memory region, not the entry. The data
in/out buffers are accessible via tht req.iov[] array. Note that
each iov.iov_base is also an offset from the start of the region.
TCMU currently does not support BIDI operations.
When completing a command, userspace sets rsp.scsi_status, and
rsp.sense_buffer if necessary. Userspace then increments
mailbox.cmd_tail by entry.hdr.length (mod cmdr_size) and signals the
kernel via the UIO method, a 4-byte write to the file descriptor.
The Data Area:
This is shared-memory space after the command ring. The organization
of this area is not defined in the TCMU interface, and userspace
should access only the parts referenced by pending iovs.
Device Discovery:
Other devices may be using UIO besides TCMU. Unrelated user processes
may also be handling different sets of TCMU devices. TCMU userspace
processes must find their devices by scanning sysfs
class/uio/uio*/name. For TCMU devices, these names will be of the
format:
tcm-user/<hba_num>/<device_name>/<subtype>/<path>
where "tcm-user" is common for all TCMU-backed UIO devices. <hba_num>
and <device_name> allow userspace to find the device's path in the
kernel target's configfs tree. Assuming the usual mount point, it is
found at:
/sys/kernel/config/target/core/user_<hba_num>/<device_name>
This location contains attributes such as "hw_block_size", that
userspace needs to know for correct operation.
<subtype> will be a userspace-process-unique string to identify the
TCMU device as expecting to be backed by a certain handler, and <path>
will be an additional handler-specific string for the user process to
configure the device, if needed. The name cannot contain ':', due to
LIO limitations.
For all devices so discovered, the user handler opens /dev/uioX and
calls mmap():
mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)
where size must be equal to the value read from
/sys/class/uio/uioX/maps/map0/size.
Device Events:
If a new device is added or removed, a notification will be broadcast
over netlink, using a generic netlink family name of "TCM-USER" and a
multicast group named "config". This will include the UIO name as
described in the previous section, as well as the UIO minor
number. This should allow userspace to identify both the UIO device and
the LIO device, so that after determining the device is supported
(based on subtype) it can take the appropriate action.
Other contingencies:
Userspace handler process never attaches:
- TCMU will post commands, and then abort them after a timeout period
(30 seconds.)
Userspace handler process is killed:
- It is still possible to restart and re-connect to TCMU
devices. Command ring is preserved. However, after the timeout period,
the kernel will abort pending tasks.
Userspace handler process hangs:
- The kernel will abort pending tasks after a timeout period.
Userspace handler process is malicious:
- The process can trivially break the handling of devices it controls,
but should not be able to access kernel memory outside its shared
memory areas.
Writing a user pass-through handler (with example code)
-------------------------------------------------------
A user process handing a TCMU device must support the following:
a) Discovering and configuring TCMU uio devices
b) Waiting for events on the device(s)
c) Managing the command ring: Parsing operations and commands,
performing work as needed, setting response fields (scsi_status and
possibly sense_buffer), updating cmd_tail, and notifying the kernel
that work has been finished
First, consider instead writing a plugin for tcmu-runner. tcmu-runner
implements all of this, and provides a higher-level API for plugin
authors.
TCMU is designed so that multiple unrelated processes can manage TCMU
devices separately. All handlers should make sure to only open their
devices, based opon a known subtype string.
a) Discovering and configuring TCMU UIO devices:
(error checking omitted for brevity)
int fd, dev_fd;
char buf[256];
unsigned long long map_len;
void *map;
fd = open("/sys/class/uio/uio0/name", O_RDONLY);
ret = read(fd, buf, sizeof(buf));
close(fd);
buf[ret-1] = '\0'; /* null-terminate and chop off the \n */
/* we only want uio devices whose name is a format we expect */
if (strncmp(buf, "tcm-user", 8))
exit(-1);
/* Further checking for subtype also needed here */
fd = open(/sys/class/uio/%s/maps/map0/size, O_RDONLY);
ret = read(fd, buf, sizeof(buf));
close(fd);
str_buf[ret-1] = '\0'; /* null-terminate and chop off the \n */
map_len = strtoull(buf, NULL, 0);
dev_fd = open("/dev/uio0", O_RDWR);
map = mmap(NULL, map_len, PROT_READ|PROT_WRITE, MAP_SHARED, dev_fd, 0);
b) Waiting for events on the device(s)
while (1) {
char buf[4];
int ret = read(dev_fd, buf, 4); /* will block */
handle_device_events(dev_fd, map);
}
c) Managing the command ring
#include <linux/target_core_user.h>
int handle_device_events(int fd, void *map)
{
struct tcmu_mailbox *mb = map;
struct tcmu_cmd_entry *ent = (void *) mb + mb->cmdr_off + mb->cmd_tail;
int did_some_work = 0;
/* Process events from cmd ring until we catch up with cmd_head */
while (ent != (void *)mb + mb->cmdr_off + mb->cmd_head) {
if (tcmu_hdr_get_op(&ent->hdr) == TCMU_OP_CMD) {
uint8_t *cdb = (void *)mb + ent->req.cdb_off;
bool success = true;
/* Handle command here. */
printf("SCSI opcode: 0x%x\n", cdb[0]);
/* Set response fields */
if (success)
ent->rsp.scsi_status = SCSI_NO_SENSE;
else {
/* Also fill in rsp->sense_buffer here */
ent->rsp.scsi_status = SCSI_CHECK_CONDITION;
}
}
else {
/* Do nothing for PAD entries */
}
/* update cmd_tail */
mb->cmd_tail = (mb->cmd_tail + tcmu_hdr_get_len(&ent->hdr)) % mb->cmdr_size;
ent = (void *) mb + mb->cmdr_off + mb->cmd_tail;
did_some_work = 1;
}
/* Notify the kernel that work has been finished */
if (did_some_work) {
uint32_t buf = 0;
write(fd, &buf, 4);
}
return 0;
}
Command filtering and pass_level
--------------------------------
TCMU supports a "pass_level" option with valid values of 0 or 1. When
the value is 0 (the default), nearly all SCSI commands received for
the device are passed through to the handler. This allows maximum
flexibility but increases the amount of code required by the handler,
to support all mandatory SCSI commands. If pass_level is set to 1,
then only IO-related commands are presented, and the rest are handled
by LIO's in-kernel command emulation. The commands presented at level
1 include all versions of:
READ
WRITE
WRITE_VERIFY
XDWRITEREAD
WRITE_SAME
COMPARE_AND_WRITE
SYNCHRONIZE_CACHE
UNMAP
A final note
------------
Please be careful to return codes as defined by the SCSI
specifications. These are different than some values defined in the
scsi/scsi.h include file. For example, CHECK CONDITION's status code
is 2, not 1.
......@@ -2185,7 +2185,7 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
isert_cmd->tx_desc.num_sge = 2;
}
isert_init_send_wr(isert_conn, isert_cmd, send_wr, true);
isert_init_send_wr(isert_conn, isert_cmd, send_wr, false);
pr_debug("Posting SCSI Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
......@@ -2871,7 +2871,7 @@ isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
&isert_cmd->tx_desc.iscsi_header);
isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
isert_init_send_wr(isert_conn, isert_cmd,
&isert_cmd->tx_desc.send_wr, true);
&isert_cmd->tx_desc.send_wr, false);
isert_cmd->rdma_wr.s_send_wr.next = &isert_cmd->tx_desc.send_wr;
wr->send_wr_num += 1;
}
......@@ -3140,7 +3140,7 @@ isert_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
accept_wait:
ret = down_interruptible(&isert_np->np_sem);
if (max_accept > 5)
if (ret || max_accept > 5)
return -ENODEV;
spin_lock_bh(&np->np_thread_lock);
......
......@@ -112,6 +112,7 @@ static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
struct qla_tgt_cmd *cmd);
static void qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
struct atio_from_isp *atio, uint16_t status, int qfull);
static void qlt_disable_vha(struct scsi_qla_host *vha);
/*
* Global Variables
*/
......@@ -210,7 +211,7 @@ static inline void qlt_decr_num_pend_cmds(struct scsi_qla_host *vha)
spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags);
}
void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
struct atio_from_isp *atio)
{
ql_dbg(ql_dbg_tgt, vha, 0xe072,
......@@ -433,7 +434,7 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
#if 0 /* FIXME: Re-enable Global event handling.. */
/* Global event */
atomic_inc(&ha->tgt.qla_tgt->tgt_global_resets_count);
qlt_clear_tgt_db(ha->tgt.qla_tgt, 1);
qlt_clear_tgt_db(ha->tgt.qla_tgt);
if (!list_empty(&ha->tgt.qla_tgt->sess_list)) {
sess = list_entry(ha->tgt.qla_tgt->sess_list.next,
typeof(*sess), sess_list_entry);
......@@ -515,7 +516,7 @@ static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
}
/* ha->hardware_lock supposed to be held on entry */
static void qlt_clear_tgt_db(struct qla_tgt *tgt, bool local_only)
static void qlt_clear_tgt_db(struct qla_tgt *tgt)
{
struct qla_tgt_sess *sess;
......@@ -867,7 +868,7 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
mutex_lock(&vha->vha_tgt.tgt_mutex);
spin_lock_irqsave(&ha->hardware_lock, flags);
tgt->tgt_stop = 1;
qlt_clear_tgt_db(tgt, true);
qlt_clear_tgt_db(tgt);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
mutex_unlock(&vha->vha_tgt.tgt_mutex);
mutex_unlock(&qla_tgt_mutex);
......@@ -1462,12 +1463,13 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm)
return -1;
}
static inline void qlt_unmap_sg(struct scsi_qla_host *vha,
struct qla_tgt_cmd *cmd)
static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
{
struct qla_hw_data *ha = vha->hw;
BUG_ON(!cmd->sg_mapped);
if (!cmd->sg_mapped)
return;
pci_unmap_sg(ha->pdev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction);
cmd->sg_mapped = 0;
......@@ -2428,8 +2430,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
return 0;
out_unmap_unlock:
if (cmd->sg_mapped)
qlt_unmap_sg(vha, cmd);
qlt_unmap_sg(vha, cmd);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return res;
......@@ -2506,8 +2507,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
return res;
out_unlock_free_unmap:
if (cmd->sg_mapped)
qlt_unmap_sg(vha, cmd);
qlt_unmap_sg(vha, cmd);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return res;
......@@ -2741,8 +2741,7 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
if (!ha_locked && !in_interrupt())
msleep(250); /* just in case */
if (cmd->sg_mapped)
qlt_unmap_sg(vha, cmd);
qlt_unmap_sg(vha, cmd);
vha->hw->tgt.tgt_ops->free_cmd(cmd);
}
return;
......@@ -3087,8 +3086,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
tfo = se_cmd->se_tfo;
cmd->cmd_sent_to_fw = 0;
if (cmd->sg_mapped)
qlt_unmap_sg(vha, cmd);
qlt_unmap_sg(vha, cmd);
if (unlikely(status != CTIO_SUCCESS)) {
switch (status & 0xFFFF) {
......@@ -5343,7 +5341,7 @@ void qlt_lport_deregister(struct scsi_qla_host *vha)
EXPORT_SYMBOL(qlt_lport_deregister);
/* Must be called under HW lock */
void qlt_set_mode(struct scsi_qla_host *vha)
static void qlt_set_mode(struct scsi_qla_host *vha)
{
struct qla_hw_data *ha = vha->hw;
......@@ -5364,7 +5362,7 @@ void qlt_set_mode(struct scsi_qla_host *vha)
}
/* Must be called under HW lock */
void qlt_clear_mode(struct scsi_qla_host *vha)
static void qlt_clear_mode(struct scsi_qla_host *vha)
{
struct qla_hw_data *ha = vha->hw;
......@@ -5428,8 +5426,7 @@ EXPORT_SYMBOL(qlt_enable_vha);
*
* Disable Target Mode and reset the adapter
*/
void
qlt_disable_vha(struct scsi_qla_host *vha)
static void qlt_disable_vha(struct scsi_qla_host *vha)
{
struct qla_hw_data *ha = vha->hw;
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
......
......@@ -1001,11 +1001,11 @@ struct qla_tgt_prm {
struct qla_tgt *tgt;
void *pkt;
struct scatterlist *sg; /* cmd data buffer SG vector */
unsigned char *sense_buffer;
int seg_cnt;
int req_cnt;
uint16_t rq_result;
uint16_t scsi_status;
unsigned char *sense_buffer;
int sense_buffer_len;
int residual;
int add_status_pkt;
......@@ -1033,10 +1033,6 @@ struct qla_tgt_srr_ctio {
extern struct qla_tgt_data qla_target;
/*
* Internal function prototypes
*/
void qlt_disable_vha(struct scsi_qla_host *);
/*
* Function prototypes for qla_target.c logic used by qla2xxx LLD code.
......@@ -1049,8 +1045,6 @@ extern void qlt_lport_deregister(struct scsi_qla_host *);
extern void qlt_unreg_sess(struct qla_tgt_sess *);
extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *);
extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *);
extern void qlt_set_mode(struct scsi_qla_host *ha);
extern void qlt_clear_mode(struct scsi_qla_host *ha);
extern int __init qlt_init(void);
extern void qlt_exit(void);
extern void qlt_update_vp_map(struct scsi_qla_host *, int);
......@@ -1083,13 +1077,9 @@ static inline void qla_reverse_ini_mode(struct scsi_qla_host *ha)
/*
* Exported symbols from qla_target.c LLD logic used by qla2xxx code..
*/
extern void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *,
struct atio_from_isp *);
extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *);
extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
extern int qlt_rdy_to_xfer_dif(struct qla_tgt_cmd *);
extern int qlt_xmit_response_dif(struct qla_tgt_cmd *, int, uint8_t);
extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
......
......@@ -786,7 +786,16 @@ static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct qla_tgt_sess *sess)
pr_debug("fc_rport domain: port_id 0x%06x\n", nacl->nport_id);
node = btree_remove32(&lport->lport_fcport_map, nacl->nport_id);
WARN_ON(node && (node != se_nacl));
if (WARN_ON(node && (node != se_nacl))) {
/*
* The nacl no longer matches what we think it should be.
* Most likely a new dynamic acl has been added while
* someone dropped the hardware lock. It clearly is a
* bug elsewhere, but this bit can't make things worse.
*/
btree_insert32(&lport->lport_fcport_map, nacl->nport_id,
node, GFP_ATOMIC);
}
pr_debug("Removed from fcport_map: %p for WWNN: 0x%016LX, port_id: 0x%06x\n",
se_nacl, nacl->nport_wwnn, nacl->nport_id);
......
......@@ -31,6 +31,13 @@ config TCM_PSCSI
Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered
passthrough access to Linux/SCSI device
config TCM_USER
tristate "TCM/USER Subsystem Plugin for Linux"
depends on UIO && NET
help
Say Y here to enable the TCM/USER subsystem plugin for a userspace
process to handle requests
source "drivers/target/loopback/Kconfig"
source "drivers/target/tcm_fc/Kconfig"
source "drivers/target/iscsi/Kconfig"
......
......@@ -22,6 +22,7 @@ obj-$(CONFIG_TARGET_CORE) += target_core_mod.o
obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o
obj-$(CONFIG_TCM_FILEIO) += target_core_file.o
obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o
obj-$(CONFIG_TCM_USER) += target_core_user.o
# Fabric modules
obj-$(CONFIG_LOOPBACK_TARGET) += loopback/
......
......@@ -3709,7 +3709,6 @@ static inline void iscsit_thread_check_cpumask(
struct task_struct *p,
int mode)
{
char buf[128];
/*
* mode == 1 signals iscsi_target_tx_thread() usage.
* mode == 0 signals iscsi_target_rx_thread() usage.
......@@ -3728,8 +3727,6 @@ static inline void iscsit_thread_check_cpumask(
* both TX and RX kthreads are scheduled to run on the
* same CPU.
*/
memset(buf, 0, 128);
cpumask_scnprintf(buf, 128, conn->conn_cpumask);
set_cpus_allowed_ptr(p, conn->conn_cpumask);
}
......@@ -4326,8 +4323,7 @@ int iscsit_close_connection(
if (conn->conn_tx_hash.tfm)
crypto_free_hash(conn->conn_tx_hash.tfm);
if (conn->conn_cpumask)
free_cpumask_var(conn->conn_cpumask);
free_cpumask_var(conn->conn_cpumask);
kfree(conn->conn_ops);
conn->conn_ops = NULL;
......
......@@ -669,12 +669,10 @@ static ssize_t lio_target_nacl_show_info(
} else {
sess = se_sess->fabric_sess_ptr;
if (sess->sess_ops->InitiatorName)
rb += sprintf(page+rb, "InitiatorName: %s\n",
sess->sess_ops->InitiatorName);
if (sess->sess_ops->InitiatorAlias)
rb += sprintf(page+rb, "InitiatorAlias: %s\n",
sess->sess_ops->InitiatorAlias);
rb += sprintf(page+rb, "InitiatorName: %s\n",
sess->sess_ops->InitiatorName);
rb += sprintf(page+rb, "InitiatorAlias: %s\n",
sess->sess_ops->InitiatorAlias);
rb += sprintf(page+rb, "LIO Session ID: %u "
"ISID: 0x%02x %02x %02x %02x %02x %02x "
......
......@@ -345,7 +345,6 @@ static int iscsit_dataout_check_datasn(
struct iscsi_cmd *cmd,
unsigned char *buf)
{
int dump = 0, recovery = 0;
u32 data_sn = 0;
struct iscsi_conn *conn = cmd->conn;
struct iscsi_data *hdr = (struct iscsi_data *) buf;
......@@ -370,13 +369,11 @@ static int iscsit_dataout_check_datasn(
pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"
" higher than expected 0x%08x.\n", cmd->init_task_tag,
be32_to_cpu(hdr->datasn), data_sn);
recovery = 1;
goto recover;
} else if (be32_to_cpu(hdr->datasn) < data_sn) {
pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"
" lower than expected 0x%08x, discarding payload.\n",
cmd->init_task_tag, be32_to_cpu(hdr->datasn), data_sn);
dump = 1;
goto dump;
}
......@@ -392,8 +389,7 @@ static int iscsit_dataout_check_datasn(
if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
return DATAOUT_CANNOT_RECOVER;
return (recovery || dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY :
DATAOUT_NORMAL;
return DATAOUT_WITHIN_COMMAND_RECOVERY;
}
static int iscsit_dataout_pre_datapduinorder_yes(
......
......@@ -978,8 +978,7 @@ int iscsit_setup_np(
return 0;
fail:
np->np_socket = NULL;
if (sock)
sock_release(sock);
sock_release(sock);
return ret;
}
......@@ -1190,8 +1189,7 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn,
if (!IS_ERR(conn->conn_tx_hash.tfm))
crypto_free_hash(conn->conn_tx_hash.tfm);
if (conn->conn_cpumask)
free_cpumask_var(conn->conn_cpumask);
free_cpumask_var(conn->conn_cpumask);
kfree(conn->conn_ops);
......@@ -1268,8 +1266,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
iscsit_put_transport(conn->conn_transport);
kfree(conn);
conn = NULL;
if (ret == -ENODEV)
goto out;
/* Get another socket */
return 1;
}
......
......@@ -1481,8 +1481,9 @@ void iscsit_collect_login_stats(
if (conn->param_list)
intrname = iscsi_find_param_from_key(INITIATORNAME,
conn->param_list);
strcpy(ls->last_intr_fail_name,
(intrname ? intrname->value : "Unknown"));
strlcpy(ls->last_intr_fail_name,
(intrname ? intrname->value : "Unknown"),
sizeof(ls->last_intr_fail_name));
ls->last_intr_fail_ip_family = conn->login_family;
......
......@@ -153,18 +153,11 @@ static int tcm_loop_change_queue_type(struct scsi_device *sdev, int tag)
/*
* Locate the SAM Task Attr from struct scsi_cmnd *
*/
static int tcm_loop_sam_attr(struct scsi_cmnd *sc)
{
if (sc->device->tagged_supported) {
switch (sc->tag) {
case HEAD_OF_QUEUE_TAG:
return MSG_HEAD_TAG;
case ORDERED_QUEUE_TAG:
return MSG_ORDERED_TAG;
default:
break;
}
}
static int tcm_loop_sam_attr(struct scsi_cmnd *sc, int tag)
{
if (sc->device->tagged_supported &&
sc->device->ordered_tags && tag >= 0)
return MSG_ORDERED_TAG;
return MSG_SIMPLE_TAG;
}
......@@ -227,7 +220,7 @@ static void tcm_loop_submission_work(struct work_struct *work)
rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd,
&tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun,
transfer_length, tcm_loop_sam_attr(sc),
transfer_length, tcm_loop_sam_attr(sc, tl_cmd->sc_cmd_tag),
sc->sc_data_direction, 0,
scsi_sglist(sc), scsi_sg_count(sc),
sgl_bidi, sgl_bidi_count,
......@@ -266,7 +259,7 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
}
tl_cmd->sc = sc;
tl_cmd->sc_cmd_tag = sc->tag;
tl_cmd->sc_cmd_tag = sc->request->tag;
INIT_WORK(&tl_cmd->work, tcm_loop_submission_work);
queue_work(tcm_loop_workqueue, &tl_cmd->work);
return 0;
......@@ -370,7 +363,7 @@ static int tcm_loop_abort_task(struct scsi_cmnd *sc)
*/
tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id];
ret = tcm_loop_issue_tmr(tl_tpg, tl_nexus, sc->device->lun,
sc->tag, TMR_ABORT_TASK);
sc->request->tag, TMR_ABORT_TASK);
return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED;
}
......@@ -960,8 +953,7 @@ static int tcm_loop_port_link(
struct tcm_loop_tpg, tl_se_tpg);
struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
atomic_inc(&tl_tpg->tl_tpg_port_count);
smp_mb__after_atomic();
atomic_inc_mb(&tl_tpg->tl_tpg_port_count);
/*
* Add Linux/SCSI struct scsi_device by HCTL
*/
......@@ -995,8 +987,7 @@ static void tcm_loop_port_unlink(
scsi_remove_device(sd);
scsi_device_put(sd);
atomic_dec(&tl_tpg->tl_tpg_port_count);
smp_mb__after_atomic();
atomic_dec_mb(&tl_tpg->tl_tpg_port_count);
pr_debug("TCM_Loop_ConfigFS: Port Unlink Successful\n");
}
......
......@@ -392,8 +392,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
if (tg_pt_id != tg_pt_gp->tg_pt_gp_id)
continue;
atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
smp_mb__after_atomic();
atomic_inc_mb(&tg_pt_gp->tg_pt_gp_ref_cnt);
spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
......@@ -403,8 +402,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
found = true;
spin_lock(&dev->t10_alua.tg_pt_gps_lock);
atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
smp_mb__after_atomic();
atomic_dec_mb(&tg_pt_gp->tg_pt_gp_ref_cnt);
break;
}
spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
......@@ -998,8 +996,7 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work)
* every I_T nexus other than the I_T nexus on which the SET
* TARGET PORT GROUPS command
*/
atomic_inc(&mem->tg_pt_gp_mem_ref_cnt);
smp_mb__after_atomic();
atomic_inc_mb(&mem->tg_pt_gp_mem_ref_cnt);
spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
spin_lock_bh(&port->sep_alua_lock);
......@@ -1028,8 +1025,7 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work)
spin_unlock_bh(&port->sep_alua_lock);
spin_lock(&tg_pt_gp->tg_pt_gp_lock);
atomic_dec(&mem->tg_pt_gp_mem_ref_cnt);
smp_mb__after_atomic();
atomic_dec_mb(&mem->tg_pt_gp_mem_ref_cnt);
}
spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
/*
......@@ -1063,7 +1059,6 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work)
core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_pending_state));
spin_lock(&dev->t10_alua.tg_pt_gps_lock);
atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
smp_mb__after_atomic();
spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
if (tg_pt_gp->tg_pt_gp_transition_complete)
......@@ -1125,7 +1120,6 @@ static int core_alua_do_transition_tg_pt(
*/
spin_lock(&dev->t10_alua.tg_pt_gps_lock);
atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
smp_mb__after_atomic();
spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
if (!explicit && tg_pt_gp->tg_pt_gp_implicit_trans_secs) {
......@@ -1168,7 +1162,6 @@ int core_alua_do_port_transition(
spin_lock(&local_lu_gp_mem->lu_gp_mem_lock);
lu_gp = local_lu_gp_mem->lu_gp;
atomic_inc(&lu_gp->lu_gp_ref_cnt);
smp_mb__after_atomic();
spin_unlock(&local_lu_gp_mem->lu_gp_mem_lock);
/*
* For storage objects that are members of the 'default_lu_gp',
......@@ -1184,8 +1177,7 @@ int core_alua_do_port_transition(
l_tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl;
rc = core_alua_do_transition_tg_pt(l_tg_pt_gp,
new_state, explicit);
atomic_dec(&lu_gp->lu_gp_ref_cnt);
smp_mb__after_atomic();
atomic_dec_mb(&lu_gp->lu_gp_ref_cnt);
return rc;
}
/*
......@@ -1198,8 +1190,7 @@ int core_alua_do_port_transition(
lu_gp_mem_list) {
dev = lu_gp_mem->lu_gp_mem_dev;
atomic_inc(&lu_gp_mem->lu_gp_mem_ref_cnt);
smp_mb__after_atomic();
atomic_inc_mb(&lu_gp_mem->lu_gp_mem_ref_cnt);
spin_unlock(&lu_gp->lu_gp_lock);
spin_lock(&dev->t10_alua.tg_pt_gps_lock);
......@@ -1227,8 +1218,7 @@ int core_alua_do_port_transition(
tg_pt_gp->tg_pt_gp_alua_port = NULL;
tg_pt_gp->tg_pt_gp_alua_nacl = NULL;
}
atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
smp_mb__after_atomic();
atomic_inc_mb(&tg_pt_gp->tg_pt_gp_ref_cnt);
spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
/*
* core_alua_do_transition_tg_pt() will always return
......@@ -1238,16 +1228,14 @@ int core_alua_do_port_transition(
new_state, explicit);
spin_lock(&dev->t10_alua.tg_pt_gps_lock);
atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
smp_mb__after_atomic();
atomic_dec_mb(&tg_pt_gp->tg_pt_gp_ref_cnt);
if (rc)
break;
}
spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
spin_lock(&lu_gp->lu_gp_lock);
atomic_dec(&lu_gp_mem->lu_gp_mem_ref_cnt);
smp_mb__after_atomic();
atomic_dec_mb(&lu_gp_mem->lu_gp_mem_ref_cnt);
}
spin_unlock(&lu_gp->lu_gp_lock);
......@@ -1260,8 +1248,7 @@ int core_alua_do_port_transition(
core_alua_dump_state(new_state));
}
atomic_dec(&lu_gp->lu_gp_ref_cnt);
smp_mb__after_atomic();
atomic_dec_mb(&lu_gp->lu_gp_ref_cnt);
return rc;
}
......
......@@ -665,6 +665,9 @@ SE_DEV_ATTR(is_nonrot, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB(emulate_rest_reord);
SE_DEV_ATTR(emulate_rest_reord, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB(force_pr_aptpl);
SE_DEV_ATTR(force_pr_aptpl, S_IRUGO | S_IWUSR);
DEF_DEV_ATTRIB_RO(hw_block_size);
SE_DEV_ATTR_RO(hw_block_size);
......@@ -719,6 +722,7 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
&target_core_dev_attrib_hw_pi_prot_type.attr,
&target_core_dev_attrib_pi_prot_format.attr,
&target_core_dev_attrib_enforce_pr_isids.attr,
&target_core_dev_attrib_force_pr_aptpl.attr,
&target_core_dev_attrib_is_nonrot.attr,
&target_core_dev_attrib_emulate_rest_reord.attr,
&target_core_dev_attrib_hw_block_size.attr,
......@@ -1263,7 +1267,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
{
unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL;
unsigned char *t_fabric = NULL, *t_port = NULL;
char *orig, *ptr, *arg_p, *opts;
char *orig, *ptr, *opts;
substring_t args[MAX_OPT_ARGS];
unsigned long long tmp_ll;
u64 sa_res_key = 0;
......@@ -1295,14 +1299,14 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
token = match_token(ptr, tokens, args);
switch (token) {
case Opt_initiator_fabric:
i_fabric = match_strdup(&args[0]);
i_fabric = match_strdup(args);
if (!i_fabric) {
ret = -ENOMEM;
goto out;
}
break;
case Opt_initiator_node:
i_port = match_strdup(&args[0]);
i_port = match_strdup(args);
if (!i_port) {
ret = -ENOMEM;
goto out;
......@@ -1316,7 +1320,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
}
break;
case Opt_initiator_sid:
isid = match_strdup(&args[0]);
isid = match_strdup(args);
if (!isid) {
ret = -ENOMEM;
goto out;
......@@ -1330,15 +1334,9 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
}
break;
case Opt_sa_res_key:
arg_p = match_strdup(&args[0]);
if (!arg_p) {
ret = -ENOMEM;
goto out;
}
ret = kstrtoull(arg_p, 0, &tmp_ll);
ret = kstrtoull(args->from, 0, &tmp_ll);
if (ret < 0) {
pr_err("kstrtoull() failed for"
" sa_res_key=\n");
pr_err("kstrtoull() failed for sa_res_key=\n");
goto out;
}
sa_res_key = (u64)tmp_ll;
......@@ -1370,14 +1368,14 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
* PR APTPL Metadata for Target Port
*/
case Opt_target_fabric:
t_fabric = match_strdup(&args[0]);
t_fabric = match_strdup(args);
if (!t_fabric) {
ret = -ENOMEM;
goto out;
}
break;
case Opt_target_node:
t_port = match_strdup(&args[0]);
t_port = match_strdup(args);
if (!t_port) {
ret = -ENOMEM;
goto out;
......
......@@ -224,8 +224,7 @@ struct se_dev_entry *core_get_se_deve_from_rtpi(
if (port->sep_rtpi != rtpi)
continue;
atomic_inc(&deve->pr_ref_count);
smp_mb__after_atomic();
atomic_inc_mb(&deve->pr_ref_count);
spin_unlock_irq(&nacl->device_list_lock);
return deve;
......@@ -1019,6 +1018,23 @@ int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag)
return 0;
}
int se_dev_set_force_pr_aptpl(struct se_device *dev, int flag)
{
if ((flag != 0) && (flag != 1)) {
printk(KERN_ERR "Illegal value %d\n", flag);
return -EINVAL;
}
if (dev->export_count) {
pr_err("dev[%p]: Unable to set force_pr_aptpl while"
" export_count is %d\n", dev, dev->export_count);
return -EINVAL;
}
dev->dev_attrib.force_pr_aptpl = flag;
pr_debug("dev[%p]: SE Device force_pr_aptpl: %d\n", dev, flag);
return 0;
}
int se_dev_set_is_nonrot(struct se_device *dev, int flag)
{
if ((flag != 0) && (flag != 1)) {
......@@ -1250,24 +1266,16 @@ struct se_lun *core_dev_add_lun(
*
*
*/
int core_dev_del_lun(
void core_dev_del_lun(
struct se_portal_group *tpg,
u32 unpacked_lun)
struct se_lun *lun)
{
struct se_lun *lun;
lun = core_tpg_pre_dellun(tpg, unpacked_lun);
if (IS_ERR(lun))
return PTR_ERR(lun);
core_tpg_post_dellun(tpg, lun);
pr_debug("%s_TPG[%u]_LUN[%u] - Deactivated %s Logical Unit from"
pr_debug("%s_TPG[%u]_LUN[%u] - Deactivating %s Logical Unit from"
" device object\n", tpg->se_tpg_tfo->get_fabric_name(),
tpg->se_tpg_tfo->tpg_get_tag(tpg), unpacked_lun,
tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun,
tpg->se_tpg_tfo->get_fabric_name());
return 0;
core_tpg_remove_lun(tpg, lun);
}
struct se_lun *core_get_lun_from_tpg(struct se_portal_group *tpg, u32 unpacked_lun)
......@@ -1396,8 +1404,7 @@ int core_dev_add_initiator_node_lun_acl(
spin_lock(&lun->lun_acl_lock);
list_add_tail(&lacl->lacl_list, &lun->lun_acl_list);
atomic_inc(&lun->lun_acl_count);
smp_mb__after_atomic();
atomic_inc_mb(&lun->lun_acl_count);
spin_unlock(&lun->lun_acl_lock);
pr_debug("%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for "
......@@ -1409,7 +1416,8 @@ int core_dev_add_initiator_node_lun_acl(
* Check to see if there are any existing persistent reservation APTPL
* pre-registrations that need to be enabled for this LUN ACL..
*/
core_scsi3_check_aptpl_registration(lun->lun_se_dev, tpg, lun, lacl);
core_scsi3_check_aptpl_registration(lun->lun_se_dev, tpg, lun, nacl,
lacl->mapped_lun);
return 0;
}
......@@ -1430,8 +1438,7 @@ int core_dev_del_initiator_node_lun_acl(
spin_lock(&lun->lun_acl_lock);
list_del(&lacl->lacl_list);
atomic_dec(&lun->lun_acl_count);
smp_mb__after_atomic();
atomic_dec_mb(&lun->lun_acl_count);
spin_unlock(&lun->lun_acl_lock);
core_disable_device_list_for_node(lun, NULL, lacl->mapped_lun,
......@@ -1554,6 +1561,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
dev->dev_attrib.emulate_3pc = DA_EMULATE_3PC;
dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE0_PROT;
dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS;
dev->dev_attrib.force_pr_aptpl = DA_FORCE_PR_APTPL;
dev->dev_attrib.is_nonrot = DA_IS_NONROT;
dev->dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD;
dev->dev_attrib.max_unmap_lba_count = DA_MAX_UNMAP_LBA_COUNT;
......
......@@ -320,7 +320,7 @@ static struct config_group *target_fabric_make_mappedlun(
struct se_node_acl, acl_group);
struct se_portal_group *se_tpg = se_nacl->se_tpg;
struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
struct se_lun_acl *lacl;
struct se_lun_acl *lacl = NULL;
struct config_item *acl_ci;
struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL;
char *buf;
......@@ -406,6 +406,7 @@ static struct config_group *target_fabric_make_mappedlun(
out:
if (lacl_cg)
kfree(lacl_cg->default_groups);
kfree(lacl);
kfree(buf);
return ERR_PTR(ret);
}
......@@ -821,7 +822,7 @@ static int target_fabric_port_unlink(
tf->tf_ops.fabric_pre_unlink(se_tpg, lun);
}
core_dev_del_lun(se_tpg, lun->unpacked_lun);
core_dev_del_lun(se_tpg, lun);
return 0;
}
......@@ -910,16 +911,12 @@ static struct config_group *target_fabric_make_lun(
GFP_KERNEL);
if (!port_stat_grp->default_groups) {
pr_err("Unable to allocate port_stat_grp->default_groups\n");
errno = -ENOMEM;
goto out;
kfree(lun_cg->default_groups);
return ERR_PTR(-ENOMEM);
}
target_stat_setup_port_default_groups(lun);
return &lun->lun_group;
out:
if (lun_cg)
kfree(lun_cg->default_groups);
return ERR_PTR(errno);
}
static void target_fabric_drop_lun(
......
......@@ -394,9 +394,9 @@ char *iscsi_parse_pr_out_transport_id(
* If the caller wants the TransportID Length, we set that value for the
* entire iSCSI Tarnsport ID now.
*/
if (out_tid_len != NULL) {
add_len = ((buf[2] >> 8) & 0xff);
add_len |= (buf[3] & 0xff);
if (out_tid_len) {
/* The shift works thanks to integer promotion rules */
add_len = (buf[2] << 8) | buf[3];
tid_len = strlen(&buf[4]);
tid_len += 4; /* Add four bytes for iSCSI Transport ID header */
......
......@@ -415,7 +415,7 @@ fd_execute_sync_cache(struct se_cmd *cmd)
} else {
start = cmd->t_task_lba * dev->dev_attrib.block_size;
if (cmd->data_length)
end = start + cmd->data_length;
end = start + cmd->data_length - 1;
else
end = LLONG_MAX;
}
......@@ -680,7 +680,12 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
struct fd_dev *fd_dev = FD_DEV(dev);
loff_t start = cmd->t_task_lba *
dev->dev_attrib.block_size;
loff_t end = start + cmd->data_length;
loff_t end;
if (cmd->data_length)
end = start + cmd->data_length - 1;
else
end = LLONG_MAX;
vfs_fsync_range(fd_dev->fd_file, start, end, 1);
}
......@@ -762,7 +767,9 @@ static ssize_t fd_set_configfs_dev_params(struct se_device *dev,
fd_dev->fbd_flags |= FBDF_HAS_SIZE;
break;
case Opt_fd_buffered_io:
match_int(args, &arg);
ret = match_int(args, &arg);
if (ret)
goto out;
if (arg != 1) {
pr_err("bogus fd_buffered_io=%d value\n", arg);
ret = -EINVAL;
......
......@@ -38,6 +38,7 @@ int se_dev_set_emulate_3pc(struct se_device *, int);
int se_dev_set_pi_prot_type(struct se_device *, int);
int se_dev_set_pi_prot_format(struct se_device *, int);
int se_dev_set_enforce_pr_isids(struct se_device *, int);
int se_dev_set_force_pr_aptpl(struct se_device *, int);
int se_dev_set_is_nonrot(struct se_device *, int);
int se_dev_set_emulate_rest_reord(struct se_device *dev, int);
int se_dev_set_queue_depth(struct se_device *, u32);
......@@ -46,7 +47,7 @@ int se_dev_set_fabric_max_sectors(struct se_device *, u32);
int se_dev_set_optimal_sectors(struct se_device *, u32);
int se_dev_set_block_size(struct se_device *, u32);
struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_device *, u32);
int core_dev_del_lun(struct se_portal_group *, u32);
void core_dev_del_lun(struct se_portal_group *, struct se_lun *);
struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32);
struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *,
struct se_node_acl *, u32, int *);
......@@ -82,8 +83,7 @@ void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *);
struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u32);
int core_tpg_add_lun(struct se_portal_group *, struct se_lun *,
u32, struct se_device *);
struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32 unpacked_lun);
int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *);
void core_tpg_remove_lun(struct se_portal_group *, struct se_lun *);
/* target_core_transport.c */
extern struct kmem_cache *se_tmr_req_cache;
......
......@@ -674,8 +674,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration(
*/
spin_lock(&dev->se_port_lock);
list_for_each_entry_safe(port, port_tmp, &dev->dev_sep_list, sep_list) {
atomic_inc(&port->sep_tg_pt_ref_cnt);
smp_mb__after_atomic();
atomic_inc_mb(&port->sep_tg_pt_ref_cnt);
spin_unlock(&dev->se_port_lock);
spin_lock_bh(&port->sep_alua_lock);
......@@ -709,8 +708,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration(
if (strcmp(nacl->initiatorname, nacl_tmp->initiatorname))
continue;
atomic_inc(&deve_tmp->pr_ref_count);
smp_mb__after_atomic();
atomic_inc_mb(&deve_tmp->pr_ref_count);
spin_unlock_bh(&port->sep_alua_lock);
/*
* Grab a configfs group dependency that is released
......@@ -722,10 +720,8 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration(
if (ret < 0) {
pr_err("core_scsi3_lunacl_depend"
"_item() failed\n");
atomic_dec(&port->sep_tg_pt_ref_cnt);
smp_mb__after_atomic();
atomic_dec(&deve_tmp->pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&port->sep_tg_pt_ref_cnt);
atomic_dec_mb(&deve_tmp->pr_ref_count);
goto out;
}
/*
......@@ -739,10 +735,8 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration(
nacl_tmp, deve_tmp, NULL,
sa_res_key, all_tg_pt, aptpl);
if (!pr_reg_atp) {
atomic_dec(&port->sep_tg_pt_ref_cnt);
smp_mb__after_atomic();
atomic_dec(&deve_tmp->pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&port->sep_tg_pt_ref_cnt);
atomic_dec_mb(&deve_tmp->pr_ref_count);
core_scsi3_lunacl_undepend_item(deve_tmp);
goto out;
}
......@@ -754,8 +748,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration(
spin_unlock_bh(&port->sep_alua_lock);
spin_lock(&dev->se_port_lock);
atomic_dec(&port->sep_tg_pt_ref_cnt);
smp_mb__after_atomic();
atomic_dec_mb(&port->sep_tg_pt_ref_cnt);
}
spin_unlock(&dev->se_port_lock);
......@@ -902,6 +895,7 @@ static int __core_scsi3_check_aptpl_registration(
spin_lock(&pr_tmpl->aptpl_reg_lock);
list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list,
pr_reg_aptpl_list) {
if (!strcmp(pr_reg->pr_iport, i_port) &&
(pr_reg->pr_res_mapped_lun == deve->mapped_lun) &&
!(strcmp(pr_reg->pr_tport, t_port)) &&
......@@ -944,10 +938,10 @@ int core_scsi3_check_aptpl_registration(
struct se_device *dev,
struct se_portal_group *tpg,
struct se_lun *lun,
struct se_lun_acl *lun_acl)
struct se_node_acl *nacl,
u32 mapped_lun)
{
struct se_node_acl *nacl = lun_acl->se_lun_nacl;
struct se_dev_entry *deve = nacl->device_list[lun_acl->mapped_lun];
struct se_dev_entry *deve = nacl->device_list[mapped_lun];
if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
return 0;
......@@ -1109,8 +1103,7 @@ static struct t10_pr_registration *__core_scsi3_locate_pr_reg(
if (dev->dev_attrib.enforce_pr_isids)
continue;
}
atomic_inc(&pr_reg->pr_res_holders);
smp_mb__after_atomic();
atomic_inc_mb(&pr_reg->pr_res_holders);
spin_unlock(&pr_tmpl->registration_lock);
return pr_reg;
}
......@@ -1124,8 +1117,7 @@ static struct t10_pr_registration *__core_scsi3_locate_pr_reg(
if (strcmp(isid, pr_reg->pr_reg_isid))
continue;
atomic_inc(&pr_reg->pr_res_holders);
smp_mb__after_atomic();
atomic_inc_mb(&pr_reg->pr_res_holders);
spin_unlock(&pr_tmpl->registration_lock);
return pr_reg;
}
......@@ -1154,8 +1146,7 @@ static struct t10_pr_registration *core_scsi3_locate_pr_reg(
static void core_scsi3_put_pr_reg(struct t10_pr_registration *pr_reg)
{
atomic_dec(&pr_reg->pr_res_holders);
smp_mb__after_atomic();
atomic_dec_mb(&pr_reg->pr_res_holders);
}
static int core_scsi3_check_implicit_release(
......@@ -1348,8 +1339,7 @@ static void core_scsi3_tpg_undepend_item(struct se_portal_group *tpg)
configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys,
&tpg->tpg_group.cg_item);
atomic_dec(&tpg->tpg_pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&tpg->tpg_pr_ref_count);
}
static int core_scsi3_nodeacl_depend_item(struct se_node_acl *nacl)
......@@ -1368,16 +1358,14 @@ static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl)
struct se_portal_group *tpg = nacl->se_tpg;
if (nacl->dynamic_node_acl) {
atomic_dec(&nacl->acl_pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&nacl->acl_pr_ref_count);
return;
}
configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys,
&nacl->acl_group.cg_item);
atomic_dec(&nacl->acl_pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&nacl->acl_pr_ref_count);
}
static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve)
......@@ -1407,8 +1395,7 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)
* For nacl->dynamic_node_acl=1
*/
if (!lun_acl) {
atomic_dec(&se_deve->pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&se_deve->pr_ref_count);
return;
}
nacl = lun_acl->se_lun_nacl;
......@@ -1417,8 +1404,7 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)
configfs_undepend_item(tpg->se_tpg_tfo->tf_subsys,
&lun_acl->se_lun_group.cg_item);
atomic_dec(&se_deve->pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&se_deve->pr_ref_count);
}
static sense_reason_t
......@@ -1551,15 +1537,13 @@ core_scsi3_decode_spec_i_port(
if (!i_str)
continue;
atomic_inc(&tmp_tpg->tpg_pr_ref_count);
smp_mb__after_atomic();
atomic_inc_mb(&tmp_tpg->tpg_pr_ref_count);
spin_unlock(&dev->se_port_lock);
if (core_scsi3_tpg_depend_item(tmp_tpg)) {
pr_err(" core_scsi3_tpg_depend_item()"
" for tmp_tpg\n");
atomic_dec(&tmp_tpg->tpg_pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&tmp_tpg->tpg_pr_ref_count);
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
goto out_unmap;
}
......@@ -1571,10 +1555,8 @@ core_scsi3_decode_spec_i_port(
spin_lock_irq(&tmp_tpg->acl_node_lock);
dest_node_acl = __core_tpg_get_initiator_node_acl(
tmp_tpg, i_str);
if (dest_node_acl) {
atomic_inc(&dest_node_acl->acl_pr_ref_count);
smp_mb__after_atomic();
}
if (dest_node_acl)
atomic_inc_mb(&dest_node_acl->acl_pr_ref_count);
spin_unlock_irq(&tmp_tpg->acl_node_lock);
if (!dest_node_acl) {
......@@ -1586,8 +1568,7 @@ core_scsi3_decode_spec_i_port(
if (core_scsi3_nodeacl_depend_item(dest_node_acl)) {
pr_err("configfs_depend_item() failed"
" for dest_node_acl->acl_group\n");
atomic_dec(&dest_node_acl->acl_pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&dest_node_acl->acl_pr_ref_count);
core_scsi3_tpg_undepend_item(tmp_tpg);
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
goto out_unmap;
......@@ -1646,8 +1627,7 @@ core_scsi3_decode_spec_i_port(
if (core_scsi3_lunacl_depend_item(dest_se_deve)) {
pr_err("core_scsi3_lunacl_depend_item()"
" failed\n");
atomic_dec(&dest_se_deve->pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&dest_se_deve->pr_ref_count);
core_scsi3_nodeacl_undepend_item(dest_node_acl);
core_scsi3_tpg_undepend_item(dest_tpg);
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
......@@ -3167,15 +3147,13 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
if (!dest_tf_ops)
continue;
atomic_inc(&dest_se_tpg->tpg_pr_ref_count);
smp_mb__after_atomic();
atomic_inc_mb(&dest_se_tpg->tpg_pr_ref_count);
spin_unlock(&dev->se_port_lock);
if (core_scsi3_tpg_depend_item(dest_se_tpg)) {
pr_err("core_scsi3_tpg_depend_item() failed"
" for dest_se_tpg\n");
atomic_dec(&dest_se_tpg->tpg_pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&dest_se_tpg->tpg_pr_ref_count);
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
goto out_put_pr_reg;
}
......@@ -3271,10 +3249,8 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
spin_lock_irq(&dest_se_tpg->acl_node_lock);
dest_node_acl = __core_tpg_get_initiator_node_acl(dest_se_tpg,
initiator_str);
if (dest_node_acl) {
atomic_inc(&dest_node_acl->acl_pr_ref_count);
smp_mb__after_atomic();
}
if (dest_node_acl)
atomic_inc_mb(&dest_node_acl->acl_pr_ref_count);
spin_unlock_irq(&dest_se_tpg->acl_node_lock);
if (!dest_node_acl) {
......@@ -3288,8 +3264,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
if (core_scsi3_nodeacl_depend_item(dest_node_acl)) {
pr_err("core_scsi3_nodeacl_depend_item() for"
" dest_node_acl\n");
atomic_dec(&dest_node_acl->acl_pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&dest_node_acl->acl_pr_ref_count);
dest_node_acl = NULL;
ret = TCM_INVALID_PARAMETER_LIST;
goto out;
......@@ -3313,8 +3288,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,
if (core_scsi3_lunacl_depend_item(dest_se_deve)) {
pr_err("core_scsi3_lunacl_depend_item() failed\n");
atomic_dec(&dest_se_deve->pr_ref_count);
smp_mb__after_atomic();
atomic_dec_mb(&dest_se_deve->pr_ref_count);
dest_se_deve = NULL;
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
goto out;
......@@ -3497,6 +3471,7 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb)
sense_reason_t
target_scsi3_emulate_pr_out(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
unsigned char *cdb = &cmd->t_task_cdb[0];
unsigned char *buf;
u64 res_key, sa_res_key;
......@@ -3561,6 +3536,13 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
aptpl = (buf[17] & 0x01);
unreg = (buf[17] & 0x02);
}
/*
* If the backend device has been configured to force APTPL metadata
* write-out, go ahead and propigate aptpl=1 down now.
*/
if (dev->dev_attrib.force_pr_aptpl)
aptpl = 1;
transport_kunmap_data_sg(cmd);
buf = NULL;
......@@ -3803,7 +3785,7 @@ core_scsi3_pri_report_capabilities(struct se_cmd *cmd)
if (!buf)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
buf[0] = ((add_len << 8) & 0xff);
buf[0] = ((add_len >> 8) & 0xff);
buf[1] = (add_len & 0xff);
buf[2] |= 0x10; /* CRH: Compatible Reservation Hanlding bit. */
buf[2] |= 0x08; /* SIP_C: Specify Initiator Ports Capable bit */
......@@ -3879,8 +3861,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
se_tpg = pr_reg->pr_reg_nacl->se_tpg;
add_desc_len = 0;
atomic_inc(&pr_reg->pr_res_holders);
smp_mb__after_atomic();
atomic_inc_mb(&pr_reg->pr_res_holders);
spin_unlock(&pr_tmpl->registration_lock);
/*
* Determine expected length of $FABRIC_MOD specific
......@@ -3893,8 +3874,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
pr_warn("SPC-3 PRIN READ_FULL_STATUS ran"
" out of buffer: %d\n", cmd->data_length);
spin_lock(&pr_tmpl->registration_lock);
atomic_dec(&pr_reg->pr_res_holders);
smp_mb__after_atomic();
atomic_dec_mb(&pr_reg->pr_res_holders);
break;
}
/*
......@@ -3955,8 +3935,7 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd)
se_nacl, pr_reg, &format_code, &buf[off+4]);
spin_lock(&pr_tmpl->registration_lock);
atomic_dec(&pr_reg->pr_res_holders);
smp_mb__after_atomic();
atomic_dec_mb(&pr_reg->pr_res_holders);
/*
* Set the ADDITIONAL DESCRIPTOR LENGTH
*/
......
......@@ -60,7 +60,7 @@ extern int core_scsi3_alloc_aptpl_registration(
unsigned char *, u16, u32, int, int, u8);
extern int core_scsi3_check_aptpl_registration(struct se_device *,
struct se_portal_group *, struct se_lun *,
struct se_lun_acl *);
struct se_node_acl *, u32);
extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *,
struct se_node_acl *);
extern void core_scsi3_free_all_registrations(struct se_device *);
......
......@@ -749,14 +749,18 @@ static ssize_t pscsi_set_configfs_dev_params(struct se_device *dev,
ret = -EINVAL;
goto out;
}
match_int(args, &arg);
ret = match_int(args, &arg);
if (ret)
goto out;
pdv->pdv_host_id = arg;
pr_debug("PSCSI[%d]: Referencing SCSI Host ID:"
" %d\n", phv->phv_host_id, pdv->pdv_host_id);
pdv->pdv_flags |= PDF_HAS_VIRT_HOST_ID;
break;
case Opt_scsi_channel_id:
match_int(args, &arg);
ret = match_int(args, &arg);
if (ret)
goto out;
pdv->pdv_channel_id = arg;
pr_debug("PSCSI[%d]: Referencing SCSI Channel"
" ID: %d\n", phv->phv_host_id,
......@@ -764,7 +768,9 @@ static ssize_t pscsi_set_configfs_dev_params(struct se_device *dev,
pdv->pdv_flags |= PDF_HAS_CHANNEL_ID;
break;
case Opt_scsi_target_id:
match_int(args, &arg);
ret = match_int(args, &arg);
if (ret)
goto out;
pdv->pdv_target_id = arg;
pr_debug("PSCSI[%d]: Referencing SCSI Target"
" ID: %d\n", phv->phv_host_id,
......@@ -772,7 +778,9 @@ static ssize_t pscsi_set_configfs_dev_params(struct se_device *dev,
pdv->pdv_flags |= PDF_HAS_TARGET_ID;
break;
case Opt_scsi_lun_id:
match_int(args, &arg);
ret = match_int(args, &arg);
if (ret)
goto out;
pdv->pdv_lun_id = arg;
pr_debug("PSCSI[%d]: Referencing SCSI LUN ID:"
" %d\n", phv->phv_host_id, pdv->pdv_lun_id);
......
......@@ -948,7 +948,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
}
/* reject any command that we don't have a handler for */
if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->execute_cmd)
if (!cmd->execute_cmd)
return TCM_UNSUPPORTED_SCSI_OPCODE;
if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
......
......@@ -64,21 +64,17 @@ int core_tmr_alloc_req(
}
EXPORT_SYMBOL(core_tmr_alloc_req);
void core_tmr_release_req(
struct se_tmr_req *tmr)
void core_tmr_release_req(struct se_tmr_req *tmr)
{
struct se_device *dev = tmr->tmr_dev;
unsigned long flags;
if (!dev) {
kfree(tmr);
return;
if (dev) {
spin_lock_irqsave(&dev->se_tmr_lock, flags);
list_del(&tmr->tmr_list);
spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
}
spin_lock_irqsave(&dev->se_tmr_lock, flags);
list_del(&tmr->tmr_list);
spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
kfree(tmr);
}
......@@ -90,9 +86,8 @@ static void core_tmr_handle_tas_abort(
bool remove = true;
/*
* TASK ABORTED status (TAS) bit support
*/
if ((tmr_nacl &&
(tmr_nacl != cmd->se_sess->se_node_acl)) && tas) {
*/
if ((tmr_nacl && (tmr_nacl != cmd->se_sess->se_node_acl)) && tas) {
remove = false;
transport_send_task_abort(cmd);
}
......@@ -120,13 +115,12 @@ void core_tmr_abort_task(
struct se_tmr_req *tmr,
struct se_session *se_sess)
{
struct se_cmd *se_cmd, *tmp_cmd;
struct se_cmd *se_cmd;
unsigned long flags;
int ref_tag;
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
list_for_each_entry_safe(se_cmd, tmp_cmd,
&se_sess->sess_cmd_list, se_cmd_list) {
list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) {
if (dev != se_cmd->se_dev)
continue;
......
......@@ -40,6 +40,7 @@
#include <target/target_core_fabric.h>
#include "target_core_internal.h"
#include "target_core_pr.h"
extern struct se_device *g_lun0_dev;
......@@ -166,6 +167,13 @@ void core_tpg_add_node_to_devs(
core_enable_device_list_for_node(lun, NULL, lun->unpacked_lun,
lun_access, acl, tpg);
/*
* Check to see if there are any existing persistent reservation
* APTPL pre-registrations that need to be enabled for this dynamic
* LUN ACL now..
*/
core_scsi3_check_aptpl_registration(dev, tpg, lun, acl,
lun->unpacked_lun);
spin_lock(&tpg->tpg_lun_lock);
}
spin_unlock(&tpg->tpg_lun_lock);
......@@ -335,7 +343,7 @@ void core_tpg_clear_object_luns(struct se_portal_group *tpg)
continue;
spin_unlock(&tpg->tpg_lun_lock);
core_dev_del_lun(tpg, lun->unpacked_lun);
core_dev_del_lun(tpg, lun);
spin_lock(&tpg->tpg_lun_lock);
}
spin_unlock(&tpg->tpg_lun_lock);
......@@ -663,13 +671,6 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg)
return 0;
}
static void core_tpg_release_virtual_lun0(struct se_portal_group *se_tpg)
{
struct se_lun *lun = &se_tpg->tpg_virt_lun0;
core_tpg_post_dellun(se_tpg, lun);
}
int core_tpg_register(
struct target_core_fabric_ops *tfo,
struct se_wwn *se_wwn,
......@@ -773,7 +774,7 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
spin_unlock_irq(&se_tpg->acl_node_lock);
if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL)
core_tpg_release_virtual_lun0(se_tpg);
core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0);
se_tpg->se_tpg_fabric_ptr = NULL;
array_free(se_tpg->tpg_lun_list, TRANSPORT_MAX_LUNS_PER_TPG);
......@@ -838,37 +839,7 @@ int core_tpg_add_lun(
return 0;
}
struct se_lun *core_tpg_pre_dellun(
struct se_portal_group *tpg,
u32 unpacked_lun)
{
struct se_lun *lun;
if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
pr_err("%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER_TPG"
"-1: %u for Target Portal Group: %u\n",
tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun,
TRANSPORT_MAX_LUNS_PER_TPG-1,
tpg->se_tpg_tfo->tpg_get_tag(tpg));
return ERR_PTR(-EOVERFLOW);
}
spin_lock(&tpg->tpg_lun_lock);
lun = tpg->tpg_lun_list[unpacked_lun];
if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) {
pr_err("%s Logical Unit Number: %u is not active on"
" Target Portal Group: %u, ignoring request.\n",
tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun,
tpg->se_tpg_tfo->tpg_get_tag(tpg));
spin_unlock(&tpg->tpg_lun_lock);
return ERR_PTR(-ENODEV);
}
spin_unlock(&tpg->tpg_lun_lock);
return lun;
}
int core_tpg_post_dellun(
void core_tpg_remove_lun(
struct se_portal_group *tpg,
struct se_lun *lun)
{
......@@ -882,6 +853,4 @@ int core_tpg_post_dellun(
spin_unlock(&tpg->tpg_lun_lock);
percpu_ref_exit(&lun->lun_ref);
return 0;
}
......@@ -232,6 +232,10 @@ void transport_subsystem_check_init(void)
if (ret != 0)
pr_err("Unable to load target_core_pscsi\n");
ret = request_module("target_core_user");
if (ret != 0)
pr_err("Unable to load target_core_user\n");
sub_api_initialized = 1;
}
......@@ -752,8 +756,7 @@ void target_qf_do_work(struct work_struct *work)
list_for_each_entry_safe(cmd, cmd_tmp, &qf_cmd_list, se_qf_node) {
list_del(&cmd->se_qf_node);
atomic_dec(&dev->dev_qf_count);
smp_mb__after_atomic();
atomic_dec_mb(&dev->dev_qf_count);
pr_debug("Processing %s cmd: %p QUEUE_FULL in work queue"
" context: %s\n", cmd->se_tfo->get_fabric_name(), cmd,
......@@ -1166,7 +1169,6 @@ transport_check_alloc_task_attr(struct se_cmd *cmd)
* Dormant to Active status.
*/
cmd->se_ordered_id = atomic_inc_return(&dev->dev_ordered_id);
smp_mb__after_atomic();
pr_debug("Allocated se_ordered_id: %u for Task Attr: 0x%02x on %s\n",
cmd->se_ordered_id, cmd->sam_task_attr,
dev->transport->name);
......@@ -1722,8 +1724,7 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
cmd->t_task_cdb[0], cmd->se_ordered_id);
return false;
case MSG_ORDERED_TAG:
atomic_inc(&dev->dev_ordered_sync);
smp_mb__after_atomic();
atomic_inc_mb(&dev->dev_ordered_sync);
pr_debug("Added ORDERED for CDB: 0x%02x to ordered list, "
" se_ordered_id: %u\n",
......@@ -1740,8 +1741,7 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
/*
* For SIMPLE and UNTAGGED Task Attribute commands
*/
atomic_inc(&dev->simple_cmds);
smp_mb__after_atomic();
atomic_inc_mb(&dev->simple_cmds);
break;
}
......@@ -1845,8 +1845,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
return;
if (cmd->sam_task_attr == MSG_SIMPLE_TAG) {
atomic_dec(&dev->simple_cmds);
smp_mb__after_atomic();
atomic_dec_mb(&dev->simple_cmds);
dev->dev_cur_ordered_id++;
pr_debug("Incremented dev->dev_cur_ordered_id: %u for"
" SIMPLE: %u\n", dev->dev_cur_ordered_id,
......@@ -1857,8 +1856,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
" HEAD_OF_QUEUE: %u\n", dev->dev_cur_ordered_id,
cmd->se_ordered_id);
} else if (cmd->sam_task_attr == MSG_ORDERED_TAG) {
atomic_dec(&dev->dev_ordered_sync);
smp_mb__after_atomic();
atomic_dec_mb(&dev->dev_ordered_sync);
dev->dev_cur_ordered_id++;
pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED:"
......@@ -1877,8 +1875,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
trace_target_cmd_complete(cmd);
ret = cmd->se_tfo->queue_status(cmd);
if (ret)
goto out;
goto out;
}
switch (cmd->data_direction) {
......@@ -1916,8 +1913,7 @@ static void transport_handle_queue_full(
{
spin_lock_irq(&dev->qf_cmd_lock);
list_add_tail(&cmd->se_qf_node, &cmd->se_dev->qf_cmd_list);
atomic_inc(&dev->dev_qf_count);
smp_mb__after_atomic();
atomic_inc_mb(&dev->dev_qf_count);
spin_unlock_irq(&cmd->se_dev->qf_cmd_lock);
schedule_work(&cmd->se_dev->qf_work_queue);
......@@ -2896,7 +2892,6 @@ void transport_send_task_abort(struct se_cmd *cmd)
if (cmd->se_tfo->write_pending_status(cmd) != 0) {
cmd->transport_state |= CMD_T_ABORTED;
cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS;
smp_mb__after_atomic();
return;
}
}
......
......@@ -161,8 +161,7 @@ int core_scsi3_ua_allocate(
spin_unlock(&deve->ua_lock);
spin_unlock_irq(&nacl->device_list_lock);
atomic_inc(&deve->ua_count);
smp_mb__after_atomic();
atomic_inc_mb(&deve->ua_count);
return 0;
}
list_add_tail(&ua->ua_nacl_list, &deve->ua_list);
......@@ -174,8 +173,7 @@ int core_scsi3_ua_allocate(
nacl->se_tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun,
asc, ascq);
atomic_inc(&deve->ua_count);
smp_mb__after_atomic();
atomic_inc_mb(&deve->ua_count);
return 0;
}
......@@ -189,8 +187,7 @@ void core_scsi3_ua_release_all(
list_del(&ua->ua_nacl_list);
kmem_cache_free(se_ua_cache, ua);
atomic_dec(&deve->ua_count);
smp_mb__after_atomic();
atomic_dec_mb(&deve->ua_count);
}
spin_unlock(&deve->ua_lock);
}
......@@ -250,8 +247,7 @@ void core_scsi3_ua_for_check_condition(
list_del(&ua->ua_nacl_list);
kmem_cache_free(se_ua_cache, ua);
atomic_dec(&deve->ua_count);
smp_mb__after_atomic();
atomic_dec_mb(&deve->ua_count);
}
spin_unlock(&deve->ua_lock);
spin_unlock_irq(&nacl->device_list_lock);
......@@ -309,8 +305,7 @@ int core_scsi3_ua_clear_for_request_sense(
list_del(&ua->ua_nacl_list);
kmem_cache_free(se_ua_cache, ua);
atomic_dec(&deve->ua_count);
smp_mb__after_atomic();
atomic_dec_mb(&deve->ua_count);
}
spin_unlock(&deve->ua_lock);
spin_unlock_irq(&nacl->device_list_lock);
......
#ifndef TARGET_CORE_UA_H
#define TARGET_CORE_UA_H
/*
* From spc4r17, Table D.1: ASC and ASCQ Assignement
......
此差异已折叠。
......@@ -98,7 +98,7 @@ static void ft_tport_delete(struct ft_tport *tport)
ft_sess_delete_all(tport);
lport = tport->lport;
BUG_ON(tport != lport->prov[FC_TYPE_FCP]);
rcu_assign_pointer(lport->prov[FC_TYPE_FCP], NULL);
RCU_INIT_POINTER(lport->prov[FC_TYPE_FCP], NULL);
tpg = tport->tpg;
if (tpg) {
......
......@@ -28,18 +28,6 @@
#define UIO_MAX_DEVICES (1U << MINORBITS)
struct uio_device {
struct module *owner;
struct device *dev;
int minor;
atomic_t event;
struct fasync_struct *async_queue;
wait_queue_head_t wait;
struct uio_info *info;
struct kobject *map_dir;
struct kobject *portio_dir;
};
static int uio_major;
static struct cdev *uio_cdev;
static DEFINE_IDR(uio_idr);
......
......@@ -63,7 +63,17 @@ struct uio_port {
#define MAX_UIO_PORT_REGIONS 5
struct uio_device;
struct uio_device {
struct module *owner;
struct device *dev;
int minor;
atomic_t event;
struct fasync_struct *async_queue;
wait_queue_head_t wait;
struct uio_info *info;
struct kobject *map_dir;
struct kobject *portio_dir;
};
/**
* struct uio_info - UIO device capabilities
......
......@@ -108,6 +108,8 @@
#define DA_EMULATE_ALUA 0
/* Enforce SCSI Initiator Port TransportID with 'ISID' for PR */
#define DA_ENFORCE_PR_ISIDS 1
/* Force SPC-3 PR Activate Persistence across Target Power Loss */
#define DA_FORCE_PR_APTPL 0
#define DA_STATUS_MAX_SECTORS_MIN 16
#define DA_STATUS_MAX_SECTORS_MAX 8192
/* By default don't report non-rotating (solid state) medium */
......@@ -680,6 +682,7 @@ struct se_dev_attrib {
enum target_prot_type pi_prot_type;
enum target_prot_type hw_pi_prot_type;
int enforce_pr_isids;
int force_pr_aptpl;
int is_nonrot;
int emulate_rest_reord;
u32 hw_block_size;
......@@ -903,4 +906,18 @@ struct se_wwn {
struct config_group fabric_stat_group;
};
static inline void atomic_inc_mb(atomic_t *v)
{
smp_mb__before_atomic();
atomic_inc(v);
smp_mb__after_atomic();
}
static inline void atomic_dec_mb(atomic_t *v)
{
smp_mb__before_atomic();
atomic_dec(v);
smp_mb__after_atomic();
}
#endif /* TARGET_CORE_BASE_H */
......@@ -374,6 +374,7 @@ header-y += swab.h
header-y += synclink.h
header-y += sysctl.h
header-y += sysinfo.h
header-y += target_core_user.h
header-y += taskstats.h
header-y += tcp.h
header-y += tcp_metrics.h
......
#ifndef __TARGET_CORE_USER_H
#define __TARGET_CORE_USER_H
/* This header will be used by application too */
#include <linux/types.h>
#include <linux/uio.h>
#ifndef __packed
#define __packed __attribute__((packed))
#endif
#define TCMU_VERSION "1.0"
/*
* Ring Design
* -----------
*
* The mmaped area is divided into three parts:
* 1) The mailbox (struct tcmu_mailbox, below)
* 2) The command ring
* 3) Everything beyond the command ring (data)
*
* The mailbox tells userspace the offset of the command ring from the
* start of the shared memory region, and how big the command ring is.
*
* The kernel passes SCSI commands to userspace by putting a struct
* tcmu_cmd_entry in the ring, updating mailbox->cmd_head, and poking
* userspace via uio's interrupt mechanism.
*
* tcmu_cmd_entry contains a header. If the header type is PAD,
* userspace should skip hdr->length bytes (mod cmdr_size) to find the
* next cmd_entry.
*
* Otherwise, the entry will contain offsets into the mmaped area that
* contain the cdb and data buffers -- the latter accessible via the
* iov array. iov addresses are also offsets into the shared area.
*
* When userspace is completed handling the command, set
* entry->rsp.scsi_status, fill in rsp.sense_buffer if appropriate,
* and also set mailbox->cmd_tail equal to the old cmd_tail plus
* hdr->length, mod cmdr_size. If cmd_tail doesn't equal cmd_head, it
* should process the next packet the same way, and so on.
*/
#define TCMU_MAILBOX_VERSION 1
#define ALIGN_SIZE 64 /* Should be enough for most CPUs */
struct tcmu_mailbox {
__u16 version;
__u16 flags;
__u32 cmdr_off;
__u32 cmdr_size;
__u32 cmd_head;
/* Updated by user. On its own cacheline */
__u32 cmd_tail __attribute__((__aligned__(ALIGN_SIZE)));
} __packed;
enum tcmu_opcode {
TCMU_OP_PAD = 0,
TCMU_OP_CMD,
};
/*
* Only a few opcodes, and length is 8-byte aligned, so use low bits for opcode.
*/
struct tcmu_cmd_entry_hdr {
__u32 len_op;
} __packed;
#define TCMU_OP_MASK 0x7
static inline enum tcmu_opcode tcmu_hdr_get_op(struct tcmu_cmd_entry_hdr *hdr)
{
return hdr->len_op & TCMU_OP_MASK;
}
static inline void tcmu_hdr_set_op(struct tcmu_cmd_entry_hdr *hdr, enum tcmu_opcode op)
{
hdr->len_op &= ~TCMU_OP_MASK;
hdr->len_op |= (op & TCMU_OP_MASK);
}
static inline __u32 tcmu_hdr_get_len(struct tcmu_cmd_entry_hdr *hdr)
{
return hdr->len_op & ~TCMU_OP_MASK;
}
static inline void tcmu_hdr_set_len(struct tcmu_cmd_entry_hdr *hdr, __u32 len)
{
hdr->len_op &= TCMU_OP_MASK;
hdr->len_op |= len;
}
/* Currently the same as SCSI_SENSE_BUFFERSIZE */
#define TCMU_SENSE_BUFFERSIZE 96
struct tcmu_cmd_entry {
struct tcmu_cmd_entry_hdr hdr;
uint16_t cmd_id;
uint16_t __pad1;
union {
struct {
uint64_t cdb_off;
uint64_t iov_cnt;
struct iovec iov[0];
} req;
struct {
uint8_t scsi_status;
uint8_t __pad1;
uint16_t __pad2;
uint32_t __pad3;
char sense_buffer[TCMU_SENSE_BUFFERSIZE];
} rsp;
};
} __packed;
#define TCMU_OP_ALIGN_SIZE sizeof(uint64_t)
enum tcmu_genl_cmd {
TCMU_CMD_UNSPEC,
TCMU_CMD_ADDED_DEVICE,
TCMU_CMD_REMOVED_DEVICE,
__TCMU_CMD_MAX,
};
#define TCMU_CMD_MAX (__TCMU_CMD_MAX - 1)
enum tcmu_genl_attr {
TCMU_ATTR_UNSPEC,
TCMU_ATTR_DEVICE,
TCMU_ATTR_MINOR,
__TCMU_ATTR_MAX,
};
#define TCMU_ATTR_MAX (__TCMU_ATTR_MAX - 1)
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册