Re: [PATCH 01/33] TCMU PR: first commit to implement TCMU PR

2018-06-15 Thread Christoph Hellwig
On Sat, Jun 16, 2018 at 02:23:10AM +0800, Zhu Lingshan wrote:
> These commits and the following intend to implement Persistent
> Reservation operations for TCMU devices.

Err, hell no.

If you are that tightly integrated with the target code that you can
implement persistent reservation you need to use kernel code.
Everything else just creates a way too complex interface.


[PATCH v2 0/8] mpt3sas: Fix static source code checker complaints

2018-06-15 Thread Bart Van Assche
Hello Martin,

This patch series addresses the complaints reported by multiple static
source code analysis tools about the mpt3sas source code. Please consider
these patches for kernel v4.19.

Thanks,

Bart.

Changes compared to v1:
- Addressed Randy Dunlap's feedback about kernel-doc headers.

Bart Van Assche (8):
  mpt3sas: Fix indentation
  mpt3sas: Remove set-but-not-used variables
  mpt3sas: Annotate switch/case fall-through
  mpt3sas: Introduce struct mpt3sas_nvme_cmd
  mpt3sas: Fix _transport_smp_handler() error path
  mpt3sas: Fix a race condition in mpt3sas_base_hard_reset_handler()
  mpt3sas: Split _base_reset_handler(), mpt3sas_scsih_reset_handler()
and mpt3sas_ctl_reset_handler()
  mpt3sas: Improve kernel-doc headers

 drivers/scsi/mpt3sas/mpt3sas_base.c | 366 +++--
 drivers/scsi/mpt3sas/mpt3sas_base.h |  23 +-
 drivers/scsi/mpt3sas/mpt3sas_config.c   |  74 ++--
 drivers/scsi/mpt3sas/mpt3sas_ctl.c  | 357 +---
 drivers/scsi/mpt3sas/mpt3sas_scsih.c| 428 +++-
 drivers/scsi/mpt3sas/mpt3sas_transport.c|  62 ++-
 drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c |  18 +-
 drivers/scsi/mpt3sas/mpt3sas_warpdrive.c|   3 -
 8 files changed, 568 insertions(+), 763 deletions(-)

-- 
2.17.0



[PATCH v2 5/8] mpt3sas: Fix _transport_smp_handler() error path

2018-06-15 Thread Bart Van Assche
This patch avoids that smatch complains about a double unlock on
ioc->transport_cmds.mutex.

Fixes: 651a01364994 ("scsi: scsi_transport_sas: switch to bsg-lib for SMP 
passthrough")
Signed-off-by: Bart Van Assche 
Cc: Christoph Hellwig 
Cc: Sathya Prakash 
Cc: Chaitra P B 
Cc: Suganath Prabu Subramani 
Cc: sta...@vger.kernel.org
---
 drivers/scsi/mpt3sas/mpt3sas_transport.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c 
b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index 05d506d78c66..f4b02dd7f6cf 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -1936,12 +1936,12 @@ _transport_smp_handler(struct bsg_job *job, struct 
Scsi_Host *shost,
pr_info(MPT3SAS_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
rc = -EFAULT;
-   goto out;
+   goto job_done;
}
 
rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
if (rc)
-   goto out;
+   goto job_done;
 
if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {
pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", ioc->name,
@@ -2066,6 +2066,7 @@ _transport_smp_handler(struct bsg_job *job, struct 
Scsi_Host *shost,
  out:
ioc->transport_cmds.status = MPT3_CMD_NOT_USED;
mutex_unlock(&ioc->transport_cmds.mutex);
+job_done:
bsg_job_done(job, rc, reslen);
 }
 
-- 
2.17.0



[PATCH v2 8/8] mpt3sas: Improve kernel-doc headers

2018-06-15 Thread Bart Van Assche
Avoids that warnings about the kernel headers appear when building
with W=1. Remove useless "@Returns - Nothing" clauses. Change
"@Return - " into "Return: ".

Signed-off-by: Bart Van Assche 
Cc: Sathya Prakash 
Cc: Chaitra P B 
Cc: Suganath Prabu Subramani 
Cc: Randy Dunlap 
---
 drivers/scsi/mpt3sas/mpt3sas_base.c | 213 +--
 drivers/scsi/mpt3sas/mpt3sas_config.c   |  74 ++---
 drivers/scsi/mpt3sas/mpt3sas_ctl.c  | 267 ++
 drivers/scsi/mpt3sas/mpt3sas_scsih.c| 288 +---
 drivers/scsi/mpt3sas/mpt3sas_transport.c|  55 ++--
 drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c |  18 +-
 drivers/scsi/mpt3sas/mpt3sas_warpdrive.c|   3 -
 7 files changed, 363 insertions(+), 555 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c 
b/drivers/scsi/mpt3sas/mpt3sas_base.c
index c2c523269414..1b63a7e218aa 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -103,7 +103,10 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc);
 
 /**
  * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
+ * @val: ?
+ * @kp: ?
  *
+ * Return: ?
  */
 static int
 _scsih_set_fwfault_debug(const char *val, const struct kernel_param *kp)
@@ -132,8 +135,6 @@ module_param_call(mpt3sas_fwfault_debug, 
_scsih_set_fwfault_debug,
  * @ioc: per adapter object
  * @reply: reply message frame(lower 32bit addr)
  * @index: System request message index.
- *
- * @Returns - Nothing
  */
 static void
 _base_clone_reply_to_sys_mem(struct MPT3SAS_ADAPTER *ioc, u32 reply,
@@ -156,7 +157,7 @@ _base_clone_reply_to_sys_mem(struct MPT3SAS_ADAPTER *ioc, 
u32 reply,
  * _base_clone_mpi_to_sys_mem - Writes/copies MPI frames
  * to system/BAR0 region.
  *
- * @dst_iomem: Pointer to the destinaltion location in BAR0 space.
+ * @dst_iomem: Pointer to the destination location in BAR0 space.
  * @src: Pointer to the Source data.
  * @size: Size of data to be copied.
  */
@@ -197,7 +198,7 @@ _base_clone_to_sys_mem(void __iomem *dst_iomem, void *src, 
u32 size)
  * @smid: system request message index
  * @sge_chain_count: Scatter gather chain count.
  *
- * @Return: chain address.
+ * Return: the chain address.
  */
 static inline void __iomem*
 _base_get_chain(struct MPT3SAS_ADAPTER *ioc, u16 smid,
@@ -223,7 +224,7 @@ _base_get_chain(struct MPT3SAS_ADAPTER *ioc, u16 smid,
  * @smid: system request message index
  * @sge_chain_count: Scatter gather chain count.
  *
- * @Return - Physical chain address.
+ * Return: Physical chain address.
  */
 static inline phys_addr_t
 _base_get_chain_phys(struct MPT3SAS_ADAPTER *ioc, u16 smid,
@@ -248,7 +249,7 @@ _base_get_chain_phys(struct MPT3SAS_ADAPTER *ioc, u16 smid,
  * @ioc: per adapter object
  * @smid: system request message index
  *
- * @Returns - Pointer to buffer location in BAR0.
+ * Return: Pointer to buffer location in BAR0.
  */
 
 static void __iomem *
@@ -270,7 +271,7 @@ _base_get_buffer_bar0(struct MPT3SAS_ADAPTER *ioc, u16 smid)
  * @ioc: per adapter object
  * @smid: system request message index
  *
- * @Returns - Pointer to buffer location in BAR0.
+ * Return: Pointer to buffer location in BAR0.
  */
 static phys_addr_t
 _base_get_buffer_phys_bar0(struct MPT3SAS_ADAPTER *ioc, u16 smid)
@@ -291,7 +292,7 @@ _base_get_buffer_phys_bar0(struct MPT3SAS_ADAPTER *ioc, u16 
smid)
  * @ioc: per adapter object
  * @chain_buffer_dma: Chain buffer dma address.
  *
- * @Returns - Pointer to chain buffer. Or Null on Failure.
+ * Return: Pointer to chain buffer. Or Null on Failure.
  */
 static void *
 _base_get_chain_buffer_dma_to_chain_buffer(struct MPT3SAS_ADAPTER *ioc,
@@ -322,8 +323,6 @@ _base_get_chain_buffer_dma_to_chain_buffer(struct 
MPT3SAS_ADAPTER *ioc,
  * @ioc: per adapter object.
  * @mpi_request: mf request pointer.
  * @smid: system request message index.
- *
- * @Returns: Nothing.
  */
 static void _clone_sg_entries(struct MPT3SAS_ADAPTER *ioc,
void *mpi_request, u16 smid)
@@ -496,8 +495,9 @@ static void _clone_sg_entries(struct MPT3SAS_ADAPTER *ioc,
  *  mpt3sas_remove_dead_ioc_func - kthread context to remove dead ioc
  * @arg: input argument, used to derive ioc
  *
- * Return 0 if controller is removed from pci subsystem.
- * Return -1 for other case.
+ * Return:
+ * 0 if controller is removed from pci subsystem.
+ * -1 for other case.
  */
 static int mpt3sas_remove_dead_ioc_func(void *arg)
 {
@@ -517,9 +517,8 @@ static int mpt3sas_remove_dead_ioc_func(void *arg)
 /**
  * _base_fault_reset_work - workq handling ioc fault conditions
  * @work: input argument, used to derive ioc
- * Context: sleep.
  *
- * Return nothing.
+ * Context: sleep.
  */
 static void
 _base_fault_reset_work(struct work_struct *work)
@@ -610,9 +609,8 @@ _base_fault_reset_work(struct work_struct *work)
 /**
  * mpt3sas_base_start_watchdog - start the fault_reset_work_q
  * @ioc: per adapter object
- * Context: sleep.
  *
- * Return nothing.
+ * Context: sleep.

[PATCH v2 3/8] mpt3sas: Annotate switch/case fall-through

2018-06-15 Thread Bart Van Assche
This patch avoids that gcc complains about switch/case fall-through
when building with W=1.

Signed-off-by: Bart Van Assche 
Cc: Sathya Prakash 
Cc: Chaitra P B 
Cc: Suganath Prabu Subramani 
---
 drivers/scsi/mpt3sas/mpt3sas_ctl.c   | 1 +
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c 
b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index 3269ef43f07e..07d28b7d5f1c 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -970,6 +970,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct 
mpt3_ioctl_command karg,
}
/* drop to default case for posting the request */
}
+   /* fall through */
default:
ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz,
data_in_dma, data_in_sz);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c 
b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index cac9a264e152..f1a748081fe4 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -5414,6 +5414,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 
msix_index, u32 reply)
 
case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
scsi_set_resid(scmd, 0);
+   /* fall through */
case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
case MPI2_IOCSTATUS_SUCCESS:
scmd->result = (DID_OK << 16) | scsi_status;
@@ -6444,6 +6445,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER 
*ioc,
if (!test_bit(handle, ioc->pend_os_device_add))
break;
 
+   /* fall through */
 
case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
 
@@ -7160,6 +7162,7 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER 
*ioc,
event_data->PortEntry[i].PortStatus &= 0xF0;
event_data->PortEntry[i].PortStatus |=
MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED;
+   /* fall through */
case MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED:
if (ioc->shost_recovery)
break;
-- 
2.17.0



[PATCH v2 1/8] mpt3sas: Fix indentation

2018-06-15 Thread Bart Van Assche
Modify the indentation such that smatch no longer complains about
inconsistent indenting.

Signed-off-by: Bart Van Assche 
Cc: Sathya Prakash 
Cc: Chaitra P B 
Cc: Suganath Prabu Subramani 
---
 drivers/scsi/mpt3sas/mpt3sas_base.c  |  2 +-
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 40 
 drivers/scsi/mpt3sas/mpt3sas_transport.c |  2 +-
 3 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c 
b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 569392d0d4c9..798ee62c97f1 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -633,7 +633,7 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc)
if (!ioc->fault_reset_work_q) {
pr_err(MPT3SAS_FMT "%s: failed (line=%d)\n",
ioc->name, __func__, __LINE__);
-   return;
+   return;
}
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->fault_reset_work_q)
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c 
b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index b8d131a455d0..42a8d79be7ec 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -2256,7 +2256,7 @@ scsih_slave_configure(struct scsi_device *sdev)
ds = "SSP";
} else {
qdepth = MPT3SAS_SATA_QUEUE_DEPTH;
-if (raid_device->device_info &
+   if (raid_device->device_info &
MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
ds = "SATA";
else
@@ -4004,19 +4004,19 @@ _scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER 
*ioc, u16 smid, U16 event,
 static void
 _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc,
u16 smid, u16 handle)
-   {
-   Mpi2SasIoUnitControlRequest_t *mpi_request;
-   u32 ioc_state;
-   int i = smid - ioc->internal_smid;
-   unsigned long flags;
+{
+   Mpi2SasIoUnitControlRequest_t *mpi_request;
+   u32 ioc_state;
+   int i = smid - ioc->internal_smid;
+   unsigned long flags;
 
-   if (ioc->remove_host) {
-   dewtprintk(ioc, pr_info(MPT3SAS_FMT
+   if (ioc->remove_host) {
+   dewtprintk(ioc, pr_info(MPT3SAS_FMT
"%s: host has been removed\n",
 __func__, ioc->name));
-   return;
-   } else if (ioc->pci_error_recovery) {
-   dewtprintk(ioc, pr_info(MPT3SAS_FMT
+   return;
+   } else if (ioc->pci_error_recovery) {
+   dewtprintk(ioc, pr_info(MPT3SAS_FMT
"%s: host in pci error recovery\n",
__func__, ioc->name));
return;
@@ -4674,19 +4674,19 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd 
*scmd)
}
 
 
-   /* host recovery or link resets sent via IOCTLs */
-   if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
+   if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) {
+   /* host recovery or link resets sent via IOCTLs */
return SCSI_MLQUEUE_HOST_BUSY;
-
-   /* device has been deleted */
-   else if (sas_target_priv_data->deleted) {
+   } else if (sas_target_priv_data->deleted) {
+   /* device has been deleted */
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
return 0;
-   /* device busy with task management */
} else if (sas_target_priv_data->tm_busy ||
-   sas_device_priv_data->block)
+  sas_device_priv_data->block) {
+   /* device busy with task management */
return SCSI_MLQUEUE_DEVICE_BUSY;
+   }
 
/*
 * Bug work around for firmware SATL handling.  The loop
@@ -5812,7 +5812,7 @@ _scsih_expander_add(struct MPT3SAS_ADAPTER *ioc, u16 
handle)
}
 
_scsih_expander_node_add(ioc, sas_expander);
-return 0;
+   return 0;
 
  out_fail:
 
@@ -9519,7 +9519,7 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct 
fw_event_work *fw_event)
break;
case MPT3SAS_PORT_ENABLE_COMPLETE:
ioc->start_scan = 0;
-   if (missing_delay[0] != -1 && missing_delay[1] != -1)
+   if (missing_delay[0] != -1 && missing_delay[1] != -1)
mpt3sas_base_update_missing_delay(ioc, missing_delay[0],
missing_delay[1]);
dewtprintk(ioc, pr_info(MPT3SAS_FMT
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c 
b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index 3a143bb5ca72..05d506d78c66 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mp

[PATCH v2 2/8] mpt3sas: Remove set-but-not-used variables

2018-06-15 Thread Bart Van Assche
This patch does not change any functionality.

Signed-off-by: Bart Van Assche 
Cc: Sathya Prakash 
Cc: Chaitra P B 
Cc: Suganath Prabu Subramani 
---
 drivers/scsi/mpt3sas/mpt3sas_base.c  | 10 --
 drivers/scsi/mpt3sas/mpt3sas_scsih.c |  5 -
 2 files changed, 15 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c 
b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 798ee62c97f1..9c233ddc5b2b 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -2127,11 +2127,9 @@ base_is_prp_possible(struct MPT3SAS_ADAPTER *ioc,
struct _pcie_device *pcie_device, struct scsi_cmnd *scmd, int sge_count)
 {
u32 data_length = 0;
-   struct scatterlist *sg_scmd;
bool build_prp = true;
 
data_length = scsi_bufflen(scmd);
-   sg_scmd = scsi_sglist(scmd);
 
/* If Datalenth is <= 16K and number of SGE’s entries are <= 2
 * we built IEEE SGL
@@ -2162,11 +2160,9 @@ _base_check_pcie_native_sgl(struct MPT3SAS_ADAPTER *ioc,
Mpi25SCSIIORequest_t *mpi_request, u16 smid, struct scsi_cmnd *scmd,
struct _pcie_device *pcie_device)
 {
-   struct scatterlist *sg_scmd;
int sges_left;
 
/* Get the SG list pointer and info. */
-   sg_scmd = scsi_sglist(scmd);
sges_left = scsi_dma_map(scmd);
if (sges_left < 0) {
sdev_printk(KERN_ERR, scmd->device,
@@ -3472,11 +3468,8 @@ mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER 
*ioc, u16 smid,
u64 *request;
 
if (ioc->is_mcpu_endpoint) {
-   MPI2RequestHeader_t *request_hdr;
-
__le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid);
 
-   request_hdr = (MPI2RequestHeader_t *)mfp;
/* TBD 256 is offset within sys register. */
mpi_req_iomem = (void __force *)ioc->chip
+ MPI_FRAME_START_OFFSET
@@ -3539,13 +3532,10 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER 
*ioc, u16 smid)
Mpi2RequestDescriptorUnion_t descriptor;
void *mpi_req_iomem;
u64 *request;
-   MPI2RequestHeader_t *request_hdr;
 
if (ioc->is_mcpu_endpoint) {
__le32 *mfp = (__le32 *)mpt3sas_base_get_msg_frame(ioc, smid);
 
-   request_hdr = (MPI2RequestHeader_t *)mfp;
-
_clone_sg_entries(ioc, (void *) mfp, smid);
/* TBD 256 is offset within sys register */
mpi_req_iomem = (void __force *)ioc->chip +
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c 
b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 42a8d79be7ec..cac9a264e152 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -1653,7 +1653,6 @@ scsih_target_destroy(struct scsi_target *starget)
struct _raid_device *raid_device;
struct _pcie_device *pcie_device;
unsigned long flags;
-   struct sas_rphy *rphy;
 
sas_target_priv_data = starget->hostdata;
if (!sas_target_priv_data)
@@ -1693,7 +1692,6 @@ scsih_target_destroy(struct scsi_target *starget)
}
 
spin_lock_irqsave(&ioc->sas_device_lock, flags);
-   rphy = dev_to_rphy(starget->dev.parent);
sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
if (sas_device && (sas_device->starget == starget) &&
(sas_device->id == starget->id) &&
@@ -6873,7 +6871,6 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 
handle)
Mpi2ConfigReply_t mpi_reply;
struct _pcie_device *pcie_device;
struct _enclosure_node *enclosure_dev;
-   u32 pcie_device_type;
u32 ioc_status;
u64 wwid;
 
@@ -6935,8 +6932,6 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 
handle)
pcie_device->port_num = pcie_device_pg0.PortNum;
pcie_device->fast_path = (le32_to_cpu(pcie_device_pg0.Flags) &
MPI26_PCIEDEV0_FLAGS_FAST_PATH_CAPABLE) ? 1 : 0;
-   pcie_device_type = pcie_device->device_info &
-   MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE;
 
pcie_device->enclosure_handle =
le16_to_cpu(pcie_device_pg0.EnclosureHandle);
-- 
2.17.0



[PATCH v2 6/8] mpt3sas: Fix a race condition in mpt3sas_base_hard_reset_handler()

2018-06-15 Thread Bart Van Assche
Since ioc->shost_recovery is set after ioc->reset_in_progress_mutex
is obtained, if concurrent resets are issued there is a short time
during which ioc->reset_in_progress_mutex is locked and
ioc->shost_recovery == 0. Avoid that this can cause trouble by
unconditionally locking ioc->shost_recovery.

Signed-off-by: Bart Van Assche 
Cc: Sathya Prakash 
Cc: Chaitra P B 
Cc: Suganath Prabu Subramani 
---
 drivers/scsi/mpt3sas/mpt3sas_base.c | 10 +-
 drivers/scsi/mpt3sas/mpt3sas_base.h |  1 -
 2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c 
b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 22e9aa0c5156..e51b42ad7a4a 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -6934,14 +6934,7 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER 
*ioc,
mpt3sas_halt_firmware(ioc);
 
/* wait for an active reset in progress to complete */
-   if (!mutex_trylock(&ioc->reset_in_progress_mutex)) {
-   do {
-   ssleep(1);
-   } while (ioc->shost_recovery == 1);
-   dtmprintk(ioc, pr_info(MPT3SAS_FMT "%s: exit\n", ioc->name,
-   __func__));
-   return ioc->ioc_reset_in_progress_status;
-   }
+   mutex_lock(&ioc->reset_in_progress_mutex);
 
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
ioc->shost_recovery = 1;
@@ -6990,7 +6983,6 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER 
*ioc,
ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED")));
 
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
-   ioc->ioc_reset_in_progress_status = r;
ioc->shost_recovery = 0;
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
ioc->ioc_reset_count++;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h 
b/drivers/scsi/mpt3sas/mpt3sas_base.h
index c6c36750deaa..a23ae2eb9c09 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -1165,7 +1165,6 @@ struct MPT3SAS_ADAPTER {
struct mutexreset_in_progress_mutex;
spinlock_t  ioc_reset_in_progress_lock;
u8  ioc_link_reset_in_progress;
-   u8  ioc_reset_in_progress_status;
 
u8  ignore_loginfos;
u8  remove_host;
-- 
2.17.0



[PATCH v2 7/8] mpt3sas: Split _base_reset_handler(), mpt3sas_scsih_reset_handler() and mpt3sas_ctl_reset_handler()

2018-06-15 Thread Bart Van Assche
Split each of these functions in three functions - one function
per reset phase. This patch does not change any functionality but
makes the code easier to read.

Note: it is much easier to review the git diff -w output after
having applied this patch than by reviewing the patch itself.

Signed-off-by: Bart Van Assche 
Cc: Sathya Prakash 
Cc: Chaitra P B 
Cc: Suganath Prabu Subramani 
---
 drivers/scsi/mpt3sas/mpt3sas_base.c  | 118 ++-
 drivers/scsi/mpt3sas/mpt3sas_base.h  |  15 ++--
 drivers/scsi/mpt3sas/mpt3sas_ctl.c   |  89 +++-
 drivers/scsi/mpt3sas/mpt3sas_scsih.c |  92 +++--
 4 files changed, 166 insertions(+), 148 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c 
b/drivers/scsi/mpt3sas/mpt3sas_base.c
index e51b42ad7a4a..c2c523269414 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -6815,65 +6815,69 @@ mpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc)
 }
 
 /**
- * _base_reset_handler - reset callback handler (for base)
+ * _base_pre_reset_handler - pre reset handler
  * @ioc: per adapter object
- * @reset_phase: phase
- *
- * The handler for doing any required cleanup or initialization.
- *
- * The reset phase can be MPT3_IOC_PRE_RESET, MPT3_IOC_AFTER_RESET,
- * MPT3_IOC_DONE_RESET
- *
- * Return nothing.
  */
-static void
-_base_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase)
+static void _base_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc)
 {
-   mpt3sas_scsih_reset_handler(ioc, reset_phase);
-   mpt3sas_ctl_reset_handler(ioc, reset_phase);
-   switch (reset_phase) {
-   case MPT3_IOC_PRE_RESET:
-   dtmprintk(ioc, pr_info(MPT3SAS_FMT
-   "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__));
-   break;
-   case MPT3_IOC_AFTER_RESET:
-   dtmprintk(ioc, pr_info(MPT3SAS_FMT
-   "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__));
-   if (ioc->transport_cmds.status & MPT3_CMD_PENDING) {
-   ioc->transport_cmds.status |= MPT3_CMD_RESET;
-   mpt3sas_base_free_smid(ioc, ioc->transport_cmds.smid);
-   complete(&ioc->transport_cmds.done);
-   }
-   if (ioc->base_cmds.status & MPT3_CMD_PENDING) {
-   ioc->base_cmds.status |= MPT3_CMD_RESET;
-   mpt3sas_base_free_smid(ioc, ioc->base_cmds.smid);
-   complete(&ioc->base_cmds.done);
-   }
-   if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) {
-   ioc->port_enable_failed = 1;
-   ioc->port_enable_cmds.status |= MPT3_CMD_RESET;
-   mpt3sas_base_free_smid(ioc, ioc->port_enable_cmds.smid);
-   if (ioc->is_driver_loading) {
-   ioc->start_scan_failed =
-   MPI2_IOCSTATUS_INTERNAL_ERROR;
-   ioc->start_scan = 0;
-   ioc->port_enable_cmds.status =
-   MPT3_CMD_NOT_USED;
-   } else
-   complete(&ioc->port_enable_cmds.done);
-   }
-   if (ioc->config_cmds.status & MPT3_CMD_PENDING) {
-   ioc->config_cmds.status |= MPT3_CMD_RESET;
-   mpt3sas_base_free_smid(ioc, ioc->config_cmds.smid);
-   ioc->config_cmds.smid = USHRT_MAX;
-   complete(&ioc->config_cmds.done);
+   mpt3sas_scsih_pre_reset_handler(ioc);
+   mpt3sas_ctl_pre_reset_handler(ioc);
+   dtmprintk(ioc, pr_info(MPT3SAS_FMT
+   "%s: MPT3_IOC_PRE_RESET\n", ioc->name, __func__));
+}
+
+/**
+ * _base_after_reset_handler - after reset handler
+ * @ioc: per adapter object
+ */
+static void _base_after_reset_handler(struct MPT3SAS_ADAPTER *ioc)
+{
+   mpt3sas_scsih_after_reset_handler(ioc);
+   mpt3sas_ctl_after_reset_handler(ioc);
+   dtmprintk(ioc, pr_info(MPT3SAS_FMT
+   "%s: MPT3_IOC_AFTER_RESET\n", ioc->name, __func__));
+   if (ioc->transport_cmds.status & MPT3_CMD_PENDING) {
+   ioc->transport_cmds.status |= MPT3_CMD_RESET;
+   mpt3sas_base_free_smid(ioc, ioc->transport_cmds.smid);
+   complete(&ioc->transport_cmds.done);
+   }
+   if (ioc->base_cmds.status & MPT3_CMD_PENDING) {
+   ioc->base_cmds.status |= MPT3_CMD_RESET;
+   mpt3sas_base_free_smid(ioc, ioc->base_cmds.smid);
+   complete(&ioc->base_cmds.done);
+   }
+   if (ioc->port_enable_cmds.status & MPT3_CMD_PENDING) {
+   ioc->port_enable_failed = 1;
+   ioc->port_enable_cmds.status |= MPT3_CMD_RESET;
+   mpt3sas_base_free_smid(ioc, ioc->port_enable_cmds.smid);
+   if (ioc->is_driver_loading) {
+   

[PATCH v2 4/8] mpt3sas: Introduce struct mpt3sas_nvme_cmd

2018-06-15 Thread Bart Van Assche
Make _base_build_nvme_prp() easier to read by introducing a structure
to access NVMe command fields.

Signed-off-by: Bart Van Assche 
Cc: Sathya Prakash 
Cc: Chaitra P B 
Cc: Suganath Prabu Subramani 
---
 drivers/scsi/mpt3sas/mpt3sas_base.c | 13 -
 drivers/scsi/mpt3sas/mpt3sas_base.h |  7 +--
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c 
b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 9c233ddc5b2b..22e9aa0c5156 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -1836,6 +1836,8 @@ _base_build_nvme_prp(struct MPT3SAS_ADAPTER *ioc, u16 
smid,
u32 offset, entry_len;
u32 page_mask_result, page_mask;
size_t  length;
+   struct mpt3sas_nvme_cmd *nvme_cmd =
+   (void *)nvme_encap_request->NVMe_Command;
 
/*
 * Not all commands require a data transfer. If no data, just return
@@ -1843,15 +1845,8 @@ _base_build_nvme_prp(struct MPT3SAS_ADAPTER *ioc, u16 
smid,
 */
if (!data_in_sz && !data_out_sz)
return;
-   /*
-* Set pointers to PRP1 and PRP2, which are in the NVMe command.
-* PRP1 is located at a 24 byte offset from the start of the NVMe
-* command.  Then set the current PRP entry pointer to PRP1.
-*/
-   prp1_entry = (__le64 *)(nvme_encap_request->NVMe_Command +
-   NVME_CMD_PRP1_OFFSET);
-   prp2_entry = (__le64 *)(nvme_encap_request->NVMe_Command +
-   NVME_CMD_PRP2_OFFSET);
+   prp1_entry = &nvme_cmd->prp1;
+   prp2_entry = &nvme_cmd->prp2;
prp_entry = prp1_entry;
/*
 * For the PRP entries, use the specially allocated buffer of
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h 
b/drivers/scsi/mpt3sas/mpt3sas_base.h
index f02974c0be4a..c6c36750deaa 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -143,14 +143,17 @@
  * NVMe defines
  */
 #defineNVME_PRP_SIZE   8   /* PRP size */
-#defineNVME_CMD_PRP1_OFFSET24  /* PRP1 offset in NVMe 
cmd */
-#defineNVME_CMD_PRP2_OFFSET32  /* PRP2 offset in NVMe 
cmd */
 #defineNVME_ERROR_RESPONSE_SIZE16  /* Max NVME Error 
Response */
 #define NVME_TASK_ABORT_MIN_TIMEOUT6
 #define NVME_TASK_ABORT_MAX_TIMEOUT60
 #define NVME_TASK_MNGT_CUSTOM_MASK (0x0010)
 #defineNVME_PRP_PAGE_SIZE  4096/* Page size */
 
+struct mpt3sas_nvme_cmd {
+   u8  rsvd[24];
+   __le64  prp1;
+   __le64  prp2;
+};
 
 /*
  * reset phases
-- 
2.17.0



Re: [PATCH 01/33] TCMU PR: first commit to implement TCMU PR

2018-06-15 Thread Zhu Lingshan

Hi,

I am replying my own thread, if you want to test these commits, maybe 
you need my tcmu-runner patch, I have attached, it works fine with PR 
register, reserve, clear, release and preempt. Or you can use my repo 
directly: https://github.com/ls-zhu/tcmu-runner/tree/rbd_v2_pr


It only works for Ceph RBD as backend for now, because other TCMU 
storage like qcow or a file does not have something like metadata. If we 
want such support for devices other than RBD, we may change their 
handler in tcmu-runner, like allocate some sectors works like metadata. 
I know gluster may support this, we can implement it after kernel side 
stabilized.


Thanks,
BR
Zhu Lingshan


On 2018/6/16 2:23, Zhu Lingshan wrote:

These commits and the following intend to implement Persistent
Reservation operations for TCMU devices.

This series of commits would implement such PR operations:
PR_Out_Register, PR_Out_Reserve, PR_Out_Clear, PR_Out_Preempt,
PR_Out_Release and PR_In_ReadKeys.

Next wave of patches will contain the other PR operations.

This patch added a struct tcmu_pr_info to store PR information
for the handling functions, added command codes and attrs for
netlink interfaces.

Design note:
In order to get consistent Persistent Reservation results from
multiple targets hosting the same TCMU device(like Ceph RBD),
this solution stores a string on the device itself(like RBD metadata).

Everytime when kernel receive a PR request against a TCMU device,
it will query this string(a netlink attr carried by a netlink cmd).
Then decide whether the PR request should be performed, after
processing, it will update this string.

For example:
When receive a PR Reserve request, kernel will send a netlink
message to tcmu-runner, try to get the string, tcmu-runner will
response, send the PR info string to kernel. Then kernel will
decode the string, find information like key, reservation holder,
then process this request. After processing, it will update the
string, send the updated string to tcmu-runner, so that tcmu-runner
will write it back to the device(like RBD metadata).

So we make the device itself as a "single" response point, (with
locks protection) we will get a consistent result even more than one
initiators sending multiple PR requests via multiple targets.

Signed-off-by: Zhu Lingshan 
---
  include/uapi/linux/target_core_user.h | 19 +++
  1 file changed, 19 insertions(+)

diff --git a/include/uapi/linux/target_core_user.h 
b/include/uapi/linux/target_core_user.h
index 0be80f72646b..2d5c3e55d3f8 100644
--- a/include/uapi/linux/target_core_user.h
+++ b/include/uapi/linux/target_core_user.h
@@ -132,9 +132,13 @@ enum tcmu_genl_cmd {
TCMU_CMD_ADDED_DEVICE,
TCMU_CMD_REMOVED_DEVICE,
TCMU_CMD_RECONFIG_DEVICE,
+   TCMU_CMD_GET_PR_INFO,
+   TCMU_CMD_SET_PR_INFO,
TCMU_CMD_ADDED_DEVICE_DONE,
TCMU_CMD_REMOVED_DEVICE_DONE,
TCMU_CMD_RECONFIG_DEVICE_DONE,
+   TCMU_CMD_GET_PR_INFO_DONE,
+   TCMU_CMD_SET_PR_INFO_DONE,
TCMU_CMD_SET_FEATURES,
__TCMU_CMD_MAX,
  };
@@ -151,8 +155,23 @@ enum tcmu_genl_attr {
TCMU_ATTR_CMD_STATUS,
TCMU_ATTR_DEVICE_ID,
TCMU_ATTR_SUPP_KERN_CMD_REPLY,
+   TCMU_ATTR_PR_INFO,
__TCMU_ATTR_MAX,
  };
  #define TCMU_ATTR_MAX (__TCMU_ATTR_MAX - 1)
  
+/* This struct help to store the Persistent Reservation which we

+ * are handling, it is encoded from or decoded to the string buffer in
+ * "struct tcmu_dev_pr_info"
+ */
+struct tcmu_pr_info {
+   u32 vers;   /* on disk format version number */
+   u32 seq;/* sequence number bumped every xattr write */
+   struct tcmu_scsi2_rsv *scsi2_rsv; /* SCSI2 reservation if any */
+   u32 gen;/* PR generation number */
+   struct tcmu_pr_rsv *rsv;/* SCSI3 reservation if any */
+   u32 num_regs;   /* number of registrations */
+   struct list_head regs;  /* list of registrations */
+};
+
  #endif


From 6a7029f03d092a86c9126bb4a72ab7c44b5abd6c Mon Sep 17 00:00:00 2001
From: Zhu Lingshan 
Date: Fri, 11 May 2018 16:54:51 +0800
Subject: [PATCH] pr_out_register and pr_in_readkeys can work

Signed-off-by: Zhu Lingshan 
---
 libtcmu.c| 98 +++-
 libtcmu.h|  4 ++
 main.c   |  2 +
 rbd.c| 36 +++
 target_core_user_local.h |  7 ++-
 tcmu-runner.h|  3 ++
 6 files changed, 147 insertions(+), 3 deletions(-)

diff --git a/libtcmu.c b/libtcmu.c
index d413020..826f482 100644
--- a/libtcmu.c
+++ b/libtcmu.c
@@ -84,6 +84,20 @@ static struct genl_cmd tcmu_cmds[] = {
.c_maxattr  = TCMU_ATTR_MAX,
.c_attr_policy  = tcmu_attr_policy,
},
+   {
+   .c_id   = TCMU_CMD_GET_PR_INFO,
+   .c_name = "GET PR_INFO",
+   .c_msg_parser   = handle_netlink,
+   .c_max

[PATCH 20/33] TCMU PR: add a func to register an existing reg

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_execute_pr_register_existing()
which will handle Persistent Reservation registration for a
currently registered IT_Nexus.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 34 +++
 1 file changed, 34 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index a6e951f04065..4b426a9061b1 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2614,6 +2614,40 @@ static int tcmu_pr_info_unregister_reg(struct 
tcmu_pr_info *pr_info,
return 0;
 }
 
+/* handle PR registration for a currently registered I_T nexus */
+static sense_reason_t
+tcmu_execute_pr_register_existing(struct tcmu_pr_info *pr_info,
+ u64 old_key, u64 new_key, char *it_nexus,
+ struct tcmu_pr_reg *existing_reg,
+ bool ignore_existing)
+{
+   sense_reason_t ret;
+   int rc;
+
+   pr_debug("PR registration for registered nexus: %s\n", it_nexus);
+
+   if (!ignore_existing && (old_key != existing_reg->key)) {
+   ret = TCM_RESERVATION_CONFLICT;
+   goto out;
+   }
+
+   if (new_key == 0) {
+   /* unregister */
+   rc = tcmu_pr_info_unregister_reg(pr_info, existing_reg);
+   if (rc < 0) {
+   ret = TCM_OUT_OF_RESOURCES;
+   goto out;
+   }
+   } else {
+   /* update key */
+   existing_reg->key = new_key;
+   }
+
+   ret = TCM_NO_SENSE;
+out:
+   return ret;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 21/33] TCMU PR: add a func to update PR info on TCMU dev

2018-06-15 Thread Zhu Lingshan
This patch  added a function tcmu_pr_info_replace() which can
help update Persistent Reservation information stored on a
TCMU device. It will generate a new string based on the provided
struct tcmu_pr_info struct, then write it to the device.For example,
If we are using RBD, it will update PR info to RBD meatada.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 43 +++
 1 file changed, 43 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 4b426a9061b1..559e0d40d63b 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -111,6 +111,8 @@
 /* don't allow encoded PR info to exceed 8K */
 #define TCMU_PR_INFO_XATTR_MAX_SIZE 8192
 
+#define TCMU_PR_REG_MAX_RETRIES5
+
 #define TCMU_PR_INFO_XATTR_ENCODED_SCSI2_RSV_MAXLEN\
(TCMU_PR_IT_NEXUS_MAXLEN + sizeof("\n"))
 
@@ -2648,6 +2650,47 @@ tcmu_execute_pr_register_existing(struct tcmu_pr_info 
*pr_info,
return ret;
 }
 
+static int tcmu_pr_info_replace(struct tcmu_dev *udev,
+   char *pr_xattr_old, int pr_xattr_len_old,
+   struct tcmu_pr_info *pr_info_new)
+{
+   int rc;
+   char *pr_xattr_new = NULL;
+   int pr_xattr_len_new = 0;
+
+   WARN_ON(!pr_xattr_old || !pr_info_new);
+
+   /* bump seqnum prior to xattr write. Not rolled back on failure */
+   pr_info_new->seq++;
+   rc = tcmu_pr_info_encode(pr_info_new, &pr_xattr_new,
+&pr_xattr_len_new);
+
+   if (rc) {
+   pr_err("failed to encode PR xattr: %d\n", rc);
+   return rc;
+   }
+
+   if (pr_xattr_len_new > TCMU_PR_INFO_XATTR_MAX_SIZE) {
+   pr_err("unable to store oversize (%d) PR info: %s\n",
+  pr_xattr_len_new, pr_xattr_new);
+   rc = -E2BIG;
+   goto err_xattr_new_free;
+   }
+
+   rc = tcmu_set_dev_pr_info(udev, pr_xattr_new);
+   if (rc) {
+   pr_err("failed to set PR xattr: %d\n", rc);
+   goto err_xattr_new_free;
+   }
+
+   pr_debug("successfully replaced PR info\n");
+   rc = 0;
+err_xattr_new_free:
+   kfree(pr_xattr_new);
+
+   return 0;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 28/33] TCMU PR: implementation of PR Reserve for TCMU

2018-06-15 Thread Zhu Lingshan
This patch added functions to handle Persistent Reservation
Reserve against TCMU devices.

Function tcm_rbd_pr_info_rsv_set() will help set PR information
in struct tcmu_pr_info, function tcmu_execute_pr_reserve() will
help handle PR reserve requests against TCMU devices.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 162 ++
 1 file changed, 162 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index bde325888477..8390b1d37873 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2970,6 +2970,167 @@ static int is_passthrough_pr_supportive_dev(struct 
tcmu_dev *udev)
return ret;
 }
 
+
+
+static int tcm_rbd_pr_info_rsv_set(struct tcmu_pr_info *pr_info, u64 key,
+  char *nexus, int type)
+{
+   struct tcmu_pr_rsv *rsv;
+
+   if (pr_info->rsv != NULL) {
+   pr_debug("rsv_set called with existing reservation\n");
+   return -EINVAL;
+   }
+
+   rsv = kmalloc(sizeof(*rsv), GFP_KERNEL);
+   if (!rsv)
+   return -ENOMEM;
+
+   rsv->key = key;
+   strlcpy(rsv->it_nexus, nexus, ARRAY_SIZE(rsv->it_nexus));
+   rsv->type = type;
+   pr_info->rsv = rsv;
+   pr_debug("pr_info rsv set: 0x%llx %s %d\n", key, nexus, type);
+
+   return 0;
+}
+
+
+static sense_reason_t
+tcmu_execute_pr_reserve(struct se_cmd *cmd, int type, u64 key)
+{
+   struct se_device *dev = cmd->se_dev;
+   struct tcmu_dev *udev = TCMU_DEV(dev);
+   char nexus_buf[TCMU_PR_IT_NEXUS_MAXLEN];
+   struct tcmu_pr_info *pr_info;
+   struct tcmu_pr_reg *reg;
+   struct tcmu_pr_reg *existing_reg;
+   char *pr_xattr;
+   int pr_xattr_len;
+   int rc;
+   sense_reason_t ret;
+   int retries = 0;
+
+   udev->pr_info.pr_info_buf = kzalloc(TCMU_PR_INFO_XATTR_MAX_SIZE,
+   GFP_KERNEL);
+   if (!udev->pr_info.pr_info_buf)
+   return TCM_OUT_OF_RESOURCES;
+
+   if (!cmd->se_sess || !cmd->se_lun) {
+   pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_info_free;
+   }
+
+   rc = tcmu_gen_it_nexus(cmd->se_sess, nexus_buf,
+ ARRAY_SIZE(nexus_buf));
+   if (rc < 0) {
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_info_free;
+   }
+
+retry:
+   pr_info = NULL;
+   pr_xattr = NULL;
+   pr_xattr_len = 0;
+   rc = tcmu_pr_info_get(udev, &pr_info, &pr_xattr,
+&pr_xattr_len);
+   if (rc < 0) {
+   /* existing registration required for reservation */
+   pr_err("failed to obtain PR info\n");
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_info_free;
+   }
+
+   /* check for an existing registration */
+   existing_reg = NULL;
+   list_for_each_entry(reg, &pr_info->regs, regs_node) {
+   if (!strncmp(reg->it_nexus, nexus_buf,
+ARRAY_SIZE(nexus_buf))) {
+   pr_debug("found existing PR reg for %s\n",
+nexus_buf);
+   existing_reg = reg;
+   break;
+   }
+   }
+
+   if (!existing_reg) {
+   pr_err("SPC-3 PR: Unable to locate registration for RESERVE\n");
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_info_free;
+   }
+
+   if (key != existing_reg->key) {
+   pr_err("SPC-3 PR RESERVE: Received res_key: 0x%016llx ", key);
+   pr_err("does not match existing SA REGISTER res_key: ");
+   pr_err("0x%016llx\n", existing_reg->key);
+   ret = TCM_RESERVATION_CONFLICT;
+   goto err_info_free;
+   }
+
+   if (pr_info->rsv) {
+   if (!tcmu_is_rsv_holder(pr_info->rsv, existing_reg, NULL)) {
+   pr_err("SPC-3 PR: Attempted RESERVE from %s while ",
+  nexus_buf);
+   pr_err("reservation already held by %s, ",
+  pr_info->rsv->it_nexus);
+   pr_err("returning RESERVATION_CONFLICT\n");
+   ret = TCM_RESERVATION_CONFLICT;
+   goto err_info_free;
+   }
+
+   if (pr_info->rsv->type != type) {
+   /* scope already checked */
+   pr_err("SPC-3 PR: Attempted RESERVE from %s ",
+  existing_reg->it_nexus);
+   pr_err("trying to change TYPE, ");
+   pr_err("returning RESERVATION_CONFLICT\n");
+   ret = TCM_RESERVATION_CONFLICT;
+   

[PATCH 23/33] TCMU PR: func to handle PR read keys but no regs

2018-06-15 Thread Zhu Lingshan
When try to execute Persistent Reservation Read Keys,
but tcmu_pr_info_get() returns -ENODATA, this means there are no
registrations, so we should generate a fake empty struct
tcmu_pr_info, so that the code can keep running, but we don't
want to store it in the TCMU device, this is different from
tcmu_pr_info_init().

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 17 +
 1 file changed, 17 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index c3adff826163..2fcdfc97ca75 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2829,6 +2829,23 @@ tcmu_execute_pr_register(struct se_cmd *cmd, u64 old_key,
return ret;
 }
 
+static int tcmu_pr_info_mock_empty(struct tcmu_pr_info **_pr_info)
+{
+   struct tcmu_pr_info *pr_info;
+
+   pr_info = kzalloc(sizeof(*pr_info), GFP_KERNEL);
+   if (!pr_info)
+   return -ENOMEM;
+
+   pr_info->vers = TCMU_PR_INFO_XATTR_VERS;
+   INIT_LIST_HEAD(&pr_info->regs);
+
+   *_pr_info = pr_info;
+   pr_debug("successfully initialized mock PR info\n");
+
+   return 0;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 30/33] TCMU PR: implementation of PR release for TCMU

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_execute_pr_release()
to handle SCSI3 Persistent Reservation Release
for TCMU devices.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 119 ++
 1 file changed, 119 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index e7daa76317bc..532401a9f433 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -3133,6 +3133,124 @@ tcmu_execute_pr_reserve(struct se_cmd *cmd, int type, 
u64 key)
 }
 
 
+static sense_reason_t
+tcmu_execute_pr_release(struct se_cmd *cmd, int type, u64 key)
+{
+   struct se_device *dev = cmd->se_dev;
+   struct tcmu_dev *udev = TCMU_DEV(dev);
+   char nexus_buf[TCMU_PR_IT_NEXUS_MAXLEN];
+   struct tcmu_pr_info *pr_info;
+   struct tcmu_pr_reg *reg;
+   struct tcmu_pr_reg *existing_reg;
+   char *pr_xattr;
+   int pr_xattr_len;
+   int rc;
+   sense_reason_t ret;
+   int retries = 0;
+
+   if (!cmd->se_sess || !cmd->se_lun) {
+   pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+   return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   }
+
+   rc = tcmu_gen_it_nexus(cmd->se_sess, nexus_buf,
+ ARRAY_SIZE(nexus_buf));
+   if (rc < 0)
+   return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   mutex_lock(&udev->pr_info.pr_info_lock);
+   udev->pr_info.pr_info_buf = kzalloc(TCMU_PR_INFO_XATTR_MAX_SIZE,
+   GFP_KERNEL);
+
+retry:
+   pr_info = NULL;
+   pr_xattr = NULL;
+   pr_xattr_len = 0;
+   rc = tcmu_pr_info_get(udev, &pr_info, &pr_xattr,
+&pr_xattr_len);
+   if (rc < 0) {
+   /* existing registration required for release */
+   pr_err("failed to obtain PR info\n");
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_info_free;
+   }
+
+   if (!pr_info->rsv) {
+   /* no persistent reservation, return GOOD status */
+   goto done;
+   }
+
+   /* check for an existing registration */
+   existing_reg = NULL;
+   list_for_each_entry(reg, &pr_info->regs, regs_node) {
+   if (!strncmp(reg->it_nexus, nexus_buf, ARRAY_SIZE(nexus_buf))) {
+   pr_debug("found existing PR reg for %s\n", nexus_buf);
+   existing_reg = reg;
+   break;
+   }
+   }
+
+   if (!existing_reg) {
+   pr_err("SPC-3 PR: Unable to locate registration for RELEASE\n");
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_info_free;
+   }
+
+   if (!tcmu_is_rsv_holder(pr_info->rsv, existing_reg, NULL)) {
+   /* registered but not a persistent reservation holder */
+   goto done;
+   }
+
+   if (key != existing_reg->key) {
+   pr_err("SPC-3 PR RELEASE: Received res_key: 0x%016llx ", key);
+   pr_err("does not match existing SA REGISTER res_key: ");
+   pr_err("0x%016llx\n", existing_reg->key);
+   ret = TCM_RESERVATION_CONFLICT;
+   goto err_info_free;
+   }
+
+   if (pr_info->rsv->type != type) {
+   pr_err("SPC-3 PR: Attempted RELEASE from %s with different ",
+  existing_reg->it_nexus);
+   pr_err("TYPE, returning RESERVATION_CONFLICT\n");
+   ret = TCM_RESERVATION_CONFLICT;
+   goto err_info_free;
+   }
+
+   /* release the persistent reservation */
+   tcmu_pr_info_rsv_clear(pr_info);
+
+   rc = tcmu_pr_info_replace(udev, pr_xattr, pr_xattr_len,
+pr_info);
+   if (rc == -ECANCELED) {
+   pr_warn("atomic PR info update failed due to parallel ");
+   pr_warn("change, expected(%d) %s. Retrying...\n",
+   pr_xattr_len, pr_xattr);
+   retries++;
+   if (retries <= TCMU_PR_REG_MAX_RETRIES) {
+   tcmu_pr_info_free(pr_info);
+   kfree(pr_xattr);
+   goto retry;
+   }
+   }
+
+   if (rc < 0) {
+   pr_err("atomic PR info update failed: %d\n", rc);
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_info_free;
+   }
+
+done:
+   ret = TCM_NO_SENSE;
+err_info_free:
+   tcmu_pr_info_free(pr_info);
+   kfree(pr_xattr);
+   kfree(udev->pr_info.pr_info_buf);
+   mutex_unlock(&udev->pr_info.pr_info_lock);
+
+   return ret;
+}
+
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
@@ -3888,6 +4006,7 @@ static struct target_pr_ops tcmu_pr_ops = {
.pr_read_keys   = tcmu_execute_pr_read_keys,
.pr

[PATCH 22/33] TCMU PR: add a function to handle TCMU PR register

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_execute_pr_register() which
can help to handle Persistent Reservation register operation
for TCMU devices.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 138 ++
 1 file changed, 138 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 559e0d40d63b..c3adff826163 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2691,6 +2691,144 @@ static int tcmu_pr_info_replace(struct tcmu_dev *udev,
return 0;
 }
 
+static sense_reason_t
+tcmu_execute_pr_register(struct se_cmd *cmd, u64 old_key,
+u64 new_key, bool aptpl, bool all_tg_pt,
+bool spec_i_pt, bool ignore_existing)
+{
+   struct se_device *dev = cmd->se_dev;
+   char nexus_buf[TCMU_PR_IT_NEXUS_MAXLEN];
+   struct tcmu_pr_info *pr_info;
+   struct tcmu_pr_reg *reg;
+   struct tcmu_pr_reg *existing_reg;
+   char *pr_xattr;
+   int pr_xattr_len;
+   int rc;
+   sense_reason_t ret;
+   int retries = 0;
+   char *pr_buf_ptr = NULL;
+   struct tcmu_dev *udev = TCMU_DEV(dev);
+
+   mutex_lock(&udev->pr_info.pr_info_lock);
+   udev->pr_info.pr_info_buf = kzalloc(TCMU_PR_INFO_XATTR_MAX_SIZE,
+   GFP_KERNEL);
+   pr_buf_ptr = udev->pr_info.pr_info_buf;
+   if (!pr_buf_ptr) {
+   ret = TCM_OUT_OF_RESOURCES;
+   goto err_out;
+   }
+
+   if (!cmd->se_sess || !cmd->se_lun) {
+   pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_out;
+   }
+
+   if (!aptpl) {
+   /*
+* Currently unsupported by block layer API (hch):
+* reservations not persistent through a power loss are
+* basically useless, so I decided to force them on in the API.
+*/
+   pr_warn("PR register with aptpl unset. Treating as aptpl=1\n");
+   aptpl = true;
+   }
+
+   if (all_tg_pt || spec_i_pt) {
+   pr_err("failing PR register with all_tg_pt=%d spec_i_pt=%d\n",
+  all_tg_pt, spec_i_pt);
+   ret = TCM_INVALID_CDB_FIELD;
+   goto err_out;
+   }
+
+   rc = tcmu_gen_it_nexus(cmd->se_sess, nexus_buf, ARRAY_SIZE(nexus_buf));
+   if (rc < 0) {
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_out;
+   }
+
+   pr_debug("generated nexus: %s\n", nexus_buf);
+
+retry:
+   pr_info = NULL;
+   pr_xattr = NULL;
+   pr_xattr_len = 0;
+   rc = tcmu_pr_info_get(udev, &pr_info, &pr_xattr, &pr_xattr_len);
+   if ((rc == -ENODATA) && (retries == 0)) {
+   pr_warn("PR info not present, initializing\n");
+   rc = tcmu_pr_info_init(udev, &pr_info, &pr_xattr,
+  &pr_xattr_len);
+   }
+   if (rc < 0) {
+   pr_err("failed to obtain PR info\n");
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_out;
+   }
+
+   /* check for an existing registration */
+   existing_reg = NULL;
+   list_for_each_entry(reg, &pr_info->regs, regs_node) {
+   if (!strncmp(reg->it_nexus, nexus_buf, ARRAY_SIZE(nexus_buf))) {
+   pr_err("found existing PR reg for %s\n", nexus_buf);
+   existing_reg = reg;
+   break;
+   }
+   }
+
+   if (!existing_reg) {
+   ret = tcmu_execute_pr_register_new(pr_info, old_key, new_key,
+  nexus_buf, ignore_existing);
+   } else {
+   ret = tcmu_execute_pr_register_existing(pr_info, old_key,
+   new_key, nexus_buf,
+   existing_reg,
+   ignore_existing);
+   }
+   if (ret)
+   goto err_out;
+
+   /*
+* The Persistent Reservations Generation (PRGENERATION) field shall
+* contain the value of a 32-bit wrapping counter that the device server
+* shall update (e.g., increment) during the processing of any
+* PERSISTENT RESERVE OUT command as described in table 216 (see
+* 6.16.2). The PRgeneration value shall not be updated by a PERSISTENT
+* RESERVE IN command or by a PERSISTENT RESERVE OUT command that is
+* terminated due to an error or reservation conflict.
+*/
+   pr_info->gen++;
+
+   rc = tcmu_pr_info_replace(udev, pr_xattr, pr_xattr_len, pr_info);
+   if (rc == -ECANCELED) {
+   int pr_xattr_changed_len = 0;
+   /* PR info has changed since we r

[PATCH 33/33] TCMU PR: enable PRO Clear for TCMU devices

2018-06-15 Thread Zhu Lingshan
This patch would enable the passthrough Persist Reservation
clear operation routine for TCMU devices.

If dev->passthrough_pr is 1, both dev->transport->pr_ops
and dev->transport->pr_ops->pr_clear are not NULL,
core_scsi3_emulate_pro_clear() will call
dev->transport->pr_ops->pr_clear to passthrough PR clear
request to user space

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_pr.c   | 5 +
 drivers/target/target_core_user.c | 1 +
 2 files changed, 6 insertions(+)

diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index c668dfb84bf1..66bb52ab0209 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -2719,6 +2719,11 @@ core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 
res_key)
struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, 
*pr_res_holder;
u64 pr_res_mapped_lun = 0;
int calling_it_nexus = 0;
+
+   if (dev->transport->pr_ops && dev->transport->pr_ops->pr_read_keys
+   && dev->passthrough_pr)
+   return dev->transport->pr_ops->pr_clear(cmd, res_key);
+
/*
 * Locate the existing *pr_reg via struct se_node_acl pointers
 */
diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index c8d0ea330984..c417021f7099 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -4115,6 +4115,7 @@ static struct target_pr_ops tcmu_pr_ops = {
.pr_register= tcmu_execute_pr_register,
.pr_reserve = tcmu_execute_pr_reserve,
.pr_release = tcmu_execute_pr_release,
+   .pr_clear   = tcmu_execute_pr_clear,
 };
 
 static struct target_backend_ops tcmu_ops = {
-- 
2.17.1



[PATCH 32/33] TCMU PR: implementation of PR clear for TCMU

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_execute_pr_clear() which can
help perform Persistent Reservation clear operation,
this means clear reservations and registrations.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 108 ++
 1 file changed, 108 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 532401a9f433..c8d0ea330984 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -3251,6 +3251,114 @@ tcmu_execute_pr_release(struct se_cmd *cmd, int type, 
u64 key)
 }
 
 
+static sense_reason_t
+tcmu_execute_pr_clear(struct se_cmd *cmd, u64 key)
+{
+   struct se_device *dev = cmd->se_dev;
+   struct tcmu_dev *udev = TCMU_DEV(dev);
+   char nexus_buf[TCMU_PR_IT_NEXUS_MAXLEN];
+   struct tcmu_pr_info *pr_info;
+   struct tcmu_pr_reg *reg;
+   struct tcmu_pr_reg *existing_reg;
+   char *pr_xattr;
+   int pr_xattr_len;
+   int rc;
+   sense_reason_t ret;
+   int retries = 0;
+
+   if (!cmd->se_sess || !cmd->se_lun) {
+   pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+   return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   }
+
+   rc = tcmu_gen_it_nexus(cmd->se_sess, nexus_buf,
+ ARRAY_SIZE(nexus_buf));
+   if (rc < 0)
+   return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+   mutex_lock(&udev->pr_info.pr_info_lock);
+   udev->pr_info.pr_info_buf = kzalloc(TCMU_PR_INFO_XATTR_MAX_SIZE,
+   GFP_KERNEL);
+
+retry:
+   pr_info = NULL;
+   pr_xattr = NULL;
+   pr_xattr_len = 0;
+   rc = tcmu_pr_info_get(udev, &pr_info, &pr_xattr,
+&pr_xattr_len);
+   if (rc < 0) {
+   /* existing registration required for clear */
+   pr_err("failed to obtain PR info\n");
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_info_free;
+   }
+
+   /* check for an existing registration */
+   existing_reg = NULL;
+   list_for_each_entry(reg, &pr_info->regs, regs_node) {
+   if (!strncmp(reg->it_nexus, nexus_buf,
+ARRAY_SIZE(nexus_buf))) {
+   pr_debug("found existing PR reg for %s\n", nexus_buf);
+   existing_reg = reg;
+   break;
+   }
+   }
+
+   if (!existing_reg) {
+   pr_err("SPC-3 PR: Unable to locate registration for CLEAR\n");
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_info_free;
+   }
+
+   if (key != existing_reg->key) {
+   pr_err("SPC-3 PR CLEAR: Received res_key: 0x%016llx ", key);
+   pr_err("does not match existing SA res_key: 0x%016llx\n",
+  existing_reg->key);
+   ret = TCM_RESERVATION_CONFLICT;
+   goto err_info_free;
+   }
+
+   /* release the persistent reservation, if any */
+   if (pr_info->rsv)
+   tcmu_pr_info_rsv_clear(pr_info);
+
+   /* remove all registrations */
+   list_for_each_entry_safe(existing_reg, reg, &pr_info->regs, regs_node) {
+   tcmu_pr_info_clear_reg(pr_info, existing_reg);
+   }
+
+   /* PR generation must be incremented on successful CLEAR */
+   pr_info->gen++;
+
+   rc = tcmu_pr_info_replace(udev, pr_xattr, pr_xattr_len,
+pr_info);
+   if (rc == -ECANCELED) {
+   pr_warn("Atomic PR info update failed due to parallel ");
+   pr_warn("change, expected(%d) %s. Retrying...\n",
+   pr_xattr_len, pr_xattr);
+   retries++;
+   if (retries <= TCMU_PR_REG_MAX_RETRIES) {
+   tcmu_pr_info_free(pr_info);
+   kfree(pr_xattr);
+   goto retry;
+   }
+   }
+   if (rc < 0) {
+   pr_err("atomic PR info update failed: %d\n", rc);
+   ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   goto err_info_free;
+   }
+
+   ret = TCM_NO_SENSE;
+err_info_free:
+   tcmu_pr_info_free(pr_info);
+   kfree(pr_xattr);
+   kfree(udev->pr_info.pr_info_buf);
+   mutex_unlock(&udev->pr_info.pr_info_lock);
+   return ret;
+}
+
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 31/33] TCMU PR: enable PRO Release for TCMU devices

2018-06-15 Thread Zhu Lingshan
This patch would enable the passthrough Persist Reservation
Release operation routine for TCMU devices.
If dev->passthrough_pr is 1, both dev->transport->pr_ops
and dev->transport->pr_ops->pr_release are not NULL,
core_scsi3_emulate_pro_release() will call
dev->transport->pr_ops->pr_release to passthrough PR release
request to user space

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_pr.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index d47ccbf05679..c668dfb84bf1 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -2554,6 +2554,15 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int 
type, int scope,
struct t10_reservation *pr_tmpl = &dev->t10_pr;
sense_reason_t ret = 0;
 
+   if (dev->transport->pr_ops && dev->transport->pr_ops->pr_register
+   && dev->passthrough_pr) {
+   if (scope != PR_SCOPE_LU_SCOPE) {
+   pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope);
+   return TCM_INVALID_PARAMETER_LIST;
+   }
+   return dev->transport->pr_ops->pr_release(cmd, type, res_key);
+   }
+
if (!se_sess || !se_lun) {
pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n");
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-- 
2.17.1



[PATCH 26/33] TCMU PR: add PR ops function pointers

2018-06-15 Thread Zhu Lingshan
This patch added a struct target_pr_ops contains TCMU
Persistent Reservation operation functions. Added a
"struct target_pr_ops" type pointer in target_backend_ops,
so that we can call TCMU PR functions from struct
target_backend_ops.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c|  6 +
 include/target/target_core_backend.h | 36 
 2 files changed, 42 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 09a341e935a9..ea3685106d35 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -3701,6 +3701,11 @@ static struct configfs_attribute *tcmu_action_attrs[] = {
NULL,
 };
 
+static struct target_pr_ops tcmu_pr_ops = {
+   .pr_read_keys   = tcmu_execute_pr_read_keys,
+   .pr_register= tcmu_execute_pr_register,
+};
+
 static struct target_backend_ops tcmu_ops = {
.name   = "user",
.owner  = THIS_MODULE,
@@ -3717,6 +3722,7 @@ static struct target_backend_ops tcmu_ops = {
.get_device_type= sbc_get_device_type,
.get_blocks = tcmu_get_blocks,
.tb_dev_action_attrs= tcmu_action_attrs,
+   .pr_ops = &tcmu_pr_ops,
 };
 
 static void find_free_blocks(void)
diff --git a/include/target/target_core_backend.h 
b/include/target/target_core_backend.h
index 34a15d59ed88..36a820429cf4 100644
--- a/include/target/target_core_backend.h
+++ b/include/target/target_core_backend.h
@@ -51,11 +51,47 @@ struct target_backend_ops {
int (*init_prot)(struct se_device *);
int (*format_prot)(struct se_device *);
void (*free_prot)(struct se_device *);
+   struct target_pr_ops *pr_ops;
 
struct configfs_attribute **tb_dev_attrib_attrs;
struct configfs_attribute **tb_dev_action_attrs;
 };
 
+enum target_pr_check_type {
+   /* check for *any* SCSI2 reservations, including own */
+   TARGET_PR_CHECK_SCSI2_ANY,
+   /* check for conflicting SCSI2 or SCSI3 reservation */
+   TARGET_PR_CHECK_SCSI2_SCSI3,
+};
+
+struct target_pr_ops {
+   sense_reason_t (*check_conflict)(struct se_cmd *cmd,
+enum target_pr_check_type);
+   sense_reason_t (*scsi2_reserve)(struct se_cmd *cmd);
+   sense_reason_t (*scsi2_release)(struct se_cmd *cmd);
+   sense_reason_t (*reset)(struct se_device *dev);
+   sense_reason_t (*pr_register)(struct se_cmd *cmd, u64 old_key,
+ u64 new_key, bool aptpl, bool all_tg_pt,
+ bool spec_i_pt, bool ignore_existing);
+   sense_reason_t (*pr_reserve)(struct se_cmd *cmd, int type, u64 key);
+   sense_reason_t (*pr_release)(struct se_cmd *cmd, int type, u64 key);
+   sense_reason_t (*pr_clear)(struct se_cmd *cmd, u64 key);
+   sense_reason_t (*pr_preempt)(struct se_cmd *cmd, u64 old_key,
+u64 new_key, int type, bool abort);
+   sense_reason_t (*pr_register_and_move)(struct se_cmd *cmd, u64 old_key,
+  u64 new_key, bool aptpl,
+  int unreg);
+   sense_reason_t (*pr_read_keys)(struct se_cmd *cmd, unsigned char *buf,
+  u32 buf_len);
+   sense_reason_t (*pr_read_reservation)(struct se_cmd *cmd,
+ unsigned char *buf, u32 buf_len);
+   sense_reason_t (*pr_report_capabilities)(struct se_cmd *cmd,
+unsigned char *buf,
+u32 buf_len);
+   sense_reason_t (*pr_read_full_status)(struct se_cmd *cmd,
+ unsigned char *buf, u32 buf_len);
+};
+
 struct sbc_ops {
sense_reason_t (*execute_rw)(struct se_cmd *cmd, struct scatterlist *,
 u32, enum dma_data_direction);
-- 
2.17.1



[PATCH 25/33] TCMU PR: netlink support for passthrough PR info

2018-06-15 Thread Zhu Lingshan
This patch added netlink support for passthrough Persistent
Reservation information.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 35 +++
 1 file changed, 35 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index a89c866a755d..09a341e935a9 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -348,6 +348,7 @@ static struct nla_policy tcmu_attr_policy[TCMU_ATTR_MAX+1] 
= {
[TCMU_ATTR_CMD_STATUS]  = { .type = NLA_S32 },
[TCMU_ATTR_DEVICE_ID]   = { .type = NLA_U32 },
[TCMU_ATTR_SUPP_KERN_CMD_REPLY] = { .type = NLA_U8 },
+   [TCMU_ATTR_PR_INFO] = { .type = NLA_STRING },
 };
 
 static int tcmu_genl_cmd_done(struct genl_info *info, int completed_cmd)
@@ -389,6 +390,16 @@ static int tcmu_genl_cmd_done(struct genl_info *info, int 
completed_cmd)
nl_cmd->status = rc;
}
 
+   if (completed_cmd == TCMU_CMD_GET_PR_INFO) {
+   if (!info->attrs[TCMU_ATTR_PR_INFO]) {
+   ret = -EINVAL;
+   } else {
+   nla_strlcpy(udev->pr_info.pr_info_buf,
+   info->attrs[TCMU_ATTR_PR_INFO],
+   TCMU_PR_INFO_XATTR_MAX_SIZE);
+   }
+   }
+
spin_unlock(&udev->nl_cmd_lock);
if (!is_removed)
 target_undepend_item(&dev->dev_group.cg_item);
@@ -413,6 +424,18 @@ static int tcmu_genl_reconfig_dev_done(struct sk_buff *skb,
return tcmu_genl_cmd_done(info, TCMU_CMD_RECONFIG_DEVICE);
 }
 
+static int tcmu_genl_get_pr_info_done(struct sk_buff *skb,
+ struct genl_info *info)
+{
+   return tcmu_genl_cmd_done(info, TCMU_CMD_GET_PR_INFO);
+}
+
+static int tcmu_genl_set_pr_info_done(struct sk_buff *skb,
+ struct genl_info *info)
+{
+   return tcmu_genl_cmd_done(info, TCMU_CMD_SET_PR_INFO);
+}
+
 static int tcmu_genl_set_features(struct sk_buff *skb, struct genl_info *info)
 {
if (info->attrs[TCMU_ATTR_SUPP_KERN_CMD_REPLY]) {
@@ -450,6 +473,18 @@ static const struct genl_ops tcmu_genl_ops[] = {
.policy = tcmu_attr_policy,
.doit   = tcmu_genl_reconfig_dev_done,
},
+   {
+   .cmd= TCMU_CMD_GET_PR_INFO_DONE,
+   .flags  = GENL_ADMIN_PERM,
+   .policy = tcmu_attr_policy,
+   .doit   = tcmu_genl_get_pr_info_done,
+   },
+   {
+   .cmd= TCMU_CMD_SET_PR_INFO_DONE,
+   .flags  = GENL_ADMIN_PERM,
+   .policy = tcmu_attr_policy,
+   .doit   = tcmu_genl_set_pr_info_done,
+   },
 };
 
 /* Our generic netlink family */
-- 
2.17.1



[PATCH 29/33] TCMU PR: enable PRO Reserve for TCMU devices

2018-06-15 Thread Zhu Lingshan
This patch would enable the passthrough Persist Reservation
Reserve operation routine for TCMU devices.
If dev->passthrough_pr is 1, both dev->transport->pr_ops
and dev->transport->pr_ops->pr_register are not NULL,
core_scsi3_emulate_pro_reserve() will call
dev->transport->pr_ops->pr_reserve to passthrough data to
user space.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_pr.c   | 11 ++-
 drivers/target/target_core_user.c |  2 ++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 0a06b8bb1134..d47ccbf05679 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -2450,6 +2450,8 @@ static sense_reason_t
 core_scsi3_emulate_pro_reserve(struct se_cmd *cmd, int type, int scope,
u64 res_key)
 {
+   struct se_device *dev = cmd->se_dev;
+
switch (type) {
case PR_TYPE_WRITE_EXCLUSIVE:
case PR_TYPE_EXCLUSIVE_ACCESS:
@@ -2457,7 +2459,14 @@ core_scsi3_emulate_pro_reserve(struct se_cmd *cmd, int 
type, int scope,
case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
-   return core_scsi3_pro_reserve(cmd, type, scope, res_key);
+   if (dev->transport->pr_ops &&
+   dev->transport->pr_ops->pr_register &&
+   dev->passthrough_pr)
+   return dev->transport->pr_ops->pr_reserve(cmd, type,
+ res_key);
+   else
+   return core_scsi3_pro_reserve(cmd, type, scope,
+ res_key);
default:
pr_err("SPC-3 PR: Unknown Service Action RESERVE Type:"
" 0x%02x\n", type);
diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 8390b1d37873..e7daa76317bc 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -3011,6 +3011,7 @@ tcmu_execute_pr_reserve(struct se_cmd *cmd, int type, u64 
key)
sense_reason_t ret;
int retries = 0;
 
+   mutex_lock(&udev->pr_info.pr_info_lock);
udev->pr_info.pr_info_buf = kzalloc(TCMU_PR_INFO_XATTR_MAX_SIZE,
GFP_KERNEL);
if (!udev->pr_info.pr_info_buf)
@@ -3127,6 +3128,7 @@ tcmu_execute_pr_reserve(struct se_cmd *cmd, int type, u64 
key)
tcmu_pr_info_free(pr_info);
kfree(pr_xattr);
kfree(udev->pr_info.pr_info_buf);
+   mutex_unlock(&udev->pr_info.pr_info_lock);
return ret;
 }
 
-- 
2.17.1



[PATCH 24/33] TCMU PR: handle PR read keys for TCMU devs

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_execute_pr_read_keys() which
can help handle Persistent Reservation Read Keys.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 74 +++
 1 file changed, 74 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 2fcdfc97ca75..a89c866a755d 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2846,6 +2846,80 @@ static int tcmu_pr_info_mock_empty(struct tcmu_pr_info 
**_pr_info)
return 0;
 }
 
+static sense_reason_t
+tcmu_execute_pr_read_keys(struct se_cmd *cmd, unsigned char *buf, u32 buf_len)
+{
+   struct se_device *dev = cmd->se_dev;
+   struct tcmu_pr_info *pr_info = NULL;
+   struct tcmu_pr_reg *reg;
+   u32 add_len = 0, off = 8;
+   int rc;
+   struct tcmu_dev *udev = TCMU_DEV(dev);
+
+   udev->pr_info.pr_info_buf = kzalloc(TCMU_PR_INFO_XATTR_MAX_SIZE,
+   GFP_KERNEL);
+   if (!udev->pr_info.pr_info_buf)
+   return TCM_OUT_OF_RESOURCES;
+
+   if (buf_len < 8) {
+   WARN_ON(1);
+   kfree(udev->pr_info.pr_info_buf);
+   return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   }
+
+   pr_debug("getting pr_info for buf: %p, %u\n", buf, buf_len);
+
+   rc = tcmu_pr_info_get(udev, &pr_info, NULL, NULL);
+   if (rc == -ENODATA) {
+   pr_debug("PR info not present for read, mocking empty\n");
+   rc = tcmu_pr_info_mock_empty(&pr_info);
+   }
+   if (rc < 0) {
+   kfree(udev->pr_info.pr_info_buf);
+   return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+   }
+   pr_debug("packing read_keys response buf: %p, %u\n", buf, buf_len);
+
+   buf[0] = ((pr_info->gen >> 24) & 0xff);
+   buf[1] = ((pr_info->gen >> 16) & 0xff);
+   buf[2] = ((pr_info->gen >> 8) & 0xff);
+   buf[3] = (pr_info->gen & 0xff);
+
+   pr_debug("packed gen %u in read_keys response\n", pr_info->gen);
+
+   list_for_each_entry(reg, &pr_info->regs, regs_node) {
+   /*
+* Check for overflow of 8byte PRI READ_KEYS payload and
+* next reservation key list descriptor.
+*/
+   if ((add_len + 8) > (buf_len - 8))
+   break;
+
+   buf[off++] = ((reg->key >> 56) & 0xff);
+   buf[off++] = ((reg->key >> 48) & 0xff);
+   buf[off++] = ((reg->key >> 40) & 0xff);
+   buf[off++] = ((reg->key >> 32) & 0xff);
+   buf[off++] = ((reg->key >> 24) & 0xff);
+   buf[off++] = ((reg->key >> 16) & 0xff);
+   buf[off++] = ((reg->key >> 8) & 0xff);
+   buf[off++] = (reg->key & 0xff);
+   pr_debug("packed key 0x%llx in read_keys response\n", reg->key);
+
+   add_len += 8;
+   }
+
+   buf[4] = ((add_len >> 24) & 0xff);
+   buf[5] = ((add_len >> 16) & 0xff);
+   buf[6] = ((add_len >> 8) & 0xff);
+   buf[7] = (add_len & 0xff);
+
+   pr_debug("packed len %u in read_keys response\n", add_len);
+   tcmu_pr_info_free(pr_info);
+   kfree(udev->pr_info.pr_info_buf);
+
+   return TCM_NO_SENSE;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 27/33] TCMU PR: enable PR register and ReadKeys for TCMU

2018-06-15 Thread Zhu Lingshan
This patch added a function is_passthrough_pr_supportive_dev()
to tell whether the device can support passthrough Persistent
Reservation, if supported, tcmu_configure_device() will set 1 to
dev->passthrough_pr to indicate it.

If dev->passthrough_pr is 1, both dev->transport->pr_ops
and dev->transport->pr_ops->pr_register are not NULL,
core_scsi3_emulate_pro_register() will call
dev->transport->pr_ops->pr_register, this means call
tcmu_execute_pr_register(). It is the same way how
core_scsi3_pri_read_keys() can call tcmu_execute_pr_read_keys.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_pr.c   | 23 +++
 drivers/target/target_core_pr.h   |  2 ++
 drivers/target/target_core_user.c | 20 
 include/target/target_core_base.h |  7 +++
 4 files changed, 52 insertions(+)

diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 01ac306131c1..0a06b8bb1134 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -2064,6 +2064,21 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 
res_key, u64 sa_res_key,
sense_reason_t ret = TCM_NO_SENSE;
int pr_holder = 0, type;
 
+   if (dev->transport->pr_ops && dev->transport->pr_ops->pr_register
+   && dev->passthrough_pr) {
+   bool ignore_existing;
+
+   if (register_type == REGISTER_AND_IGNORE_EXISTING_KEY)
+   ignore_existing = true;
+   else
+   ignore_existing = false;
+   ret = dev->transport->pr_ops->pr_register(cmd, res_key,
+ sa_res_key, aptpl,
+ all_tg_pt, spec_i_pt,
+ ignore_existing);
+   return ret;
+   }
+
if (!se_sess || !se_lun) {
pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n");
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -3707,6 +3722,7 @@ core_scsi3_pri_read_keys(struct se_cmd *cmd)
struct t10_pr_registration *pr_reg;
unsigned char *buf;
u32 add_len = 0, off = 8;
+   sense_reason_t ret = 0;
 
if (cmd->data_length < 8) {
pr_err("PRIN SA READ_KEYS SCSI Data Length: %u"
@@ -3718,6 +3734,13 @@ core_scsi3_pri_read_keys(struct se_cmd *cmd)
if (!buf)
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
 
+   if (dev->transport->pr_ops && dev->transport->pr_ops->pr_read_keys
+   && dev->passthrough_pr) {
+   ret = dev->transport->pr_ops->pr_read_keys(cmd, buf,
+  cmd->data_length);
+   return ret;
+   }
+
put_unaligned_be32(dev->t10_pr.pr_generation, buf);
 
spin_lock(&dev->t10_pr.registration_lock);
diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h
index 198fad5c89dc..1a74112c35d3 100644
--- a/drivers/target/target_core_pr.h
+++ b/drivers/target/target_core_pr.h
@@ -49,6 +49,8 @@
 #define PR_APTPL_MAX_IPORT_LEN 256
 #define PR_APTPL_MAX_TPORT_LEN 256
 
+#define PASSTHROUGH_PR_SUPPORT 1
+
 /*
  *  Function defined in target_core_spc.c
  */
diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index ea3685106d35..bde325888477 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2955,6 +2955,21 @@ tcmu_execute_pr_read_keys(struct se_cmd *cmd, unsigned 
char *buf, u32 buf_len)
return TCM_NO_SENSE;
 }
 
+/*
+ * This function can help to check wheterh the device support
+ * pass through PR operations. Now only Ceph RBD support
+ * passthrough PR. When someday we have another kind of
+ * device can support passthrough PR, we can easily add
+ * a line like ret |= !strncmp(udev->dev_config, "qcow/", 5);
+ */
+static int is_passthrough_pr_supportive_dev(struct tcmu_dev *udev)
+{
+   int ret = 0;
+
+   ret |= !strncmp(udev->dev_config, "rbd/", 4);
+   return ret;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
@@ -3046,6 +3061,11 @@ static int tcmu_configure_device(struct se_device *dev)
list_add(&udev->node, &root_udev);
mutex_unlock(&root_udev_mutex);
 
+   if (is_passthrough_pr_supportive_dev(udev) && dev->transport->pr_ops) {
+   mutex_init(&udev->pr_info.pr_info_lock);
+   dev->passthrough_pr = PASSTHROUGH_PR_SUPPORT;
+   }
+
return 0;
 
 err_netlink:
diff --git a/include/target/target_core_base.h 
b/include/target/target_core_base.h
index 9f9f5902af38..9acb3363fd2b 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -825,6 +825,13 @@ struct se_device {
/* For se_lun->lun_se_dev RCU read-side critic

[PATCH 01/33] TCMU PR: first commit to implement TCMU PR

2018-06-15 Thread Zhu Lingshan
These commits and the following intend to implement Persistent
Reservation operations for TCMU devices.

This series of commits would implement such PR operations:
PR_Out_Register, PR_Out_Reserve, PR_Out_Clear, PR_Out_Preempt,
PR_Out_Release and PR_In_ReadKeys.

Next wave of patches will contain the other PR operations.

This patch added a struct tcmu_pr_info to store PR information
for the handling functions, added command codes and attrs for
netlink interfaces.

Design note:
In order to get consistent Persistent Reservation results from
multiple targets hosting the same TCMU device(like Ceph RBD),
this solution stores a string on the device itself(like RBD metadata).

Everytime when kernel receive a PR request against a TCMU device,
it will query this string(a netlink attr carried by a netlink cmd).
Then decide whether the PR request should be performed, after
processing, it will update this string.

For example:
When receive a PR Reserve request, kernel will send a netlink
message to tcmu-runner, try to get the string, tcmu-runner will
response, send the PR info string to kernel. Then kernel will
decode the string, find information like key, reservation holder,
then process this request. After processing, it will update the
string, send the updated string to tcmu-runner, so that tcmu-runner
will write it back to the device(like RBD metadata).

So we make the device itself as a "single" response point, (with
locks protection) we will get a consistent result even more than one
initiators sending multiple PR requests via multiple targets.

Signed-off-by: Zhu Lingshan 
---
 include/uapi/linux/target_core_user.h | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/include/uapi/linux/target_core_user.h 
b/include/uapi/linux/target_core_user.h
index 0be80f72646b..2d5c3e55d3f8 100644
--- a/include/uapi/linux/target_core_user.h
+++ b/include/uapi/linux/target_core_user.h
@@ -132,9 +132,13 @@ enum tcmu_genl_cmd {
TCMU_CMD_ADDED_DEVICE,
TCMU_CMD_REMOVED_DEVICE,
TCMU_CMD_RECONFIG_DEVICE,
+   TCMU_CMD_GET_PR_INFO,
+   TCMU_CMD_SET_PR_INFO,
TCMU_CMD_ADDED_DEVICE_DONE,
TCMU_CMD_REMOVED_DEVICE_DONE,
TCMU_CMD_RECONFIG_DEVICE_DONE,
+   TCMU_CMD_GET_PR_INFO_DONE,
+   TCMU_CMD_SET_PR_INFO_DONE,
TCMU_CMD_SET_FEATURES,
__TCMU_CMD_MAX,
 };
@@ -151,8 +155,23 @@ enum tcmu_genl_attr {
TCMU_ATTR_CMD_STATUS,
TCMU_ATTR_DEVICE_ID,
TCMU_ATTR_SUPP_KERN_CMD_REPLY,
+   TCMU_ATTR_PR_INFO,
__TCMU_ATTR_MAX,
 };
 #define TCMU_ATTR_MAX (__TCMU_ATTR_MAX - 1)
 
+/* This struct help to store the Persistent Reservation which we
+ * are handling, it is encoded from or decoded to the string buffer in
+ * "struct tcmu_dev_pr_info"
+ */
+struct tcmu_pr_info {
+   u32 vers;   /* on disk format version number */
+   u32 seq;/* sequence number bumped every xattr write */
+   struct tcmu_scsi2_rsv *scsi2_rsv; /* SCSI2 reservation if any */
+   u32 gen;/* PR generation number */
+   struct tcmu_pr_rsv *rsv;/* SCSI3 reservation if any */
+   u32 num_regs;   /* number of registrations */
+   struct list_head regs;  /* list of registrations */
+};
+
 #endif
-- 
2.17.1



[PATCH 14/33] TCMU PR: add a function can get PR info from a dev

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_pr_info_get() which can help
get Persistent Reservation information from a TCMU device.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 51 +++
 1 file changed, 51 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 12f4a5a5c1e1..0f8eeed61c60 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2253,6 +2253,57 @@ static int tcmu_pr_info_decode(char *pr_xattr, int 
pr_xattr_len,
return rc;
 }
 
+static int tcmu_pr_info_get(struct tcmu_dev *udev,
+   struct tcmu_pr_info **_pr_info,
+   char **_pr_xattr, int *_pr_xattr_len)
+{
+   int rc;
+   char *pr_xattr = udev->pr_info.pr_info_buf;
+   char *dup_xattr = NULL;
+   int pr_xattr_len = 0;
+   struct tcmu_pr_info *pr_info = NULL;
+
+   if (!_pr_info) {
+   WARN_ON(1);
+   return -EINVAL;
+   }
+
+   rc = tcmu_get_dev_pr_info(udev, &pr_xattr_len);
+
+   if (rc) {
+   if (rc != -ENODATA)
+   pr_err("failed to obtain PR xattr: %d\n", rc);
+   return rc;
+   }
+
+   if (_pr_xattr) {
+   /* dup before decode, which trashes @pr_xattr */
+   dup_xattr = kstrdup(pr_xattr, GFP_KERNEL);
+   if (!dup_xattr)
+   return -ENOMEM;
+   }
+
+   rc = tcmu_pr_info_decode(pr_xattr, pr_xattr_len, &pr_info);
+   if (rc) {
+   pr_err("failed to decode PR xattr: %d\n", rc);
+   goto err_dup_xattr_free;
+   }
+
+   if (_pr_xattr) {
+   WARN_ON(!_pr_xattr_len);
+   *_pr_xattr = dup_xattr;
+   *_pr_xattr_len = pr_xattr_len;
+   }
+
+   *_pr_info = pr_info;
+   pr_debug("successfully obtained PR info\n");
+   return 0;
+
+err_dup_xattr_free:
+   kfree(dup_xattr);
+   return rc;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 05/33] TCMU PR: add a function to get IT_Nexus

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_gen_it_nexus() which can help
generate a string contain IT_Nexus information from a session.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 44 +++
 1 file changed, 44 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index d368c656ef79..26d8aee40719 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -1769,6 +1769,50 @@ static int tcmu_set_dev_pr_info(struct tcmu_dev *udev, 
void *val)
return tcmu_send_set_pr_info_event(udev, val);
 }
 
+static int
+tcmu_gen_it_nexus(struct se_session *se_sess,
+char *nexus_buf,
+size_t buflen)
+{
+   struct se_portal_group *se_tpg;
+   const struct target_core_fabric_ops *tfo;
+   u32 tpg_tag = 0;
+   char *tpg_wwn = "";
+   int rc;
+
+   if (!se_sess || !se_sess->se_node_acl || !se_sess->se_tpg
+   || !se_sess->se_tpg->se_tpg_tfo) {
+   pr_warn("invalid session for IT nexus generation\n");
+   return -EINVAL;
+   }
+
+   se_tpg = se_sess->se_tpg;
+   tfo = se_tpg->se_tpg_tfo;
+
+   /*
+* nexus generation may be coming from an xcopy, in which case tfo
+* refers to xcopy_pt_tfo (tpg_get_wwn and tpg_get_tag are NULL).
+*/
+   if (tfo->tpg_get_tag)
+   tpg_tag = tfo->tpg_get_tag(se_tpg);
+   if (tfo->tpg_get_wwn)
+   tpg_wwn = tfo->tpg_get_wwn(se_tpg);
+
+   rc = snprintf(nexus_buf, buflen, "%s,i,0x%llx,%s,t,0x%x",
+ se_sess->se_node_acl->initiatorname,
+ se_sess->sess_bin_isid,
+ tpg_wwn,
+ tpg_tag);
+   if ((rc < 0) || (rc >= buflen)) {
+   pr_debug("error formatting reserve cookie\n");
+   return -EINVAL;
+   }
+
+   pr_debug("generated nexus: %s\n", nexus_buf);
+
+   return 0;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 04/33] TCMU PR: add functions can store PR info into devs

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_send_set_pr_info_event() to
store Persistent Reservation information into a TCMU
device (for example, if we use a RBD device, the information
will be stored in it's metadata), added it's wrapper function
tcmu_set_dev_pr_info() as well.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 29 +
 1 file changed, 29 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index a1ed70d0988a..d368c656ef79 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -1698,6 +1698,26 @@ static int tcmu_send_get_pr_info_event(struct tcmu_dev 
*udev)
   &skb, &msg_header);
 }
 
+static int tcmu_send_set_pr_info_event(struct tcmu_dev *udev, char *buf)
+{
+   struct sk_buff *skb = NULL;
+   void *msg_header = NULL;
+   int ret = 0;
+
+   ret = tcmu_netlink_event_init(udev, TCMU_CMD_SET_PR_INFO,
+ &skb, &msg_header);
+   if (ret < 0)
+   return ret;
+   ret = nla_put_string(skb, TCMU_ATTR_PR_INFO, buf);
+   if (ret < 0) {
+   nlmsg_free(skb);
+   return ret;
+   }
+
+   return tcmu_netlink_event_send(udev, TCMU_CMD_SET_PR_INFO,
+  &skb, &msg_header);
+}
+
 static int tcmu_update_uio_info(struct tcmu_dev *udev)
 {
struct tcmu_hba *hba = udev->hba->hba_ptr;
@@ -1740,6 +1760,15 @@ static int tcmu_get_dev_pr_info(struct tcmu_dev *udev, 
int *val_len)
return ret;
 }
 
+/*
+ * This function will store PR INFO(a string) to a TCMU
+ * device metadata.
+ */
+static int tcmu_set_dev_pr_info(struct tcmu_dev *udev, void *val)
+{
+   return tcmu_send_set_pr_info_event(udev, val);
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 13/33] TCMU PR: add a PR info decoder function

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_pr_info_decode() which can decode
Persistent Reservation info, from the string to a struct
tcmu_pr_info. This function will call the pervious added decoder
like tcmu_pr_info_reg_decode() to do it's work.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 108 ++
 1 file changed, 108 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 09a4f97243b8..12f4a5a5c1e1 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -99,6 +99,14 @@
 
 #define TCMU_PR_IT_NEXUS_MAXLEN484
 
+#define TCMU_PR_INFO_XATTR_FIELD_VER   0
+#define TCMU_PR_INFO_XATTR_FIELD_SEQ   1
+#define TCMU_PR_INFO_XATTR_FIELD_SCSI2_RSV 2
+#define TCMU_PR_INFO_XATTR_FIELD_GEN   3
+#define TCMU_PR_INFO_XATTR_FIELD_SCSI3_RSV 4
+#define TCMU_PR_INFO_XATTR_FIELD_NUM_REGS  5
+#define TCMU_PR_INFO_XATTR_FIELD_REGS_START6
+
 static u8 tcmu_kern_cmd_reply_supported;
 
 static struct device *tcmu_root_device;
@@ -2145,6 +2153,106 @@ tcmu_pr_info_free(struct tcmu_pr_info *pr_info)
kfree(pr_info);
 }
 
+static int tcmu_pr_info_decode(char *pr_xattr, int pr_xattr_len,
+  struct tcmu_pr_info **_pr_info)
+{
+   struct tcmu_pr_info *pr_info;
+   int rc;
+   int field;
+   int i;
+   char *p;
+   char *str;
+   char *end;
+
+   WARN_ON(!_pr_info);
+
+   if (!pr_xattr_len) {
+   pr_err("zero length PR xattr\n");
+   return -EINVAL;
+   }
+
+   pr_debug("decoding PR xattr: %s\n", pr_xattr);
+
+   pr_info = kzalloc(sizeof(*pr_info), GFP_KERNEL);
+   if (!pr_info)
+   return -ENOMEM;
+
+   INIT_LIST_HEAD(&pr_info->regs);
+
+   p = pr_xattr;
+   end = pr_xattr + pr_xattr_len;
+   field = 0;
+   i = 0;
+   /*
+* '\n' separator between header fields and each reg entry.
+* reg subfields are further separated by ' '.
+*/
+   for (str = strsep(&p, "\n"); str && *str != '\0' && (p <= end);
+str = strsep(&p, "\n")) {
+   if (field == TCMU_PR_INFO_XATTR_FIELD_VER) {
+   rc = tcmu_pr_info_vers_decode(str, &pr_info->vers);
+   if (rc < 0)
+   goto err_info_free;
+   } else if (field == TCMU_PR_INFO_XATTR_FIELD_SEQ) {
+   rc = tcmu_pr_info_seq_decode(str, &pr_info->seq);
+   if (rc < 0)
+   goto err_info_free;
+   } else if (field == TCMU_PR_INFO_XATTR_FIELD_SCSI2_RSV) {
+   rc = tcmu_pr_info_scsi2_rsv_decode(str,
+  &pr_info->scsi2_rsv);
+   if (rc < 0)
+   goto err_info_free;
+   } else if (field == TCMU_PR_INFO_XATTR_FIELD_GEN) {
+   rc = tcmu_pr_info_gen_decode(str, &pr_info->gen);
+   if (rc < 0)
+   goto err_info_free;
+   } else if (field == TCMU_PR_INFO_XATTR_FIELD_SCSI3_RSV) {
+   rc = tcmu_pr_info_rsv_decode(str, &pr_info->rsv);
+   if (rc < 0)
+   goto err_info_free;
+   } else if (field == TCMU_PR_INFO_XATTR_FIELD_NUM_REGS) {
+   rc = tcmu_pr_info_num_regs_decode(str,
+ &pr_info->num_regs);
+   if (rc < 0)
+   goto err_info_free;
+   } else if (field >= TCMU_PR_INFO_XATTR_FIELD_REGS_START) {
+   struct tcmu_pr_reg *reg;
+
+   rc = tcmu_pr_info_reg_decode(str, ®);
+   if (rc < 0)
+   goto err_info_free;
+   list_add_tail(®->regs_node, &pr_info->regs);
+   i++;
+   } else {
+   pr_debug("skipping parsing of field %d\n", field);
+   }
+
+   field++;
+   }
+
+   if (field <= TCMU_PR_INFO_XATTR_FIELD_NUM_REGS) {
+   pr_err("pr_info missing basic fields, stopped at %d\n", field);
+   rc = -EINVAL;
+   goto err_info_free;
+   }
+
+   if (i != pr_info->num_regs) {
+   pr_err("processed %d registrations, expected %d\n",
+  i, pr_info->num_regs);
+   rc = -EINVAL;
+   goto err_info_free;
+   }
+
+   pr_debug("successfully processed all PR data\n");
+   *_pr_info = pr_info;
+
+   return 0;
+
+err_info_free:
+   tcmu_pr_info_free(pr_info);
+   return rc;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.

[PATCH 09/33] TCMU PR: add func to handle PR type, key, IT nexus

2018-06-15 Thread Zhu Lingshan
This patch add two functions: tcmu_pr_info_rsv_decode() and
tcmu_pr_info_rsv_encode() to handle Persistent Reservations type,
key and IT_Nexus. This patch added a struct tcmu_pr_rsv to
store such information as well.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 72 +++
 1 file changed, 72 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index ef79de7622b6..b72c61d81f98 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -95,6 +95,7 @@
 
 #define TCMU_PR_INFO_XATTR_VERS1
 #define TCMU_PR_INFO_XATTR_VAL_SCSI2_RSV_ABSENT"No SPC-2 
Reservation holder"
+#define TCMU_PR_INFO_XATTR_VAL_SCSI3_RSV_ABSENT"No SPC-3 
Reservation holder"
 
 #define TCMU_PR_IT_NEXUS_MAXLEN484
 
@@ -123,6 +124,22 @@ struct tcmu_dev_pr_info {
char *pr_info_buf;
};
 
+/*
+ * Persistent reservation info. This structure is converted to and from a
+ * string in a TCMU device storage (for example, if we use a RBD, we store such
+ * a string in it's metadata) which contain PR information.
+ */
+struct tcmu_pr_rsv {
+   u64 key;/* registered key */
+   /*
+* I-T nexus for reservation. Separate to reg, so that all_tg_pt flag
+* can be supported in future.
+*/
+   char it_nexus[TCMU_PR_IT_NEXUS_MAXLEN];
+   int type;   /* PR_TYPE */
+   /* scope is always PR_SCOPE_LU_SCOPE */
+   };
+
 struct tcmu_dev {
struct list_head node;
struct kref kref;
@@ -1974,6 +1991,61 @@ tcmu_pr_info_gen_encode(char *buf, size_t buf_remain, 
u32 gen)
return rc;
 }
 
+static int tcmu_pr_info_rsv_decode(char *str, struct tcmu_pr_rsv **_rsv)
+{
+   struct tcmu_pr_rsv *rsv;
+   int rc;
+
+   if (!_rsv) {
+   WARN_ON(1);
+   return -EINVAL;
+   }
+   if (!strncmp(str, TCMU_PR_INFO_XATTR_VAL_SCSI3_RSV_ABSENT,
+sizeof(TCMU_PR_INFO_XATTR_VAL_SCSI3_RSV_ABSENT))) {
+   /* no reservation. Ensure pr_info->rsv is NULL */
+   rsv = NULL;
+   } else {
+   rsv = kzalloc(sizeof(*rsv), GFP_KERNEL);
+   if (!rsv)
+   return -ENOMEM;
+
+   /* reservation key, I-T nexus and type with space separators */
+   rc = sscanf(str, "0x%016llx %"
+   __stringify(TCMU_PR_IT_NEXUS_MAXLEN)
+   "s 0x%08x", &rsv->key, rsv->it_nexus, &rsv->type);
+   if (rc != 3) {
+   pr_err("failed to parse PR rsv: %s\n", str);
+   kfree(rsv);
+   return -EINVAL;
+   }
+   }
+
+   pr_debug("processed pr_info rsv: %s\n", str);
+   *_rsv = rsv;
+   return 0;
+}
+
+static int tcmu_pr_info_rsv_encode(char *buf, size_t buf_remain,
+  struct tcmu_pr_rsv *rsv)
+{
+   int rc;
+
+   if (!rsv) {
+   /* no reservation */
+   rc = snprintf(buf, buf_remain, "%s\n",
+ TCMU_PR_INFO_XATTR_VAL_SCSI3_RSV_ABSENT);
+   } else {
+   rc = snprintf(buf, buf_remain, "0x%016llx %s 0x%08x\n",
+ rsv->key, rsv->it_nexus, rsv->type);
+   }
+   if ((rc < 0) || (rc >= buf_remain)) {
+   pr_err("failed to encode PR reservation\n");
+   return -EINVAL;
+   }
+
+   return rc;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 16/33] TCMU PR: init PR info when empty for TCMU dev

2018-06-15 Thread Zhu Lingshan
When try to register an IT_Nexus, if tcmu_pr_info_get()
returns -ENODATA, this means the string stored on the
TCMU DEVICE records(for example, RBD metadata) which represent
Persistent Reservation information is empty,there are no
registrations, we should initialize a new struct
tcmu_pr_info.

This patch added a function tcmu_pr_info_init() to initialize
Persistent Reservation struct tcmu_pr_info, encode it to a
string, and store this string in the TCMU device records.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 48 +++
 1 file changed, 48 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 957e444d853b..8d860b59d277 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2437,6 +2437,54 @@ static int tcmu_pr_info_encode(struct tcmu_pr_info 
*pr_info,
return rc;
 }
 
+static int tcmu_pr_info_init(struct tcmu_dev *udev,
+struct tcmu_pr_info **_pr_info,
+char **_pr_xattr, int *_pr_xattr_len)
+{
+   struct tcmu_pr_info *pr_info;
+   char *pr_xattr = NULL;
+   int pr_xattr_len = 0;
+   int rc;
+
+   pr_info = kzalloc(sizeof(*pr_info), GFP_KERNEL);
+   if (!pr_info)
+   return -ENOMEM;
+
+   pr_info->vers = TCMU_PR_INFO_XATTR_VERS;
+   INIT_LIST_HEAD(&pr_info->regs);
+   pr_info->seq = 1;
+
+   rc = tcmu_pr_info_encode(pr_info, &pr_xattr, &pr_xattr_len);
+   if (rc) {
+   pr_err("failed to encode PR xattr: %d\n", rc);
+   goto err_info_free;
+   }
+
+   rc = tcmu_set_dev_pr_info(udev, pr_xattr);
+   if (rc) {
+   pr_err("failed to set PR xattr: %d\n", rc);
+   goto err_xattr_free;
+   }
+
+   *_pr_info = pr_info;
+   if (_pr_xattr) {
+   WARN_ON(!_pr_xattr_len);
+   *_pr_xattr = pr_xattr;
+   *_pr_xattr_len = pr_xattr_len;
+   } else {
+   kfree(pr_xattr);
+   }
+   pr_debug("successfully initialized PR info\n");
+
+   return 0;
+
+err_xattr_free:
+   kfree(pr_xattr);
+err_info_free:
+   kfree(pr_info);
+   return rc;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 15/33] TCMU PR: add a PR info encoder function

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_pr_info_encode() which can
encode Persistent Reservation info, from a struct tcmu_pr_info
to a string, so that we can store this string on a TCMU device.
This function will call the pervious added encoder like
tcmu_pr_info_reg_encode() to do it's work.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 133 ++
 1 file changed, 133 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 0f8eeed61c60..957e444d853b 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -107,6 +107,31 @@
 #define TCMU_PR_INFO_XATTR_FIELD_NUM_REGS  5
 #define TCMU_PR_INFO_XATTR_FIELD_REGS_START6
 
+/* don't allow encoded PR info to exceed 8K */
+#define TCMU_PR_INFO_XATTR_MAX_SIZE 8192
+
+#define TCMU_PR_INFO_XATTR_ENCODED_SCSI2_RSV_MAXLEN\
+   (TCMU_PR_IT_NEXUS_MAXLEN + sizeof("\n"))
+
+#define TCMU_PR_INFO_XATTR_ENCODED_PR_RSV_MAXLEN   \
+   ((sizeof("0x") + sizeof(u64) * 2) + sizeof(" ") +   \
+TCMU_PR_IT_NEXUS_MAXLEN + sizeof(" ") +\
+(sizeof("0x") + sizeof(u64) * 2) + sizeof("\n"))
+
+#define TCMU_PR_INFO_XATTR_ENCODED_PR_REG_MAXLEN   \
+   ((sizeof("0x") + sizeof(u64) * 2) + sizeof(" ") +   \
+TCMU_PR_IT_NEXUS_MAXLEN + sizeof("\n"))
+
+#define TCMU_PR_INFO_XATTR_ENCODED_MAXLEN(_num_regs)   \
+((sizeof("0x") + sizeof(u32) * 2) + sizeof("\n") + \
+(sizeof("0x") + sizeof(u32) * 2) + sizeof("\n") +  \
+TCMU_PR_INFO_XATTR_ENCODED_SCSI2_RSV_MAXLEN +  \
+(sizeof("0x") + sizeof(u32) * 2) + sizeof("\n") +  \
+TCMU_PR_INFO_XATTR_ENCODED_PR_RSV_MAXLEN + \
+(sizeof("0x") + sizeof(u32) * 2) + sizeof("\n") +  \
+(TCMU_PR_INFO_XATTR_ENCODED_PR_REG_MAXLEN * _num_regs) +   \
+sizeof("\0"))
+
 static u8 tcmu_kern_cmd_reply_supported;
 
 static struct device *tcmu_root_device;
@@ -2304,6 +2329,114 @@ static int tcmu_pr_info_get(struct tcmu_dev *udev,
return rc;
 }
 
+static int tcmu_pr_info_encode(struct tcmu_pr_info *pr_info,
+  char **_pr_xattr, int *pr_xattr_len)
+{
+   struct tcmu_pr_reg *reg;
+   char *pr_xattr;
+   char *p;
+   size_t buf_remain;
+   int rc;
+   int i;
+
+   if (pr_info->vers != TCMU_PR_INFO_XATTR_VERS) {
+   pr_err("unsupported PR info version: %u\n", pr_info->vers);
+   return -EINVAL;
+   }
+
+   buf_remain = TCMU_PR_INFO_XATTR_ENCODED_MAXLEN(pr_info->num_regs);
+   if (buf_remain > TCMU_PR_INFO_XATTR_MAX_SIZE) {
+   pr_err("PR info too large for encoding: %zd\n", buf_remain);
+   return -EINVAL;
+   }
+   pr_debug("encoding PR info: vers=%u, seq=%u, gen=%u, num regs=%u ",
+  pr_info->vers, pr_info->seq, pr_info->gen, pr_info->num_regs);
+   pr_debug("into %zd bytes\n", buf_remain);
+
+   pr_xattr = kmalloc(buf_remain, GFP_KERNEL);
+   if (!pr_xattr)
+   return -ENOMEM;
+
+   p = pr_xattr;
+   rc = tcmu_pr_info_vers_seq_encode(p, buf_remain, pr_info->vers,
+ pr_info->seq);
+   if (rc < 0) {
+   rc = -EINVAL;
+   goto err_xattr_free;
+   }
+
+   p += rc;
+   buf_remain -= rc;
+
+   rc = tcmu_pr_info_scsi2_rsv_encode(p, buf_remain, pr_info->scsi2_rsv);
+   if (rc < 0) {
+   rc = -EINVAL;
+   goto err_xattr_free;
+   }
+
+   p += rc;
+   buf_remain -= rc;
+
+   rc = tcmu_pr_info_gen_encode(p, buf_remain, pr_info->gen);
+   if (rc < 0) {
+   rc = -EINVAL;
+   goto err_xattr_free;
+   }
+
+   p += rc;
+   buf_remain -= rc;
+
+   rc = tcmu_pr_info_rsv_encode(p, buf_remain, pr_info->rsv);
+   if (rc < 0) {
+   rc = -EINVAL;
+   goto err_xattr_free;
+   }
+
+   p += rc;
+   buf_remain -= rc;
+
+   rc = tcmu_pr_info_num_regs_encode(p, buf_remain, pr_info->num_regs);
+   if (rc < 0) {
+   rc = -EINVAL;
+   goto err_xattr_free;
+   }
+
+   p += rc;
+   buf_remain -= rc;
+
+   i = 0;
+   list_for_each_entry(reg, &pr_info->regs, regs_node) {
+   rc = tcmu_pr_info_reg_encode(p, buf_remain, reg);
+   if (rc < 0) {
+   rc = -EINVAL;
+   goto err_xattr_free;
+   }
+
+   p += rc;
+   buf_remain -= rc;
+   i++;
+   }
+
+   if (i != pr_info->num_regs) {
+   pr_err("mismatch between PR num_regs and list entries!\n");
+   rc = -EINVAL;
+   goto err_xattr_free;
+   }
+
+   *_pr_xattr = pr_xattr;
+   /* +1 to include null 

[PATCH 19/33] TCMU PR: add functions to unregister a reg

2018-06-15 Thread Zhu Lingshan
This patch added four functions: tcmu_pr_info_clear_reg() would
delete a registration from a struct tcmu_pr_info,
tcmu_pr_info_rsv_clear() would clear the reservation,
tcmu_is_rsv_holder() would check whether the registration is a
reservation holder. Then tcmu_pr_info_unregister_reg() would
call the functions above to unregister the registration.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 75 +++
 1 file changed, 75 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 5d0da54072cd..a6e951f04065 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -41,6 +41,7 @@
 #include 
 
 #include 
+#include "target_core_pr.h"
 
 /*
  * Define a shared-memory interface for LIO to pass SCSI commands and
@@ -2539,6 +2540,80 @@ tcmu_execute_pr_register_new(struct tcmu_pr_info 
*pr_info, u64 old_key,
return ret;
 }
 
+static bool tcmu_is_rsv_holder(struct tcmu_pr_rsv *rsv,
+  struct tcmu_pr_reg *reg, bool *rsv_is_all_reg)
+{
+   if (!rsv || !reg) {
+   WARN_ON(1);
+   return false;
+   }
+   if ((rsv->type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG)
+   || (rsv->type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
+   /* any registeration is a reservation holder */
+   if (rsv_is_all_reg)
+   *rsv_is_all_reg = true;
+   return true;
+   }
+
+   if (rsv_is_all_reg)
+   *rsv_is_all_reg = false;
+
+   if ((rsv->key == reg->key)
+   && !strncmp(rsv->it_nexus, reg->it_nexus,
+   ARRAY_SIZE(rsv->it_nexus))) {
+   return true;
+   }
+
+   return false;
+}
+
+static void tcmu_pr_info_clear_reg(struct tcmu_pr_info *pr_info,
+  struct tcmu_pr_reg *reg)
+{
+   list_del(®->regs_node);
+   pr_info->num_regs--;
+
+   pr_debug("deleted pr_info reg: 0x%llx\n", reg->key);
+
+   kfree(reg);
+}
+
+static void tcmu_pr_info_rsv_clear(struct tcmu_pr_info *pr_info)
+{
+   kfree(pr_info->rsv);
+   pr_info->rsv = NULL;
+
+   pr_debug("pr_info rsv cleared\n");
+}
+
+static int tcmu_pr_info_unregister_reg(struct tcmu_pr_info *pr_info,
+  struct tcmu_pr_reg *reg)
+{
+   struct tcmu_pr_rsv *rsv;
+   bool all_reg = false;
+
+   rsv = pr_info->rsv;
+   if (rsv && tcmu_is_rsv_holder(rsv, reg, &all_reg)) {
+   /*
+* If the persistent reservation holder is more than one I_T
+* nexus, the reservation shall not be released until the
+* registrations for all persistent reservation holder I_T
+* nexuses are removed.
+*/
+   if (!all_reg || (pr_info->num_regs == 1)) {
+   pr_warn("implicitly releasing PR of type %d",
+   rsv->type);
+   pr_warn("on unregister I_T Nexus %s\n",
+   reg->it_nexus);
+   tcmu_pr_info_rsv_clear(pr_info);
+   }
+   }
+
+   tcmu_pr_info_clear_reg(pr_info, reg);
+
+   return 0;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 11/33] TCMU PR: add funcs to handle TCMU PR registrations

2018-06-15 Thread Zhu Lingshan
This patch added a struct tcmu_pr_reg which contain Persistent
Reservation registrations information, also added two functions
tcmu_pr_info_reg_decode() and tcmu_pr_info_reg_encode() to handle
it.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 51 +++
 1 file changed, 51 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 8e61641f34ac..55f1ba98a688 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -228,6 +228,13 @@ struct tcmu_scsi2_rsv {
char it_nexus[TCMU_PR_IT_NEXUS_MAXLEN];
};
 
+struct tcmu_pr_reg {
+   struct list_head regs_node;
+   u64 key;/* registered key */
+   /* I-T nexus for registration */
+   char it_nexus[TCMU_PR_IT_NEXUS_MAXLEN];
+};
+
 /*
  * To avoid dead lock the mutex lock order should always be:
  *
@@ -2080,6 +2087,50 @@ static int tcmu_pr_info_num_regs_encode(char *buf, 
size_t buf_remain,
return rc;
 }
 
+static int tcmu_pr_info_reg_decode(char *str, struct tcmu_pr_reg **_reg)
+{
+   struct tcmu_pr_reg *reg;
+   int rc;
+
+   if (!_reg) {
+   WARN_ON(1);
+   return -EINVAL;
+   }
+
+   reg = kzalloc(sizeof(*reg), GFP_KERNEL);
+   if (!reg)
+   return -ENOMEM;
+
+   /* registration key and I-T nexus with space separator */
+   rc = sscanf(str, "0x%016llx %" __stringify(TCMU_PR_IT_NEXUS_MAXLEN)
+"s", ®->key, reg->it_nexus);
+   if (rc != 2) {
+   pr_err("failed to parse PR reg: %s\n", str);
+   kfree(reg);
+   return -EINVAL;
+   }
+
+   pr_debug("processed pr_info reg: %s\n", str);
+   *_reg = reg;
+
+   return 0;
+}
+
+static int tcmu_pr_info_reg_encode(char *buf, size_t buf_remain,
+  struct tcmu_pr_reg *reg)
+{
+   int rc;
+
+   rc = snprintf(buf, buf_remain, "0x%016llx %s\n", reg->key,
+ reg->it_nexus);
+   if ((rc < 0) || (rc >= buf_remain)) {
+   pr_err("failed to encode PR registration\n");
+   return -EINVAL;
+   }
+
+   return rc;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 18/33] TCMU PR: add a function to register a new IT Nexus

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_execute_pr_register_new() which
can help to register an unregistered I_T Nexus.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 34 +++
 1 file changed, 34 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 291b3ff4555d..5d0da54072cd 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2505,6 +2505,40 @@ static int tcmu_pr_info_append_reg(struct tcmu_pr_info 
*pr_info,
return 0;
 }
 
+/* handle PR registration for a currently unregistered I_T nexus */
+static sense_reason_t
+tcmu_execute_pr_register_new(struct tcmu_pr_info *pr_info, u64 old_key,
+u64 new_key, char *it_nexus,
+bool ignore_existing)
+{
+   sense_reason_t ret;
+   int rc;
+
+   pr_debug("PR registration for unregistered nexus: %s\n", it_nexus);
+   if (!ignore_existing && (old_key != 0)) {
+   ret = TCM_RESERVATION_CONFLICT;
+   goto out;
+   }
+   if (new_key == 0) {
+   ret = TCM_NO_SENSE;
+   goto out;
+   }
+   /*
+* Register the I_T nexus on which the command was received with
+* the value specified in the SERVICE ACTION RESERVATION KEY
+* field.
+*/
+   rc = tcmu_pr_info_append_reg(pr_info, it_nexus, new_key);
+   if (rc < 0) {
+   ret = TCM_OUT_OF_RESOURCES;
+   goto out;
+   }
+
+   ret = TCM_NO_SENSE;
+out:
+   return ret;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 17/33] TCMU PR: add a function to append a new PR reg

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_pr_info_append_reg() which can
help to append a new Persistent Reservation registration to
struct tcmu_pr_info.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 20 
 1 file changed, 20 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 8d860b59d277..291b3ff4555d 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2485,6 +2485,26 @@ static int tcmu_pr_info_init(struct tcmu_dev *udev,
return rc;
 }
 
+static int tcmu_pr_info_append_reg(struct tcmu_pr_info *pr_info,
+  char *nexus, u64 key)
+{
+   struct tcmu_pr_reg *reg;
+
+   reg = kmalloc(sizeof(*reg), GFP_KERNEL);
+   if (!reg)
+   return -ENOMEM;
+
+   reg->key = key;
+   strlcpy(reg->it_nexus, nexus, ARRAY_SIZE(reg->it_nexus));
+
+   list_add_tail(®->regs_node, &pr_info->regs);
+   pr_info->num_regs++;
+
+   pr_debug("appended pr_info reg: 0x%llx\n", reg->key);
+
+   return 0;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 12/33] TCMU PR: add a function to free tcmu_pr_info

2018-06-15 Thread Zhu Lingshan
This patch added a function tcmu_pr_info_free() which can
help free struct tcmu_pr_info.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 55f1ba98a688..09a4f97243b8 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2131,6 +2131,20 @@ static int tcmu_pr_info_reg_encode(char *buf, size_t 
buf_remain,
return rc;
 }
 
+static void
+tcmu_pr_info_free(struct tcmu_pr_info *pr_info)
+{
+   struct tcmu_pr_reg *reg;
+   struct tcmu_pr_reg *reg_n;
+
+   kfree(pr_info->scsi2_rsv);
+   kfree(pr_info->rsv);
+   list_for_each_entry_safe(reg, reg_n, &pr_info->regs, regs_node) {
+   kfree(reg);
+   }
+   kfree(pr_info);
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 10/33] TCMU PR: add funcs to handle PR registrations num

2018-06-15 Thread Zhu Lingshan
This patch added two functions: tcmu_pr_info_num_regs_decode()
and tcmu_pr_info_num_regs_encode() to handle the number of
Persistent Reservation registrations.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 34 +++
 1 file changed, 34 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index b72c61d81f98..8e61641f34ac 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -2046,6 +2046,40 @@ static int tcmu_pr_info_rsv_encode(char *buf, size_t 
buf_remain,
return rc;
 }
 
+static int
+tcmu_pr_info_num_regs_decode(char *str, u32 *num_regs)
+{
+   int rc;
+
+   if (!num_regs) {
+   WARN_ON(1);
+   return -EINVAL;
+   }
+
+   rc = sscanf(str, "0x%08x", num_regs);
+   if (rc != 1) {
+   pr_err("failed to parse PR num regs: %s\n", str);
+   return -EINVAL;
+   }
+   pr_debug("processed pr_info num_regs: %s\n", str);
+
+   return 0;
+}
+
+static int tcmu_pr_info_num_regs_encode(char *buf, size_t buf_remain,
+   u32 num_regs)
+{
+   int rc;
+
+   rc = snprintf(buf, buf_remain, "0x%08x\n", num_regs);
+   if ((rc < 0) || (rc >= buf_remain)) {
+   pr_err("failed to encode PR num_regs\n");
+   return -EINVAL;
+   }
+
+   return rc;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 08/33] TCMU PR: add functions to handle PR generation

2018-06-15 Thread Zhu Lingshan
This patch added two functions: tcmu_pr_info_gen_encode()
and tcmu_pr_info_gen_decode() to encode/decode the generations of
Persistent Reservations

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 34 +++
 1 file changed, 34 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 50723ac0ed22..ef79de7622b6 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -1940,6 +1940,40 @@ tcmu_pr_info_scsi2_rsv_encode(char *buf, size_t 
buf_remain,
return rc;
 }
 
+static int
+tcmu_pr_info_gen_decode(char *str, u32 *gen)
+{
+   int rc;
+
+   if (!gen) {
+   WARN_ON(1);
+   return -EINVAL;
+   }
+   rc = sscanf(str, "0x%08x", gen);
+   if (rc != 1) {
+   pr_err("failed to parse PR gen: %s\n", str);
+   return -EINVAL;
+   }
+
+   pr_debug("processed pr_info generation: %s\n", str);
+
+   return 0;
+}
+
+static int
+tcmu_pr_info_gen_encode(char *buf, size_t buf_remain, u32 gen)
+{
+   int rc;
+
+   rc = snprintf(buf, buf_remain, "0x%08x\n", gen);
+   if ((rc < 0) || (rc >= buf_remain)) {
+   pr_err("failed to encode PR gen\n");
+   return -EINVAL;
+   }
+
+   return rc;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 07/33] TCMU PR: add functions to handle SCSI2 Reservation

2018-06-15 Thread Zhu Lingshan
This patch added two functions: tcmu_pr_info_scsi2_rsv_encode()
and tcmu_pr_info_scsi2_rsv_decode() to encode and decode SCSI2
Reservations.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 65 +++
 1 file changed, 65 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index ccb1607edd0a..50723ac0ed22 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -94,6 +94,9 @@
 #define TCMU_GLOBAL_MAX_BLOCKS_DEF (512 * 1024)
 
 #define TCMU_PR_INFO_XATTR_VERS1
+#define TCMU_PR_INFO_XATTR_VAL_SCSI2_RSV_ABSENT"No SPC-2 
Reservation holder"
+
+#define TCMU_PR_IT_NEXUS_MAXLEN484
 
 static u8 tcmu_kern_cmd_reply_supported;
 
@@ -200,6 +203,14 @@ struct tcmu_cmd {
 #define TCMU_CMD_BIT_EXPIRED 0
unsigned long flags;
 };
+
+/*
+ * I-T nexus for SCSI2 (RESERVE/RELEASE) reservation.
+ */
+struct tcmu_scsi2_rsv {
+   char it_nexus[TCMU_PR_IT_NEXUS_MAXLEN];
+   };
+
 /*
  * To avoid dead lock the mutex lock order should always be:
  *
@@ -1875,6 +1886,60 @@ tcmu_pr_info_vers_decode(char *str, u32 *vers)
return 0;
 }
 
+static int
+tcmu_pr_info_scsi2_rsv_decode(char *str, struct tcmu_scsi2_rsv **_scsi2_rsv)
+{
+   struct tcmu_scsi2_rsv *scsi2_rsv;
+
+   if (!_scsi2_rsv) {
+   WARN_ON(1);
+   return -EINVAL;
+   }
+   if (!strncmp(str, TCMU_PR_INFO_XATTR_VAL_SCSI2_RSV_ABSENT,
+sizeof(TCMU_PR_INFO_XATTR_VAL_SCSI2_RSV_ABSENT))) {
+   scsi2_rsv = NULL;
+   } else {
+   size_t n;
+
+   scsi2_rsv = kzalloc(sizeof(*scsi2_rsv), GFP_KERNEL);
+   if (!scsi2_rsv)
+   return -ENOMEM;
+
+   n = strlcpy(scsi2_rsv->it_nexus, str,
+   TCMU_PR_IT_NEXUS_MAXLEN);
+   if (n >= TCMU_PR_IT_NEXUS_MAXLEN) {
+   kfree(scsi2_rsv);
+   return -EINVAL;
+   }
+   }
+
+   pr_debug("processed pr_info SCSI2 rsv: %s\n", str);
+
+   *_scsi2_rsv = scsi2_rsv;
+   return 0;
+}
+
+static int
+tcmu_pr_info_scsi2_rsv_encode(char *buf, size_t buf_remain,
+ struct tcmu_scsi2_rsv *scsi2_rsv)
+{
+   int rc;
+
+   if (!scsi2_rsv) {
+   /* no reservation */
+   rc = snprintf(buf, buf_remain, "%s\n",
+ TCMU_PR_INFO_XATTR_VAL_SCSI2_RSV_ABSENT);
+   } else {
+   rc = snprintf(buf, buf_remain, "%s\n", scsi2_rsv->it_nexus);
+   }
+   if ((rc < 0) || (rc >= buf_remain)) {
+   pr_err("failed to encode SCSI2 reservation\n");
+   return -EINVAL;
+   }
+
+   return rc;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 06/33] TCMU PR: add decode/encode func for PR seq and ver

2018-06-15 Thread Zhu Lingshan
This patch added three functions, tcmu_pr_info_vers_seq_encode()
to encode PR sequence and version into a string,
tcmu_pr_info_vers_decode() and tcmu_pr_info_seq_decode() used
to decode them.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 62 +++
 1 file changed, 62 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 26d8aee40719..ccb1607edd0a 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -93,6 +93,8 @@
  */
 #define TCMU_GLOBAL_MAX_BLOCKS_DEF (512 * 1024)
 
+#define TCMU_PR_INFO_XATTR_VERS1
+
 static u8 tcmu_kern_cmd_reply_supported;
 
 static struct device *tcmu_root_device;
@@ -1813,6 +1815,66 @@ tcmu_gen_it_nexus(struct se_session *se_sess,
return 0;
 }
 
+static int
+tcmu_pr_info_seq_decode(char *str, u32 *seq)
+{
+   int rc;
+
+   if (!seq) {
+   WARN_ON(1);
+   return -EINVAL;
+   }
+   rc = sscanf(str, "0x%08x", seq);
+   if (rc != 1) {
+   pr_err("failed to decode PR info seqnum in: %s\n", str);
+   return -EINVAL;
+   }
+
+   pr_debug("processed pr_info seqnum: %u\n", *seq);
+
+   return 0;
+}
+
+static int
+tcmu_pr_info_vers_seq_encode(char *buf, size_t buf_remain, u32 vers, u32 seq)
+{
+   int rc;
+
+   rc = snprintf(buf, buf_remain, "0x%08x\n0x%08x\n",
+ vers, seq);
+   if ((rc < 0) || (rc >= buf_remain)) {
+   pr_err("failed to encode PR vers and seq\n");
+   return -EINVAL;
+   }
+
+   return rc;
+}
+
+static int
+tcmu_pr_info_vers_decode(char *str, u32 *vers)
+{
+   int rc;
+
+   if (!vers) {
+   WARN_ON(1);
+   return -EINVAL;
+   }
+   rc = sscanf(str, "0x%08x", vers);
+   if (rc != 1) {
+   pr_err("failed to decode PR info version in: %s\n", str);
+   return -EINVAL;
+   }
+
+   if (*vers != TCMU_PR_INFO_XATTR_VERS) {
+   pr_err("unsupported PR info version: %u\n", *vers);
+   return -EINVAL;
+   }
+
+   pr_debug("processed pr_info version: %u\n", *vers);
+
+   return 0;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 03/33] TCMU PR: add functions can get PR info from a dev

2018-06-15 Thread Zhu Lingshan
This patch  added a function tcmu_send_get_pr_info_event() to
get Persistent Reservation info from a TCMU device, added it's
wrapper function tcmu_get_dev_pr_info() as well.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 31 +++
 1 file changed, 31 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 1efc2800ca14..a1ed70d0988a 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -1683,6 +1683,21 @@ static int tcmu_send_dev_remove_event(struct tcmu_dev 
*udev)
   &skb, &msg_header);
 }
 
+static int tcmu_send_get_pr_info_event(struct tcmu_dev *udev)
+{
+   struct sk_buff *skb = NULL;
+   void *msg_header = NULL;
+   int ret = 0;
+
+   ret = tcmu_netlink_event_init(udev, TCMU_CMD_GET_PR_INFO,
+ &skb, &msg_header);
+   if (ret < 0)
+   return ret;
+
+   return tcmu_netlink_event_send(udev, TCMU_CMD_GET_PR_INFO,
+  &skb, &msg_header);
+}
+
 static int tcmu_update_uio_info(struct tcmu_dev *udev)
 {
struct tcmu_hba *hba = udev->hba->hba_ptr;
@@ -1709,6 +1724,22 @@ static int tcmu_update_uio_info(struct tcmu_dev *udev)
return 0;
 }
 
+/*
+ * This funtion will get PR INFO(a string)from a TCMU device.
+ * PR INFO will be stored at udev->pr_info.pr_info_buf.
+ */
+static int tcmu_get_dev_pr_info(struct tcmu_dev *udev, int *val_len)
+{
+   int ret = 0;
+
+   ret = tcmu_send_get_pr_info_event(udev);
+   *val_len = strlen(udev->pr_info.pr_info_buf);
+   if (*val_len == 0)
+   ret = -ENODATA;
+
+   return ret;
+}
+
 static int tcmu_configure_device(struct se_device *dev)
 {
struct tcmu_dev *udev = TCMU_DEV(dev);
-- 
2.17.1



[PATCH 02/33] TCMU PR: add tcmu_dev_pr_info to store PR buffer

2018-06-15 Thread Zhu Lingshan
This patch added a struct tcmu_dev_pr_info, which can help
store the string buffer we got from a TCMU device record (for
example, for RBD devices, the records should be stored in
their metadata). So that we can decode / encode them.

Signed-off-by: Zhu Lingshan 
---
 drivers/target/target_core_user.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/target/target_core_user.c 
b/drivers/target/target_core_user.c
index 1dea66a851dd..1efc2800ca14 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -110,6 +110,14 @@ struct tcmu_nl_cmd {
int status;
 };
 
+/* This struct help to store the string buffer which contain
+ * Persistent Reservation info record from the device metadata.
+ */
+struct tcmu_dev_pr_info {
+   struct mutex pr_info_lock;
+   char *pr_info_buf;
+   };
+
 struct tcmu_dev {
struct list_head node;
struct kref kref;
@@ -165,6 +173,7 @@ struct tcmu_dev {
char dev_config[TCMU_CONFIG_LEN];
 
int nl_reply_supported;
+   struct tcmu_dev_pr_info pr_info;
 };
 
 #define TCMU_DEV(_se_dev) container_of(_se_dev, struct tcmu_dev, se_dev)
-- 
2.17.1



Re: [PATCH 2/2] qla2xxx: remove irq save in qla2x00_poll()

2018-06-15 Thread Sebastian Andrzej Siewior
On 2018-06-11 16:56:35 [+0200], Johannes Thumshirn wrote:
> Looks good,
> Reviewed-by: Johannes Thumshirn 

Martin, what about this one?

Sebastian


Re: [PATCH 1/2 v2] libsas: remove irq save in sas_ata_qc_issue()

2018-06-15 Thread Sebastian Andrzej Siewior
On 2018-06-14 21:59:18 [-0400], Martin K. Petersen wrote:
> 
> Sebastian,
Martin,

> Applied to 4.19/scsi-queue. Thank you!

Thank you.

Sebastian