[PATCH 4/4] sg: use standard lists for sg_requests

2017-02-03 Thread Hannes Reinecke
'Sg_request' is using a private list implementation; convert it
to standard lists.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/sg.c | 107 ++
 1 file changed, 44 insertions(+), 63 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 3599551..9b0429d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -122,7 +122,7 @@
 struct sg_fd;
 
 typedef struct sg_request {/* SG_MAX_QUEUE requests outstanding per file */
-   struct sg_request *nextrp;  /* NULL -> tail request (slist) */
+   struct list_head nextrp;/* list entry */
struct sg_fd *parentfp; /* NULL -> not in use */
Sg_scatter_hold data;   /* hold buffer, perhaps scatter list */
sg_io_hdr_t header; /* scsi command+info, see  */
@@ -146,7 +146,7 @@
int timeout_user;   /* defaults to SG_DEFAULT_TIMEOUT_USER */
Sg_scatter_hold reserve;/* buffer held for this file descriptor 
*/
unsigned save_scat_len; /* original length of trunc. scat. element */
-   Sg_request *headrp; /* head of request slist, NULL->empty */
+   struct list_head rq_list; /* head of request list */
struct fasync_struct *async_qp; /* used by asynchronous notification */
Sg_request req_arr[SG_MAX_QUEUE];   /* used as singly-linked list */
char force_packid;  /* 1 -> pack_id input to read(), 0 -> ignored */
@@ -942,7 +942,7 @@ static int max_sectors_bytes(struct request_queue *q)
if (!access_ok(VERIFY_WRITE, ip, sizeof (int)))
return -EFAULT;
read_lock_irqsave(&sfp->rq_list_lock, iflags);
-   for (srp = sfp->headrp; srp; srp = srp->nextrp) {
+   list_for_each_entry(srp, &sfp->rq_list, nextrp) {
if ((1 == srp->done) && (!srp->sg_io_owned)) {
read_unlock_irqrestore(&sfp->rq_list_lock,
   iflags);
@@ -955,7 +955,8 @@ static int max_sectors_bytes(struct request_queue *q)
return 0;
case SG_GET_NUM_WAITING:
read_lock_irqsave(&sfp->rq_list_lock, iflags);
-   for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) {
+   val = 0;
+   list_for_each_entry(srp, &sfp->rq_list, nextrp) {
if ((1 == srp->done) && (!srp->sg_io_owned))
++val;
}
@@ -1026,35 +1027,33 @@ static int max_sectors_bytes(struct request_queue *q)
if (!rinfo)
return -ENOMEM;
read_lock_irqsave(&sfp->rq_list_lock, iflags);
-   for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
-++val, srp = srp ? srp->nextrp : srp) {
+   val = 0;
+   list_for_each_entry(srp, &sfp->rq_list, nextrp) {
+   if (val > SG_MAX_QUEUE)
+   break;
memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
-   if (srp) {
-   rinfo[val].req_state = srp->done + 1;
-   rinfo[val].problem =
-   srp->header.masked_status & 
-   srp->header.host_status & 
-   srp->header.driver_status;
-   if (srp->done)
-   rinfo[val].duration =
-   srp->header.duration;
-   else {
-   ms = jiffies_to_msecs(jiffies);
-   rinfo[val].duration =
-   (ms > srp->header.duration) 
?
-   (ms - srp->header.duration) 
: 0;
-   }
-   rinfo[val].orphan = srp->orphan;
-   rinfo[val].sg_io_owned =
-   srp->sg_io_owned;
-   rinfo[val].pack_id =
-   srp->header.pack_id;
-   rinfo[val].usr_ptr =
-   srp->header.usr_ptr;
+   rinfo[val].req_state = srp->done + 1;
+   rinfo[val].problem =
+   srp->header.masked_status &
+   srp->header.host_status &
+   srp->header.driver_s

[PATCH 0/4] sanitize sg

2017-02-03 Thread Hannes Reinecke
Hi all,

the infamous syzkaller incovered some more issues in the sg driver.
This patchset fixes those two issues (and adds a fix for yet another
potential issue; checking for a NULL dxferp when dxfer_len is not 0).
It also removes handling of the SET_FORCE_LOW_DMA ioctl, which never
worked since the initial git checkin. And does some code cleanup by
removing the private list implementation, using standard lists instead.

As usual, comments and reviews are welcome.

Hannes Reinecke (3):
  sg: disable SET_FORCE_LOW_DMA
  sg: protect access to to 'reserved' page array
  sg: use standard lists for sg_requests

Johannes Thumshirn (1):
  sg: check for valid direction before starting the request

 drivers/scsi/sg.c | 183 --
 include/scsi/sg.h |   1 -
 2 files changed, 80 insertions(+), 104 deletions(-)

-- 
1.8.5.6



[PATCH 1/4] sg: disable SET_FORCE_LOW_DMA

2017-02-03 Thread Hannes Reinecke
The ioctl SET_FORCE_LOW_DMA has never worked since the initial
git check-in, and the respective setting is nowadays handled
correctly.
So disable it entirely.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/sg.c | 27 +--
 include/scsi/sg.h |  1 -
 2 files changed, 5 insertions(+), 23 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index dbe5b4b..8a959b2 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -149,7 +149,6 @@
Sg_request *headrp; /* head of request slist, NULL->empty */
struct fasync_struct *async_qp; /* used by asynchronous notification */
Sg_request req_arr[SG_MAX_QUEUE];   /* used as singly-linked list */
-   char low_dma;   /* as in parent but possibly overridden to 1 */
char force_packid;  /* 1 -> pack_id input to read(), 0 -> ignored */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
@@ -887,24 +886,9 @@ static int max_sectors_bytes(struct request_queue *q)
/* strange ..., for backward compatibility */
return sfp->timeout_user;
case SG_SET_FORCE_LOW_DMA:
-   result = get_user(val, ip);
-   if (result)
-   return result;
-   if (val) {
-   sfp->low_dma = 1;
-   if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
-   val = (int) sfp->reserve.bufflen;
-   sg_remove_scat(sfp, &sfp->reserve);
-   sg_build_reserve(sfp, val);
-   }
-   } else {
-   if (atomic_read(&sdp->detaching))
-   return -ENODEV;
-   sfp->low_dma = sdp->device->host->unchecked_isa_dma;
-   }
-   return 0;
+   return -EINVAL;
case SG_GET_LOW_DMA:
-   return put_user((int) sfp->low_dma, ip);
+   return put_user((int) sdp->device->host->unchecked_isa_dma, ip);
case SG_GET_SCSI_ID:
if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t)))
return -EFAULT;
@@ -1821,6 +1805,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
int sg_tablesize = sfp->parentdp->sg_tablesize;
int blk_size = buff_size, order;
gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
+   struct sg_device *sdp = sfp->parentdp;
 
if (blk_size < 0)
return -EFAULT;
@@ -1846,7 +1831,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
scatter_elem_sz_prev = num;
}
 
-   if (sfp->low_dma)
+   if (sdp->device->host->unchecked_isa_dma)
gfp_mask |= GFP_DMA;
 
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -2132,8 +2117,6 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
sfp->timeout = SG_DEFAULT_TIMEOUT;
sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
sfp->force_packid = SG_DEF_FORCE_PACK_ID;
-   sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
-   sdp->device->host->unchecked_isa_dma : 1;
sfp->cmd_q = SG_DEF_COMMAND_Q;
sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
sfp->parentdp = sdp;
@@ -2603,7 +2586,7 @@ static void sg_proc_debug_helper(struct seq_file *s, 
Sg_device * sdp)
   jiffies_to_msecs(fp->timeout),
   fp->reserve.bufflen,
   (int) fp->reserve.k_use_sg,
-  (int) fp->low_dma);
+  (int) sdp->device->host->unchecked_isa_dma);
seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
   (int) fp->cmd_q, (int) fp->force_packid,
   (int) fp->keep_orphan);
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
index 3afec70..20bc71c 100644
--- a/include/scsi/sg.h
+++ b/include/scsi/sg.h
@@ -197,7 +197,6 @@
 #define SG_DEFAULT_RETRIES 0
 
 /* Defaults, commented if they differ from original sg driver */
-#define SG_DEF_FORCE_LOW_DMA 0  /* was 1 -> memory below 16MB on i386 */
 #define SG_DEF_FORCE_PACK_ID 0
 #define SG_DEF_KEEP_ORPHAN 0
 #define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */
-- 
1.8.5.6



[PATCH 3/4] sg: check for valid direction before starting the request

2017-02-03 Thread Hannes Reinecke
From: Johannes Thumshirn 

Check for a valid direction before starting the request, otherwise we risk
running into an assertion in the scsi midlayer checking for vaild requests.

Signed-off-by: Johannes Thumshirn 
Link: http://www.spinics.net/lists/linux-scsi/msg104400.html
Reported-by: Dmitry Vyukov 
Reviewed-by: Hannes Reinecke 
---
 drivers/scsi/sg.c | 19 +++
 1 file changed, 19 insertions(+)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index c29962c..3599551 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -752,6 +752,20 @@ static int sg_allow_access(struct file *filp, unsigned 
char *cmd)
return count;
 }
 
+static bool sg_is_valid_direction(int dxfer_direction)
+{
+   switch (dxfer_direction) {
+   case SG_DXFER_NONE:
+   case SG_DXFER_TO_DEV:
+   case SG_DXFER_FROM_DEV:
+   case SG_DXFER_TO_FROM_DEV:
+   case SG_DXFER_UNKNOWN:
+   return true;
+   default:
+   return false;
+   }
+}
+
 static int
 sg_common_write(Sg_fd * sfp, Sg_request * srp,
unsigned char *cmnd, int timeout, int blocking)
@@ -772,6 +786,11 @@ static int sg_allow_access(struct file *filp, unsigned 
char *cmd)
"sg_common_write:  scsi opcode=0x%02x, cmd_size=%d\n",
(int) cmnd[0], (int) hp->cmd_len));
 
+   if (!sg_is_valid_direction(hp->dxfer_direction))
+   return -EINVAL;
+   if (hp->dxferp == NULL && hp->dxfer_len > 0)
+   return -EINVAL;
+
k = sg_start_req(srp, cmnd);
if (k) {
SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
-- 
1.8.5.6



[PATCH 2/4] sg: protect access to to 'reserved' page array

2017-02-03 Thread Hannes Reinecke
The 'reserved' page array is used as a short-cut for mapping
data, saving us to allocate pages per request.
However, the 'reserved' array is only capable of holding one
request, so we need to protect it against concurrent accesses.

Cc: sta...@vger.kernel.org
Reported-by: Dmitry Vyukov 
Link: http://www.spinics.net/lists/linux-scsi/msg104326.html
Signed-off-by: Hannes Reinecke 
Tested-by: Johannes Thumshirn 
---
 drivers/scsi/sg.c | 30 --
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 8a959b2..c29962c 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -154,6 +154,8 @@
unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() 
*/
char mmap_called;   /* 0 -> mmap() never called on this fd */
+   unsigned long flags;
+#define SG_RESERVED_IN_USE 1
struct kref f_ref;
struct execute_work ew;
 } Sg_fd;
@@ -197,7 +199,6 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
 static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
 static Sg_request *sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
-static int sg_res_in_use(Sg_fd * sfp);
 static Sg_device *sg_get_dev(int dev);
 static void sg_device_destroy(struct kref *kref);
 
@@ -720,7 +721,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
sg_remove_request(sfp, srp);
return -EINVAL; /* either MMAP_IO or DIRECT_IO (not 
both) */
}
-   if (sg_res_in_use(sfp)) {
+   if (test_bit(SG_RESERVED_IN_USE, &sfp->flags)) {
sg_remove_request(sfp, srp);
return -EBUSY;  /* reserve buffer already being used */
}
@@ -952,10 +953,14 @@ static int max_sectors_bytes(struct request_queue *q)
val = min_t(int, val,
max_sectors_bytes(sdp->device->request_queue));
if (val != sfp->reserve.bufflen) {
-   if (sg_res_in_use(sfp) || sfp->mmap_called)
+   if (sfp->mmap_called)
+   return -EBUSY;
+   if (test_and_set_bit(SG_RESERVED_IN_USE, &sfp->flags))
return -EBUSY;
+
sg_remove_scat(sfp, &sfp->reserve);
sg_build_reserve(sfp, val);
+   clear_bit(SG_RESERVED_IN_USE, &sfp->flags);
}
return 0;
case SG_GET_RESERVED_SIZE:
@@ -1709,7 +1714,9 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
md = &map_data;
 
if (md) {
-   if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen)
+   if (dxfer_len <= rsv_schp->bufflen &&
+   test_and_set_bit(SG_RESERVED_IN_USE,
+&sfp->flags) == 0)
sg_link_reserve(sfp, srp, dxfer_len);
else {
res = sg_build_indirect(req_schp, sfp, dxfer_len);
@@ -2003,6 +2010,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
req_schp->sglist_len = 0;
sfp->save_scat_len = 0;
srp->res_used = 0;
+   clear_bit(SG_RESERVED_IN_USE, &sfp->flags);
 }
 
 static Sg_request *
@@ -2187,20 +2195,6 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
schedule_work(&sfp->ew.work);
 }
 
-static int
-sg_res_in_use(Sg_fd * sfp)
-{
-   const Sg_request *srp;
-   unsigned long iflags;
-
-   read_lock_irqsave(&sfp->rq_list_lock, iflags);
-   for (srp = sfp->headrp; srp; srp = srp->nextrp)
-   if (srp->res_used)
-   break;
-   read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-   return srp ? 1 : 0;
-}
-
 #ifdef CONFIG_SCSI_PROC_FS
 static int
 sg_idr_max_id(int id, void *p, void *data)
-- 
1.8.5.6



Re: [PATCH V4 08/24] aacraid: Added support for response path

2017-02-03 Thread Johannes Thumshirn


On 02/03/2017 12:53 AM, Raghava Aditya Renukunta wrote:

This patch enables the driver to actually process the I/O, or srb replies
from adapter. In addition to any HBA1000 or SmartIOC2000 adapter events.

Signed-off-by: Raghava Aditya Renukunta 
Signed-off-by: Dave Carroll 
---


Reviewed-by: Johannes Thumshirn 


Re: [PATCH V4 10/24] aacraid: Reworked aac_command_thread

2017-02-03 Thread Johannes Thumshirn


On 02/03/2017 12:53 AM, Raghava Aditya Renukunta wrote:

Reworked aac_command_thread into aac_process_events

Signed-off-by: Raghava Aditya Renukunta 
Signed-off-by: Dave Carroll 
---


Reviewed-by: Johannes Thumshirn 


Re: [PATCH V4 11/24] aacraid: Added support for periodic wellness sync

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 12:53 AM, Raghava Aditya Renukunta wrote:

This patch adds a new functions that periodically sync the time of host
to the adapter. In addition also informs the adapter that the driver is
alive and kicking. Only applicable to the HBA1000 and SMARTIOC2000.

Signed-off-by: Raghava Aditya Renukunta 
Signed-off-by: Dave Carroll 
---


Reviewed-by: Johannes Thumshirn 


Re: [PATCH V4 12/24] aacraid: Retrieve Queue Depth from Adapter FW

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 12:53 AM, Raghava Aditya Renukunta wrote:

Retrieved queue depth from fw and saved it for future use.
Only applicable for HBA1000 drives.

Signed-off-by: Raghava Aditya Renukunta 
Signed-off-by: Dave Carroll 
---


Reviewed-by: Johannes Thumshirn 


Re: [PATCH V4 13/24] aacraid: Added support to set QD of attached drives

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 12:53 AM, Raghava Aditya Renukunta wrote:

Added support to set qd of drives in slave_configure.This only works for
HBA1000 attached drives.

Signed-off-by: Raghava Aditya Renukunta 
Signed-off-by: Dave Carroll 
---


Reviewed-by: Johannes Thumshirn 


Re: [PATCH V4 14/24] aacraid: Added support for hotplug

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 12:53 AM, Raghava Aditya Renukunta wrote:

Added support for drive hotplug add and removal

Signed-off-by: Raghava Aditya Renukunta 
Signed-off-by: Dave Carroll 
---


Reviewed-by: Johannes Thumshirn 


Re: [PATCH v5 02/11] phy: exynos-ufs: add UFS PHY driver for EXYNOS SoC

2017-02-03 Thread Alim Akhtar

Hi Kishon,

On 11/19/2015 07:09 PM, Kishon Vijay Abraham I wrote:

Hi,

On Tuesday 17 November 2015 01:41 PM, Alim Akhtar wrote:

Hi
Thanks again for looking into this.

On 11/17/2015 11:46 AM, Kishon Vijay Abraham I wrote:

Hi,

On Monday 09 November 2015 10:56 AM, Alim Akhtar wrote:

From: Seungwon Jeon 

This patch introduces Exynos UFS PHY driver. This driver
supports to deal with phy calibration and power control
according to UFS host driver's behavior.

Signed-off-by: Seungwon Jeon 
Signed-off-by: Alim Akhtar 
Cc: Kishon Vijay Abraham I 
---
  drivers/phy/Kconfig|7 ++
  drivers/phy/Makefile   |1 +
  drivers/phy/phy-exynos-ufs.c   |  241

  drivers/phy/phy-exynos-ufs.h   |   85 +
  drivers/phy/phy-exynos7-ufs.h  |   89 +
  include/linux/phy/phy-exynos-ufs.h |   85 +
  6 files changed, 508 insertions(+)
  create mode 100644 drivers/phy/phy-exynos-ufs.c
  create mode 100644 drivers/phy/phy-exynos-ufs.h
  create mode 100644 drivers/phy/phy-exynos7-ufs.h
  create mode 100644 include/linux/phy/phy-exynos-ufs.h

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 7eb5859dd035..7d38a92e0297 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -389,4 +389,11 @@ config PHY_CYGNUS_PCIE
Enable this to support the Broadcom Cygnus PCIe PHY.
If unsure, say N.

+config PHY_EXYNOS_UFS
+tristate "EXYNOS SoC series UFS PHY driver"
+depends on OF && ARCH_EXYNOS || COMPILE_TEST
+select GENERIC_PHY
+help
+  Support for UFS PHY on Samsung EXYNOS chipsets.
+
  endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 075db1a81aa5..9bec4d1a89e1 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY)+=
phy-armada375-usb2.o
  obj-$(CONFIG_BCM_KONA_USB2_PHY)+= phy-bcm-kona-usb2.o
  obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)+= phy-exynos-dp-video.o
  obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)+= phy-exynos-mipi-video.o
+obj-$(CONFIG_PHY_EXYNOS_UFS)+= phy-exynos-ufs.o
  obj-$(CONFIG_PHY_LPC18XX_USB_OTG)+= phy-lpc18xx-usb-otg.o
  obj-$(CONFIG_PHY_PXA_28NM_USB2)+= phy-pxa-28nm-usb2.o
  obj-$(CONFIG_PHY_PXA_28NM_HSIC)+= phy-pxa-28nm-hsic.o
diff --git a/drivers/phy/phy-exynos-ufs.c b/drivers/phy/phy-exynos-ufs.c
new file mode 100644
index ..cb1aeaa3d4eb
--- /dev/null
+++ b/drivers/phy/phy-exynos-ufs.c
@@ -0,0 +1,241 @@
+/*
+ * UFS PHY driver for Samsung EXYNOS SoC
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ * Author: Seungwon Jeon 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "phy-exynos-ufs.h"
+
+#define for_each_phy_lane(phy, i) \
+for (i = 0; i < (phy)->lane_cnt; i++)
+#define for_each_phy_cfg(cfg) \
+for (; (cfg)->id; (cfg)++)
+
+#define PHY_DEF_LANE_CNT1
+
+static void exynos_ufs_phy_config(struct exynos_ufs_phy *phy,
+const struct exynos_ufs_phy_cfg *cfg, u8 lane)
+{
+enum {LANE_0, LANE_1}; /* lane index */
+
+switch (lane) {
+case LANE_0:
+writel(cfg->val, (phy)->reg_pma + cfg->off_0);
+break;
+case LANE_1:
+if (cfg->id == PHY_TRSV_BLK)
+writel(cfg->val, (phy)->reg_pma + cfg->off_1);
+break;
+}
+}
+
+static bool match_cfg_to_pwr_mode(u8 desc, u8 required_pwr)
+{
+if (IS_PWR_MODE_ANY(desc))
+return true;
+
+if (IS_PWR_MODE_HS(required_pwr) && IS_PWR_MODE_HS_ANY(desc))
+return true;
+
+if (COMP_PWR_MODE(required_pwr, desc))
+return true;
+
+if (COMP_PWR_MODE_MD(required_pwr, desc) &&
+COMP_PWR_MODE_GEAR(required_pwr, desc) &&
+COMP_PWR_MODE_SER(required_pwr, desc))
+return true;
+
+return false;
+}
+
+int exynos_ufs_phy_calibrate(struct phy *phy,
+enum phy_cfg_tag tag, u8 pwr)


This is similar to the first version of your patch without EXPORT_SYMBOL.

I think you have to create a new generic PHY_OPS for calibrate PHY while making
sure that it is as generic as possible (which means calibrate_phy shouldn't
have tag and pwr arguments or a strong justification as to why those arguments
are required in a generic API).

I don't see the advantage to making this a generic phy_ops, this is exynos
specific ufs-phy, please have a look at other implementations


only the implementation is specific to exynos. I've seen lot of other vendors
want to do something like calibrate phy.

So if we add something like (*calibrate)(struct phy *phy), then it can be used
by others as well. Russell King also want to minimize t

Re: [PATCH V4 16/24] aacraid: Add task management functionality

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 12:53 AM, Raghava Aditya Renukunta wrote:

Added support to send out task management commands.

Signed-off-by: Raghava Aditya Renukunta 
Signed-off-by: Dave Carroll 
---

[...]

Zapped C++ comment

[...]

+static int aac_adapter_hba(struct fib *fib, struct scsi_cmnd *cmd)
+{
+   struct aac_hba_cmd_req *hbacmd = aac_construct_hbacmd(fib, cmd);
+   struct aac_dev *dev;
+   // u16 fibsize;


Here you missed one ;-)
Anyways,
Reviewed-by: Johannes Thumshirn 



Re: [PATCH V4 18/24] aacraid: VPD 83 type3 support

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 12:53 AM, Raghava Aditya Renukunta wrote:

This patch adds support to retrieve the unique identifier data (VPD page
83 type3) for Logical drives created on SmartIOC 2000 products. In
addition  added a sysfs device structure to expose the id information.

Signed-off-by: Raghava Aditya Renukunta 
Signed-off-by: Dave Carroll 
---

Reviewed-by: Johannes Thumshirn 


Re: [PATCH V4 19/24] aacraid: Added new IWBR reset

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 12:53 AM, Raghava Aditya Renukunta wrote:

Added a new IWBR soft reset type, reworked the IOP reset interface for
a bit.

Signed-off-by: Raghava Aditya Renukunta 
Signed-off-by: Dave Carroll 
---



Reviewed-by: Johannes Thumshirn 


Re: [PATCH 1/4] sg: disable SET_FORCE_LOW_DMA

2017-02-03 Thread Johannes Thumshirn


On 02/03/2017 09:54 AM, Hannes Reinecke wrote:

The ioctl SET_FORCE_LOW_DMA has never worked since the initial
git check-in, and the respective setting is nowadays handled
correctly.
So disable it entirely.

Signed-off-by: Hannes Reinecke 
---


[...]


case SG_SET_FORCE_LOW_DMA:
-   result = get_user(val, ip);
-   if (result)
-   return result;
-   if (val) {
-   sfp->low_dma = 1;
-   if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
-   val = (int) sfp->reserve.bufflen;
-   sg_remove_scat(sfp, &sfp->reserve);
-   sg_build_reserve(sfp, val);
-   }
-   } else {
-   if (atomic_read(&sdp->detaching))
-   return -ENODEV;
-   sfp->low_dma = sdp->device->host->unchecked_isa_dma;
-   }
-   return 0;
+   return -EINVAL;


I'm not sure if returning a bogus '0' is better here to not break any 
existing application, which assumed it always worked.





Re: [PATCH 2/4] sg: protect access to to 'reserved' page array

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 09:54 AM, Hannes Reinecke wrote:

The 'reserved' page array is used as a short-cut for mapping
data, saving us to allocate pages per request.
However, the 'reserved' array is only capable of holding one
request, so we need to protect it against concurrent accesses.

Cc: sta...@vger.kernel.org
Reported-by: Dmitry Vyukov 
Link: http://www.spinics.net/lists/linux-scsi/msg104326.html
Signed-off-by: Hannes Reinecke 
Tested-by: Johannes Thumshirn 
---


Reviewed-by: Johannes Thumshirn 

--
Johannes Thumshirn  Storage
jthumsh...@suse.de+49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850


Re: [PATCH 4/4] sg: use standard lists for sg_requests

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 09:54 AM, Hannes Reinecke wrote:

'Sg_request' is using a private list implementation; convert it
to standard lists.

Signed-off-by: Hannes Reinecke 
---

Looks good,
Reviewed-by: Johannes Thumshirn 

--
Johannes Thumshirn  Storage
jthumsh...@suse.de+49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850



Re: [PATCH 1/4] sg: disable SET_FORCE_LOW_DMA

2017-02-03 Thread Hannes Reinecke
On 02/03/2017 10:32 AM, Johannes Thumshirn wrote:
> 
> On 02/03/2017 09:54 AM, Hannes Reinecke wrote:
>> The ioctl SET_FORCE_LOW_DMA has never worked since the initial
>> git check-in, and the respective setting is nowadays handled
>> correctly.
>> So disable it entirely.
>>
>> Signed-off-by: Hannes Reinecke 
>> ---
> 
> [...]
> 
>>   case SG_SET_FORCE_LOW_DMA:
>> -result = get_user(val, ip);
>> -if (result)
>> -return result;
>> -if (val) {
>> -sfp->low_dma = 1;
>> -if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
>> -val = (int) sfp->reserve.bufflen;
>> -sg_remove_scat(sfp, &sfp->reserve);
>> -sg_build_reserve(sfp, val);
>> -}
>> -} else {
>> -if (atomic_read(&sdp->detaching))
>> -return -ENODEV;
>> -sfp->low_dma = sdp->device->host->unchecked_isa_dma;
>> -}
>> -return 0;
>> +return -EINVAL;
> 
> I'm not sure if returning a bogus '0' is better here to not break any
> existing application, which assumed it always worked.
> 
Well, the ioctl already was returning error numbers, so any calling
application had to protect against that.
And I don't really see the point to protect against failures in legacy
applications relying on a functionality which never did anything.

Cheers,

Hannes
-- 
Dr. Hannes ReineckezSeries & Storage
h...@suse.com  +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)


Re: [PATCH 1/4] sg: disable SET_FORCE_LOW_DMA

2017-02-03 Thread Christoph Hellwig
On Fri, Feb 03, 2017 at 10:32:28AM +0100, Johannes Thumshirn wrote:
> I'm not sure if returning a bogus '0' is better here to not break any 
> existing application, which assumed it always worked.

Agreed, this should return 0, and maybe also print a (ratelimited)
warning.


Re: [PATCH 2/4] sg: protect access to to 'reserved' page array

2017-02-03 Thread Christoph Hellwig
On Fri, Feb 03, 2017 at 09:54:49AM +0100, Hannes Reinecke wrote:
> The 'reserved' page array is used as a short-cut for mapping
> data, saving us to allocate pages per request.
> However, the 'reserved' array is only capable of holding one
> request, so we need to protect it against concurrent accesses.

Can you please explain how you protect the access here a bit more,
as mentioned before the set_bit for exclusion trick is always
suspicious, so the changelog needs to have a justification for it.


Re: [PATCH 3/4] sg: check for valid direction before starting the request

2017-02-03 Thread Christoph Hellwig
On Fri, Feb 03, 2017 at 09:54:50AM +0100, Hannes Reinecke wrote:
> From: Johannes Thumshirn 
> 
> Check for a valid direction before starting the request, otherwise we risk
> running into an assertion in the scsi midlayer checking for vaild requests.

Good idea, but..

> +static bool sg_is_valid_direction(int dxfer_direction)
> +{
> + switch (dxfer_direction) {
> + case SG_DXFER_NONE:
> + case SG_DXFER_TO_DEV:
> + case SG_DXFER_FROM_DEV:
> + case SG_DXFER_TO_FROM_DEV:

This isn't strictly valid as sg doesn't actually handle real bidi
commands, but we work around it.

It might be a good idea to move the warning about it from sg_write
to here and use printk_ratelimited instead of the hand-rolled
per-thread warning there.

> + case SG_DXFER_UNKNOWN:
> + return true;

And how valid is this one (Question to Doug I guess): for a 0-sized
transfer we should be fine, but otherwise it should probably be
rejected.


Re: [PATCH 4/4] sg: use standard lists for sg_requests

2017-02-03 Thread Christoph Hellwig
>  typedef struct sg_request {  /* SG_MAX_QUEUE requests outstanding per file */
> - struct sg_request *nextrp;  /* NULL -> tail request (slist) */
> + struct list_head nextrp;/* list entry */

s/nextrp/entry/

> @@ -2078,16 +2076,13 @@ static long sg_compat_ioctl(struct file *filp, 
> unsigned int cmd_in, unsigned lon
>   if (k < SG_MAX_QUEUE) {
>   memset(rp, 0, sizeof (Sg_request));
>   rp->parentfp = sfp;
> + list_add(&rp->nextrp, &sfp->rq_list);

The old code did a tail insertation.  And this whole function should
become a lot simpler with proper lists anyway:

static Sg_request *
sg_add_request(Sg_fd * sfp)
{
int k;
unsigned long iflags;
Sg_request *rp = sfp->req_arr;

write_lock_irqsave(&sfp->rq_list_lock, iflags);
if (!list_empty(&sfp->rq_list)) {
if (!sfp->cmd_q)
goto out_unlock;

for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
if (!rp->parentfp)
break;
}
if (k >= SG_MAX_QUEUE)
goto out_unlock;
}

memset(rp, 0, sizeof (Sg_request));
rp->parentfp = sfp;
rp->header.duration = jiffies_to_msecs(jiffies);
list_add_tail(&rp->nextrp, &sfp->rq_list);
write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
return rp;

out_unlock:
write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
return NULL;

> + if ((!sfp) || (!srp) || (list_empty(&sfp->rq_list)))

No need for all these braces.

> + if (!list_empty(&srp->nextrp)) {
> + list_del_init(&srp->nextrp);

I don't think we need the _init as we never check for an empty entry.

>  {
>   struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
>   struct sg_device *sdp = sfp->parentdp;
> + Sg_request *srp, *tmp;
>  
>   /* Cleanup any responses which were never read(). */
> - while (sfp->headrp)
> - sg_finish_rem_req(sfp->headrp);
> + list_for_each_entry_safe(srp, tmp, &sfp->rq_list, nextrp)
> + sg_finish_rem_req(srp);

What protects us from concurrent removals here?

Either way I'd rather keep the whіle not emptry style even with
proper lists.


Re: [PATCH 2/4] sg: protect access to to 'reserved' page array

2017-02-03 Thread Hannes Reinecke
On 02/03/2017 11:24 AM, Christoph Hellwig wrote:
> On Fri, Feb 03, 2017 at 09:54:49AM +0100, Hannes Reinecke wrote:
>> The 'reserved' page array is used as a short-cut for mapping
>> data, saving us to allocate pages per request.
>> However, the 'reserved' array is only capable of holding one
>> request, so we need to protect it against concurrent accesses.
> 
> Can you please explain how you protect the access here a bit more,
> as mentioned before the set_bit for exclusion trick is always
> suspicious, so the changelog needs to have a justification for it.
> 
The 'reserved' array provides for a fast/reliable mechanism for mapping
data of a request. However, it only has enough room to hold one request
at a time.
Plus we can change the size of the buffer during runtime via an ioctl.
So we need to mark the array as 'in use' atomically, and keep that
marker as long as the request using it is active.
While I surely can introduce a variable 'in_use' and protect accesses to
it via mutex or somesuch, I found this to be a bit pointless given that
it's actually just one bit which needs to be checked.
Which is what I did.

But okay, I'll update the description.

Cheers,

Hannes
-- 
Dr. Hannes ReineckeTeamlead Storage & Networking
h...@suse.de   +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)


Re: [PATCH 4/4] sg: use standard lists for sg_requests

2017-02-03 Thread Hannes Reinecke
On 02/03/2017 11:43 AM, Christoph Hellwig wrote:
>>  typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
>> -struct sg_request *nextrp;  /* NULL -> tail request (slist) */
>> +struct list_head nextrp;/* list entry */
> 
> s/nextrp/entry/
> 
>> @@ -2078,16 +2076,13 @@ static long sg_compat_ioctl(struct file *filp, 
>> unsigned int cmd_in, unsigned lon
>>  if (k < SG_MAX_QUEUE) {
>>  memset(rp, 0, sizeof (Sg_request));
>>  rp->parentfp = sfp;
>> +list_add(&rp->nextrp, &sfp->rq_list);
> 
> The old code did a tail insertation.  And this whole function should
> become a lot simpler with proper lists anyway:
> 
Yeah, thought about that, too, but then I just went for the sloppy
approach to minimize changes.

> static Sg_request *
> sg_add_request(Sg_fd * sfp)
> {
>   int k;
>   unsigned long iflags;
>   Sg_request *rp = sfp->req_arr;
> 
>   write_lock_irqsave(&sfp->rq_list_lock, iflags);
>   if (!list_empty(&sfp->rq_list)) {
>   if (!sfp->cmd_q)
>   goto out_unlock;
> 
>   for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
>   if (!rp->parentfp)
>   break;
>   }
>   if (k >= SG_MAX_QUEUE)
>   goto out_unlock;
>   }
> 
>   memset(rp, 0, sizeof (Sg_request));
>   rp->parentfp = sfp;
>   rp->header.duration = jiffies_to_msecs(jiffies);
>   list_add_tail(&rp->nextrp, &sfp->rq_list);
>   write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
>   return rp;
> 
> out_unlock:
>   write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
>   return NULL;
> 
Okay, will be updating the patch.

>> +if ((!sfp) || (!srp) || (list_empty(&sfp->rq_list)))
> 
> No need for all these braces.
> 
Okay.

>> +if (!list_empty(&srp->nextrp)) {
>> +list_del_init(&srp->nextrp);
> 
> I don't think we need the _init as we never check for an empty entry.
> 
Yes.

>>  {
>>  struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
>>  struct sg_device *sdp = sfp->parentdp;
>> +Sg_request *srp, *tmp;
>>  
>>  /* Cleanup any responses which were never read(). */
>> -while (sfp->headrp)
>> -sg_finish_rem_req(sfp->headrp);
>> +list_for_each_entry_safe(srp, tmp, &sfp->rq_list, nextrp)
>> +sg_finish_rem_req(srp);
> 
> What protects us from concurrent removals here?
> 
Nothing.
But this patch is intended to just replace the hand-rolled list
implementation, not fixing bugs here.
The problem is that 'sg_finish_rem_req()' is taking the rq_list_lock,
so it needs a bit of rework to make that work properly.
But I'll give it a go.

> Either way I'd rather keep the whіle not empty style even with
> proper lists.
> 
Okay.

Cheers,

Hannes
-- 
Dr. Hannes ReineckeTeamlead Storage & Networking
h...@suse.de   +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)


Re: [PATCH 3/4] sg: check for valid direction before starting the request

2017-02-03 Thread Hannes Reinecke
On 02/03/2017 11:28 AM, Christoph Hellwig wrote:
> On Fri, Feb 03, 2017 at 09:54:50AM +0100, Hannes Reinecke wrote:
>> From: Johannes Thumshirn 
>>
>> Check for a valid direction before starting the request, otherwise we risk
>> running into an assertion in the scsi midlayer checking for vaild requests.
> 
> Good idea, but..
> 
>> +static bool sg_is_valid_direction(int dxfer_direction)
>> +{
>> +switch (dxfer_direction) {
>> +case SG_DXFER_NONE:
>> +case SG_DXFER_TO_DEV:
>> +case SG_DXFER_FROM_DEV:
>> +case SG_DXFER_TO_FROM_DEV:
> 
> This isn't strictly valid as sg doesn't actually handle real bidi
> commands, but we work around it.
> 
> It might be a good idea to move the warning about it from sg_write
> to here and use printk_ratelimited instead of the hand-rolled
> per-thread warning there.
> 
>> +case SG_DXFER_UNKNOWN:
>> +return true;
> 
> And how valid is this one (Question to Doug I guess): for a 0-sized
> transfer we should be fine, but otherwise it should probably be
> rejected.
> 
yes, we should be checking for dxferp and dxfer_len here, too.

Cheers,

Hannes
-- 
Dr. Hannes ReineckeTeamlead Storage & Networking
h...@suse.de   +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)


Re: [PATCH 3/4] sg: check for valid direction before starting the request

2017-02-03 Thread Hannes Reinecke
On 02/03/2017 11:28 AM, Christoph Hellwig wrote:
> On Fri, Feb 03, 2017 at 09:54:50AM +0100, Hannes Reinecke wrote:
>> From: Johannes Thumshirn 
>>
>> Check for a valid direction before starting the request, otherwise we risk
>> running into an assertion in the scsi midlayer checking for vaild requests.
> 
> Good idea, but..
> 
>> +static bool sg_is_valid_direction(int dxfer_direction)
>> +{
>> +switch (dxfer_direction) {
>> +case SG_DXFER_NONE:
>> +case SG_DXFER_TO_DEV:
>> +case SG_DXFER_FROM_DEV:
>> +case SG_DXFER_TO_FROM_DEV:
> 
> This isn't strictly valid as sg doesn't actually handle real bidi
> commands, but we work around it.
> 
> It might be a good idea to move the warning about it from sg_write
> to here and use printk_ratelimited instead of the hand-rolled
> per-thread warning there.
> 
Well, that warning is only applicable to sg_write(); sg_new_write() is
supposed to have the correct header, so that warning doesn't apply.
We could drop the per-thread-thingie, though.


>> +case SG_DXFER_UNKNOWN:
>> +return true;
> 
> And how valid is this one (Question to Doug I guess): for a 0-sized
> transfer we should be fine, but otherwise it should probably be
> rejected.
> 
Yes, true.
Will be fixing it up.

Cheers,

Hannes
-- 
Dr. Hannes ReineckeTeamlead Storage & Networking
h...@suse.de   +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)


[PATCHv2 6/6] sg: close race condition in sg_remove_sfp_usercontext()

2017-02-03 Thread Hannes Reinecke
sg_remove_sfp_usercontext() is clearing any sg requests,
but needs to take 'rq_list_lock' when modifying the list.

Reported-by: Christoph Hellwig 
Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/sg.c | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 4b7e140..2b9d3325b 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -524,6 +524,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
} else
count = (old_hdr->result == 0) ? 0 : -EIO;
sg_finish_rem_req(srp);
+   sg_remove_request(sfp, srp);
retval = count;
 free_old_hdr:
kfree(old_hdr);
@@ -564,6 +565,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
}
 err_out:
err2 = sg_finish_rem_req(srp);
+   sg_remove_request(sfp, srp);
return err ? : err2 ? : count;
 }
 
@@ -803,6 +805,7 @@ static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
"sg_common_write: start_req err=%d\n", k));
sg_finish_rem_req(srp);
+   sg_remove_request(sfp, srp);
return k;   /* probably out of space --> ENOMEM */
}
if (atomic_read(&sdp->detaching)) {
@@ -815,6 +818,7 @@ static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
}
 
sg_finish_rem_req(srp);
+   sg_remove_request(sfp, srp);
return -ENODEV;
}
 
@@ -1291,6 +1295,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
struct sg_fd *sfp = srp->parentfp;
 
sg_finish_rem_req(srp);
+   sg_remove_request(sfp, srp);
kref_put(&sfp->f_ref, sg_remove_sfp);
 }
 
@@ -1825,8 +1830,6 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
else
sg_remove_scat(sfp, req_schp);
 
-   sg_remove_request(sfp, srp);
-
return ret;
 }
 
@@ -2171,12 +2174,17 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
struct sg_device *sdp = sfp->parentdp;
Sg_request *srp;
+   unsigned long iflags;
 
/* Cleanup any responses which were never read(). */
+   write_lock_irqsave(&sfp->rq_list_lock, iflags);
while (!list_empty(&sfp->rq_list)) {
srp = list_first_entry(&sfp->rq_list, Sg_request, entry);
sg_finish_rem_req(srp);
+   list_del(&srp->entry);
+   srp->parentfp = NULL;
}
+   write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
 
if (sfp->reserve.bufflen > 0) {
SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp,
-- 
1.8.5.6



[PATCHv2 4/6] sg: check for valid direction before starting the request

2017-02-03 Thread Hannes Reinecke
From: Johannes Thumshirn 

Check for a valid direction before starting the request, otherwise we risk
running into an assertion in the scsi midlayer checking for vaild requests.

Signed-off-by: Johannes Thumshirn 
Link: http://www.spinics.net/lists/linux-scsi/msg104400.html
Reported-by: Dmitry Vyukov 
Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/sg.c | 46 ++
 1 file changed, 34 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 89ca76c..3045370 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -663,18 +663,14 @@ static int sg_allow_access(struct file *filp, unsigned 
char *cmd)
 * is a non-zero input_size, so emit a warning.
 */
if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
-   static char cmd[TASK_COMM_LEN];
-   if (strcmp(current->comm, cmd)) {
-   printk_ratelimited(KERN_WARNING
-  "sg_write: data in/out %d/%d bytes "
-  "for SCSI command 0x%x-- guessing "
-  "data in;\n   program %s not setting 
"
-  "count and/or reply_len properly\n",
-  old_hdr.reply_len - 
(int)SZ_SG_HEADER,
-  input_size, (unsigned int) cmnd[0],
-  current->comm);
-   strcpy(cmd, current->comm);
-   }
+   printk_ratelimited(KERN_WARNING
+  "sg_write: data in/out %d/%d bytes "
+  "for SCSI command 0x%x-- guessing "
+  "data in;\n   program %s not setting "
+  "count and/or reply_len properly\n",
+  old_hdr.reply_len - (int)SZ_SG_HEADER,
+  input_size, (unsigned int) cmnd[0],
+  current->comm);
}
k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
return (k < 0) ? k : count;
@@ -756,6 +752,29 @@ static int sg_allow_access(struct file *filp, unsigned 
char *cmd)
return count;
 }
 
+static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
+{
+   switch (dxfer_direction) {
+   case SG_DXFER_NONE:
+   if (hp->dxferp || hp->dxfer_len > 0)
+   return false;
+   return true;
+   case SG_DXFER_TO_DEV:
+   case SG_DXFER_FROM_DEV:
+   case SG_DXFER_TO_FROM_DEV:
+   if (!hp->dxferp || hp->dxfer_len == 0)
+   return false;
+   return true;
+   case SG_DXFER_UNKNOWN:
+   if ((!hp->dxferp && hp->dxfer_len) ||
+   (hp->dxferp && hp->dxfer_len == 0))
+   return false;
+   return true;
+   default:
+   return false;
+   }
+}
+
 static int
 sg_common_write(Sg_fd * sfp, Sg_request * srp,
unsigned char *cmnd, int timeout, int blocking)
@@ -776,6 +795,9 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
"sg_common_write:  scsi opcode=0x%02x, cmd_size=%d\n",
(int) cmnd[0], (int) hp->cmd_len));
 
+   if (!sg_is_valid_dxfer(hp))
+   return -EINVAL;
+
k = sg_start_req(srp, cmnd);
if (k) {
SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
-- 
1.8.5.6



[PATCHv2 0/6] sanitize sg

2017-02-03 Thread Hannes Reinecke
Hi all,

the infamous syzkaller incovered some more issues in the sg driver.
This patchset fixes those two issues (and adds a fix for yet another
potential issue; checking for a NULL dxferp when dxfer_len is not 0).
It also removes handling of the SET_FORCE_LOW_DMA ioctl, which never
worked since the initial git checkin. And does some code cleanup by
removing the private list implementation, using standard lists instead.

As usual, comments and reviews are welcome.

Changes to v1:
- Include reviews from Christoph
- Add patch to close race condition in sg_remove_sfp_usercontext()
- Remove stale variable 'save_scat_len'

Hannes Reinecke (5):
  sg: disable SET_FORCE_LOW_DMA
  sg: remove 'save_scat_len'
  sg: protect accesses to 'reserved' page array
  sg: use standard lists for sg_requests
  sg: close race condition in sg_remove_sfp_usercontext()

Johannes Thumshirn (1):
  sg: check for valid direction before starting the request

 drivers/scsi/sg.c | 284 +++---
 include/scsi/sg.h |   1 -
 2 files changed, 141 insertions(+), 144 deletions(-)

-- 
1.8.5.6



[PATCHv2 2/6] sg: remove 'save_scat_len'

2017-02-03 Thread Hannes Reinecke
Unused.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/sg.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 55cd641..0b1279d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -145,7 +145,6 @@
int timeout;/* defaults to SG_DEFAULT_TIMEOUT  */
int timeout_user;   /* defaults to SG_DEFAULT_TIMEOUT_USER */
Sg_scatter_hold reserve;/* buffer held for this file descriptor 
*/
-   unsigned save_scat_len; /* original length of trunc. scat. element */
Sg_request *headrp; /* head of request slist, NULL->empty */
struct fasync_struct *async_qp; /* used by asynchronous notification */
Sg_request req_arr[SG_MAX_QUEUE];   /* used as singly-linked list */
@@ -2006,7 +2005,6 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
req_schp->pages = NULL;
req_schp->page_order = 0;
req_schp->sglist_len = 0;
-   sfp->save_scat_len = 0;
srp->res_used = 0;
 }
 
-- 
1.8.5.6



[PATCHv2 5/6] sg: use standard lists for sg_requests

2017-02-03 Thread Hannes Reinecke
'Sg_request' is using a private list implementation; convert it
to standard lists.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/sg.c | 149 +++---
 1 file changed, 62 insertions(+), 87 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 3045370..4b7e140 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -122,7 +122,7 @@
 struct sg_fd;
 
 typedef struct sg_request {/* SG_MAX_QUEUE requests outstanding per file */
-   struct sg_request *nextrp;  /* NULL -> tail request (slist) */
+   struct list_head entry; /* list entry */
struct sg_fd *parentfp; /* NULL -> not in use */
Sg_scatter_hold data;   /* hold buffer, perhaps scatter list */
sg_io_hdr_t header; /* scsi command+info, see  */
@@ -146,7 +146,7 @@
int timeout;/* defaults to SG_DEFAULT_TIMEOUT  */
int timeout_user;   /* defaults to SG_DEFAULT_TIMEOUT_USER */
Sg_scatter_hold reserve;/* buffer held for this file descriptor 
*/
-   Sg_request *headrp; /* head of request slist, NULL->empty */
+   struct list_head rq_list; /* head of request list */
struct fasync_struct *async_qp; /* used by asynchronous notification */
Sg_request req_arr[SG_MAX_QUEUE];   /* used as singly-linked list */
char force_packid;  /* 1 -> pack_id input to read(), 0 -> ignored */
@@ -754,7 +754,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
 
 static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
 {
-   switch (dxfer_direction) {
+   switch (hp->dxfer_direction) {
case SG_DXFER_NONE:
if (hp->dxferp || hp->dxfer_len > 0)
return false;
@@ -954,7 +954,7 @@ static int max_sectors_bytes(struct request_queue *q)
if (!access_ok(VERIFY_WRITE, ip, sizeof (int)))
return -EFAULT;
read_lock_irqsave(&sfp->rq_list_lock, iflags);
-   for (srp = sfp->headrp; srp; srp = srp->nextrp) {
+   list_for_each_entry(srp, &sfp->rq_list, entry) {
if ((1 == srp->done) && (!srp->sg_io_owned)) {
read_unlock_irqrestore(&sfp->rq_list_lock,
   iflags);
@@ -967,7 +967,8 @@ static int max_sectors_bytes(struct request_queue *q)
return 0;
case SG_GET_NUM_WAITING:
read_lock_irqsave(&sfp->rq_list_lock, iflags);
-   for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) {
+   val = 0;
+   list_for_each_entry(srp, &sfp->rq_list, entry) {
if ((1 == srp->done) && (!srp->sg_io_owned))
++val;
}
@@ -1042,35 +1043,33 @@ static int max_sectors_bytes(struct request_queue *q)
if (!rinfo)
return -ENOMEM;
read_lock_irqsave(&sfp->rq_list_lock, iflags);
-   for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
-++val, srp = srp ? srp->nextrp : srp) {
+   val = 0;
+   list_for_each_entry(srp, &sfp->rq_list, entry) {
+   if (val > SG_MAX_QUEUE)
+   break;
memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
-   if (srp) {
-   rinfo[val].req_state = srp->done + 1;
-   rinfo[val].problem =
-   srp->header.masked_status & 
-   srp->header.host_status & 
-   srp->header.driver_status;
-   if (srp->done)
-   rinfo[val].duration =
-   srp->header.duration;
-   else {
-   ms = jiffies_to_msecs(jiffies);
-   rinfo[val].duration =
-   (ms > srp->header.duration) 
?
-   (ms - srp->header.duration) 
: 0;
-   }
-   rinfo[val].orphan = srp->orphan;
-   rinfo[val].sg_io_owned =
-   srp->sg_io_owned;
-   rinfo[val].pack_id =
-   srp->header.pack_id;
-   rinfo[val].usr_ptr =
-   srp->header.usr_ptr;

[PATCHv2 3/6] sg: protect accesses to 'reserved' page array

2017-02-03 Thread Hannes Reinecke
The 'reserved' page array is used as a short-cut for mapping
data, saving us to allocate pages per request.
However, the 'reserved' array is only capable of holding one
request, so this patch introduces a mutex for protect
'sg_fd' against concurrent accesses.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/sg.c | 47 +++
 1 file changed, 27 insertions(+), 20 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 0b1279d..89ca76c 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -142,6 +142,7 @@
struct sg_device *parentdp; /* owning device */
wait_queue_head_t read_wait;/* queue read until command done */
rwlock_t rq_list_lock;  /* protect access to list in req_arr */
+   struct mutex f_mutex;   /* protect against changes in this fd */
int timeout;/* defaults to SG_DEFAULT_TIMEOUT  */
int timeout_user;   /* defaults to SG_DEFAULT_TIMEOUT_USER */
Sg_scatter_hold reserve;/* buffer held for this file descriptor 
*/
@@ -153,6 +154,7 @@
unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() 
*/
char mmap_called;   /* 0 -> mmap() never called on this fd */
+   char res_in_use;/* 1 -> 'reserve' array in use */
struct kref f_ref;
struct execute_work ew;
 } Sg_fd;
@@ -196,7 +198,6 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
 static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
 static Sg_request *sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
-static int sg_res_in_use(Sg_fd * sfp);
 static Sg_device *sg_get_dev(int dev);
 static void sg_device_destroy(struct kref *kref);
 
@@ -612,6 +613,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
}
buf += SZ_SG_HEADER;
__get_user(opcode, buf);
+   mutex_lock(&sfp->f_mutex);
if (sfp->next_cmd_len > 0) {
cmd_size = sfp->next_cmd_len;
sfp->next_cmd_len = 0;  /* reset so only this write() effected 
*/
@@ -620,6 +622,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
if ((opcode >= 0xc0) && old_hdr.twelve_byte)
cmd_size = 12;
}
+   mutex_unlock(&sfp->f_mutex);
SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
"sg_write:   scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, 
cmd_size));
 /* Determine buffer size.  */
@@ -719,10 +722,13 @@ static int sg_allow_access(struct file *filp, unsigned 
char *cmd)
sg_remove_request(sfp, srp);
return -EINVAL; /* either MMAP_IO or DIRECT_IO (not 
both) */
}
-   if (sg_res_in_use(sfp)) {
+   mutex_lock(&sfp->f_mutex);
+   if (sfp->res_in_use) {
+   mutex_unlock(&sfp->f_mutex);
sg_remove_request(sfp, srp);
return -EBUSY;  /* reserve buffer already being used */
}
+   mutex_unlock(&sfp->f_mutex);
}
ul_timeout = msecs_to_jiffies(srp->header.timeout);
timeout = (ul_timeout < INT_MAX) ? ul_timeout : INT_MAX;
@@ -955,12 +961,18 @@ static int max_sectors_bytes(struct request_queue *q)
 return -EINVAL;
val = min_t(int, val,
max_sectors_bytes(sdp->device->request_queue));
+   mutex_lock(&sfp->f_mutex);
if (val != sfp->reserve.bufflen) {
-   if (sg_res_in_use(sfp) || sfp->mmap_called)
+   if (sfp->mmap_called ||
+   sfp->res_in_use) {
+   mutex_unlock(&sfp->f_mutex);
return -EBUSY;
+   }
+
sg_remove_scat(sfp, &sfp->reserve);
sg_build_reserve(sfp, val);
}
+   mutex_unlock(&sfp->f_mutex);
return 0;
case SG_GET_RESERVED_SIZE:
val = min_t(int, sfp->reserve.bufflen,
@@ -986,7 +998,9 @@ static int max_sectors_bytes(struct request_queue *q)
result = get_user(val, ip);
if (result)
return result;
+   mutex_lock(&sfp->f_mutex);
sfp->next_cmd_len = (val > 0) ? val : 0;
+   mutex_unlock(&sfp->f_mutex);
return 0;
case SG_GET_VERSION_NUM:
return put_user(sg_version_num, ip);
@@ -1713,13 +1727,19 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
md = &map_data;
 
if (md) {
-   if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen)
+   mutex_lo

[PATCHv2 1/6] sg: disable SET_FORCE_LOW_DMA

2017-02-03 Thread Hannes Reinecke
The ioctl SET_FORCE_LOW_DMA has never worked since the initial
git check-in, and the respective setting is nowadays handled
correctly.
So disable it entirely.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/sg.c | 30 +-
 include/scsi/sg.h |  1 -
 2 files changed, 9 insertions(+), 22 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index dbe5b4b..55cd641 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -149,7 +149,6 @@
Sg_request *headrp; /* head of request slist, NULL->empty */
struct fasync_struct *async_qp; /* used by asynchronous notification */
Sg_request req_arr[SG_MAX_QUEUE];   /* used as singly-linked list */
-   char low_dma;   /* as in parent but possibly overridden to 1 */
char force_packid;  /* 1 -> pack_id input to read(), 0 -> ignored */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
@@ -887,24 +886,14 @@ static int max_sectors_bytes(struct request_queue *q)
/* strange ..., for backward compatibility */
return sfp->timeout_user;
case SG_SET_FORCE_LOW_DMA:
-   result = get_user(val, ip);
-   if (result)
-   return result;
-   if (val) {
-   sfp->low_dma = 1;
-   if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
-   val = (int) sfp->reserve.bufflen;
-   sg_remove_scat(sfp, &sfp->reserve);
-   sg_build_reserve(sfp, val);
-   }
-   } else {
-   if (atomic_read(&sdp->detaching))
-   return -ENODEV;
-   sfp->low_dma = sdp->device->host->unchecked_isa_dma;
-   }
+   /*
+* N.B. This ioctl never worked properly, but failed to
+* return an error value. So returning '0' to keep compability
+* with legacy applications.
+*/
return 0;
case SG_GET_LOW_DMA:
-   return put_user((int) sfp->low_dma, ip);
+   return put_user((int) sdp->device->host->unchecked_isa_dma, ip);
case SG_GET_SCSI_ID:
if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t)))
return -EFAULT;
@@ -1821,6 +1810,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
int sg_tablesize = sfp->parentdp->sg_tablesize;
int blk_size = buff_size, order;
gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
+   struct sg_device *sdp = sfp->parentdp;
 
if (blk_size < 0)
return -EFAULT;
@@ -1846,7 +1836,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
scatter_elem_sz_prev = num;
}
 
-   if (sfp->low_dma)
+   if (sdp->device->host->unchecked_isa_dma)
gfp_mask |= GFP_DMA;
 
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -2132,8 +2122,6 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
sfp->timeout = SG_DEFAULT_TIMEOUT;
sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
sfp->force_packid = SG_DEF_FORCE_PACK_ID;
-   sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
-   sdp->device->host->unchecked_isa_dma : 1;
sfp->cmd_q = SG_DEF_COMMAND_Q;
sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
sfp->parentdp = sdp;
@@ -2603,7 +2591,7 @@ static void sg_proc_debug_helper(struct seq_file *s, 
Sg_device * sdp)
   jiffies_to_msecs(fp->timeout),
   fp->reserve.bufflen,
   (int) fp->reserve.k_use_sg,
-  (int) fp->low_dma);
+  (int) sdp->device->host->unchecked_isa_dma);
seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
   (int) fp->cmd_q, (int) fp->force_packid,
   (int) fp->keep_orphan);
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
index 3afec70..20bc71c 100644
--- a/include/scsi/sg.h
+++ b/include/scsi/sg.h
@@ -197,7 +197,6 @@
 #define SG_DEFAULT_RETRIES 0
 
 /* Defaults, commented if they differ from original sg driver */
-#define SG_DEF_FORCE_LOW_DMA 0  /* was 1 -> memory below 16MB on i386 */
 #define SG_DEF_FORCE_PACK_ID 0
 #define SG_DEF_KEEP_ORPHAN 0
 #define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */
-- 
1.8.5.6



Re: [PATCHv2 1/6] sg: disable SET_FORCE_LOW_DMA

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 01:18 PM, Hannes Reinecke wrote:

The ioctl SET_FORCE_LOW_DMA has never worked since the initial
git check-in, and the respective setting is nowadays handled
correctly.
So disable it entirely.

Signed-off-by: Hannes Reinecke 
---


Reviewed-by: Johannes Thumshirn 


Re: [PATCHv2 2/6] sg: remove 'save_scat_len'

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 01:18 PM, Hannes Reinecke wrote:

Unused.

Signed-off-by: Hannes Reinecke 
---



Reviewed-by: Johannes Thumshirn 


Re: [PATCHv2 3/6] sg: protect accesses to 'reserved' page array

2017-02-03 Thread Johannes Thumshirn


On 02/03/2017 01:18 PM, Hannes Reinecke wrote:

The 'reserved' page array is used as a short-cut for mapping
data, saving us to allocate pages per request.
However, the 'reserved' array is only capable of holding one
request, so this patch introduces a mutex for protect
'sg_fd' against concurrent accesses.

Signed-off-by: Hannes Reinecke 
---


Tested-by: Johannes Thumshirn 
Reviewed-by: Johannes Thumshirn 


Re: [PATCHv2 4/6] sg: check for valid direction before starting the request

2017-02-03 Thread Johannes Thumshirn


On 02/03/2017 01:18 PM, Hannes Reinecke wrote:

From: Johannes Thumshirn 

Check for a valid direction before starting the request, otherwise we risk
running into an assertion in the scsi midlayer checking for vaild requests.

Signed-off-by: Johannes Thumshirn 
Link: http://www.spinics.net/lists/linux-scsi/msg104400.html
Reported-by: Dmitry Vyukov 
Signed-off-by: Hannes Reinecke 
---

[...]

  
+static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)

+{
+   switch (dxfer_direction) {


This wont build now... needs a +hp




Re: [PATCHv2 5/6] sg: use standard lists for sg_requests

2017-02-03 Thread Johannes Thumshirn


On 02/03/2017 01:18 PM, Hannes Reinecke wrote:

'Sg_request' is using a private list implementation; convert it
to standard lists.

Signed-off-by: Hannes Reinecke 
---

[..]

  
  static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)

  {
-   switch (dxfer_direction) {
+   switch (hp->dxfer_direction) {


And here it is



Re: [PATCHv2 0/6] sanitize sg

2017-02-03 Thread Johannes Thumshirn

On 02/03/2017 01:18 PM, Hannes Reinecke wrote:

Hi all,

the infamous syzkaller incovered some more issues in the sg driver.
This patchset fixes those two issues (and adds a fix for yet another
potential issue; checking for a NULL dxferp when dxfer_len is not 0).
It also removes handling of the SET_FORCE_LOW_DMA ioctl, which never
worked since the initial git checkin. And does some code cleanup by
removing the private list implementation, using standard lists instead.

As usual, comments and reviews are welcome.

Changes to v1:
- Include reviews from Christoph
- Add patch to close race condition in sg_remove_sfp_usercontext()
- Remove stale variable 'save_scat_len'

Hannes Reinecke (5):
   sg: disable SET_FORCE_LOW_DMA
   sg: remove 'save_scat_len'
   sg: protect accesses to 'reserved' page array
   sg: use standard lists for sg_requests
   sg: close race condition in sg_remove_sfp_usercontext()

Johannes Thumshirn (1):
   sg: check for valid direction before starting the request

  drivers/scsi/sg.c | 284 +++---
  include/scsi/sg.h |   1 -
  2 files changed, 141 insertions(+), 144 deletions(-)



For the whole series
Tested-by: Johannes Thumshirn 

(sg_inq not broken, sg_turs not broken, syzcaller bug on fixed  and 
syzcaller use-after-free fixed, no additional messages in dmesg with a 
KASAN and LOCKDEP enabled kernel)



--
Johannes Thumshirn  Storage
jthumsh...@suse.de+49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850



[PATCHv3 2/6] sg: remove 'save_scat_len'

2017-02-03 Thread Hannes Reinecke
Unused.

Signed-off-by: Hannes Reinecke 
Reviewed-by: Johannes Thumshirn 
Tested-by: Johannes Thumshirn 
---
 drivers/scsi/sg.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 55cd641..0b1279d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -145,7 +145,6 @@
int timeout;/* defaults to SG_DEFAULT_TIMEOUT  */
int timeout_user;   /* defaults to SG_DEFAULT_TIMEOUT_USER */
Sg_scatter_hold reserve;/* buffer held for this file descriptor 
*/
-   unsigned save_scat_len; /* original length of trunc. scat. element */
Sg_request *headrp; /* head of request slist, NULL->empty */
struct fasync_struct *async_qp; /* used by asynchronous notification */
Sg_request req_arr[SG_MAX_QUEUE];   /* used as singly-linked list */
@@ -2006,7 +2005,6 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
req_schp->pages = NULL;
req_schp->page_order = 0;
req_schp->sglist_len = 0;
-   sfp->save_scat_len = 0;
srp->res_used = 0;
 }
 
-- 
1.8.5.6



[PATCHv3 4/6] sg: check for valid direction before starting the request

2017-02-03 Thread Hannes Reinecke
From: Johannes Thumshirn 

Check for a valid direction before starting the request, otherwise we risk
running into an assertion in the scsi midlayer checking for vaild requests.

Signed-off-by: Johannes Thumshirn 
Link: http://www.spinics.net/lists/linux-scsi/msg104400.html
Reported-by: Dmitry Vyukov 
Signed-off-by: Hannes Reinecke 
Tested-by: Johannes Thumshirn 
---
 drivers/scsi/sg.c | 46 ++
 1 file changed, 34 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 89ca76c..3045370 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -663,18 +663,14 @@ static int sg_allow_access(struct file *filp, unsigned 
char *cmd)
 * is a non-zero input_size, so emit a warning.
 */
if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
-   static char cmd[TASK_COMM_LEN];
-   if (strcmp(current->comm, cmd)) {
-   printk_ratelimited(KERN_WARNING
-  "sg_write: data in/out %d/%d bytes "
-  "for SCSI command 0x%x-- guessing "
-  "data in;\n   program %s not setting 
"
-  "count and/or reply_len properly\n",
-  old_hdr.reply_len - 
(int)SZ_SG_HEADER,
-  input_size, (unsigned int) cmnd[0],
-  current->comm);
-   strcpy(cmd, current->comm);
-   }
+   printk_ratelimited(KERN_WARNING
+  "sg_write: data in/out %d/%d bytes "
+  "for SCSI command 0x%x-- guessing "
+  "data in;\n   program %s not setting "
+  "count and/or reply_len properly\n",
+  old_hdr.reply_len - (int)SZ_SG_HEADER,
+  input_size, (unsigned int) cmnd[0],
+  current->comm);
}
k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
return (k < 0) ? k : count;
@@ -756,6 +752,29 @@ static int sg_allow_access(struct file *filp, unsigned 
char *cmd)
return count;
 }
 
+static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
+{
+   switch (dxfer_direction) {
+   case SG_DXFER_NONE:
+   if (hp->dxferp || hp->dxfer_len > 0)
+   return false;
+   return true;
+   case SG_DXFER_TO_DEV:
+   case SG_DXFER_FROM_DEV:
+   case SG_DXFER_TO_FROM_DEV:
+   if (!hp->dxferp || hp->dxfer_len == 0)
+   return false;
+   return true;
+   case SG_DXFER_UNKNOWN:
+   if ((!hp->dxferp && hp->dxfer_len) ||
+   (hp->dxferp && hp->dxfer_len == 0))
+   return false;
+   return true;
+   default:
+   return false;
+   }
+}
+
 static int
 sg_common_write(Sg_fd * sfp, Sg_request * srp,
unsigned char *cmnd, int timeout, int blocking)
@@ -776,6 +795,9 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
"sg_common_write:  scsi opcode=0x%02x, cmd_size=%d\n",
(int) cmnd[0], (int) hp->cmd_len));
 
+   if (!sg_is_valid_dxfer(hp))
+   return -EINVAL;
+
k = sg_start_req(srp, cmnd);
if (k) {
SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
-- 
1.8.5.6



[PATCHv3 6/6] sg: close race condition in sg_remove_sfp_usercontext()

2017-02-03 Thread Hannes Reinecke
sg_remove_sfp_usercontext() is clearing any sg requests,
but needs to take 'rq_list_lock' when modifying the list.

Reported-by: Christoph Hellwig 
Signed-off-by: Hannes Reinecke 
Reviewed-by: Johannes Thumshirn 
Tested-by: Johannes Thumshirn 
---
 drivers/scsi/sg.c | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 4b7e140..2b9d3325b 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -524,6 +524,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
} else
count = (old_hdr->result == 0) ? 0 : -EIO;
sg_finish_rem_req(srp);
+   sg_remove_request(sfp, srp);
retval = count;
 free_old_hdr:
kfree(old_hdr);
@@ -564,6 +565,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
}
 err_out:
err2 = sg_finish_rem_req(srp);
+   sg_remove_request(sfp, srp);
return err ? : err2 ? : count;
 }
 
@@ -803,6 +805,7 @@ static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp,
"sg_common_write: start_req err=%d\n", k));
sg_finish_rem_req(srp);
+   sg_remove_request(sfp, srp);
return k;   /* probably out of space --> ENOMEM */
}
if (atomic_read(&sdp->detaching)) {
@@ -815,6 +818,7 @@ static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
}
 
sg_finish_rem_req(srp);
+   sg_remove_request(sfp, srp);
return -ENODEV;
}
 
@@ -1291,6 +1295,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
struct sg_fd *sfp = srp->parentfp;
 
sg_finish_rem_req(srp);
+   sg_remove_request(sfp, srp);
kref_put(&sfp->f_ref, sg_remove_sfp);
 }
 
@@ -1825,8 +1830,6 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
else
sg_remove_scat(sfp, req_schp);
 
-   sg_remove_request(sfp, srp);
-
return ret;
 }
 
@@ -2171,12 +2174,17 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
struct sg_device *sdp = sfp->parentdp;
Sg_request *srp;
+   unsigned long iflags;
 
/* Cleanup any responses which were never read(). */
+   write_lock_irqsave(&sfp->rq_list_lock, iflags);
while (!list_empty(&sfp->rq_list)) {
srp = list_first_entry(&sfp->rq_list, Sg_request, entry);
sg_finish_rem_req(srp);
+   list_del(&srp->entry);
+   srp->parentfp = NULL;
}
+   write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
 
if (sfp->reserve.bufflen > 0) {
SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp,
-- 
1.8.5.6



[PATCHv3 0/6] sanitize sg

2017-02-03 Thread Hannes Reinecke
Hi all,

the infamous syzkaller incovered some more issues in the sg driver.
This patchset fixes those two issues (and adds a fix for yet another
potential issue; checking for a NULL dxferp when dxfer_len is not 0).
It also removes handling of the SET_FORCE_LOW_DMA ioctl, which never
worked since the initial git checkin. And does some code cleanup by
removing the private list implementation, using standard lists instead.

As usual, comments and reviews are welcome.

Changes to v1:
- Include reviews from Christoph
- Add patch to close race condition in sg_remove_sfp_usercontext()
- Remove stale variable 'save_scat_len'

Changes to v2:
- Move misplaced hunk
- Add Reviewed-by: and Tested-by: tags

Hannes Reinecke (5):
  sg: disable SET_FORCE_LOW_DMA
  sg: remove 'save_scat_len'
  sg: protect accesses to 'reserved' page array
  sg: use standard lists for sg_requests
  sg: close race condition in sg_remove_sfp_usercontext()

Johannes Thumshirn (1):
  sg: check for valid direction before starting the request

 drivers/scsi/sg.c | 284 +++---
 include/scsi/sg.h |   1 -
 2 files changed, 141 insertions(+), 144 deletions(-)

-- 
1.8.5.6



[PATCHv3 1/6] sg: disable SET_FORCE_LOW_DMA

2017-02-03 Thread Hannes Reinecke
The ioctl SET_FORCE_LOW_DMA has never worked since the initial
git check-in, and the respective setting is nowadays handled
correctly.
So disable it entirely.

Signed-off-by: Hannes Reinecke 
Reviewed-by: Johannes Thumshirn 
Tested-by: Johannes Thumshirn 
---
 drivers/scsi/sg.c | 30 +-
 include/scsi/sg.h |  1 -
 2 files changed, 9 insertions(+), 22 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index dbe5b4b..55cd641 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -149,7 +149,6 @@
Sg_request *headrp; /* head of request slist, NULL->empty */
struct fasync_struct *async_qp; /* used by asynchronous notification */
Sg_request req_arr[SG_MAX_QUEUE];   /* used as singly-linked list */
-   char low_dma;   /* as in parent but possibly overridden to 1 */
char force_packid;  /* 1 -> pack_id input to read(), 0 -> ignored */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
@@ -887,24 +886,14 @@ static int max_sectors_bytes(struct request_queue *q)
/* strange ..., for backward compatibility */
return sfp->timeout_user;
case SG_SET_FORCE_LOW_DMA:
-   result = get_user(val, ip);
-   if (result)
-   return result;
-   if (val) {
-   sfp->low_dma = 1;
-   if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
-   val = (int) sfp->reserve.bufflen;
-   sg_remove_scat(sfp, &sfp->reserve);
-   sg_build_reserve(sfp, val);
-   }
-   } else {
-   if (atomic_read(&sdp->detaching))
-   return -ENODEV;
-   sfp->low_dma = sdp->device->host->unchecked_isa_dma;
-   }
+   /*
+* N.B. This ioctl never worked properly, but failed to
+* return an error value. So returning '0' to keep compability
+* with legacy applications.
+*/
return 0;
case SG_GET_LOW_DMA:
-   return put_user((int) sfp->low_dma, ip);
+   return put_user((int) sdp->device->host->unchecked_isa_dma, ip);
case SG_GET_SCSI_ID:
if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t)))
return -EFAULT;
@@ -1821,6 +1810,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
int sg_tablesize = sfp->parentdp->sg_tablesize;
int blk_size = buff_size, order;
gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;
+   struct sg_device *sdp = sfp->parentdp;
 
if (blk_size < 0)
return -EFAULT;
@@ -1846,7 +1836,7 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
scatter_elem_sz_prev = num;
}
 
-   if (sfp->low_dma)
+   if (sdp->device->host->unchecked_isa_dma)
gfp_mask |= GFP_DMA;
 
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -2132,8 +2122,6 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
sfp->timeout = SG_DEFAULT_TIMEOUT;
sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
sfp->force_packid = SG_DEF_FORCE_PACK_ID;
-   sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
-   sdp->device->host->unchecked_isa_dma : 1;
sfp->cmd_q = SG_DEF_COMMAND_Q;
sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
sfp->parentdp = sdp;
@@ -2603,7 +2591,7 @@ static void sg_proc_debug_helper(struct seq_file *s, 
Sg_device * sdp)
   jiffies_to_msecs(fp->timeout),
   fp->reserve.bufflen,
   (int) fp->reserve.k_use_sg,
-  (int) fp->low_dma);
+  (int) sdp->device->host->unchecked_isa_dma);
seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
   (int) fp->cmd_q, (int) fp->force_packid,
   (int) fp->keep_orphan);
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
index 3afec70..20bc71c 100644
--- a/include/scsi/sg.h
+++ b/include/scsi/sg.h
@@ -197,7 +197,6 @@
 #define SG_DEFAULT_RETRIES 0
 
 /* Defaults, commented if they differ from original sg driver */
-#define SG_DEF_FORCE_LOW_DMA 0  /* was 1 -> memory below 16MB on i386 */
 #define SG_DEF_FORCE_PACK_ID 0
 #define SG_DEF_KEEP_ORPHAN 0
 #define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */
-- 
1.8.5.6



[PATCHv3 3/6] sg: protect accesses to 'reserved' page array

2017-02-03 Thread Hannes Reinecke
The 'reserved' page array is used as a short-cut for mapping
data, saving us to allocate pages per request.
However, the 'reserved' array is only capable of holding one
request, so this patch introduces a mutex for protect
'sg_fd' against concurrent accesses.

Signed-off-by: Hannes Reinecke 
Reviewed-by: Johannes Thumshirn 
Tested-by: Johannes Thumshirn 
---
 drivers/scsi/sg.c | 47 +++
 1 file changed, 27 insertions(+), 20 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 0b1279d..89ca76c 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -142,6 +142,7 @@
struct sg_device *parentdp; /* owning device */
wait_queue_head_t read_wait;/* queue read until command done */
rwlock_t rq_list_lock;  /* protect access to list in req_arr */
+   struct mutex f_mutex;   /* protect against changes in this fd */
int timeout;/* defaults to SG_DEFAULT_TIMEOUT  */
int timeout_user;   /* defaults to SG_DEFAULT_TIMEOUT_USER */
Sg_scatter_hold reserve;/* buffer held for this file descriptor 
*/
@@ -153,6 +154,7 @@
unsigned char next_cmd_len; /* 0: automatic, >0: use on next write() */
char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() 
*/
char mmap_called;   /* 0 -> mmap() never called on this fd */
+   char res_in_use;/* 1 -> 'reserve' array in use */
struct kref f_ref;
struct execute_work ew;
 } Sg_fd;
@@ -196,7 +198,6 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
 static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
 static Sg_request *sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
-static int sg_res_in_use(Sg_fd * sfp);
 static Sg_device *sg_get_dev(int dev);
 static void sg_device_destroy(struct kref *kref);
 
@@ -612,6 +613,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
}
buf += SZ_SG_HEADER;
__get_user(opcode, buf);
+   mutex_lock(&sfp->f_mutex);
if (sfp->next_cmd_len > 0) {
cmd_size = sfp->next_cmd_len;
sfp->next_cmd_len = 0;  /* reset so only this write() effected 
*/
@@ -620,6 +622,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
if ((opcode >= 0xc0) && old_hdr.twelve_byte)
cmd_size = 12;
}
+   mutex_unlock(&sfp->f_mutex);
SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp,
"sg_write:   scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, 
cmd_size));
 /* Determine buffer size.  */
@@ -719,10 +722,13 @@ static int sg_allow_access(struct file *filp, unsigned 
char *cmd)
sg_remove_request(sfp, srp);
return -EINVAL; /* either MMAP_IO or DIRECT_IO (not 
both) */
}
-   if (sg_res_in_use(sfp)) {
+   mutex_lock(&sfp->f_mutex);
+   if (sfp->res_in_use) {
+   mutex_unlock(&sfp->f_mutex);
sg_remove_request(sfp, srp);
return -EBUSY;  /* reserve buffer already being used */
}
+   mutex_unlock(&sfp->f_mutex);
}
ul_timeout = msecs_to_jiffies(srp->header.timeout);
timeout = (ul_timeout < INT_MAX) ? ul_timeout : INT_MAX;
@@ -955,12 +961,18 @@ static int max_sectors_bytes(struct request_queue *q)
 return -EINVAL;
val = min_t(int, val,
max_sectors_bytes(sdp->device->request_queue));
+   mutex_lock(&sfp->f_mutex);
if (val != sfp->reserve.bufflen) {
-   if (sg_res_in_use(sfp) || sfp->mmap_called)
+   if (sfp->mmap_called ||
+   sfp->res_in_use) {
+   mutex_unlock(&sfp->f_mutex);
return -EBUSY;
+   }
+
sg_remove_scat(sfp, &sfp->reserve);
sg_build_reserve(sfp, val);
}
+   mutex_unlock(&sfp->f_mutex);
return 0;
case SG_GET_RESERVED_SIZE:
val = min_t(int, sfp->reserve.bufflen,
@@ -986,7 +998,9 @@ static int max_sectors_bytes(struct request_queue *q)
result = get_user(val, ip);
if (result)
return result;
+   mutex_lock(&sfp->f_mutex);
sfp->next_cmd_len = (val > 0) ? val : 0;
+   mutex_unlock(&sfp->f_mutex);
return 0;
case SG_GET_VERSION_NUM:
return put_user(sg_version_num, ip);
@@ -1713,13 +1727,19 @@ static long sg_compat_ioctl(struct file *filp, unsigned 
int cmd_in, unsigned lon
md = &map_data;
 
if (md) {
-   if (!sg_res_in_use(

[PATCHv3 5/6] sg: use standard lists for sg_requests

2017-02-03 Thread Hannes Reinecke
'Sg_request' is using a private list implementation; convert it
to standard lists.

Signed-off-by: Hannes Reinecke 
Reviewed-by: Johannes Thumshirn 
Tested-by: Johannes Thumshirn 
---
 drivers/scsi/sg.c | 149 +++---
 1 file changed, 62 insertions(+), 87 deletions(-)

diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 3045370..4b7e140 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -122,7 +122,7 @@
 struct sg_fd;
 
 typedef struct sg_request {/* SG_MAX_QUEUE requests outstanding per file */
-   struct sg_request *nextrp;  /* NULL -> tail request (slist) */
+   struct list_head entry; /* list entry */
struct sg_fd *parentfp; /* NULL -> not in use */
Sg_scatter_hold data;   /* hold buffer, perhaps scatter list */
sg_io_hdr_t header; /* scsi command+info, see  */
@@ -146,7 +146,7 @@
int timeout;/* defaults to SG_DEFAULT_TIMEOUT  */
int timeout_user;   /* defaults to SG_DEFAULT_TIMEOUT_USER */
Sg_scatter_hold reserve;/* buffer held for this file descriptor 
*/
-   Sg_request *headrp; /* head of request slist, NULL->empty */
+   struct list_head rq_list; /* head of request list */
struct fasync_struct *async_qp; /* used by asynchronous notification */
Sg_request req_arr[SG_MAX_QUEUE];   /* used as singly-linked list */
char force_packid;  /* 1 -> pack_id input to read(), 0 -> ignored */
@@ -754,7 +754,7 @@ static int sg_allow_access(struct file *filp, unsigned char 
*cmd)
 
 static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
 {
-   switch (dxfer_direction) {
+   switch (hp->dxfer_direction) {
case SG_DXFER_NONE:
if (hp->dxferp || hp->dxfer_len > 0)
return false;
@@ -954,7 +954,7 @@ static int max_sectors_bytes(struct request_queue *q)
if (!access_ok(VERIFY_WRITE, ip, sizeof (int)))
return -EFAULT;
read_lock_irqsave(&sfp->rq_list_lock, iflags);
-   for (srp = sfp->headrp; srp; srp = srp->nextrp) {
+   list_for_each_entry(srp, &sfp->rq_list, entry) {
if ((1 == srp->done) && (!srp->sg_io_owned)) {
read_unlock_irqrestore(&sfp->rq_list_lock,
   iflags);
@@ -967,7 +967,8 @@ static int max_sectors_bytes(struct request_queue *q)
return 0;
case SG_GET_NUM_WAITING:
read_lock_irqsave(&sfp->rq_list_lock, iflags);
-   for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) {
+   val = 0;
+   list_for_each_entry(srp, &sfp->rq_list, entry) {
if ((1 == srp->done) && (!srp->sg_io_owned))
++val;
}
@@ -1042,35 +1043,33 @@ static int max_sectors_bytes(struct request_queue *q)
if (!rinfo)
return -ENOMEM;
read_lock_irqsave(&sfp->rq_list_lock, iflags);
-   for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
-++val, srp = srp ? srp->nextrp : srp) {
+   val = 0;
+   list_for_each_entry(srp, &sfp->rq_list, entry) {
+   if (val > SG_MAX_QUEUE)
+   break;
memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
-   if (srp) {
-   rinfo[val].req_state = srp->done + 1;
-   rinfo[val].problem =
-   srp->header.masked_status & 
-   srp->header.host_status & 
-   srp->header.driver_status;
-   if (srp->done)
-   rinfo[val].duration =
-   srp->header.duration;
-   else {
-   ms = jiffies_to_msecs(jiffies);
-   rinfo[val].duration =
-   (ms > srp->header.duration) 
?
-   (ms - srp->header.duration) 
: 0;
-   }
-   rinfo[val].orphan = srp->orphan;
-   rinfo[val].sg_io_owned =
-   srp->sg_io_owned;
-   rinfo[val].pack_id =
-   srp->header.pack_id;
-   rinfo[val].usr_ptr =
-   

Re: [PATCHv3 1/6] sg: disable SET_FORCE_LOW_DMA

2017-02-03 Thread Christoph Hellwig
Looks fine:

Reviewed-by: Christoph Hellwig 


Re: [PATCHv3 2/6] sg: remove 'save_scat_len'

2017-02-03 Thread Christoph Hellwig
Looks fine,

Reviewed-by: Christoph Hellwig 


Re: [PATCHv3 3/6] sg: protect accesses to 'reserved' page array

2017-02-03 Thread Christoph Hellwig
> - if (sg_res_in_use(sfp)) {
> + mutex_lock(&sfp->f_mutex);
> + if (sfp->res_in_use) {
> + mutex_unlock(&sfp->f_mutex);
>   sg_remove_request(sfp, srp);
>   return -EBUSY;  /* reserve buffer already being used */
>   }
> + mutex_unlock(&sfp->f_mutex);

Holding a mutex over a the check of a single scalar doesn't make sense.


Re: [PATCHv3 3/6] sg: protect accesses to 'reserved' page array

2017-02-03 Thread Hannes Reinecke
On 02/03/2017 02:31 PM, Christoph Hellwig wrote:
>> -if (sg_res_in_use(sfp)) {
>> +mutex_lock(&sfp->f_mutex);
>> +if (sfp->res_in_use) {
>> +mutex_unlock(&sfp->f_mutex);
>>  sg_remove_request(sfp, srp);
>>  return -EBUSY;  /* reserve buffer already being used */
>>  }
>> +mutex_unlock(&sfp->f_mutex);
> 
> Holding a mutex over a the check of a single scalar doesn't make sense.
> 
It's adds a synchronisation point, doesn't it?

Cheers,

Hannes
-- 
Dr. Hannes ReineckeTeamlead Storage & Networking
h...@suse.de   +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)


Re: [PATCHv2 4/6] sg: check for valid direction before starting the request

2017-02-03 Thread kbuild test robot
Hi Johannes,

[auto build test ERROR on scsi/for-next]
[also build test ERROR on v4.10-rc6 next-20170203]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/Hannes-Reinecke/sanitize-sg/20170203-202314
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
config: x86_64-acpi-redef (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64 

Note: the linux-review/Hannes-Reinecke/sanitize-sg/20170203-202314 HEAD 
c442f1293c347b17429edecbc5d29d4eb39152b0 builds fine.
  It only hurts bisectibility.

All error/warnings (new ones prefixed by >>):

   drivers/scsi/sg.c: In function 'sg_is_valid_dxfer':
>> drivers/scsi/sg.c:757:10: error: 'dxfer_direction' undeclared (first use in 
>> this function)
 switch (dxfer_direction) {
 ^~~
   drivers/scsi/sg.c:757:10: note: each undeclared identifier is reported only 
once for each function it appears in
>> drivers/scsi/sg.c:776:1: warning: control reaches end of non-void function 
>> [-Wreturn-type]
}
^

vim +/dxfer_direction +757 drivers/scsi/sg.c

   751  *o_srp = srp;
   752  return count;
   753  }
   754  
   755  static bool sg_is_valid_dxfer(sg_io_hdr_t *hp)
   756  {
 > 757  switch (dxfer_direction) {
   758  case SG_DXFER_NONE:
   759  if (hp->dxferp || hp->dxfer_len > 0)
   760  return false;
   761  return true;
   762  case SG_DXFER_TO_DEV:
   763  case SG_DXFER_FROM_DEV:
   764  case SG_DXFER_TO_FROM_DEV:
   765  if (!hp->dxferp || hp->dxfer_len == 0)
   766  return false;
   767  return true;
   768  case SG_DXFER_UNKNOWN:
   769  if ((!hp->dxferp && hp->dxfer_len) ||
   770  (hp->dxferp && hp->dxfer_len == 0))
   771  return false;
   772  return true;
   773  default:
   774  return false;
   775  }
 > 776  }
   777  
   778  static int
   779  sg_common_write(Sg_fd * sfp, Sg_request * srp,

---
0-DAY kernel test infrastructureOpen Source Technology Center
https://lists.01.org/pipermail/kbuild-all   Intel Corporation


.config.gz
Description: application/gzip


Re: [REGRESSION v4.10-rc1] blkdev_issue_zeroout() returns -EREMOTEIO on the first call for SCSI device that doesn't support WRITE SAME

2017-02-03 Thread Jens Axboe
On 02/03/2017 12:55 AM, Junichi Nomura wrote:
> I found following ext4 error occurs on a certain storage since v4.10-rc1:
>   EXT4-fs (sdc1): Delayed block allocation failed for inode 12 at logical 
> offset 100 with max blocks 2 with error 121
>   EXT4-fs (sdc1): This should not happen!! Data will be lost
> 
> Error 121 (EREMOTEIO) was returned from blkdev_issue_zeroout().
> That came from sd driver because WRITE SAME was sent to the device
> which didn't support it.
> 
> The problem was introduced by commit e73c23ff736e ("block: add async
> variant of blkdev_issue_zeroout"). Before the commit, blkdev_issue_zeroout
> fell back to normal zero writing when WRITE SAME failed and it seems
> sd driver's heuristics depends on that behaviour.

CC Christoph and Chaitanya.

-- 
Jens Axboe



Re: [REGRESSION v4.10-rc1] blkdev_issue_zeroout() returns -EREMOTEIO on the first call for SCSI device that doesn't support WRITE SAME

2017-02-03 Thread Christoph Hellwig
On Fri, Feb 03, 2017 at 08:21:31AM -0700, Jens Axboe wrote:
> > Error 121 (EREMOTEIO) was returned from blkdev_issue_zeroout().
> > That came from sd driver because WRITE SAME was sent to the device
> > which didn't support it.
> > 
> > The problem was introduced by commit e73c23ff736e ("block: add async
> > variant of blkdev_issue_zeroout"). Before the commit, blkdev_issue_zeroout
> > fell back to normal zero writing when WRITE SAME failed and it seems
> > sd driver's heuristics depends on that behaviour.
> 
> CC Christoph and Chaitanya.

And adding Martin as the sd.c Write Same code is his.

I suspect we'll have to restore the old way this works for 4.10 as it's
too late in the cycle, but that whole idea of trying Write Same first
and just disabling it if it doesn't work is a receipe for desaster -
it kinda works for a synchronous blkdev_issue_zeroout, but if we want
to be able to submit it asynchronously it's getting too hairy to handle.

I think we should fix sd.c to only send WRITE SAME if either of the
variants are explicitly listed as supported through
REPORT SUPPORTED OPERATION CODES, or maybe through a whitelist if
there are important enough devices.


Re: [REGRESSION v4.10-rc1] blkdev_issue_zeroout() returns -EREMOTEIO on the first call for SCSI device that doesn't support WRITE SAME

2017-02-03 Thread Jens Axboe
On 02/03/2017 09:12 AM, Christoph Hellwig wrote:
> On Fri, Feb 03, 2017 at 08:21:31AM -0700, Jens Axboe wrote:
>>> Error 121 (EREMOTEIO) was returned from blkdev_issue_zeroout().
>>> That came from sd driver because WRITE SAME was sent to the device
>>> which didn't support it.
>>>
>>> The problem was introduced by commit e73c23ff736e ("block: add async
>>> variant of blkdev_issue_zeroout"). Before the commit, blkdev_issue_zeroout
>>> fell back to normal zero writing when WRITE SAME failed and it seems
>>> sd driver's heuristics depends on that behaviour.
>>
>> CC Christoph and Chaitanya.
> 
> And adding Martin as the sd.c Write Same code is his.
> 
> I suspect we'll have to restore the old way this works for 4.10 as it's
> too late in the cycle, but that whole idea of trying Write Same first
> and just disabling it if it doesn't work is a receipe for desaster -
> it kinda works for a synchronous blkdev_issue_zeroout, but if we want
> to be able to submit it asynchronously it's getting too hairy to handle.

I agree, the current approach is a hot and ugly mess.

> I think we should fix sd.c to only send WRITE SAME if either of the
> variants are explicitly listed as supported through
> REPORT SUPPORTED OPERATION CODES, or maybe through a whitelist if
> there are important enough devices.

Yep

-- 
Jens Axboe



Re: [PATCHv3 3/6] sg: protect accesses to 'reserved' page array

2017-02-03 Thread Christoph Hellwig
On Fri, Feb 03, 2017 at 02:38:35PM +0100, Hannes Reinecke wrote:
> On 02/03/2017 02:31 PM, Christoph Hellwig wrote:
> >> -  if (sg_res_in_use(sfp)) {
> >> +  mutex_lock(&sfp->f_mutex);
> >> +  if (sfp->res_in_use) {
> >> +  mutex_unlock(&sfp->f_mutex);
> >>sg_remove_request(sfp, srp);
> >>return -EBUSY;  /* reserve buffer already being used */
> >>}
> >> +  mutex_unlock(&sfp->f_mutex);
> > 
> > Holding a mutex over a the check of a single scalar doesn't make sense.
> > 
> It's adds a synchronisation point, doesn't it?

It does, but it doesn't actually protect anything..


Re: [PATCH 00/15] qla2xxx: Bug Fixes and updates for target.

2017-02-03 Thread Bart Van Assche
On Thu, 2017-02-02 at 11:42 -0800, Himanshu Madhani wrote:
> Please consider this series for inclusion in target-pending.

Hello Himanshu,

What tree have these patches been generated against? Not all patches can be
applied on top of the scsi-target-for-v4.11 branch.

Thanks,

Bart.

Re: [PATCH 1/2] qla2xxx: Fix a recently introduced memory leak

2017-02-03 Thread Bart Van Assche
On Wed, 2017-01-25 at 18:28 -0500, Martin K. Petersen wrote:
> > > > > > "Bart" == Bart Van Assche  writes:
> 
> Bart> qla2x00_probe_one() allocates IRQs before it initializes rsp_q_map
> Bart> so IRQs must be freed even if rsp_q_map allocation did not occur.
> Bart> This was detected by kmemleak.
> 
> I queued this one yesterday but was waiting for a resolution on patch
> 2...

Hello Martin,

Since there is now a resolution for patch 2: have you already decided when
to submit these patches upstream?

Thanks,

Bart.

Re: [PATCH 00/15] qla2xxx: Bug Fixes and updates for target.

2017-02-03 Thread Madhani, Himanshu
Hi Bart, 



On 2/3/17, 8:26 AM, "Bart Van Assche"  wrote:

>On Thu, 2017-02-02 at 11:42 -0800, Himanshu Madhani wrote:
>> Please consider this series for inclusion in target-pending.
>
>Hello Himanshu,
>
>What tree have these patches been generated against? Not all patches can be
>applied on top of the scsi-target-for-v4.11 branch.

These patches were rebased on 4.10-rc6+ and qla2xxx patches accepted for 4.11 
branch. I’ll rebase them on top of scsi-target-for-v4.11 brach and repost.

>
>Thanks,
>
>Bart.


Re: [PATCHv3 3/6] sg: protect accesses to 'reserved' page array

2017-02-03 Thread Johannes Thumshirn



On 02/03/2017 05:19 PM, Christoph Hellwig wrote:

On Fri, Feb 03, 2017 at 02:38:35PM +0100, Hannes Reinecke wrote:

On 02/03/2017 02:31 PM, Christoph Hellwig wrote:

-   if (sg_res_in_use(sfp)) {
+   mutex_lock(&sfp->f_mutex);
+   if (sfp->res_in_use) {
+   mutex_unlock(&sfp->f_mutex);
sg_remove_request(sfp, srp);
return -EBUSY;  /* reserve buffer already being used */
}
+   mutex_unlock(&sfp->f_mutex);

Holding a mutex over a the check of a single scalar doesn't make sense.


It's adds a synchronisation point, doesn't it?

It does, but it doesn't actually protect anything..


But all the other mutex_{un,}locks() do (for instance guarding 
sg_build_indirect()) and this one provides a synchronization point.


Sorry but I really don't get your point here.

The sole purpose is to guard the reserved list from being altered while 
blk_rq_map_* or similar functions are in progess (that's what the 
syzcaller reproducer was doing).


Byte,
Johannes


Re: [PATCHv3 3/6] sg: protect accesses to 'reserved' page array

2017-02-03 Thread James Bottomley
On Fri, 2017-02-03 at 19:06 +0100, Johannes Thumshirn wrote:
> 
> On 02/03/2017 05:19 PM, Christoph Hellwig wrote:
> > On Fri, Feb 03, 2017 at 02:38:35PM +0100, Hannes Reinecke wrote:
> > > On 02/03/2017 02:31 PM, Christoph Hellwig wrote:
> > > > > - if (sg_res_in_use(sfp)) {
> > > > > + mutex_lock(&sfp->f_mutex);
> > > > > + if (sfp->res_in_use) {
> > > > > + mutex_unlock(&sfp->f_mutex);
> > > > >   sg_remove_request(sfp, srp);
> > > > >   return -EBUSY;  /* reserve
> > > > > buffer already being used */
> > > > >   }
> > > > > + mutex_unlock(&sfp->f_mutex);
> > > > Holding a mutex over a the check of a single scalar doesn't
> > > > make sense.
> > > > 
> > > It's adds a synchronisation point, doesn't it?
> > It does, but it doesn't actually protect anything..
> 
> But all the other mutex_{un,}locks() do (for instance guarding 
> sg_build_indirect()) and this one provides a synchronization point.
> 
> Sorry but I really don't get your point here.
> 
> The sole purpose is to guard the reserved list from being altered 
> while blk_rq_map_* or similar functions are in progess (that's what 
> the syzcaller reproducer was doing).

What he means is that naturally aligned reads are always atomic, so
adding further synchronisation gains nothing (you already atomically
get either the prior or next value) and only causes an unnecessary
pipeline stall.  From a reviewer's perspective, the sequence

lock
read
unlock

is always a red flag because it means the writer may not understand how
locking works.  Usually because the writer thinks there's some other
synchronization they need that this sequence doesn't give.

James



[PATCH V3 0/2] Add QLogic FastLinQ FCoE (qedf) driver

2017-02-03 Thread Dupuis, Chad
From: "Dupuis, Chad" 

Dave, please apply the qed patch to net-next at your earliest convenience.
Martin, the qed patch needs to be applied first as the qedf patch is dependent
on the FCoE bits in the first qed driver patch.

This series introduces the hardware offload FCoE initiator driver for the
41000 Series Converged Network Adapters (579xx chip) by Cavium. The overall
driver design includes a common module ('qed') and protocol specific
dependent modules ('qedf' for FCoE).

This driver uses the kernel components of libfc and libfcoe as is and does not
make use of the open-fcoe user space components.  Therefore, no changes will 
need to be
made to any open-fcoe components.

The 'qed' common module, under drivers/net/ethernet/qlogic/qed/, is
enhanced with functionality required for FCoE support.

Changes from V2 -> V3

- Fix uninitialized variables reported by kbuild robot in qedf
- Remove superfluous comments from qedf.h
- Introduce new qedf_ctx flag to different stopping I/O for debug purposes.
- Don't take lport->disc.disc_mutex when restarting an rport.
- Remove extra whitespace in qedf_hsi.h

Changes from V1 -> V2

Changes in qed:
- Fix compiler warning when CONFIG_DCB is not set.

Fixes in qedf:
- Add qedf to scsi directory Makefile.
- Updates to convert LightL2 and I/O processing kthreads to workqueues.

Changes from RFC -> V1

- Squash qedf patches to one patch now that the initial review has taken place
- Convert qedf to use hotplug state machine
- Return via va_end to match corresponding va_start in logging functions
- Convert qedf_ctx offloaded port list to a RCU list so searches do not need
  to make use of spinlocks.  Also eliminates the need to fcport conn_id's.
- Use IS_ERR(fp) in qedf_flogi_resp() instead of checking individual FC_EX_* 
errors.
- Remove scsi_block_target when executing TMF request.
- Checkpatch fixes in the qed and qedf patches

Arun Easi (1):
  qed: Add support for hardware offloaded FCoE.

Dupuis, Chad (1):
  qedf: Add QLogic FastLinQ offload FCoE driver framework.

 MAINTAINERS   |6 +
 drivers/net/ethernet/qlogic/Kconfig   |3 +
 drivers/net/ethernet/qlogic/qed/Makefile  |1 +
 drivers/net/ethernet/qlogic/qed/qed.h |   11 +
 drivers/net/ethernet/qlogic/qed/qed_cxt.c |   98 +-
 drivers/net/ethernet/qlogic/qed/qed_cxt.h |3 +
 drivers/net/ethernet/qlogic/qed/qed_dcbx.c|   13 +-
 drivers/net/ethernet/qlogic/qed/qed_dcbx.h|5 +-
 drivers/net/ethernet/qlogic/qed/qed_dev.c |  205 +-
 drivers/net/ethernet/qlogic/qed/qed_dev_api.h |   42 +
 drivers/net/ethernet/qlogic/qed/qed_fcoe.c|  990 ++
 drivers/net/ethernet/qlogic/qed/qed_fcoe.h|   52 +
 drivers/net/ethernet/qlogic/qed/qed_hsi.h |  781 -
 drivers/net/ethernet/qlogic/qed/qed_hw.c  |3 +
 drivers/net/ethernet/qlogic/qed/qed_ll2.c |   25 +
 drivers/net/ethernet/qlogic/qed/qed_ll2.h |2 +-
 drivers/net/ethernet/qlogic/qed/qed_main.c|7 +
 drivers/net/ethernet/qlogic/qed/qed_mcp.c |3 +
 drivers/net/ethernet/qlogic/qed/qed_mcp.h |1 +
 drivers/net/ethernet/qlogic/qed/qed_reg_addr.h|8 +
 drivers/net/ethernet/qlogic/qed/qed_sp.h  |4 +
 drivers/net/ethernet/qlogic/qed/qed_sp_commands.c |3 +
 drivers/scsi/Kconfig  |1 +
 drivers/scsi/Makefile |1 +
 drivers/scsi/qedf/Kconfig |   11 +
 drivers/scsi/qedf/Makefile|5 +
 drivers/scsi/qedf/qedf.h  |  545 
 drivers/scsi/qedf/qedf_attr.c |  165 +
 drivers/scsi/qedf/qedf_dbg.c  |  195 ++
 drivers/scsi/qedf/qedf_dbg.h  |  154 +
 drivers/scsi/qedf/qedf_debugfs.c  |  460 +++
 drivers/scsi/qedf/qedf_els.c  |  981 ++
 drivers/scsi/qedf/qedf_fip.c  |  269 ++
 drivers/scsi/qedf/qedf_hsi.h  |  422 +++
 drivers/scsi/qedf/qedf_io.c   | 2282 ++
 drivers/scsi/qedf/qedf_main.c | 3336 +
 drivers/scsi/qedf/qedf_version.h  |   15 +
 include/linux/qed/common_hsi.h|   10 +-
 include/linux/qed/fcoe_common.h   |  715 +
 include/linux/qed/qed_fcoe_if.h   |  145 +
 include/linux/qed/qed_if.h|   41 +-
 41 files changed, 12000 insertions(+), 19 deletions(-)
 create mode 100644 drivers/net/ethernet/qlogic/qed/qed_fcoe.c
 create mode 100644 drivers/net/ethernet/qlogic/qed/qed_fcoe.h
 create mode 100644 drivers/scsi/qedf/Kconfig
 create mode 100644 drivers/scsi/qedf/Makefile
 create mode 100644 drivers/scsi/qedf/qedf.h
 create mode 100644 drivers/scsi/qedf/qedf_attr.c
 create mode 100644 drivers/scsi/qedf/qedf_dbg.c
 create mode 10

[PATCH V3 net-next 1/2] qed: Add support for hardware offloaded FCoE.

2017-02-03 Thread Dupuis, Chad
From: Arun Easi 

This adds the backbone required for the various HW initalizations
which are necessary for the FCoE driver (qedf) for QLogic FastLinQ
4 line of adapters - FW notification, resource initializations, etc.

Signed-off-by: Arun Easi 
Signed-off-by: Yuval Mintz 
---
 drivers/net/ethernet/qlogic/Kconfig   |   3 +
 drivers/net/ethernet/qlogic/qed/Makefile  |   1 +
 drivers/net/ethernet/qlogic/qed/qed.h |  11 +
 drivers/net/ethernet/qlogic/qed/qed_cxt.c |  98 ++-
 drivers/net/ethernet/qlogic/qed/qed_cxt.h |   3 +
 drivers/net/ethernet/qlogic/qed/qed_dcbx.c|  13 +-
 drivers/net/ethernet/qlogic/qed/qed_dcbx.h|   5 +-
 drivers/net/ethernet/qlogic/qed/qed_dev.c | 205 -
 drivers/net/ethernet/qlogic/qed/qed_dev_api.h |  42 +
 drivers/net/ethernet/qlogic/qed/qed_fcoe.c| 990 ++
 drivers/net/ethernet/qlogic/qed/qed_fcoe.h|  52 ++
 drivers/net/ethernet/qlogic/qed/qed_hsi.h | 781 -
 drivers/net/ethernet/qlogic/qed/qed_hw.c  |   3 +
 drivers/net/ethernet/qlogic/qed/qed_ll2.c |  25 +
 drivers/net/ethernet/qlogic/qed/qed_ll2.h |   2 +-
 drivers/net/ethernet/qlogic/qed/qed_main.c|   7 +
 drivers/net/ethernet/qlogic/qed/qed_mcp.c |   3 +
 drivers/net/ethernet/qlogic/qed/qed_mcp.h |   1 +
 drivers/net/ethernet/qlogic/qed/qed_reg_addr.h|   8 +
 drivers/net/ethernet/qlogic/qed/qed_sp.h  |   4 +
 drivers/net/ethernet/qlogic/qed/qed_sp_commands.c |   3 +
 include/linux/qed/common_hsi.h|  10 +-
 include/linux/qed/fcoe_common.h   | 715 
 include/linux/qed/qed_fcoe_if.h   | 145 
 include/linux/qed/qed_if.h|  41 +-
 25 files changed, 3152 insertions(+), 19 deletions(-)
 create mode 100644 drivers/net/ethernet/qlogic/qed/qed_fcoe.c
 create mode 100644 drivers/net/ethernet/qlogic/qed/qed_fcoe.h
 create mode 100644 include/linux/qed/fcoe_common.h
 create mode 100644 include/linux/qed/qed_fcoe_if.h

diff --git a/drivers/net/ethernet/qlogic/Kconfig 
b/drivers/net/ethernet/qlogic/Kconfig
index 3cfd105..737b303 100644
--- a/drivers/net/ethernet/qlogic/Kconfig
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -113,4 +113,7 @@ config QED_RDMA
 config QED_ISCSI
bool
 
+config QED_FCOE
+   bool
+
 endif # NET_VENDOR_QLOGIC
diff --git a/drivers/net/ethernet/qlogic/qed/Makefile 
b/drivers/net/ethernet/qlogic/qed/Makefile
index 729e437..e234083 100644
--- a/drivers/net/ethernet/qlogic/qed/Makefile
+++ b/drivers/net/ethernet/qlogic/qed/Makefile
@@ -7,3 +7,4 @@ qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
 qed-$(CONFIG_QED_LL2) += qed_ll2.o
 qed-$(CONFIG_QED_RDMA) += qed_roce.o
 qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o qed_ooo.o
+qed-$(CONFIG_QED_FCOE) += qed_fcoe.o
diff --git a/drivers/net/ethernet/qlogic/qed/qed.h 
b/drivers/net/ethernet/qlogic/qed/qed.h
index 1f61cf3..08f2885 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -60,6 +60,7 @@
 #define QED_WFQ_UNIT   100
 
 #define ISCSI_BDQ_ID(_port_id) (_port_id)
+#define FCOE_BDQ_ID(_port_id) ((_port_id) + 2)
 #define QED_WID_SIZE(1024)
 #define QED_PF_DEMS_SIZE(4)
 
@@ -167,6 +168,7 @@ struct qed_tunn_update_params {
  */
 enum qed_pci_personality {
QED_PCI_ETH,
+   QED_PCI_FCOE,
QED_PCI_ISCSI,
QED_PCI_ETH_ROCE,
QED_PCI_DEFAULT /* default in shmem */
@@ -204,6 +206,7 @@ enum QED_FEATURE {
QED_VF,
QED_RDMA_CNQ,
QED_VF_L2_QUE,
+   QED_FCOE_CQ,
QED_MAX_FEATURES,
 };
 
@@ -221,6 +224,7 @@ enum QED_PORT_MODE {
 
 enum qed_dev_cap {
QED_DEV_CAP_ETH,
+   QED_DEV_CAP_FCOE,
QED_DEV_CAP_ISCSI,
QED_DEV_CAP_ROCE,
 };
@@ -255,6 +259,10 @@ struct qed_hw_info {
u32 part_num[4];
 
unsigned char   hw_mac_addr[ETH_ALEN];
+   u64 node_wwn;
+   u64 port_wwn;
+
+   u16 num_fcoe_conns;
 
struct qed_igu_info *p_igu_info;
 
@@ -410,6 +418,7 @@ struct qed_hwfn {
struct qed_ooo_info *p_ooo_info;
struct qed_rdma_info*p_rdma_info;
struct qed_iscsi_info   *p_iscsi_info;
+   struct qed_fcoe_info*p_fcoe_info;
struct qed_pf_paramspf_params;
 
bool b_rdma_enabled_in_prs;
@@ -618,11 +627,13 @@ struct qed_dev {
 
u8  protocol;
 #define IS_QED_ETH_IF(cdev) ((cdev)->protocol == QED_PROTOCOL_ETH)
+#define IS_QED_FCOE_IF(cdev)((cdev)->protocol == QED_PROTOCOL_FCOE)
 
/* Callbacks to protocol driver */
union {
struct qed_common_cb_ops*common;
struct qed_eth_cb_ops   *eth;
+   struct qed_fcoe_cb_o

[PATCH] scsi, block: fix memory leak of sdpk on when gd fails to allocate

2017-02-03 Thread Colin King
From: Colin Ian King 

On an allocation failure of gd, the current exit path is via out_free_devt
which leaves sdpk still allocated and hence it gets leaked. Fix this by
correcting the order of resource free'ing with a change in the error exit
path labels.

Detected by CoverityScan, CID#1399519 ("Resource Leak")

Fixes: 0dba1314d4f81115dc ("scsi, block: fix duplicate bdi name registration 
crashes")
Signed-off-by: Colin Ian King 
---
 drivers/scsi/sd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index cb6e68d..99e1206 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -3213,10 +3213,10 @@ static int sd_probe(struct device *dev)
sd_devt = NULL;
  out_put:
put_disk(gd);
- out_free:
-   kfree(sdkp);
  out_free_devt:
kfree(sd_devt);
+ out_free:
+   kfree(sdkp);
  out:
scsi_autopm_put_device(sdp);
return error;
-- 
2.10.2



[GIT PULL] SCSI fixes for 4.10-rc6

2017-02-03 Thread James Bottomley
A single fix this time: a fix for a virtqueue removal bug which only
appears to affect S390, but which results in the queue hanging forever
thus causing the machine to fail shutdown.

The patch is available here:

git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git scsi-fixes

The short changelog is:

Eric Farman (1):
  scsi: virtio_scsi: Reject commands when virtqueue is broken

And the diffstat:

 drivers/scsi/virtio_scsi.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

With full diff below.

James

---

diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index ec91bd0..c680d76 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -534,7 +534,9 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
 {
struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc);
+   unsigned long flags;
int req_size;
+   int ret;
 
BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize);
 
@@ -562,8 +564,15 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
req_size = sizeof(cmd->req.cmd);
}
 
-   if (virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)) != 
0)
+   ret = virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd));
+   if (ret == -EIO) {
+   cmd->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
+   spin_lock_irqsave(&req_vq->vq_lock, flags);
+   virtscsi_complete_cmd(vscsi, cmd);
+   spin_unlock_irqrestore(&req_vq->vq_lock, flags);
+   } else if (ret != 0) {
return SCSI_MLQUEUE_HOST_BUSY;
+   }
return 0;
 }
 


[PATCH v2 03/14] qla2xxx: Allow vref count to timeout on vport delete.

2017-02-03 Thread Himanshu Madhani
From: Joe Carnuccio 

Signed-off-by: Joe Carnuccio 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_attr.c |  4 +---
 drivers/scsi/qla2xxx/qla_mid.c  | 12 +++-
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index f610103..435ff7f 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -2154,8 +2154,6 @@ struct device_attribute *qla2x00_host_attrs[] = {
"Timer for the VP[%d] has stopped\n", vha->vp_idx);
}
 
-   BUG_ON(atomic_read(&vha->vref_count));
-
qla2x00_free_fcports(vha);
 
mutex_lock(&ha->vport_lock);
@@ -2166,7 +2164,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
dma_free_coherent(&ha->pdev->dev, vha->gnl.size, vha->gnl.l,
vha->gnl.ldma);
 
-   if (vha->qpair->vp_idx == vha->vp_idx) {
+   if (vha->qpair && vha->qpair->vp_idx == vha->vp_idx) {
if (qla2xxx_delete_qpair(vha, vha->qpair) != QLA_SUCCESS)
ql_log(ql_log_warn, vha, 0x7087,
"Queue Pair delete failed.\n");
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index c6d6f0d..bf8e1e2 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -65,6 +65,7 @@
uint16_t vp_id;
struct qla_hw_data *ha = vha->hw;
unsigned long flags = 0;
+   unsigned int count = 10;
 
mutex_lock(&ha->vport_lock);
/*
@@ -74,13 +75,14 @@
 * ensures no active vp_list traversal while the vport is removed
 * from the queue)
 */
-   spin_lock_irqsave(&ha->vport_slock, flags);
-   while (atomic_read(&vha->vref_count)) {
-   spin_unlock_irqrestore(&ha->vport_slock, flags);
-
+   while (count-- && atomic_read(&vha->vref_count))
msleep(500);
 
-   spin_lock_irqsave(&ha->vport_slock, flags);
+   spin_lock_irqsave(&ha->vport_slock, flags);
+   if (atomic_read(&vha->vref_count)) {
+   ql_dbg(ql_dbg_vport, vha, 0xfffa,
+   "vha->vref_count=%u timeout\n", vha->vref_count.counter);
+   vha->vref_count = (atomic_t)ATOMIC_INIT(0);
}
list_del(&vha->list);
qlt_update_vp_map(vha, RESET_VP_IDX);
-- 
1.8.3.1



[PATCH v2 04/14] qla2xxx: Use IOCB interface to submit non-critical MBX.

2017-02-03 Thread Himanshu Madhani
From: Quinn Tran 

The Mailbox interface is currently over subscribed. We like
to reserve the Mailbox interface for the chip managment and
link initialization. Any non essential Mailbox command will
be routed through the IOCB interface. The IOCB interface is
able to absorb more commands.

Following commands are being routed through IOCB interface

- Get ID List (007Ch)
- Get Port DB (0064h)
- Get Link Priv Stats (006Dh)

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_def.h|   8 +-
 drivers/scsi/qla2xxx/qla_gbl.h|  10 +-
 drivers/scsi/qla2xxx/qla_init.c   |  46 +--
 drivers/scsi/qla2xxx/qla_isr.c|   2 +-
 drivers/scsi/qla2xxx/qla_mbx.c| 273 --
 drivers/scsi/qla2xxx/qla_target.c |   4 +-
 6 files changed, 279 insertions(+), 64 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index bf2ae8d3..f92977b 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -395,11 +395,15 @@ struct srb_iocb {
struct completion comp;
} abt;
struct ct_arg ctarg;
+#define MAX_IOCB_MB_REG 28
+#define SIZEOF_IOCB_MB_REG (MAX_IOCB_MB_REG * sizeof(uint16_t))
struct {
-   __le16 in_mb[28];   /* fr fw */
-   __le16 out_mb[28];  /* to fw */
+   __le16 in_mb[MAX_IOCB_MB_REG];  /* from FW */
+   __le16 out_mb[MAX_IOCB_MB_REG]; /* to FW */
void *out, *in;
dma_addr_t out_dma, in_dma;
+   struct completion comp;
+   int rc;
} mbx;
struct {
struct imm_ntfy_from_isp *ntfy;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 862d5f5..48a1190 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -194,6 +194,7 @@ void qla2x00_handle_login_done_event(struct scsi_qla_host 
*, fc_port_t *,
uint16_t *);
 int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *);
 void qla2x00_schedule_work(struct scsi_qla_host *);
+int qla24xx_async_abort_cmd(srb_t *);
 
 /*
  * Global Functions in qla_mid.c source file.
@@ -369,7 +370,7 @@ extern int qla24xx_build_scsi_crc_2_iocbs(srb_t *,
 
 extern int
 qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *,
-dma_addr_t, uint);
+dma_addr_t, uint16_t);
 
 extern int qla24xx_abort_command(srb_t *);
 extern int qla24xx_async_abort_command(srb_t *);
@@ -473,6 +474,13 @@ extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, 
uint16_t, uint16_t,
 extern int
 qla26xx_dport_diagnostics(scsi_qla_host_t *, void *, uint, uint);
 
+int qla24xx_send_mb_cmd(struct scsi_qla_host *, mbx_cmd_t *);
+int qla24xx_gpdb_wait(struct scsi_qla_host *, fc_port_t *, u8);
+int qla24xx_gidlist_wait(struct scsi_qla_host *, void *, dma_addr_t,
+uint16_t *);
+int __qla24xx_parse_gpdb(struct scsi_qla_host *, fc_port_t *,
+   struct port_database_24xx *);
+
 /*
  * Global Function Prototypes in qla_isr.c source file.
  */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index e84ab37..5aca3df 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -629,7 +629,6 @@ void qla24xx_async_gpdb_sp_done(void *s, int res)
struct srb *sp = s;
struct scsi_qla_host *vha = sp->vha;
struct qla_hw_data *ha = vha->hw;
-   uint64_t zero = 0;
struct port_database_24xx *pd;
fc_port_t *fcport = sp->fcport;
u16 *mb = sp->u.iocb_cmd.u.mbx.in_mb;
@@ -649,48 +648,7 @@ void qla24xx_async_gpdb_sp_done(void *s, int res)
 
pd = (struct port_database_24xx *)sp->u.iocb_cmd.u.mbx.in;
 
-   /* Check for logged in state. */
-   if (pd->current_login_state != PDS_PRLI_COMPLETE &&
-   pd->last_login_state != PDS_PRLI_COMPLETE) {
-   ql_dbg(ql_dbg_mbx, vha, 0x,
-   "Unable to verify login-state (%x/%x) for "
-   "loop_id %x.\n", pd->current_login_state,
-   pd->last_login_state, fcport->loop_id);
-   rval = QLA_FUNCTION_FAILED;
-   goto gpd_error_out;
-   }
-
-   if (fcport->loop_id == FC_NO_LOOP_ID ||
-   (memcmp(fcport->port_name, (uint8_t *)&zero, 8) &&
-   memcmp(fcport->port_name, pd->port_name, 8))) {
-   /* We lost the device mid way. */
-   rval = QLA_NOT_LOGGED_IN;
-   goto gpd_error_out;
-   }
-
-   /* Names are little-endian. */
-   memcpy(fcport->node_name, pd->node_name, WWN_SIZE);
-
-   /* Get port_id of device. */
-   fcport->d_id.b.domain = pd->port_id[0];
-   fcport->d_id.b.area = pd->port_id[1];
-   fcport->d_id.b.al_pa = pd->port_id[2];
-   fcport->d_id.b.rsvd_1 = 0;
-
-   /* If not targe

[PATCH v2 14/14] qla2xxx: Update driver version to 9.00.00.00-k

2017-02-03 Thread Himanshu Madhani
Signed-off-by: Himanshu Madhani 
signed-off-by: Giridhar Malavali 
---
 drivers/scsi/qla2xxx/qla_version.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_version.h 
b/drivers/scsi/qla2xxx/qla_version.h
index 3cb1964..45bc84e 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION  "8.07.00.38-k"
+#define QLA2XXX_VERSION  "9.00.00.00-k"
 
-#define QLA_DRIVER_MAJOR_VER   8
-#define QLA_DRIVER_MINOR_VER   7
+#define QLA_DRIVER_MAJOR_VER   9
+#define QLA_DRIVER_MINOR_VER   0
 #define QLA_DRIVER_PATCH_VER   0
 #define QLA_DRIVER_BETA_VER0
-- 
1.8.3.1



[PATCH v2 10/14] qla2xxx: Fix request queue corruption.

2017-02-03 Thread Himanshu Madhani
From: Quinn Tran 

When FW notify driver or driver detects low FW resource,
driver tries to send out Busy SCSI Status to tell Initiator
side to back off. During the send process, the lock was not held.

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_target.c | 12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index b61cbb8..b5fb9c55 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -5170,16 +5170,22 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
 
 static int
 qlt_chk_qfull_thresh_hold(struct scsi_qla_host *vha,
-   struct atio_from_isp *atio)
+   struct atio_from_isp *atio, uint8_t ha_locked)
 {
struct qla_hw_data *ha = vha->hw;
uint16_t status;
+   unsigned long flags;
 
if (ha->tgt.num_pend_cmds < Q_FULL_THRESH_HOLD(ha))
return 0;
 
+   if (!ha_locked)
+   spin_lock_irqsave(&ha->hardware_lock, flags);
status = temp_sam_status;
qlt_send_busy(vha, atio, status);
+   if (!ha_locked)
+   spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
return 1;
 }
 
@@ -5224,7 +5230,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 
 
if (likely(atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0)) {
-   rc = qlt_chk_qfull_thresh_hold(vha, atio);
+   rc = qlt_chk_qfull_thresh_hold(vha, atio, ha_locked);
if (rc != 0) {
tgt->atio_irq_cmd_count--;
return;
@@ -5347,7 +5353,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, 
response_t *pkt)
break;
}
 
-   rc = qlt_chk_qfull_thresh_hold(vha, atio);
+   rc = qlt_chk_qfull_thresh_hold(vha, atio, 1);
if (rc != 0) {
tgt->irq_cmd_count--;
return;
-- 
1.8.3.1



[PATCH v2 05/14] qla2xxx: Add DebugFS node to display Port Database

2017-02-03 Thread Himanshu Madhani
Signed-off-by: Himanshu Madhani 
Signed-off-by: Giridhar Malavali 
---
 drivers/scsi/qla2xxx/qla_def.h |  2 +
 drivers/scsi/qla2xxx/qla_dfs.c | 92 --
 2 files changed, 90 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index f92977b..8bc 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3278,6 +3278,8 @@ struct qlt_hw_data {
uint8_t tgt_node_name[WWN_SIZE];
 
struct dentry *dfs_tgt_sess;
+   struct dentry *dfs_tgt_port_database;
+
struct list_head q_full_list;
uint32_t num_pend_cmds;
uint32_t num_qfull_cmds_alloc;
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index b48cce6..0fb33e6 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -19,11 +19,11 @@
struct qla_hw_data *ha = vha->hw;
unsigned long flags;
struct fc_port *sess = NULL;
-   struct qla_tgt *tgt= vha->vha_tgt.qla_tgt;
+   struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
 
-   seq_printf(s, "%s\n",vha->host_str);
+   seq_printf(s, "%s\n", vha->host_str);
if (tgt) {
-   seq_printf(s, "Port ID   Port NameHandle\n");
+   seq_puts(s, "Port ID   Port NameHandle\n");
 
spin_lock_irqsave(&ha->tgt.sess_lock, flags);
list_for_each_entry(sess, &vha->vp_fcports, list)
@@ -44,7 +44,6 @@
return single_open(file, qla2x00_dfs_tgt_sess_show, vha);
 }
 
-
 static const struct file_operations dfs_tgt_sess_ops = {
.open   = qla2x00_dfs_tgt_sess_open,
.read   = seq_read,
@@ -53,6 +52,78 @@
 };
 
 static int
+qla2x00_dfs_tgt_port_database_show(struct seq_file *s, void *unused)
+{
+   scsi_qla_host_t *vha = s->private;
+   struct qla_hw_data *ha = vha->hw;
+   struct gid_list_info *gid_list;
+   dma_addr_t gid_list_dma;
+   fc_port_t fc_port;
+   char *id_iter;
+   int rc, i;
+   uint16_t entries, loop_id;
+   struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
+
+   seq_printf(s, "%s\n", vha->host_str);
+   if (tgt) {
+   gid_list = dma_alloc_coherent(&ha->pdev->dev,
+   qla2x00_gid_list_size(ha),
+   &gid_list_dma, GFP_KERNEL);
+   if (!gid_list) {
+   ql_dbg(ql_dbg_user, vha, 0x705c,
+   "DMA allocation failed for %u\n",
+qla2x00_gid_list_size(ha));
+   return 0;
+   }
+
+   rc = qla24xx_gidlist_wait(vha, gid_list, gid_list_dma,
+   &entries);
+   if (rc != QLA_SUCCESS)
+   goto out_free_id_list;
+
+   id_iter = (char *)gid_list;
+
+   seq_puts(s, "Port Name  Port ID Loop ID\n");
+
+   for (i = 0; i < entries; i++) {
+   struct gid_list_info *gid =
+   (struct gid_list_info *)id_iter;
+   loop_id = le16_to_cpu(gid->loop_id);
+   memset(&fc_port, 0, sizeof(fc_port_t));
+
+   fc_port.loop_id = loop_id;
+
+   rc = qla24xx_gpdb_wait(vha, &fc_port, 0);
+   seq_printf(s, "%8phC  %02x%02x%02x  %d\n",
+   fc_port.port_name, fc_port.d_id.b.domain,
+   fc_port.d_id.b.area, fc_port.d_id.b.al_pa,
+   fc_port.loop_id);
+   id_iter += ha->gid_list_info_size;
+   }
+out_free_id_list:
+   dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha),
+   gid_list, gid_list_dma);
+   }
+
+   return 0;
+}
+
+static int
+qla2x00_dfs_tgt_port_database_open(struct inode *inode, struct file *file)
+{
+   scsi_qla_host_t *vha = inode->i_private;
+
+   return single_open(file, qla2x00_dfs_tgt_port_database_show, vha);
+}
+
+static const struct file_operations dfs_tgt_port_database_ops = {
+   .open   = qla2x00_dfs_tgt_port_database_open,
+   .read   = seq_read,
+   .llseek = seq_lseek,
+   .release= single_release,
+};
+
+static int
 qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
 {
struct scsi_qla_host *vha = s->private;
@@ -281,6 +352,14 @@
goto out;
}
 
+   ha->tgt.dfs_tgt_port_database = debugfs_create_file("tgt_port_database",
+   S_IRUSR,  ha->dfs_dir, vha, &dfs_tgt_port_database_ops);
+   if (!ha->tgt.dfs_tgt_port_database) {
+   ql_log(ql_log_warn, vha, 0x,
+   "Unable to create debugFS tgt_port_database node.\n");
+   goto out;
+   }
+
ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
&d

[PATCH v2 01/14] qla2xxx: Fix delayed response to command for loop mode/direct connect.

2017-02-03 Thread Himanshu Madhani
From: Quinn Tran 

Current driver wait for FW to be in the ready state before
processing in-coming commands. For Arbitrated Loop or
Point-to- Point (not switch), FW Ready state can take a while.
FW will transition to ready state after all Nports have been
logged in. In the mean time, certain initiators have completed
the login and starts IO. Driver needs to start processing all
queues if FW is already started.

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_def.h| 13 +--
 drivers/scsi/qla2xxx/qla_gbl.h|  1 +
 drivers/scsi/qla2xxx/qla_init.c   | 12 +++
 drivers/scsi/qla2xxx/qla_isr.c| 14 +++-
 drivers/scsi/qla2xxx/qla_mbx.c|  6 +++---
 drivers/scsi/qla2xxx/qla_os.c | 45 ++-
 drivers/scsi/qla2xxx/qla_target.c | 38 ++---
 7 files changed, 109 insertions(+), 20 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index ac37e91..fbaa39b 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3290,6 +3290,10 @@ struct qlt_hw_data {
 
 #define LEAK_EXCHG_THRESH_HOLD_PERCENT 75  /* 75 percent */
 
+#define QLA_EARLY_LINKUP(_ha) \
+   ((_ha->flags.n2n_ae || _ha->flags.lip_ae) && \
+_ha->flags.fw_started && !_ha->flags.fw_init_done)
+
 /*
  * Qlogic host adapter specific data structure.
 */
@@ -3339,7 +3343,11 @@ struct qla_hw_data {
uint32_tfawwpn_enabled:1;
uint32_texlogins_enabled:1;
uint32_texchoffld_enabled:1;
-   /* 35 bits */
+
+   uint32_tlip_ae:1;
+   uint32_tn2n_ae:1;
+   uint32_tfw_started:1;
+   uint32_tfw_init_done:1;
} flags;
 
/* This spinlock is used to protect "io transactions", you must
@@ -3432,7 +3440,6 @@ struct qla_hw_data {
 #define P2P_LOOP  3
uint8_t interrupts_on;
uint32_tisp_abort_cnt;
-
 #define PCI_DEVICE_ID_QLOGIC_ISP25320x2532
 #define PCI_DEVICE_ID_QLOGIC_ISP84320x8432
 #define PCI_DEVICE_ID_QLOGIC_ISP8001   0x8001
@@ -3913,6 +3920,7 @@ struct qla_tgt_counters {
struct list_head vp_fcports;/* list of fcports */
struct list_head work_list;
spinlock_t work_lock;
+   struct work_struct iocb_work;
 
/* Commonly used flags and state information. */
struct Scsi_Host *host;
@@ -3932,6 +3940,7 @@ struct qla_tgt_counters {
uint32_tfw_tgt_reported:1;
uint32_tbbcr_enable:1;
uint32_tqpairs_available:1;
+   uint32_tiocb_work_sheduled:1;
} flags;
 
atomic_tloop_state;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index b3d6441..862d5f5 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -193,6 +193,7 @@ extern struct scsi_qla_host *qla2x00_create_host(struct 
scsi_host_template *,
 void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
 int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *);
+void qla2x00_schedule_work(struct scsi_qla_host *);
 
 /*
  * Global Functions in qla_mid.c source file.
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index f654314..9f3db52 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3212,6 +3212,7 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, 
struct event_arg *ea)
} else {
ql_dbg(ql_dbg_init, vha, 0x00d3,
"Init Firmware -- success.\n");
+   ha->flags.fw_started = 1;
}
 
return (rval);
@@ -4036,6 +4037,7 @@ static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t 
*vha, nvram_t *nv)
atomic_set(&vha->loop_state, LOOP_READY);
ql_dbg(ql_dbg_disc, vha, 0x2069,
"LOOP READY.\n");
+   ha->flags.fw_init_done = 1;
 
/*
 * Process any ATIO queue entries that came in
@@ -5526,6 +5528,11 @@ int qla2x00_perform_loop_resync(scsi_qla_host_t *ha)
if (!(IS_P3P_TYPE(ha)))
ha->isp_ops->reset_chip(vha);
 
+   ha->flags.n2n_ae = 0;
+   ha->flags.lip_ae = 0;
+   ha->current_topology = 0;
+   ha->flags.fw_started = 0;
+   ha->flags.fw_init_done = 0;
ha->chip_reset++;
 
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
@@ -6802,6 +6809,8 @@ uint8_t qla27xx_find_valid_image(struct scsi_qla_host 
*vha)
return;
if (!ha->fw_major_version)
return;
+   if (!ha->flags.fw_started)
+   return;
 
ret = qla2x00_stop_firmware(vha);
for (retries = 5; ret != QLA_SUCCESS

[PATCH v2 02/14] qla2xxx: Allow relogin to proceed if remote login did not finish

2017-02-03 Thread Himanshu Madhani
From: Quinn Tran 

If the remote port have started the login process, then the
PLOGI and PRLI should be back to back. Driver will allow
the remote port to complete the process. For the case where
the remote port decide to back off from sending PRLI, this
local port sets an expiration timer for the PRLI. Once the
expiration time passes, the relogin retry logic is allowed
to go through and perform login with the remote port.

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_def.h|  2 ++
 drivers/scsi/qla2xxx/qla_init.c   | 16 ++--
 drivers/scsi/qla2xxx/qla_isr.c| 25 +++--
 drivers/scsi/qla2xxx/qla_target.c |  1 +
 4 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index fbaa39b..bf2ae8d3 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2300,6 +2300,8 @@ enum rscn_addr_format {
struct ct_sns_desc ct_desc;
enum discovery_state disc_state;
enum login_state fw_login_state;
+   unsigned long plogi_nack_done_jiff;
+
u32 login_gen, last_login_gen;
u32 rscn_gen, last_rscn_gen;
u32 chip_reset;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 9f3db52..e84ab37 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -876,10 +876,16 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host 
*vha, fc_port_t *fcport)
fcport->login_retry--;
 
if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
-   (fcport->fw_login_state == DSC_LS_PLOGI_COMP) ||
(fcport->fw_login_state == DSC_LS_PRLI_PEND))
return 0;
 
+   if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) {
+   unsigned long t = fcport->plogi_nack_done_jiff + HZ;
+
+   if (time_before_eq(jiffies, t))
+   return 0;
+   }
+
/* for pure Target Mode. Login will not be initiated */
if (vha->host->active_mode == MODE_TARGET)
return 0;
@@ -1041,10 +1047,16 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha,
fcport->flags);
 
if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
-   (fcport->fw_login_state == DSC_LS_PLOGI_COMP) ||
(fcport->fw_login_state == DSC_LS_PRLI_PEND))
return;
 
+   if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) {
+   unsigned long t = fcport->plogi_nack_done_jiff + HZ;
+
+   if (time_before_eq(jiffies, t))
+   return;
+   }
+
if (fcport->flags & FCF_ASYNC_SENT) {
fcport->login_retry++;
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 0fd3258..f1da53d 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1630,9 +1630,9 @@ static void qla2x00_error_entry(scsi_qla_host_t *, struct 
rsp_que *,
QLA_LOGIO_LOGIN_RETRIED : 0;
if (logio->entry_status) {
ql_log(ql_log_warn, fcport->vha, 0x5034,
-   "Async-%s error entry - hdl=%x"
+   "Async-%s error entry - %8phC hdl=%x"
"portid=%02x%02x%02x entry-status=%x.\n",
-   type, sp->handle, fcport->d_id.b.domain,
+   type, fcport->port_name, sp->handle, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa,
logio->entry_status);
ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d,
@@ -1643,8 +1643,9 @@ static void qla2x00_error_entry(scsi_qla_host_t *, struct 
rsp_que *,
 
if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
ql_dbg(ql_dbg_async, fcport->vha, 0x5036,
-   "Async-%s complete - hdl=%x portid=%02x%02x%02x "
-   "iop0=%x.\n", type, sp->handle, fcport->d_id.b.domain,
+   "Async-%s complete - %8phC hdl=%x portid=%02x%02x%02x "
+   "iop0=%x.\n", type, fcport->port_name, sp->handle,
+   fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa,
le32_to_cpu(logio->io_parameter[0]));
 
@@ -1684,6 +1685,17 @@ static void qla2x00_error_entry(scsi_qla_host_t *, 
struct rsp_que *,
case LSC_SCODE_NPORT_USED:
data[0] = MBS_LOOP_ID_USED;
break;
+   case LSC_SCODE_CMD_FAILED:
+   if (iop[1] == 0x0606) {
+   /*
+* PLOGI/PRLI Completed. We must have Recv PLOGI/PRLI,
+* Target side acked.
+*/
+   data[0] = MBS_COMMAND_COMPLETE;
+   goto logio_done;
+   }
+   data[0] = MBS_COMMAND_E

[PATCH v2 07/14] qla2xxx: Export DIF stats via debugfs

2017-02-03 Thread Himanshu Madhani
From: Anil Gurumurthy 

Signed-off-by: Anil Gurumurthy 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_def.h | 12 
 drivers/scsi/qla2xxx/qla_dfs.c | 15 +++
 2 files changed, 27 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index d6436fc..a15614d 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3129,6 +3129,16 @@ struct qla_chip_state_84xx {
uint32_t gold_fw_version;
 };
 
+struct qla_dif_statistics {
+   uint64_t dif_input_bytes;
+   uint64_t dif_output_bytes;
+   uint64_t dif_input_requests;
+   uint64_t dif_output_requests;
+   uint32_t dif_guard_err;
+   uint32_t dif_ref_tag_err;
+   uint32_t dif_app_tag_err;
+};
+
 struct qla_statistics {
uint32_t total_isp_aborts;
uint64_t input_bytes;
@@ -3141,6 +3151,8 @@ struct qla_statistics {
uint32_t stat_max_pend_cmds;
uint32_t stat_max_qfull_cmds_alloc;
uint32_t stat_max_qfull_cmds_dropped;
+
+   struct qla_dif_statistics qla_dif_stats;
 };
 
 struct bidi_statistics {
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 0fb33e6..989e17b 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -185,6 +185,21 @@
seq_printf(s, "num Q full sent = %lld\n",
vha->tgt_counters.num_q_full_sent);
 
+   /* DIF stats */
+   seq_printf(s, "DIF Inp Bytes = %lld\n",
+   vha->qla_stats.qla_dif_stats.dif_input_bytes);
+   seq_printf(s, "DIF Outp Bytes = %lld\n",
+   vha->qla_stats.qla_dif_stats.dif_output_bytes);
+   seq_printf(s, "DIF Inp Req = %lld\n",
+   vha->qla_stats.qla_dif_stats.dif_input_requests);
+   seq_printf(s, "DIF Outp Req = %lld\n",
+   vha->qla_stats.qla_dif_stats.dif_output_requests);
+   seq_printf(s, "DIF Guard err = %d\n",
+   vha->qla_stats.qla_dif_stats.dif_guard_err);
+   seq_printf(s, "DIF Ref tag err = %d\n",
+   vha->qla_stats.qla_dif_stats.dif_ref_tag_err);
+   seq_printf(s, "DIF App tag err = %d\n",
+   vha->qla_stats.qla_dif_stats.dif_app_tag_err);
return 0;
 }
 
-- 
1.8.3.1



[PATCH v2 06/14] qla2xxx: Improve T10-DIF/PI handling in driver.

2017-02-03 Thread Himanshu Madhani
From: Quinn Tran 

Add routines to support T10 DIF tag.

Signed-off-by: Quinn Tran 
Signed-off-by: Anil Gurumurthy 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_dbg.h |   1 +
 drivers/scsi/qla2xxx/qla_def.h |  17 ++
 drivers/scsi/qla2xxx/qla_target.c  | 598 +
 drivers/scsi/qla2xxx/qla_target.h  |  37 ++-
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |  84 +-
 5 files changed, 465 insertions(+), 272 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index e1fc4e6..c6bffe9 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -348,6 +348,7 @@ void __attribute__((format (printf, 4, 5)))
 #define ql_dbg_tgt 0x4000 /* Target mode */
 #define ql_dbg_tgt_mgt 0x2000 /* Target mode management */
 #define ql_dbg_tgt_tmr 0x1000 /* Target mode task management */
+#define ql_dbg_tgt_dif  0x0800 /* Target mode dif */
 
 extern int qla27xx_dump_mpi_ram(struct qla_hw_data *, uint32_t, uint32_t *,
uint32_t, void **);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 8bc..d6436fc 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2189,6 +2189,23 @@ struct qlt_plogi_ack_t {
void*fcport;
 };
 
+enum qla_tgt_prot_op {
+   QLA_PROT_NORMAL  = 0,
+   QLA_PROT_DIN_INSERT,
+   QLA_PROT_DOUT_INSERT,
+   QLA_PROT_DIN_STRIP,
+   QLA_PROT_DOUT_STRIP,
+   QLA_PROT_DIN_PASS,
+   QLA_PROT_DOUT_PASS,
+};
+
+enum qla_tgt_prot_type {
+   QLA_TGT_PROT_TYPE0,
+   QLA_TGT_PROT_TYPE1,
+   QLA_TGT_PROT_TYPE2,
+   QLA_TGT_PROT_TYPE3,
+};
+
 struct ct_sns_desc {
struct ct_sns_pkt   *ct_sns;
dma_addr_t  ct_sns_dma;
diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index a4cc14b..a36258d 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -36,8 +36,6 @@
 #include 
 #include 
 #include 
-#include 
-#include 
 
 #include "qla_def.h"
 #include "qla_target.h"
@@ -140,6 +138,20 @@ static struct fc_port *qlt_create_sess(struct 
scsi_qla_host *vha,
 static DEFINE_MUTEX(qla_tgt_mutex);
 static LIST_HEAD(qla_tgt_glist);
 
+static char *prot_op_str(u32 prot_op)
+{
+   switch (prot_op) {
+   case QLA_PROT_NORMAL:   return "NORMAL";
+   case QLA_PROT_DIN_INSERT:   return "DIN_INSERT";
+   case QLA_PROT_DOUT_INSERT:  return "DOUT_INSERT";
+   case QLA_PROT_DIN_STRIP:return "DIN_STRIP";
+   case QLA_PROT_DOUT_STRIP:   return "DOUT_STRIP";
+   case QLA_PROT_DIN_PASS: return "DIN_PASS";
+   case QLA_PROT_DOUT_PASS:return "DOUT_PASS";
+   default:return "UNKNOWN";
+   }
+}
+
 /* This API intentionally takes dest as a parameter, rather than returning
  * int value to avoid caller forgetting to issue wmb() after the store */
 void qlt_do_generation_tick(struct scsi_qla_host *vha, int *dest)
@@ -1997,6 +2009,68 @@ void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd)
 }
 EXPORT_SYMBOL(qlt_free_mcmd);
 
+/*
+ * ha->hardware_lock supposed to be held on entry. Might drop it, then
+ * reacquire
+ */
+void qlt_send_resp_ctio(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
+uint8_t scsi_status, uint8_t sense_key, uint8_t asc, uint8_t ascq)
+{
+   struct atio_from_isp *atio = &cmd->atio;
+   struct ctio7_to_24xx *ctio;
+   uint16_t temp;
+
+   ql_dbg(ql_dbg_tgt_dif, vha, 0x3066,
+   "Sending response CTIO7 (vha=%p, atio=%p, scsi_status=%02x, "
+   "sense_key=%02x, asc=%02x, ascq=%02x",
+   vha, atio, scsi_status, sense_key, asc, ascq);
+
+   ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs(vha, NULL);
+   if (!ctio) {
+   ql_dbg(ql_dbg_async, vha, 0x3067,
+   "qla2x00t(%ld): %s failed: unable to allocate request 
packet",
+   vha->host_no, __func__);
+   goto out;
+   }
+
+   ctio->entry_type = CTIO_TYPE7;
+   ctio->entry_count = 1;
+   ctio->handle = QLA_TGT_SKIP_HANDLE;
+   ctio->nport_handle = cmd->sess->loop_id;
+   ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
+   ctio->vp_index = vha->vp_idx;
+   ctio->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2];
+   ctio->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1];
+   ctio->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0];
+   ctio->exchange_addr = atio->u.isp24.exchange_addr;
+   ctio->u.status1.flags = (atio->u.isp24.attr << 9) |
+   cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS);
+   temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id);
+   ctio->u.status1.ox_id = cpu_to_le16(temp);
+   ctio->u.status1.scsi_status =
+   cpu_to_le16(SS_RESPONSE_INFO_LEN_VALID | scsi_status);
+   ctio->u.status1.response_len = cpu_to_le16(18);
+   ctio->

[PATCH v2 11/14] qla2xxx: Fix inadequate lock protection for ABTS.

2017-02-03 Thread Himanshu Madhani
From: Quinn Tran 

Normally, ABTS is sent to Target Core as Task MGMT command.
In the case of error, qla2xxx needs to send response, hardware_lock
is required to prevent request queue corruption.

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_target.c | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index b5fb9c55..8b372b2 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -128,6 +128,9 @@ static void qlt_send_term_imm_notif(struct scsi_qla_host 
*vha,
 static struct fc_port *qlt_create_sess(struct scsi_qla_host *vha,
fc_port_t *fcport, bool local);
 void qlt_unreg_sess(struct fc_port *sess);
+static void qlt_24xx_handle_abts(struct scsi_qla_host *,
+   struct abts_recv_from_24xx *);
+
 /*
  * Global Variables
  */
@@ -403,6 +406,8 @@ static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host 
*vha,
(struct abts_recv_from_24xx *)atio;
struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha,
entry->vp_index);
+   unsigned long flags;
+
if (unlikely(!host)) {
ql_dbg(ql_dbg_tgt, vha, 0x,
"qla_target(%d): Response pkt (ABTS_RECV_24XX) "
@@ -410,9 +415,12 @@ static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host 
*vha,
vha->vp_idx, entry->vp_index);
break;
}
-   qlt_response_pkt(host, (response_t *)atio);
+   if (!ha_locked)
+   spin_lock_irqsave(&host->hw->hardware_lock, flags);
+   qlt_24xx_handle_abts(host, (struct abts_recv_from_24xx *)atio);
+   if (!ha_locked)
+   spin_unlock_irqrestore(&host->hw->hardware_lock, flags);
break;
-
}
 
/* case PUREX_IOCB_TYPE: ql2xmvasynctoatio */
-- 
1.8.3.1



[PATCH v2 00/14] qla2xxx: Bug Fixes and updates for target.

2017-02-03 Thread Himanshu Madhani
Hi Bart,

Please consider this series for inclusion in target-pending.

This series contains following changes.

o Fix for the deadlock because of inconsistent lock usage reported by you. 
o Added patch to submit non-critical MBX command via IOCB path.
o Improved T10-DIF/PI handling with target stack.
o Changed scsi host lookup method.
o Some minor bug fixes.

Changes from v1 -> v2

o Dropped patch for indentation as its already part of scsi-target-for-v4.11 
branch.
o Rebased series based on scsi-target-for-v4.11 branch.

Please apply to target-pending.

Thanks,
Himanshu  

Anil Gurumurthy (1):
  qla2xxx: Export DIF stats via debugfs

Himanshu Madhani (2):
  qla2xxx: Add DebugFS node to display Port Database
  qla2xxx: Update driver version to 9.00.00.00-k

Joe Carnuccio (1):
  qla2xxx: Allow vref count to timeout on vport delete.

Quinn Tran (10):
  qla2xxx: Fix delayed response to command for loop mode/direct connect.
  qla2xxx: Allow relogin to proceed if remote login did not finish
  qla2xxx: Use IOCB interface to submit non-critical MBX.
  qla2xxx: Improve T10-DIF/PI handling in driver.
  qla2xxx: Change scsi host lookup method
  qla2xxx: Fix memory leak for abts processing
  qla2xxx: Fix request queue corruption.
  qla2xxx: Fix inadequate lock protection for ABTS.
  qla2xxx: Add async new target notification
  qla2xxx: Fix sess_lock & hardware_lock lock order problem.

 drivers/scsi/qla2xxx/Kconfig   |   1 +
 drivers/scsi/qla2xxx/qla_attr.c|   4 +-
 drivers/scsi/qla2xxx/qla_dbg.h |   1 +
 drivers/scsi/qla2xxx/qla_def.h |  56 ++-
 drivers/scsi/qla2xxx/qla_dfs.c | 107 -
 drivers/scsi/qla2xxx/qla_gbl.h |  13 +-
 drivers/scsi/qla2xxx/qla_init.c|  88 ++--
 drivers/scsi/qla2xxx/qla_isr.c |  41 +-
 drivers/scsi/qla2xxx/qla_mbx.c | 307 --
 drivers/scsi/qla2xxx/qla_mid.c |  12 +-
 drivers/scsi/qla2xxx/qla_os.c  |  46 ++-
 drivers/scsi/qla2xxx/qla_target.c  | 804 +++--
 drivers/scsi/qla2xxx/qla_target.h  |  38 +-
 drivers/scsi/qla2xxx/qla_version.h |   6 +-
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |  84 +++-
 15 files changed, 1158 insertions(+), 450 deletions(-)

-- 
1.8.3.1



[PATCH v2 12/14] qla2xxx: Add async new target notification

2017-02-03 Thread Himanshu Madhani
From: Quinn Tran 

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_target.c | 6 +++---
 drivers/scsi/qla2xxx/qla_target.h | 1 +
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 8b372b2..2909b7b 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -5998,13 +5998,13 @@ int qlt_add_target(struct qla_hw_data *ha, struct 
scsi_qla_host *base_vha)
tgt->datasegs_per_cmd = QLA_TGT_DATASEGS_PER_CMD_24XX;
tgt->datasegs_per_cont = QLA_TGT_DATASEGS_PER_CONT_24XX;
 
-   if (base_vha->fc_vport)
-   return 0;
-
mutex_lock(&qla_tgt_mutex);
list_add_tail(&tgt->tgt_list_entry, &qla_tgt_glist);
mutex_unlock(&qla_tgt_mutex);
 
+   if (ha->tgt.tgt_ops && ha->tgt.tgt_ops->add_target)
+   ha->tgt.tgt_ops->add_target(base_vha);
+
return 0;
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_target.h 
b/drivers/scsi/qla2xxx/qla_target.h
index 82d53f3..20e25e5 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -693,6 +693,7 @@ struct qla_tgt_func_tmpl {
void (*shutdown_sess)(struct fc_port *);
int (*get_dif_tags)(struct qla_tgt_cmd *cmd, uint16_t *pfw_prot_opts);
int (*chk_dif_tags)(uint32_t tag);
+   void (*add_target)(struct scsi_qla_host *);
 };
 
 int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
-- 
1.8.3.1



[PATCH v2 08/14] qla2xxx: Change scsi host lookup method

2017-02-03 Thread Himanshu Madhani
From: Quinn Tran 

For target mode, when new scsi command arrive, driver first performs
a look up of the SCSI Host. The current look up method is based on
the ALPA portion of the NPort ID. For Cisco switch, the ALPA can
not be used as the index. Instead, the new search method is based
on the full value of the Nport_ID via btree lib.

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/Kconfig  |  1 +
 drivers/scsi/qla2xxx/qla_def.h|  2 +
 drivers/scsi/qla2xxx/qla_gbl.h|  2 +
 drivers/scsi/qla2xxx/qla_init.c   | 14 +++---
 drivers/scsi/qla2xxx/qla_mbx.c| 28 
 drivers/scsi/qla2xxx/qla_os.c |  1 +
 drivers/scsi/qla2xxx/qla_target.c | 90 +--
 7 files changed, 98 insertions(+), 40 deletions(-)

diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig
index 67c0d5a..de95293 100644
--- a/drivers/scsi/qla2xxx/Kconfig
+++ b/drivers/scsi/qla2xxx/Kconfig
@@ -3,6 +3,7 @@ config SCSI_QLA_FC
depends on PCI && SCSI
depends on SCSI_FC_ATTRS
select FW_LOADER
+   select BTREE
---help---
This qla2xxx driver supports all QLogic Fibre Channel
PCI and PCIe host adapters.
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index a15614d..160d74c 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -3318,6 +3319,7 @@ struct qlt_hw_data {
spinlock_t sess_lock;
int rspq_vector_cpuid;
spinlock_t atio_lock cacheline_aligned;
+   struct btree_head32 host_map;
 };
 
 #define MAX_QFULL_CMDS_ALLOC   8192
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 48a1190..b1e7b82 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -855,5 +855,7 @@ extern struct fc_port 
*qlt_find_sess_invalidate_other(scsi_qla_host_t *,
uint64_t wwn, port_id_t port_id, uint16_t loop_id, struct fc_port **);
 void qla24xx_delete_sess_fn(struct work_struct *);
 void qlt_unknown_atio_work_fn(struct work_struct *);
+void qlt_update_host_map(struct scsi_qla_host *, port_id_t);
+void qlt_remove_target_resources(struct qla_hw_data *);
 
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 5aca3df..ea6ddcf 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3345,8 +3345,8 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, 
struct event_arg *ea)
uint8_t   domain;
charconnect_type[22];
struct qla_hw_data *ha = vha->hw;
-   unsigned long flags;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+   port_id_t id;
 
/* Get host addresses. */
rval = qla2x00_get_adapter_id(vha,
@@ -3424,13 +3424,11 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, 
struct event_arg *ea)
 
/* Save Host port and loop ID. */
/* byte order - Big Endian */
-   vha->d_id.b.domain = domain;
-   vha->d_id.b.area = area;
-   vha->d_id.b.al_pa = al_pa;
-
-   spin_lock_irqsave(&ha->vport_slock, flags);
-   qlt_update_vp_map(vha, SET_AL_PA);
-   spin_unlock_irqrestore(&ha->vport_slock, flags);
+   id.b.domain = domain;
+   id.b.area = area;
+   id.b.al_pa = al_pa;
+   id.b.rsvd_1 = 0;
+   qlt_update_host_map(vha, id);
 
if (!vha->flags.init_done)
ql_log(ql_log_info, vha, 0x2010,
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 4225256..f352889 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3624,6 +3624,7 @@ struct tsk_mgmt_cmd {
scsi_qla_host_t *vp = NULL;
unsigned long   flags;
int found;
+   port_id_t id;
 
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b6,
"Entered %s.\n", __func__);
@@ -3631,6 +3632,11 @@ struct tsk_mgmt_cmd {
if (rptid_entry->entry_status != 0)
return;
 
+   id.b.domain = rptid_entry->port_id[2];
+   id.b.area   = rptid_entry->port_id[1];
+   id.b.al_pa  = rptid_entry->port_id[0];
+   id.b.rsvd_1 = 0;
+
if (rptid_entry->format == 0) {
/* loop */
ql_dbg(ql_dbg_async, vha, 0x10b7,
@@ -3642,13 +3648,7 @@ struct tsk_mgmt_cmd {
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]);
 
-   vha->d_id.b.domain = rptid_entry->port_id[2];
-   vha->d_id.b.area = rptid_entry->port_id[1];
-   vha->d_id.b.al_pa = rptid_entry->port_id[0];
-
-   spin_lock_irqsave(&ha->vport_slock, flags);
-   qlt_update_vp_map(vha, SET_AL_PA);
-   spin_unlock_irqrestore(&ha->vport_slock, flags);
+   qlt_update_

[PATCH v2 09/14] qla2xxx: Fix memory leak for abts processing

2017-02-03 Thread Himanshu Madhani
From: Quinn Tran 

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_target.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 359a79d..b61cbb8 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -6753,6 +6753,8 @@ static void qlt_disable_vha(struct scsi_qla_host *vha)
spin_lock_irqsave(&ha->hardware_lock, flags);
qlt_response_pkt_all_vps(vha, (response_t *)&op->atio);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+   kfree(op);
 }
 
 void
-- 
1.8.3.1



[PATCH v2 13/14] qla2xxx: Fix sess_lock & hardware_lock lock order problem.

2017-02-03 Thread Himanshu Madhani
From: Quinn Tran 

The main lock that needs to be held for CMD or TMR submission
to upper layer is the sess_lock. The sess_lock is used to
serialize cmd submission and session deletion. The addition
of hardware_lock being held is not necessary. This patch removes
hardware_lock dependency from CMD/TMR submission.

Use hardware_lock only for error response in this case.

Path1
   CPU0CPU1
   
  lock(&(&ha->tgt.sess_lock)->rlock);
   lock(&(&ha->hardware_lock)->rlock);
   lock(&(&ha->tgt.sess_lock)->rlock);
  lock(&(&ha->hardware_lock)->rlock);

Path2/deadlock
*** DEADLOCK ***
Call Trace:
dump_stack+0x85/0xc2
print_circular_bug+0x1e3/0x250
__lock_acquire+0x1425/0x1620
lock_acquire+0xbf/0x210
_raw_spin_lock_irqsave+0x53/0x70
qlt_sess_work_fn+0x21d/0x480 [qla2xxx]
process_one_work+0x1f4/0x6e0

Cc: 
Cc: Bart Van Assche 
Reported-by: Bart Van Assche 
Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_target.c | 41 +--
 1 file changed, 18 insertions(+), 23 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 2909b7b..fb7156c 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -5818,30 +5818,23 @@ static void qlt_abort_work(struct qla_tgt *tgt,
}
}
 
-   spin_lock_irqsave(&ha->hardware_lock, flags);
-
-   if (tgt->tgt_stop)
-   goto out_term;
-
rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
+   ha->tgt.tgt_ops->put_sess(sess);
+   spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
+
if (rc != 0)
goto out_term;
-   spin_unlock_irqrestore(&ha->hardware_lock, flags);
-   if (sess)
-   ha->tgt.tgt_ops->put_sess(sess);
-   spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
return;
 
 out_term2:
-   spin_lock_irqsave(&ha->hardware_lock, flags);
+   if (sess)
+   ha->tgt.tgt_ops->put_sess(sess);
+   spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
 
 out_term:
+   spin_lock_irqsave(&ha->hardware_lock, flags);
qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-   if (sess)
-   ha->tgt.tgt_ops->put_sess(sess);
-   spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
 }
 
 static void qlt_tmr_work(struct qla_tgt *tgt,
@@ -5861,7 +5854,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
spin_lock_irqsave(&ha->tgt.sess_lock, flags);
 
if (tgt->tgt_stop)
-   goto out_term;
+   goto out_term2;
 
s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id;
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
@@ -5873,11 +5866,11 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
 
spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (!sess)
-   goto out_term;
+   goto out_term2;
} else {
if (sess->deleted) {
sess = NULL;
-   goto out_term;
+   goto out_term2;
}
 
if (!kref_get_unless_zero(&sess->sess_kref)) {
@@ -5885,7 +5878,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
"%s: kref_get fail %8phC\n",
 __func__, sess->port_name);
sess = NULL;
-   goto out_term;
+   goto out_term2;
}
}
 
@@ -5895,17 +5888,19 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
 
rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0);
-   if (rc != 0)
-   goto out_term;
-
ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
+   if (rc != 0)
+   goto out_term;
return;
 
+out_term2:
+   if (sess)
+   ha->tgt.tgt_ops->put_sess(sess);
+   spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 out_term:
qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0);
-   ha->tgt.tgt_ops->put_sess(sess);
-   spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 }
 
 static void qlt_sess_work_fn(struct work_struct *work)
-- 
1.8.3.1



Re: [REGRESSION v4.10-rc1] blkdev_issue_zeroout() returns -EREMOTEIO on the first call for SCSI device that doesn't support WRITE SAME

2017-02-03 Thread Martin K. Petersen
> "Jens" == Jens Axboe  writes:

>> I think we should fix sd.c to only send WRITE SAME if either of the
>> variants are explicitly listed as supported through REPORT SUPPORTED
>> OPERATION CODES, or maybe through a whitelist if there are important
>> enough devices.

Jens> Yep

I hate it too. But the reason it's assumed on is that there is
essentially no heuristic that works. Just like we assume that READ
always works.

Out of the ~200 devices I have access to in the lab:

 - 100% of the SAS/FC disk drives and SSDs support WRITE SAME
 - Only 2 out of about 50 different drive models support RSOC
 - About half of the arrays support WRITE SAME(10/16)
 - None of the arrays I have support RSOC

So even if we were to entertain using RSOC for "enterprise" transport
classes (which I concur would be nice for other reasons), it wouldn't
solve the WRITE SAME problem...

-- 
Martin K. Petersen  Oracle Linux Engineering


[PATCH v1 0/8] scsi: ufs: enhancements, bug fixes and debug support

2017-02-03 Thread Subhash Jadavani
This patch series adds following things:
 - Gear scaling during clock scaling to save additional power
 - Make clock scaling independent clock gating so that we can set lower
   clock gating timeout than clock scaling window
 - one bug fix to clock scaling
 - additional debug support

Gilad Broner (3):
  scsi: ufs: skip request abort task when previous aborts failed
  scsi: ufs: reduce printout for aborted requests
  scsi: ufs: add host state prints in failure cases

Subhash Jadavani (3):
  scsi: ufs: add load based scaling of UFS gear
  scsi: ufs: don't suspend clock scaling during clock gating
  scsi: ufs: kick start clock scaling only after device detection

Venkat Gopalakrishnan (2):
  scsi: ufs-qcom: dump additional testbus registers
  scsi: ufs: dump hw regs on link failures

 drivers/scsi/ufs/ufs-qcom.c |  48 ++-
 drivers/scsi/ufs/ufs-qcom.h |   1 +
 drivers/scsi/ufs/ufshcd.c   | 863 
 drivers/scsi/ufs/ufshcd.h   |  44 ++-
 4 files changed, 726 insertions(+), 230 deletions(-)

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 1/8] scsi: ufs: skip request abort task when previous aborts failed

2017-02-03 Thread Subhash Jadavani
From: Gilad Broner 

On certain error conditions request abort task itself might fail
when aborting a request. In such case, subsequent request aborts
should skip issuing the abort task as it is expected to fail as well,
and device reset handler will be called next.

Signed-off-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 20 
 drivers/scsi/ufs/ufshcd.h |  3 +++
 2 files changed, 23 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a70bf06..61fea17 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1877,6 +1877,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
lrbp->task_tag = tag;
lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false;
+   lrbp->req_abort_skip = false;
 
ufshcd_comp_scsi_upiu(hba, lrbp);
 
@@ -4979,6 +4980,17 @@ static int ufshcd_eh_device_reset_handler(struct 
scsi_cmnd *cmd)
return err;
 }
 
+static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long 
bitmap)
+{
+   struct ufshcd_lrb *lrbp;
+   int tag;
+
+   for_each_set_bit(tag, &bitmap, hba->nutrs) {
+   lrbp = &hba->lrb[tag];
+   lrbp->req_abort_skip = true;
+   }
+}
+
 /**
  * ufshcd_abort - abort a specific command
  * @cmd: SCSI command pointer
@@ -5047,6 +5059,13 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
ufshcd_print_pwr_info(hba);
ufshcd_print_trs(hba, 1 << tag, true);
 
+
+   /* Skip task abort in case previous aborts failed and report failure */
+   if (lrbp->req_abort_skip) {
+   err = -EIO;
+   goto out;
+   }
+
for (poll_cnt = 100; poll_cnt; poll_cnt--) {
err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag,
UFS_QUERY_TASK, &resp);
@@ -5120,6 +5139,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
err = SUCCESS;
} else {
dev_err(hba->dev, "%s: failed with err %d\n", __func__, err);
+   ufshcd_set_req_abort_skip(hba, hba->outstanding_reqs);
err = FAILED;
}
 
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 7ffcde2..292fc14 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -165,6 +165,7 @@ struct ufs_pm_lvl_states {
  * @lun: LUN of the command
  * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
  * @issue_time_stamp: time stamp for debug purposes
+ * @req_abort_skip: skip request abort task flag
  */
 struct ufshcd_lrb {
struct utp_transfer_req_desc *utr_descriptor_ptr;
@@ -187,6 +188,8 @@ struct ufshcd_lrb {
u8 lun; /* UPIU LUN id field is only 8-bit wide */
bool intr_cmd;
ktime_t issue_time_stamp;
+
+   bool req_abort_skip;
 };
 
 /**
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 2/8] scsi: ufs: reduce printout for aborted requests

2017-02-03 Thread Subhash Jadavani
From: Gilad Broner 

Details printed for each request that is aborted can overload the
target as there can be several requests that are aborted at once.
This change will print full request details only for the first
aborted request since the last link reset, and minimal details
for other subsequent requests.

Signed-off-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 46 --
 drivers/scsi/ufs/ufshcd.h |  3 +++
 2 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 61fea17..64d619a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -396,6 +396,7 @@ static void ufshcd_print_host_regs(struct ufs_hba *hba)
 void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt)
 {
struct ufshcd_lrb *lrbp;
+   int prdt_length;
int tag;
 
for_each_set_bit(tag, &bitmap, hba->nutrs) {
@@ -417,18 +418,17 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long 
bitmap, bool pr_prdt)
(u64)lrbp->ucd_rsp_dma_addr);
ufshcd_hex_dump("UPIU RSP: ", lrbp->ucd_rsp_ptr,
sizeof(struct utp_upiu_rsp));
-   if (pr_prdt) {
-   int prdt_length = le16_to_cpu(
-   lrbp->utr_descriptor_ptr->prd_table_length);
 
-   dev_err(hba->dev,
-   "UPIU[%d] - PRDT - %d entries  phys@0x%llx\n",
-   tag, prdt_length,
-   (u64)lrbp->ucd_prdt_dma_addr);
+   prdt_length = le16_to_cpu(
+   lrbp->utr_descriptor_ptr->prd_table_length);
+   dev_err(hba->dev,
+   "UPIU[%d] - PRDT - %d entries  phys@0x%llx\n",
+   tag, prdt_length,
+   (u64)lrbp->ucd_prdt_dma_addr);
+
+   if (pr_prdt)
ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr,
-   sizeof(struct ufshcd_sg_entry) *
-   prdt_length);
-   }
+   sizeof(struct ufshcd_sg_entry) * prdt_length);
}
 }
 
@@ -1848,6 +1848,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, 
struct scsi_cmnd *cmd)
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
 
+   hba->req_abort_count = 0;
+
/* acquire the tag to make sure device cmds don't use it */
if (test_and_set_bit_lock(tag, &hba->lrb_in_use)) {
/*
@@ -4970,7 +4972,9 @@ static int ufshcd_eh_device_reset_handler(struct 
scsi_cmnd *cmd)
spin_lock_irqsave(host->host_lock, flags);
ufshcd_transfer_req_compl(hba);
spin_unlock_irqrestore(host->host_lock, flags);
+
 out:
+   hba->req_abort_count = 0;
if (!err) {
err = SUCCESS;
} else {
@@ -5054,11 +5058,23 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
 
/* Print Transfer Request of aborted task */
dev_err(hba->dev, "%s: Device abort task at tag %d\n", __func__, tag);
-   scsi_print_command(hba->lrb[tag].cmd);
-   ufshcd_print_host_regs(hba);
-   ufshcd_print_pwr_info(hba);
-   ufshcd_print_trs(hba, 1 << tag, true);
 
+   /*
+* Print detailed info about aborted request.
+* As more than one request might get aborted at the same time,
+* print full information only for the first aborted request in order
+* to reduce repeated printouts. For other aborted requests only print
+* basic details.
+*/
+   scsi_print_command(hba->lrb[tag].cmd);
+   if (!hba->req_abort_count) {
+   ufshcd_print_host_regs(hba);
+   ufshcd_print_pwr_info(hba);
+   ufshcd_print_trs(hba, 1 << tag, true);
+   } else {
+   ufshcd_print_trs(hba, 1 << tag, false);
+   }
+   hba->req_abort_count++;
 
/* Skip task abort in case previous aborts failed and report failure */
if (lrbp->req_abort_skip) {
@@ -5707,6 +5723,8 @@ static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba 
*hba)
memset(&hba->ufs_stats.nl_err, 0, err_reg_hist_size);
memset(&hba->ufs_stats.tl_err, 0, err_reg_hist_size);
memset(&hba->ufs_stats.dme_err, 0, err_reg_hist_size);
+
+   hba->req_abort_count = 0;
 }
 
 /**
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 292fc14..b7ce129 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -594,6 +594,9 @@ struct ufs_hba {
 
bool wlun_dev_clr_ua;
 
+   /* Number of requests aborts */
+   int req_abort_count;
+
/* Number of lanes available (1 or 2) for Rx/Tx */
u32 lanes_per_direction;
struct ufs_pa_layer_attr pwr_info;
-- 
The Qualcomm Innovation Center, Inc.

[PATCH v1 3/8] scsi: ufs: add load based scaling of UFS gear

2017-02-03 Thread Subhash Jadavani
UFS driver's load based clock scaling feature scales down the ufs related
clocks in order to allow low power modes of chipsets. UniPro 1.6 supports
maximum gear up to HS-G3 (High Speed Gear3) and some of the chipsets
low power modes may not be allowed in HS-G3 hence this change adds support
to scale gear between HS-G3 and HS-G1 based on same existing load based
clock scaling logic.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 594 --
 drivers/scsi/ufs/ufshcd.h |   9 +
 2 files changed, 428 insertions(+), 175 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 64d619a..e75e50d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -867,6 +867,396 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct 
ufs_hba *hba)
return false;
 }
 
+static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
+{
+   int ret = 0;
+   struct ufs_clk_info *clki;
+   struct list_head *head = &hba->clk_list_head;
+   ktime_t start = ktime_get();
+   bool clk_state_changed = false;
+
+   if (!head || list_empty(head))
+   goto out;
+
+   ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
+   if (ret)
+   return ret;
+
+   list_for_each_entry(clki, head, list) {
+   if (!IS_ERR_OR_NULL(clki->clk)) {
+   if (scale_up && clki->max_freq) {
+   if (clki->curr_freq == clki->max_freq)
+   continue;
+
+   clk_state_changed = true;
+   ret = clk_set_rate(clki->clk, clki->max_freq);
+   if (ret) {
+   dev_err(hba->dev, "%s: %s clk set 
rate(%dHz) failed, %d\n",
+   __func__, clki->name,
+   clki->max_freq, ret);
+   break;
+   }
+   trace_ufshcd_clk_scaling(dev_name(hba->dev),
+   "scaled up", clki->name,
+   clki->curr_freq,
+   clki->max_freq);
+
+   clki->curr_freq = clki->max_freq;
+
+   } else if (!scale_up && clki->min_freq) {
+   if (clki->curr_freq == clki->min_freq)
+   continue;
+
+   clk_state_changed = true;
+   ret = clk_set_rate(clki->clk, clki->min_freq);
+   if (ret) {
+   dev_err(hba->dev, "%s: %s clk set 
rate(%dHz) failed, %d\n",
+   __func__, clki->name,
+   clki->min_freq, ret);
+   break;
+   }
+   trace_ufshcd_clk_scaling(dev_name(hba->dev),
+   "scaled down", clki->name,
+   clki->curr_freq,
+   clki->min_freq);
+   clki->curr_freq = clki->min_freq;
+   }
+   }
+   dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__,
+   clki->name, clk_get_rate(clki->clk));
+   }
+
+   ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
+
+out:
+   if (clk_state_changed)
+   trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
+   (scale_up ? "up" : "down"),
+   ktime_to_us(ktime_sub(ktime_get(), start)), ret);
+   return ret;
+}
+
+/**
+ * ufshcd_is_devfreq_scaling_required - check if scaling is required or not
+ * @hba: per adapter instance
+ * @scale_up: True if scaling up and false if scaling down
+ *
+ * Returns true if scaling is required, false otherwise.
+ */
+static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba,
+  bool scale_up)
+{
+   struct ufs_clk_info *clki;
+   struct list_head *head = &hba->clk_list_head;
+
+   if (!head || list_empty(head))
+   return false;
+
+   list_for_each_entry(clki, head, list) {
+   if (!IS_ERR_OR_NULL(clki->clk)) {
+   if (scale_up && clki->max_freq) {
+   if (clki->curr_freq == clki->max_freq)
+   continue;
+   return true;
+   } else if (!scale_up && clki->min_freq) {
+   if (clki->curr_fre

[PATCH v1 5/8] scsi: ufs: don't suspend clock scaling during clock gating

2017-02-03 Thread Subhash Jadavani
Currently we are suspending clock scaling during clock gating which doesn't
allow us to have clock gating timeout lower than clock scaling polling
window. If clock gating timeout is smaller than the clock scaling polling
window then we will mostly suspend the clock scaling before clock scaling
polling window expires and we might get stuck in same state (scaled down
or scaled up) for quite a long time. And for this reason, we have clock
gating timeout (150ms) greater than clock scaling polling window (100ms).

We would like to have aggressive clock gating timeout even lower than the
clock scaling polling window hence this change is decoupling the clock
scaling suspend/resume from clock gate/ungate. We will not suspend the
clock scaling as part of clock gating instead clock scaling context will
schedule scaling suspend work if there are no more pending transfer
requests.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 185 --
 drivers/scsi/ufs/ufshcd.h |  31 +++-
 2 files changed, 171 insertions(+), 45 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 056e912..4f6ba24 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -248,6 +248,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool 
on,
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba);
 static void ufshcd_resume_clkscaling(struct ufs_hba *hba);
 static void ufshcd_suspend_clkscaling(struct ufs_hba *hba);
+static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba);
 static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up);
 static irqreturn_t ufshcd_intr(int irq, void *__hba);
 static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
@@ -1135,6 +1136,9 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool 
scale_up)
 {
int ret = 0;
 
+   /* let's not get into low power until clock scaling is completed */
+   ufshcd_hold(hba, false);
+
ret = ufshcd_clock_scaling_prepare(hba);
if (ret)
return ret;
@@ -1166,16 +1170,51 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, 
bool scale_up)
 
 out:
ufshcd_clock_scaling_unprepare(hba);
+   ufshcd_release(hba);
return ret;
 }
 
+static void ufshcd_clk_scaling_suspend_work(struct work_struct *work)
+{
+   struct ufs_hba *hba = container_of(work, struct ufs_hba,
+  clk_scaling.suspend_work);
+   unsigned long irq_flags;
+
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (hba->clk_scaling.active_reqs || hba->clk_scaling.is_suspended) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return;
+   }
+   hba->clk_scaling.is_suspended = true;
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
+   __ufshcd_suspend_clkscaling(hba);
+}
+
+static void ufshcd_clk_scaling_resume_work(struct work_struct *work)
+{
+   struct ufs_hba *hba = container_of(work, struct ufs_hba,
+  clk_scaling.resume_work);
+   unsigned long irq_flags;
+
+   spin_lock_irqsave(hba->host->host_lock, irq_flags);
+   if (!hba->clk_scaling.is_suspended) {
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+   return;
+   }
+   hba->clk_scaling.is_suspended = false;
+   spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
+
+   devfreq_resume_device(hba->devfreq);
+}
+
 static int ufshcd_devfreq_target(struct device *dev,
unsigned long *freq, u32 flags)
 {
int ret = 0;
struct ufs_hba *hba = dev_get_drvdata(dev);
ktime_t start;
-   bool scale_up, release_clk_hold = false;
+   bool scale_up, sched_clk_scaling_suspend_work = false;
unsigned long irq_flags;
 
if (!ufshcd_is_clkscaling_supported(hba))
@@ -1186,50 +1225,35 @@ static int ufshcd_devfreq_target(struct device *dev,
return -EINVAL;
}
 
-   scale_up = (*freq == UINT_MAX) ? true : false;
-   if (!ufshcd_is_devfreq_scaling_required(hba, scale_up))
-   return 0; /* no state change required */
-
spin_lock_irqsave(hba->host->host_lock, irq_flags);
if (ufshcd_eh_in_progress(hba)) {
spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
return 0;
}
 
-   if (ufshcd_is_clkgating_allowed(hba)) {
-   if (cancel_delayed_work(&hba->clk_gating.gate_work) ||
-   (hba->clk_gating.state == CLKS_ON)) {
-   /* hold the vote until the scaling work is completed */
-   hba->clk_gating.active_reqs++;
-   release_clk_hold = true;
-   if (hba->clk_gating.state != CLKS_ON) {
-   hba->clk_gating.state = CLKS_ON;
-  

[PATCH v1 4/8] scsi: ufs: add host state prints in failure cases

2017-02-03 Thread Subhash Jadavani
From: Gilad Broner 

Whenever some UFS failure occurs the driver prints the UFS
registers in order to help with analysis of the failure.
However this may not be sufficient in some cases, so having
the host controller state as it is represented and managed in
the driver will contribute to analysis efforts.
Added prints of various fields in the hba struct which may be
of interest.

Signed-off-by: Gilad Broner 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 25 +
 1 file changed, 25 insertions(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index e75e50d..056e912 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -453,6 +453,28 @@ static void ufshcd_print_tmrs(struct ufs_hba *hba, 
unsigned long bitmap)
}
 }
 
+static void ufshcd_print_host_state(struct ufs_hba *hba)
+{
+   dev_err(hba->dev, "UFS Host state=%d\n", hba->ufshcd_state);
+   dev_err(hba->dev, "lrb in use=0x%lx, outstanding reqs=0x%lx 
tasks=0x%lx\n",
+   hba->lrb_in_use, hba->outstanding_tasks, hba->outstanding_reqs);
+   dev_err(hba->dev, "saved_err=0x%x, saved_uic_err=0x%x\n",
+   hba->saved_err, hba->saved_uic_err);
+   dev_err(hba->dev, "Device power mode=%d, UIC link state=%d\n",
+   hba->curr_dev_pwr_mode, hba->uic_link_state);
+   dev_err(hba->dev, "PM in progress=%d, sys. suspended=%d\n",
+   hba->pm_op_in_progress, hba->is_sys_suspended);
+   dev_err(hba->dev, "Auto BKOPS=%d, Host self-block=%d\n",
+   hba->auto_bkops_enabled, hba->host->host_self_blocked);
+   dev_err(hba->dev, "Clk gate=%d\n", hba->clk_gating.state);
+   dev_err(hba->dev, "error handling flags=0x%x, req. abort count=%d\n",
+   hba->eh_flags, hba->req_abort_count);
+   dev_err(hba->dev, "Host capabilities=0x%x, caps=0x%x\n",
+   hba->capabilities, hba->caps);
+   dev_err(hba->dev, "quirks=0x%x, dev. quirks=0x%x\n", hba->quirks,
+   hba->dev_quirks);
+}
+
 /**
  * ufshcd_print_pwr_info - print power params as saved in hba
  * power info
@@ -4426,6 +4448,7 @@ static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 
index, u8 *resp)
"OCS error from controller = %x for tag %d\n",
ocs, lrbp->task_tag);
ufshcd_print_host_regs(hba);
+   ufshcd_print_host_state(hba);
break;
} /* end of switch */
 
@@ -5477,6 +5500,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
scsi_print_command(hba->lrb[tag].cmd);
if (!hba->req_abort_count) {
ufshcd_print_host_regs(hba);
+   ufshcd_print_host_state(hba);
ufshcd_print_pwr_info(hba);
ufshcd_print_trs(hba, 1 << tag, true);
} else {
@@ -7738,6 +7762,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
if (err) {
dev_err(hba->dev, "Host controller enable failed\n");
ufshcd_print_host_regs(hba);
+   ufshcd_print_host_state(hba);
goto out_remove_scsi_host;
}
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 8/8] scsi: ufs: dump hw regs on link failures

2017-02-03 Thread Subhash Jadavani
From: Venkat Gopalakrishnan 

Dump host state, power info and host/vendor specific registers
on link failures. This provides useful info to debug the failures.

Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 12 +++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a99a673..8b721f4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3554,6 +3554,12 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, 
struct uic_command *cmd)
ret = (status != PWR_OK) ? status : -1;
}
 out:
+   if (ret) {
+   ufshcd_print_host_state(hba);
+   ufshcd_print_pwr_info(hba);
+   ufshcd_print_host_regs(hba);
+   }
+
spin_lock_irqsave(hba->host->host_lock, flags);
hba->active_uic_cmd = NULL;
hba->uic_async_done = NULL;
@@ -4146,8 +4152,12 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
 
ret = ufshcd_make_hba_operational(hba);
 out:
-   if (ret)
+   if (ret) {
dev_err(hba->dev, "link startup failed %d\n", ret);
+   ufshcd_print_host_state(hba);
+   ufshcd_print_pwr_info(hba);
+   ufshcd_print_host_regs(hba);
+   }
return ret;
 }
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 6/8] scsi: ufs: kick start clock scaling only after device detection

2017-02-03 Thread Subhash Jadavani
UFS clock scaling might start kicking in even before the device
is running at the fastest interface speed which is undesirable.
This change moves the clock scaling kick start only after the
device is detected and running at the fastest interface speed.

Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufshcd.c | 45 +++--
 1 file changed, 23 insertions(+), 22 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4f6ba24..a99a673 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6330,19 +6330,31 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
if (ufshcd_scsi_add_wlus(hba))
goto out;
 
+   /* Initialize devfreq after UFS device is detected */
+   if (ufshcd_is_clkscaling_supported(hba)) {
+   memcpy(&hba->clk_scaling.saved_pwr_info.info,
+   &hba->pwr_info,
+   sizeof(struct ufs_pa_layer_attr));
+   hba->clk_scaling.saved_pwr_info.is_valid = true;
+   if (!hba->devfreq) {
+   hba->devfreq = devm_devfreq_add_device(hba->dev,
+   &ufs_devfreq_profile,
+   "simple_ondemand",
+   NULL);
+   if (IS_ERR(hba->devfreq)) {
+   ret = PTR_ERR(hba->devfreq);
+   dev_err(hba->dev, "Unable to register 
with devfreq %d\n",
+   ret);
+   goto out;
+   }
+   }
+   hba->clk_scaling.is_allowed = true;
+   }
+
scsi_scan_host(hba->host);
pm_runtime_put_sync(hba->dev);
}
 
-   /* Resume devfreq after UFS device is detected */
-   if (ufshcd_is_clkscaling_supported(hba)) {
-   memcpy(&hba->clk_scaling.saved_pwr_info.info, &hba->pwr_info,
-  sizeof(struct ufs_pa_layer_attr));
-   hba->clk_scaling.saved_pwr_info.is_valid = true;
-   ufshcd_resume_clkscaling(hba);
-   hba->clk_scaling.is_allowed = true;
-   }
-
if (!hba->is_init_prefetch)
hba->is_init_prefetch = true;
 
@@ -6865,7 +6877,8 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
ufshcd_setup_vreg(hba, false);
ufshcd_suspend_clkscaling(hba);
if (ufshcd_is_clkscaling_supported(hba)) {
-   ufshcd_suspend_clkscaling(hba);
+   if (hba->devfreq)
+   ufshcd_suspend_clkscaling(hba);
destroy_workqueue(hba->clk_scaling.workq);
}
ufshcd_setup_clocks(hba, false);
@@ -7859,16 +7872,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
if (ufshcd_is_clkscaling_supported(hba)) {
char wq_name[sizeof("ufs_clkscaling_00")];
 
-   hba->devfreq = devm_devfreq_add_device(dev, 
&ufs_devfreq_profile,
-  "simple_ondemand", NULL);
-   if (IS_ERR(hba->devfreq)) {
-   dev_err(hba->dev, "Unable to register with devfreq 
%ld\n",
-   PTR_ERR(hba->devfreq));
-   err = PTR_ERR(hba->devfreq);
-   goto out_remove_scsi_host;
-   }
-   hba->clk_scaling.is_suspended = false;
-
INIT_WORK(&hba->clk_scaling.suspend_work,
  ufshcd_clk_scaling_suspend_work);
INIT_WORK(&hba->clk_scaling.resume_work,
@@ -7878,8 +7881,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem 
*mmio_base, unsigned int irq)
 host->host_no);
hba->clk_scaling.workq = create_singlethread_workqueue(wq_name);
 
-   /* Suspend devfreq until the UFS device is detected */
-   ufshcd_suspend_clkscaling(hba);
ufshcd_clkscaling_init_sysfs(hba);
}
 
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



[PATCH v1 7/8] scsi: ufs-qcom: dump additional testbus registers

2017-02-03 Thread Subhash Jadavani
From: Venkat Gopalakrishnan 

Change testbus default config, dump additional testbus registers along
with other debug vendor specific registers. These additional info are
useful in debugging link related failures.

Signed-off-by: Venkat Gopalakrishnan 
Signed-off-by: Subhash Jadavani 
---
 drivers/scsi/ufs/ufs-qcom.c | 48 +++--
 drivers/scsi/ufs/ufs-qcom.h |  1 +
 2 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 5ff8a6b..ce5d023 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1497,17 +1497,21 @@ static void ufs_qcom_print_hw_debug_reg_all(struct 
ufs_hba *hba,
 
 static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
 {
-   if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+   if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN) {
+   ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN,
+   UFS_REG_TEST_BUS_EN, REG_UFS_CFG1);
ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
-   else
+   } else {
+   ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN, 0, REG_UFS_CFG1);
ufshcd_rmwl(host->hba, TEST_BUS_EN, 0, REG_UFS_CFG1);
+   }
 }
 
 static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
 {
/* provide a legal default configuration */
-   host->testbus.select_major = TSTBUS_UAWM;
-   host->testbus.select_minor = 1;
+   host->testbus.select_major = TSTBUS_UNIPRO;
+   host->testbus.select_minor = 37;
 }
 
 static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
@@ -1524,7 +1528,7 @@ static bool ufs_qcom_testbus_cfg_is_ok(struct 
ufs_qcom_host *host)
 * mappings of select_minor, since there is no harm in
 * configuring a non-existent select_minor
 */
-   if (host->testbus.select_minor > 0x1F) {
+   if (host->testbus.select_minor > 0xFF) {
dev_err(host->hba->dev,
"%s: 0x%05X is not a legal testbus option\n",
__func__, host->testbus.select_minor);
@@ -1593,7 +1597,8 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
break;
case TSTBUS_UNIPRO:
reg = UFS_UNIPRO_CFG;
-   offset = 1;
+   offset = 20;
+   mask = 0xFFF;
break;
/*
 * No need for a default case, since
@@ -1612,6 +1617,11 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
(u32)host->testbus.select_minor << offset,
reg);
ufs_qcom_enable_test_bus(host);
+   /*
+* Make sure the test bus configuration is
+* committed before returning.
+*/
+   mb();
ufshcd_release(host->hba);
pm_runtime_put_sync(host->hba->dev);
 
@@ -1623,13 +1633,39 @@ static void ufs_qcom_testbus_read(struct ufs_hba *hba)
ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS ");
 }
 
+static void ufs_qcom_print_unipro_testbus(struct ufs_hba *hba)
+{
+   struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+   u32 *testbus = NULL;
+   int i, nminor = 256, testbus_len = nminor * sizeof(u32);
+
+   testbus = kmalloc(testbus_len, GFP_KERNEL);
+   if (!testbus)
+   return;
+
+   host->testbus.select_major = TSTBUS_UNIPRO;
+   for (i = 0; i < nminor; i++) {
+   host->testbus.select_minor = i;
+   ufs_qcom_testbus_config(host);
+   testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS);
+   }
+   print_hex_dump(KERN_ERR, "UNIPRO_TEST_BUS ", DUMP_PREFIX_OFFSET,
+   16, 4, testbus, testbus_len, false);
+   kfree(testbus);
+}
+
 static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
 {
ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
"HCI Vendor Specific Registers ");
 
+   /* sleep a bit intermittently as we are dumping too much data */
ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
+   usleep_range(1000, 1100);
ufs_qcom_testbus_read(hba);
+   usleep_range(1000, 1100);
+   ufs_qcom_print_unipro_testbus(hba);
+   usleep_range(1000, 1100);
 }
 
 /**
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index fe517cd..076f528 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -95,6 +95,7 @@ enum {
 #define QUNIPRO_SELUFS_BIT(0)
 #define TEST_BUS_ENBIT(18)
 #define TEST_BUS_SEL   GENMASK(22, 19)
+#define UFS_REG_TEST_BUS_ENBIT(30)
 
 /* bit definitions for REG_UFS_CFG2 register */
 #define UAWM_HW_CGC_EN (1 << 0)
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project



Re: [REGRESSION v4.10-rc1] blkdev_issue_zeroout() returns -EREMOTEIO on the first call for SCSI device that doesn't support WRITE SAME

2017-02-03 Thread Jens Axboe
On 02/03/2017 03:45 PM, Martin K. Petersen wrote:
>> "Jens" == Jens Axboe  writes:
> 
>>> I think we should fix sd.c to only send WRITE SAME if either of the
>>> variants are explicitly listed as supported through REPORT SUPPORTED
>>> OPERATION CODES, or maybe through a whitelist if there are important
>>> enough devices.
> 
> Jens> Yep
> 
> I hate it too. But the reason it's assumed on is that there is
> essentially no heuristic that works. Just like we assume that READ
> always works.
> 
> Out of the ~200 devices I have access to in the lab:
> 
>  - 100% of the SAS/FC disk drives and SSDs support WRITE SAME
>  - Only 2 out of about 50 different drive models support RSOC
>  - About half of the arrays support WRITE SAME(10/16)
>  - None of the arrays I have support RSOC
> 
> So even if we were to entertain using RSOC for "enterprise" transport
> classes (which I concur would be nice for other reasons), it wouldn't
> solve the WRITE SAME problem...

We're at (almost) -rc7 time, we have to do more than hand wave about
this. What's the plan for 4.10 final?


-- 
Jens Axboe



[PATCH] net-next: treewide use is_vlan_dev() helper function.

2017-02-03 Thread Parav Pandit
This patch makes use of is_vlan_dev() function instead of flag
comparison which is exactly done by is_vlan_dev() helper function.

Signed-off-by: Parav Pandit 
Reviewed-by: Daniel Jurgens 
---
 drivers/infiniband/core/cma.c|  6 ++
 drivers/infiniband/sw/rxe/rxe_net.c  |  2 +-
 drivers/net/ethernet/broadcom/cnic.c |  2 +-
 drivers/net/ethernet/chelsio/cxgb3/l2t.c |  2 +-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c  |  4 ++--
 drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c |  8 
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c |  4 ++--
 drivers/net/hyperv/netvsc_drv.c  |  2 +-
 drivers/scsi/bnx2fc/bnx2fc_fcoe.c|  6 +++---
 drivers/scsi/cxgbi/libcxgbi.c|  6 +++---
 drivers/scsi/fcoe/fcoe.c | 13 ++---
 include/rdma/ib_addr.h   |  6 ++
 net/hsr/hsr_slave.c  |  3 ++-
 13 files changed, 30 insertions(+), 34 deletions(-)

diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 3e70a9c..4eb5a80 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -2467,14 +2467,12 @@ static int iboe_tos_to_sl(struct net_device *ndev, int 
tos)
struct net_device *dev;
 
prio = rt_tos2priority(tos);
-   dev = ndev->priv_flags & IFF_802_1Q_VLAN ?
-   vlan_dev_real_dev(ndev) : ndev;
-
+   dev = is_vlan_dev(ndev) ? vlan_dev_real_dev(ndev) : ndev;
if (dev->num_tc)
return netdev_get_prio_tc_map(dev, prio);
 
 #if IS_ENABLED(CONFIG_VLAN_8021Q)
-   if (ndev->priv_flags & IFF_802_1Q_VLAN)
+   if (is_vlan_dev(ndev))
return (vlan_dev_get_egress_qos_mask(ndev, prio) &
VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
 #endif
diff --git a/drivers/infiniband/sw/rxe/rxe_net.c 
b/drivers/infiniband/sw/rxe/rxe_net.c
index 4abdeb3..d9d1556 100644
--- a/drivers/infiniband/sw/rxe/rxe_net.c
+++ b/drivers/infiniband/sw/rxe/rxe_net.c
@@ -118,7 +118,7 @@ static struct device *dma_device(struct rxe_dev *rxe)
 
ndev = rxe->ndev;
 
-   if (ndev->priv_flags & IFF_802_1Q_VLAN)
+   if (is_vlan_dev(ndev))
ndev = vlan_dev_real_dev(ndev);
 
return ndev->dev.parent;
diff --git a/drivers/net/ethernet/broadcom/cnic.c 
b/drivers/net/ethernet/broadcom/cnic.c
index b1d2ac8..cec94bb 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -3665,7 +3665,7 @@ static int cnic_cm_destroy(struct cnic_sock *csk)
 static inline u16 cnic_get_vlan(struct net_device *dev,
struct net_device **vlan_dev)
 {
-   if (dev->priv_flags & IFF_802_1Q_VLAN) {
+   if (is_vlan_dev(dev)) {
*vlan_dev = vlan_dev_real_dev(dev);
return vlan_dev_vlan_id(dev);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/l2t.c 
b/drivers/net/ethernet/chelsio/cxgb3/l2t.c
index 5f226ed..5206358 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/l2t.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/l2t.c
@@ -351,7 +351,7 @@ struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct 
dst_entry *dst,
e->smt_idx = smt_idx;
atomic_set(&e->refcnt, 1);
neigh_replace(e, neigh);
-   if (neigh->dev->priv_flags & IFF_802_1Q_VLAN)
+   if (is_vlan_dev(neigh->dev))
e->vlan = vlan_dev_vlan_id(neigh->dev);
else
e->vlan = VLAN_NONE;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c 
b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index f4f5690..7059014 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -1805,7 +1805,7 @@ static void check_neigh_update(struct neighbour *neigh)
const struct device *parent;
const struct net_device *netdev = neigh->dev;
 
-   if (netdev->priv_flags & IFF_802_1Q_VLAN)
+   if (is_vlan_dev(netdev))
netdev = vlan_dev_real_dev(netdev);
parent = netdev->dev.parent;
if (parent && parent->driver == &cxgb4_driver.driver)
@@ -2111,7 +2111,7 @@ static int cxgb4_inet6addr_handler(struct notifier_block 
*this,
 #if IS_ENABLED(CONFIG_BONDING)
struct adapter *adap;
 #endif
-   if (event_dev->priv_flags & IFF_802_1Q_VLAN)
+   if (is_vlan_dev(event_dev))
event_dev = vlan_dev_real_dev(event_dev);
 #if IS_ENABLED(CONFIG_BONDING)
if (event_dev->flags & IFF_MASTER) {
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c 
b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 0cf8a37..3b5d7cf 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -3264,7 +3264,7 @@ static ssize_t

Re: [PATCH] net-next: treewide use is_vlan_dev() helper function.

2017-02-03 Thread Joe Perches
On Fri, 2017-02-03 at 22:26 -0600, Parav Pandit wrote:
> This patch makes use of is_vlan_dev() function instead of flag
> comparison which is exactly done by is_vlan_dev() helper function.

Thanks.

btw:  after applying this patch, there is one left

$ git grep -E -n "&\s*IFF_802_1Q_VLAN\b" -- "*.c"
drivers/net/ethernet/chelsio/cxgb4/l2t.c:435:   if (neigh->dev->priv_flags & 
IFF_802_1Q_VLAN)