[PATCH 19/20] scsi_dh_alua: update 'access_state' field

2015-12-07 Thread Hannes Reinecke
Track attached SCSI devices and update the 'access_state' field
whenever an ALUA state change has been detected.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 29 +
 1 file changed, 29 insertions(+)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6c6ff0b..d01c86407 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -76,6 +77,7 @@ static struct workqueue_struct *kaluad_wq;
 struct alua_port_group {
struct kref kref;
struct list_headnode;
+   struct list_headdh_list;
unsigned char   device_id_str[256];
int device_id_len;
int group_id;
@@ -93,6 +95,7 @@ struct alua_port_group {
 };
 
 struct alua_dh_data {
+   struct list_headnode;
struct alua_port_group  *pg;
int rel_port;
spinlock_t  pg_lock;
@@ -243,6 +246,7 @@ struct alua_port_group *alua_get_pg(struct scsi_device 
*sdev,
INIT_DELAYED_WORK(>rtpg_work, alua_rtpg_work);
INIT_LIST_HEAD(>rtpg_list);
INIT_LIST_HEAD(>node);
+   INIT_LIST_HEAD(>dh_list);
spin_lock_init(>lock);
 
/* Re-check list again to catch concurrent updates */
@@ -370,13 +374,26 @@ static int alua_check_vpd(struct scsi_device *sdev, 
struct alua_dh_data *h,
old_pg = pg;
/* port_group has changed. Update to new port group */
if (h->pg != pg) {
+   unsigned long flags;
+
old_pg = h->pg;
rcu_assign_pointer(h->pg, pg);
+   spin_lock_irqsave(_pg->lock, flags);
+   list_del_rcu(>node);
+   spin_unlock_irqrestore(_pg->lock, flags);
+   spin_lock_irqsave(>lock, flags);
+   list_add_rcu(>node, >dh_list);
+   spin_unlock_irqrestore(>lock, flags);
h->pg->expiry = 0;
pg_found = true;
}
} else {
+   unsigned long flags;
+
rcu_assign_pointer(h->pg, pg);
+   spin_lock_irqsave(>lock, flags);
+   list_add_rcu(>node, >dh_list);
+   spin_unlock_irqrestore(>lock, flags);
pg_found = true;
}
alua_rtpg_queue(h->pg, sdev, NULL, true);
@@ -630,6 +647,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg)
 
spin_lock_irqsave(_group_lock, flags);
list_for_each_entry(tmp_pg, _group_list, node) {
+   struct alua_dh_data *h;
+
if (tmp_pg->group_id != group_id)
continue;
if (tmp_pg->device_id_len != pg->device_id_len)
@@ -639,6 +658,12 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg)
continue;
tmp_pg->state = desc[0] & 0x0f;
tmp_pg->pref = desc[0] >> 7;
+   rcu_read_lock();
+   list_for_each_entry_rcu(h, _pg->dh_list, node) {
+   if (h->sdev)
+   h->sdev->access_state = desc[0];
+   }
+   rcu_read_unlock();
if (tmp_pg == pg)
valid_states = desc[1];
}
@@ -1056,6 +1081,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
h->rel_port = -1;
h->init_error = SCSI_DH_OK;
h->sdev = sdev;
+   INIT_LIST_HEAD(>node);
 
mutex_init(>init_mutex);
err = alua_initialize(sdev, h);
@@ -1086,6 +1112,9 @@ static void alua_bus_detach(struct scsi_device *sdev)
h->sdev = NULL;
spin_unlock(>pg_lock);
if (pg) {
+   spin_lock(>lock);
+   list_del_rcu(>node);
+   spin_unlock(>lock);
synchronize_rcu();
if (pg->rtpg_sdev)
flush_delayed_work(>rtpg_work);
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 12/20] scsi_dh_alua: Allow workqueue to run synchronously

2015-12-07 Thread Hannes Reinecke
Some arrays may only capable of handling one STPG at a time,
so this patch implements a module option 'sync_stpg' to have
STPGs submitted synchronously.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6fcdcd5..525449f 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -73,6 +73,10 @@ static uint optimize_stpg;
 module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather 
than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 
0.");
 
+static uint sync_stpg;
+module_param(sync_stpg, uint, S_IRUGO);
+MODULE_PARM_DESC(sync_stpg, "Issue STPG synchronously (0=No,1=Yes). Default is 
0.");
+
 static LIST_HEAD(port_group_list);
 static DEFINE_SPINLOCK(port_group_lock);
 static struct workqueue_struct *kaluad_wq;
@@ -1019,9 +1023,11 @@ static struct scsi_device_handler alua_dh = {
 
 static int __init alua_init(void)
 {
-   int r;
+   int r, max_active = 0;
 
-   kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM, 0);
+   if (sync_stpg)
+   max_active = 1;
+   kaluad_wq = alloc_workqueue("kaluad", WQ_MEM_RECLAIM, max_active);
if (!kaluad_wq) {
/* Temporary failure, bypass */
return SCSI_DH_DEV_TEMP_BUSY;
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 11/20] scsi_dh_alua: Use workqueue for RTPG

2015-12-07 Thread Hannes Reinecke
The current ALUA device_handler has two drawbacks:
- We're sending a 'SET TARGET PORT GROUP' command to every LUN,
  disregarding the fact that several LUNs might be in a port group
  and will be automatically switched whenever _any_ LUN within
  that port group receives the command.
- Whenever a LUN is in 'transitioning' mode we cannot block I/O
  to that LUN, instead the controller has to abort the command.
  This leads to increased traffic across the wire and heavy load
  on the controller during switchover.

With this patch the RTPG handling is moved to a per-portgroup
workqueue. This reduces the number of 'REPORT TARGET PORT GROUP'
and 'SET TARGET PORT GROUPS' sent to the controller as we're sending
them now per port group, and not per device as previously.
It also allows us to block I/O to any LUN / port group found to be
in 'transitioning' ALUA mode, as the workqueue item will be requeued
until the controller moves out of transitioning.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 331 +++--
 1 file changed, 270 insertions(+), 61 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 8d80ac6..6fcdcd5 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -59,13 +59,23 @@
 #define ALUA_RTPG_SIZE 128
 #define ALUA_FAILOVER_TIMEOUT  60
 #define ALUA_FAILOVER_RETRIES  5
+#define ALUA_RTPG_DELAY_MSECS  5
 
 /* device handler flags */
-#define ALUA_OPTIMIZE_STPG 1
-#define ALUA_RTPG_EXT_HDR_UNSUPP   2
+#define ALUA_OPTIMIZE_STPG 0x01
+#define ALUA_RTPG_EXT_HDR_UNSUPP   0x02
+/* State machine flags */
+#define ALUA_PG_RUN_RTPG   0x10
+#define ALUA_PG_RUN_STPG   0x20
+#define ALUA_PG_RUNNING0x40
+
+static uint optimize_stpg;
+module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather 
than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 
0.");
 
 static LIST_HEAD(port_group_list);
 static DEFINE_SPINLOCK(port_group_lock);
+static struct workqueue_struct *kaluad_wq;
 
 struct alua_port_group {
struct kref kref;
@@ -78,12 +88,25 @@ struct alua_port_group {
int pref;
unsignedflags; /* used for optimizing STPG */
unsigned char   transition_tmo;
+   unsigned long   expiry;
+   unsigned long   interval;
+   struct delayed_work rtpg_work;
+   spinlock_t  lock;
+   struct list_headrtpg_list;
+   struct scsi_device  *rtpg_sdev;
 };
 
 struct alua_dh_data {
struct alua_port_group  *pg;
int rel_port;
+   spinlock_t  pg_lock;
struct scsi_device  *sdev;
+   int init_error;
+   struct mutexinit_mutex;
+};
+
+struct alua_queue_data {
+   struct list_headentry;
activate_complete   callback_fn;
void*callback_data;
 };
@@ -91,8 +114,10 @@ struct alua_dh_data {
 #define ALUA_POLICY_SWITCH_CURRENT 0
 #define ALUA_POLICY_SWITCH_ALL 1
 
-static int alua_rtpg(struct scsi_device *, struct alua_port_group *);
-static char print_alua_state(int);
+static void alua_rtpg_work(struct work_struct *work);
+static void alua_rtpg_queue(struct alua_port_group *pg,
+   struct scsi_device *sdev,
+   struct alua_queue_data *qdata);
 
 static void release_port_group(struct kref *kref)
 {
@@ -102,6 +127,7 @@ static void release_port_group(struct kref *kref)
spin_lock(_group_lock);
list_del(>node);
spin_unlock(_group_lock);
+   WARN_ON(pg->rtpg_sdev);
kfree(pg);
 }
 
@@ -167,7 +193,7 @@ static int submit_stpg(struct scsi_device *sdev, int 
group_id,
 struct alua_port_group *alua_lookup_pg(char *id_str, size_t id_size,
   int group_id)
 {
-   struct alua_port_group *pg = NULL;
+   struct alua_port_group *pg;
 
list_for_each_entry(pg, _group_list, node) {
if (pg->group_id != group_id)
@@ -214,18 +240,26 @@ struct alua_port_group *alua_get_pg(struct scsi_device 
*sdev,
pg->group_id = group_id;
pg->tpgs = tpgs;
pg->state = TPGS_STATE_OPTIMIZED;
+   if (optimize_stpg)
+   pg->flags |= ALUA_OPTIMIZE_STPG;
kref_init(>kref);
+   INIT_DELAYED_WORK(>rtpg_work, alua_rtpg_work);
+   INIT_LIST_HEAD(>rtpg_list);
+   INIT_LIST_HEAD(>node);
+   spin_lock_init(>lock);
 
/* Re-check list again to catch concurrent updates */
spin_lock(_group_lock);
tmp_pg = alua_lookup_pg(id_str, id_size, group_id);
if 

[PATCH v2 78/71] ncr5380: Add support for HP 53C400A-based cards (C2502)

2015-12-07 Thread Ondrej Zary
HP C2502 cards (based on 53C400A chips) use different magic numbers for
software-based I/O address configuration than other cards.
The configuration is also extended to allow setting the IRQ.

Move the configuration to a new function magic_configure() and move
magic the magic numbers into an array. Add new magic numbers for these
HP cards and hp_53c400a module parameter to use them.

Tested with HP C2502 and DTCT-436P.

Signed-off-by: Ondrej Zary 
---
 drivers/scsi/g_NCR5380.c |   76 --
 drivers/scsi/g_NCR5380.h |1 +
 2 files changed, 61 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 42fdeaf..121d143 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -80,6 +80,7 @@ static int ncr_5380;
 static int ncr_53c400;
 static int ncr_53c400a;
 static int dtc_3181e;
+static int hp_53c400a;
 
 static struct override {
NCR5380_map_type NCR5380_map_name;
@@ -225,6 +226,32 @@ static int __init do_DTC3181E_setup(char *str)
 
 #endif
 
+#ifndef SCSI_G_NCR5380_MEM
+/*
+ * Configure I/O address of 53C400A or DTC 3181 by writing magic numbers
+ * to ports 0x779 and 0x379. Two magic number sequences are known:
+ *  1. for generic NCR 53C400A-based cards and DTC436 chips
+ *  2. for HP C2502 card (also based on 53C400A but different decode logic)
+ */
+static void magic_configure(int idx, u8 irq, u8 magic[])
+{
+   u8 cfg = 0;
+
+   outb(magic[0], 0x779);
+   outb(magic[1], 0x379);
+   outb(magic[2], 0x379);
+   outb(magic[3], 0x379);
+   outb(magic[4], 0x379);
+
+   /* allowed IRQs for HP 53C400A */
+   if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7)
+   irq = 0;
+   if (idx >= 0 && idx <= 7)
+   cfg = 0x80 | idx | (irq << 4);
+   outb(cfg, 0x379);
+}
+#endif
+
 /**
  * generic_NCR5380_detect  -   look for NCR5380 controllers
  * @tpnt: the scsi template
@@ -241,8 +268,9 @@ static int __init generic_NCR5380_detect(struct 
scsi_host_template *tpnt)
static int current_override;
int count;
unsigned int *ports;
+   u8 *magic;
 #ifndef SCSI_G_NCR5380_MEM
-   int i;
+   int i, port_idx;
unsigned long region_size = 16;
 #endif
static unsigned int __initdata ncr_53c400a_ports[] = {
@@ -251,6 +279,12 @@ static int __init generic_NCR5380_detect(struct 
scsi_host_template *tpnt)
static unsigned int __initdata dtc_3181e_ports[] = {
0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0
};
+   static u8 ncr_53c400a_magic[] __initdata = {/* 53C400A & DTC 3181 */
+   0x59, 0xb9, 0xc5, 0xae, 0xa6
+   };
+   static u8 hp_53c400a_magic[] __initdata = { /* HP C2502 */
+   0x0f, 0x22, 0xf0, 0x20, 0x80
+   };
int flags;
struct Scsi_Host *instance;
struct NCR5380_hostdata *hostdata;
@@ -273,6 +307,8 @@ static int __init generic_NCR5380_detect(struct 
scsi_host_template *tpnt)
overrides[0].board = BOARD_NCR53C400A;
else if (dtc_3181e)
overrides[0].board = BOARD_DTC3181E;
+   else if (hp_53c400a)
+   overrides[0].board = BOARD_HP53C400A;
 #ifndef SCSI_G_NCR5380_MEM
if (!current_override && isapnp_present()) {
struct pnp_dev *dev = NULL;
@@ -326,10 +362,17 @@ static int __init generic_NCR5380_detect(struct 
scsi_host_template *tpnt)
case BOARD_NCR53C400A:
flags = FLAG_NO_DMA_FIXUP;
ports = ncr_53c400a_ports;
+   magic = ncr_53c400a_magic;
+   break;
+   case BOARD_HP53C400A:
+   flags = FLAG_NO_DMA_FIXUP;
+   ports = ncr_53c400a_ports;
+   magic = hp_53c400a_magic;
break;
case BOARD_DTC3181E:
flags = FLAG_NO_DMA_FIXUP;
ports = dtc_3181e_ports;
+   magic = ncr_53c400a_magic;
break;
}
 
@@ -338,12 +381,7 @@ static int __init generic_NCR5380_detect(struct 
scsi_host_template *tpnt)
/* wakeup sequence for the NCR53C400A and DTC3181E */
 
/* Disable the adapter and look for a free io port */
-   outb(0x59, 0x779);
-   outb(0xb9, 0x379);
-   outb(0xc5, 0x379);
-   outb(0xae, 0x379);
-   outb(0xa6, 0x379);
-   outb(0x00, 0x379);
+   magic_configure(-1, 0, magic);
 
if (overrides[current_override].NCR5380_map_name != 
PORT_AUTO)
for (i = 0; ports[i]; i++) {
@@ -362,17 +400,14 @@ static int __init 

[PATCH 07/20] scsi_dh_alua: allocate RTPG buffer separately

2015-12-07 Thread Hannes Reinecke
The RTPG buffer will only evaluated within alua_rtpg(),
so we can allocate it locally there and avoid having to
put it into the global structure.

Reviewed-by: Ewan Milne 
Reviewed-by: Christoph Hellwig 
Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 56 +++---
 1 file changed, 21 insertions(+), 35 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index f3191f7..ca6322d 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -56,7 +56,7 @@
 #define TPGS_MODE_IMPLICIT 0x1
 #define TPGS_MODE_EXPLICIT 0x2
 
-#define ALUA_INQUIRY_SIZE  36
+#define ALUA_RTPG_SIZE 128
 #define ALUA_FAILOVER_TIMEOUT  60
 #define ALUA_FAILOVER_RETRIES  5
 
@@ -75,9 +75,6 @@ struct alua_port_group {
int state;
int pref;
unsignedflags; /* used for optimizing STPG */
-   unsigned char   inq[ALUA_INQUIRY_SIZE];
-   unsigned char   *buff;
-   int bufflen;
unsigned char   transition_tmo;
 };
 
@@ -95,21 +92,6 @@ struct alua_dh_data {
 
 static char print_alua_state(int);
 
-static int realloc_buffer(struct alua_port_group *pg, unsigned len)
-{
-   if (pg->buff && pg->buff != pg->inq)
-   kfree(pg->buff);
-
-   pg->buff = kmalloc(len, GFP_NOIO);
-   if (!pg->buff) {
-   pg->buff = pg->inq;
-   pg->bufflen = ALUA_INQUIRY_SIZE;
-   return 1;
-   }
-   pg->bufflen = len;
-   return 0;
-}
-
 static void release_port_group(struct kref *kref)
 {
struct alua_port_group *pg;
@@ -118,8 +100,6 @@ static void release_port_group(struct kref *kref)
spin_lock(_group_lock);
list_del(>node);
spin_unlock(_group_lock);
-   if (pg->buff && pg->inq != pg->buff)
-   kfree(pg->buff);
kfree(pg);
 }
 
@@ -201,8 +181,6 @@ struct alua_port_group *alua_get_pg(struct scsi_device 
*sdev,
return NULL;
 
pg->group_id = group_id;
-   pg->buff = pg->inq;
-   pg->bufflen = ALUA_INQUIRY_SIZE;
pg->tpgs = tpgs;
pg->state = TPGS_STATE_OPTIMIZED;
kref_init(>kref);
@@ -387,8 +365,8 @@ static int alua_check_sense(struct scsi_device *sdev,
 static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int 
wait_for_transition)
 {
struct scsi_sense_hdr sense_hdr;
-   int len, k, off, valid_states = 0;
-   unsigned char *ucp;
+   int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
+   unsigned char *ucp, *buff;
unsigned err, retval;
unsigned long expiry, interval = 0;
unsigned int tpg_desc_tbl_off;
@@ -399,15 +377,19 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg, int w
else
expiry = round_jiffies_up(jiffies + pg->transition_tmo * HZ);
 
+   buff = kzalloc(bufflen, GFP_KERNEL);
+   if (!buff)
+   return SCSI_DH_DEV_TEMP_BUSY;
+
  retry:
-   retval = submit_rtpg(sdev, pg->buff, pg->bufflen,
-_hdr, pg->flags);
+   retval = submit_rtpg(sdev, buff, bufflen, _hdr, pg->flags);
 
if (retval) {
if (!scsi_sense_valid(_hdr)) {
sdev_printk(KERN_INFO, sdev,
"%s: rtpg failed, result %d\n",
ALUA_DH_NAME, retval);
+   kfree(buff);
if (driver_byte(retval) == DRIVER_ERROR)
return SCSI_DH_DEV_TEMP_BUSY;
return SCSI_DH_IO;
@@ -445,14 +427,18 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg, int w
sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
ALUA_DH_NAME);
scsi_print_sense_hdr(sdev, ALUA_DH_NAME, _hdr);
+   kfree(buff);
return SCSI_DH_IO;
}
 
-   len = get_unaligned_be32(>buff[0]) + 4;
+   len = get_unaligned_be32([0]) + 4;
 
-   if (len > pg->bufflen) {
+   if (len > bufflen) {
/* Resubmit with the correct length */
-   if (realloc_buffer(pg, len)) {
+   kfree(buff);
+   bufflen = len;
+   buff = kmalloc(bufflen, GFP_KERNEL);
+   if (!buff) {
sdev_printk(KERN_WARNING, sdev,
"%s: kmalloc buffer failed\n",__func__);
/* Temporary failure, bypass */
@@ -462,9 +448,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg, int w
}
 
orig_transition_tmo = 

[PATCH 13/20] scsi_dh_alua: Recheck state on unit attention

2015-12-07 Thread Hannes Reinecke
When we receive a unit attention code of 'ALUA state changed'
we should recheck the state, as it might be due to an implicit
ALUA state transition. This allows us to return NEEDS_RETRY
instead of ADD_TO_MLQUEUE, allowing to terminate the retries
after a certain time.
At the same time a workqueue item might already be queued, which
should be started immediately to avoid any delays.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 58 --
 1 file changed, 47 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 525449f..04a3a543 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -121,7 +121,8 @@ struct alua_queue_data {
 static void alua_rtpg_work(struct work_struct *work);
 static void alua_rtpg_queue(struct alua_port_group *pg,
struct scsi_device *sdev,
-   struct alua_queue_data *qdata);
+   struct alua_queue_data *qdata, bool force);
+static void alua_check(struct scsi_device *sdev, bool force);
 
 static void release_port_group(struct kref *kref)
 {
@@ -386,7 +387,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct 
alua_dh_data *h,
rcu_assign_pointer(h->pg, pg);
pg_found = true;
}
-   alua_rtpg_queue(h->pg, sdev, NULL);
+   alua_rtpg_queue(h->pg, sdev, NULL, true);
spin_unlock(>pg_lock);
 
if (pg_found)
@@ -427,18 +428,24 @@ static int alua_check_sense(struct scsi_device *sdev,
 {
switch (sense_hdr->sense_key) {
case NOT_READY:
-   if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a)
+   if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) {
/*
 * LUN Not Accessible - ALUA state transition
 */
-   return ADD_TO_MLQUEUE;
+   alua_check(sdev, false);
+   return NEEDS_RETRY;
+   }
break;
case UNIT_ATTENTION:
-   if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
+   if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) {
/*
-* Power On, Reset, or Bus Device Reset, just retry.
+* Power On, Reset, or Bus Device Reset.
+* Might have obscured a state transition,
+* so schedule a recheck.
 */
+   alua_check(sdev, true);
return ADD_TO_MLQUEUE;
+   }
if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x04)
/*
 * Device internal reset
@@ -449,16 +456,20 @@ static int alua_check_sense(struct scsi_device *sdev,
 * Mode Parameters Changed
 */
return ADD_TO_MLQUEUE;
-   if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06)
+   if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
/*
 * ALUA state changed
 */
+   alua_check(sdev, true);
return ADD_TO_MLQUEUE;
-   if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07)
+   }
+   if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
/*
 * Implicit ALUA state transition failed
 */
+   alua_check(sdev, true);
return ADD_TO_MLQUEUE;
+   }
if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03)
/*
 * Inquiry data has changed
@@ -777,7 +788,7 @@ static void alua_rtpg_work(struct work_struct *work)
 
 static void alua_rtpg_queue(struct alua_port_group *pg,
struct scsi_device *sdev,
-   struct alua_queue_data *qdata)
+   struct alua_queue_data *qdata, bool force)
 {
int start_queue = 0;
unsigned long flags;
@@ -797,7 +808,9 @@ static void alua_rtpg_queue(struct alua_port_group *pg,
pg->rtpg_sdev = sdev;
scsi_device_get(sdev);
start_queue = 1;
-   }
+   } else if (!(pg->flags & ALUA_PG_RUN_RTPG) && force)
+   start_queue = 1;
+
spin_unlock_irqrestore(>lock, flags);
 
if (start_queue &&
@@ -912,7 +925,7 @@ static int alua_activate(struct scsi_device *sdev,
kref_get(>kref);
rcu_read_unlock();
 
-   alua_rtpg_queue(pg, sdev, qdata);
+   alua_rtpg_queue(pg, sdev, qdata, true);

[PATCH 09/20] scsi_dh_alua: simplify alua_initialize()

2015-12-07 Thread Hannes Reinecke
Rework alua_check_vpd() to use scsi_vpd_get_tpg()
and move the port group selection into the function, too.
With that we can simplify alua_initialize() to just
call alua_check_tpgs() and alua_check_vpd();

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 70 +-
 1 file changed, 29 insertions(+), 41 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 688e0f7..1eacf3f 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -82,7 +82,6 @@ struct alua_port_group {
 
 struct alua_dh_data {
struct alua_port_group  *pg;
-   int group_id;
int rel_port;
struct scsi_device  *sdev;
activate_complete   callback_fn;
@@ -92,6 +91,7 @@ struct alua_dh_data {
 #define ALUA_POLICY_SWITCH_CURRENT 0
 #define ALUA_POLICY_SWITCH_ALL 1
 
+static int alua_rtpg(struct scsi_device *, struct alua_port_group *, int);
 static char print_alua_state(int);
 
 static void release_port_group(struct kref *kref)
@@ -288,10 +288,15 @@ static int alua_check_tpgs(struct scsi_device *sdev)
  *
  * Extract the relative target port and the target port group
  * descriptor from the list of identificators.
+ *
+ * Returns 0 or SCSI_DH_ error code on failure.
  */
-static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h,
+ int tpgs)
 {
int rel_port = -1, group_id;
+   char id_str[256];
+   int id_size;
 
group_id = scsi_vpd_tpg_id(sdev, _port);
if (group_id < 0) {
@@ -305,14 +310,28 @@ static int alua_check_vpd(struct scsi_device *sdev, 
struct alua_dh_data *h)
ALUA_DH_NAME);
return SCSI_DH_DEV_UNSUPP;
}
-   h->state = TPGS_STATE_OPTIMIZED;
-   h->group_id = group_id;
+   h->rel_port = rel_port;
 
+   id_size = scsi_vpd_lun_id(sdev, id_str, 256);
+   if (id_size <= 0) {
+   /*
+* Internal error: TPGS supported but no device
+* identifcation found. Disable ALUA support.
+*/
+   sdev_printk(KERN_INFO, sdev,
+   "%s: No device descriptors found\n",
+   ALUA_DH_NAME);
+   return SCSI_DH_DEV_UNSUPP;
+   }
sdev_printk(KERN_INFO, sdev,
-   "%s: port group %02x rel port %02x\n",
-   ALUA_DH_NAME, h->group_id, h->rel_port);
+   "%s: device %s port group %02x rel port %02x\n",
+   ALUA_DH_NAME, id_str, group_id, h->rel_port);
 
-   return 0;
+   h->pg = alua_get_pg(sdev, group_id, tpgs, id_str, id_size);
+   if (!h->pg)
+   return SCSI_DH_NOMEM;
+
+   return alua_rtpg(sdev, h->pg, 0);
 }
 
 static char print_alua_state(int state)
@@ -631,45 +650,14 @@ static unsigned alua_stpg(struct scsi_device *sdev, 
struct alua_port_group *pg)
 static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
 {
int err = SCSI_DH_DEV_UNSUPP, tpgs;
-   char device_id_str[256];
-   int device_id_len;
 
tpgs = alua_check_tpgs(sdev);
-   if (tpgs == TPGS_MODE_NONE)
-   goto out;
-
-   err = alua_check_vpd(sdev, h);
-   if (err != SCSI_DH_OK)
-   goto out;
+   if (tpgs != TPGS_MODE_NONE)
+   err = alua_check_vpd(sdev, h, tpgs);
 
-   device_id_len = scsi_vpd_lun_id(sdev, device_id_str,
-   sizeof(device_id_str));
-   if (device_id_len <= 0) {
-   /*
-* Internal error: TPGS supported but no device
-* identifcation found. Disable ALUA support.
-*/
-   sdev_printk(KERN_INFO, sdev,
-   "%s: No device descriptors found\n",
-   ALUA_DH_NAME);
-   goto out;
-   }
-   sdev_printk(KERN_INFO, sdev,
-   "%s: device %s port group %02x rel port %02x\n",
-   ALUA_DH_NAME, device_id_str, h->group_id, h->rel_port);
-
-   h->pg = alua_get_pg(sdev, h->group_id, tpgs,
-   device_id_str, device_id_len);
-   if (!h->pg) {
-   err = SCSI_DH_NOMEM;
-   goto out;
-   }
-   kref_get(>pg->kref);
-   err = alua_rtpg(sdev, h->pg, 0);
-   kref_put(>pg->kref, release_port_group);
-out:
return err;
 }
+
 /*
  * alua_set_params - set/unset the optimize flag
  * @sdev: device on the path to be activated
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  

[PATCH 10/20] revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach should succeed while TPG is transitioning")

2015-12-07 Thread Hannes Reinecke
Obsoleted by the next patch.

Reviewed-by: Ewan Milne 
Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 31 --
 1 file changed, 12 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 1eacf3f..8d80ac6 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -91,7 +91,7 @@ struct alua_dh_data {
 #define ALUA_POLICY_SWITCH_CURRENT 0
 #define ALUA_POLICY_SWITCH_ALL 1
 
-static int alua_rtpg(struct scsi_device *, struct alua_port_group *, int);
+static int alua_rtpg(struct scsi_device *, struct alua_port_group *);
 static char print_alua_state(int);
 
 static void release_port_group(struct kref *kref)
@@ -331,7 +331,7 @@ static int alua_check_vpd(struct scsi_device *sdev, struct 
alua_dh_data *h,
if (!h->pg)
return SCSI_DH_NOMEM;
 
-   return alua_rtpg(sdev, h->pg, 0);
+   return alua_rtpg(sdev, h->pg);
 }
 
 static char print_alua_state(int state)
@@ -414,13 +414,12 @@ static int alua_check_sense(struct scsi_device *sdev,
 /*
  * alua_rtpg - Evaluate REPORT TARGET GROUP STATES
  * @sdev: the device to be evaluated.
- * @wait_for_transition: if nonzero, wait ALUA_FAILOVER_TIMEOUT seconds for 
device to exit transitioning state
  *
  * Evaluate the Target Port Group State.
  * Returns SCSI_DH_DEV_OFFLINED if the path is
  * found to be unusable.
  */
-static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int 
wait_for_transition)
+static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
 {
struct scsi_sense_hdr sense_hdr;
int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
@@ -511,8 +510,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg, int w
else
pg->transition_tmo = ALUA_FAILOVER_TIMEOUT;
 
-   if (wait_for_transition &&
-   (orig_transition_tmo != pg->transition_tmo)) {
+   if (orig_transition_tmo != pg->transition_tmo) {
sdev_printk(KERN_INFO, sdev,
"%s: transition timeout set to %d seconds\n",
ALUA_DH_NAME, pg->transition_tmo);
@@ -550,19 +548,14 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg, int w
 
switch (pg->state) {
case TPGS_STATE_TRANSITIONING:
-   if (wait_for_transition) {
-   if (time_before(jiffies, expiry)) {
-   /* State transition, retry */
-   interval += 2000;
-   msleep(interval);
-   goto retry;
-   }
-   err = SCSI_DH_RETRY;
-   } else {
-   err = SCSI_DH_OK;
+   if (time_before(jiffies, expiry)) {
+   /* State transition, retry */
+   interval += 2000;
+   msleep(interval);
+   goto retry;
}
-
/* Transitioning time exceeded, set port to standby */
+   err = SCSI_DH_RETRY;
pg->state = TPGS_STATE_STANDBY;
break;
case TPGS_STATE_OFFLINE:
@@ -723,14 +716,14 @@ static int alua_activate(struct scsi_device *sdev,
if (optimize_stpg)
h->pg->flags |= ALUA_OPTIMIZE_STPG;
 
-   err = alua_rtpg(sdev, h->pg, 1);
+   err = alua_rtpg(sdev, h->pg);
if (err != SCSI_DH_OK) {
kref_put(>pg->kref, release_port_group);
goto out;
}
err = alua_stpg(sdev, h->pg);
if (err == SCSI_DH_RETRY)
-   err = alua_rtpg(sdev, h->pg, 1);
+   err = alua_rtpg(sdev, h->pg);
kref_put(>pg->kref, release_port_group);
 out:
if (fn)
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 04/20] scsi_dh_alua: call alua_rtpg() if stpg fails

2015-12-07 Thread Hannes Reinecke
If the call to SET TARGET PORT GROUPS fails we have no idea what
state the array is left in, so we need to issue a call to
REPORT TARGET PORT GROUPS in these cases.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 609691f..ba3d23e 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -678,6 +678,8 @@ static int alua_activate(struct scsi_device *sdev,
h->flags |= ALUA_OPTIMIZE_STPG;
 
err = alua_stpg(sdev, h);
+   if (err == SCSI_DH_RETRY)
+   err = alua_rtpg(sdev, h, 1);
 out:
if (fn)
fn(data, err);
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 20/20] scsi_dh_alua: Update version to 2.0

2015-12-07 Thread Hannes Reinecke
Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index d01c86407..1f97b65 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -30,7 +30,7 @@
 #include 
 
 #define ALUA_DH_NAME "alua"
-#define ALUA_DH_VER "1.3"
+#define ALUA_DH_VER "2.0"
 
 #define TPGS_SUPPORT_NONE  0x00
 #define TPGS_SUPPORT_OPTIMIZED 0x01
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 08/20] scsi_dh_alua: use unique device id

2015-12-07 Thread Hannes Reinecke
Use scsi_vpd_lun_id() to assign a unique device identification
to the alua port group structure.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 64 --
 1 file changed, 61 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index ca6322d..688e0f7 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -70,6 +70,8 @@ static DEFINE_SPINLOCK(port_group_lock);
 struct alua_port_group {
struct kref kref;
struct list_headnode;
+   unsigned char   device_id_str[256];
+   int device_id_len;
int group_id;
int tpgs;
int state;
@@ -162,6 +164,25 @@ static int submit_stpg(struct scsi_device *sdev, int 
group_id,
  ALUA_FAILOVER_RETRIES, NULL, req_flags);
 }
 
+struct alua_port_group *alua_lookup_pg(char *id_str, size_t id_size,
+  int group_id)
+{
+   struct alua_port_group *pg = NULL;
+
+   list_for_each_entry(pg, _group_list, node) {
+   if (pg->group_id != group_id)
+   continue;
+   if (pg->device_id_len != id_size)
+   continue;
+   if (strncmp(pg->device_id_str, id_str, id_size))
+   continue;
+   kref_get(>kref);
+   return pg;
+   }
+
+   return NULL;
+}
+
 /*
  * alua_get_pg - Allocate a new port_group structure
  * @sdev: scsi device
@@ -172,19 +193,37 @@ static int submit_stpg(struct scsi_device *sdev, int 
group_id,
  * device.
  */
 struct alua_port_group *alua_get_pg(struct scsi_device *sdev,
-   int group_id, int tpgs)
+   int group_id, int tpgs,
+   char *id_str, size_t id_size)
 {
-   struct alua_port_group *pg = NULL;
+   struct alua_port_group *pg = NULL, *tmp_pg;
+
+   spin_lock(_group_lock);
+   pg = alua_lookup_pg(id_str, id_size, group_id);
+   spin_unlock(_group_lock);
+   if (pg)
+   return pg;
 
pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
if (!pg)
return NULL;
 
+   strncpy(pg->device_id_str, id_str, sizeof(pg->device_id_str));
+
+   pg->device_id_len = id_size;
pg->group_id = group_id;
pg->tpgs = tpgs;
pg->state = TPGS_STATE_OPTIMIZED;
kref_init(>kref);
+
+   /* Re-check list again to catch concurrent updates */
spin_lock(_group_lock);
+   tmp_pg = alua_lookup_pg(id_str, id_size, group_id);
+   if (tmp_pg) {
+   spin_unlock(_group_lock);
+   kfree(pg);
+   return tmp_pg;
+   }
list_add(>node, _group_list);
spin_unlock(_group_lock);
 
@@ -592,6 +631,8 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct 
alua_port_group *pg)
 static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
 {
int err = SCSI_DH_DEV_UNSUPP, tpgs;
+   char device_id_str[256];
+   int device_id_len;
 
tpgs = alua_check_tpgs(sdev);
if (tpgs == TPGS_MODE_NONE)
@@ -601,7 +642,24 @@ static int alua_initialize(struct scsi_device *sdev, 
struct alua_dh_data *h)
if (err != SCSI_DH_OK)
goto out;
 
-   h->pg = alua_get_pg(sdev, h->group_id, tpgs);
+   device_id_len = scsi_vpd_lun_id(sdev, device_id_str,
+   sizeof(device_id_str));
+   if (device_id_len <= 0) {
+   /*
+* Internal error: TPGS supported but no device
+* identifcation found. Disable ALUA support.
+*/
+   sdev_printk(KERN_INFO, sdev,
+   "%s: No device descriptors found\n",
+   ALUA_DH_NAME);
+   goto out;
+   }
+   sdev_printk(KERN_INFO, sdev,
+   "%s: device %s port group %02x rel port %02x\n",
+   ALUA_DH_NAME, device_id_str, h->group_id, h->rel_port);
+
+   h->pg = alua_get_pg(sdev, h->group_id, tpgs,
+   device_id_str, device_id_len);
if (!h->pg) {
err = SCSI_DH_NOMEM;
goto out;
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 16/20] scsi_dh: add 'rescan' callback

2015-12-07 Thread Hannes Reinecke
If a device needs to be rescanned the device_handler might need
to be rechecked, too.
So add a 'rescan' callback to the device handler and call it
upon scsi_rescan_device().

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 8 
 drivers/scsi/scsi_lib.c| 1 +
 drivers/scsi/scsi_scan.c   | 8 +++-
 include/scsi/scsi_dh.h | 1 +
 4 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6014750..58c51ad 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -1040,6 +1040,13 @@ static int alua_prep_fn(struct scsi_device *sdev, struct 
request *req)
 
 }
 
+static void alua_rescan(struct scsi_device *sdev)
+{
+   struct alua_dh_data *h = sdev->handler_data;
+
+   alua_initialize(sdev, h);
+}
+
 /*
  * alua_bus_attach - Attach device handler
  * @sdev: device to be attached to
@@ -1104,6 +,7 @@ static struct scsi_device_handler alua_dh = {
.prep_fn = alua_prep_fn,
.check_sense = alua_check_sense,
.activate = alua_activate,
+   .rescan = alua_rescan,
.set_params = alua_set_params,
 };
 
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index fa6b2c4..d46193a 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2699,6 +2699,7 @@ static void scsi_evt_emit(struct scsi_device *sdev, 
struct scsi_event *evt)
envp[idx++] = "SDEV_MEDIA_CHANGE=1";
break;
case SDEV_EVT_INQUIRY_CHANGE_REPORTED:
+   scsi_rescan_device(>sdev_gendev);
envp[idx++] = "SDEV_UA=INQUIRY_DATA_HAS_CHANGED";
break;
case SDEV_EVT_CAPACITY_CHANGE_REPORTED:
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index a1c195d..05dc1aa 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -43,6 +43,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "scsi_priv.h"
@@ -1516,9 +1517,14 @@ EXPORT_SYMBOL(scsi_add_device);
 
 void scsi_rescan_device(struct device *dev)
 {
+   struct scsi_device *sdev = to_scsi_device(dev);
+
device_lock(dev);
 
-   scsi_attach_vpd(to_scsi_device(dev));
+   scsi_attach_vpd(sdev);
+
+   if (sdev->handler && sdev->handler->rescan)
+   sdev->handler->rescan(sdev);
 
if (dev->driver && try_module_get(dev->driver->owner)) {
struct scsi_driver *drv = to_scsi_driver(dev->driver);
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h
index 7e184c6..c7bba2b 100644
--- a/include/scsi/scsi_dh.h
+++ b/include/scsi/scsi_dh.h
@@ -71,6 +71,7 @@ struct scsi_device_handler {
int (*activate)(struct scsi_device *, activate_complete, void *);
int (*prep_fn)(struct scsi_device *, struct request *);
int (*set_params)(struct scsi_device *, const char *);
+   void (*rescan)(struct scsi_device *);
 };
 
 #ifdef CONFIG_SCSI_DH
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 03/20] scsi_dh_alua: Make stpg synchronous

2015-12-07 Thread Hannes Reinecke
The 'activate_complete' function needs to be executed after
stpg has finished, so we can as well execute stpg synchronously
and call the function directly.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 156 ++---
 1 file changed, 55 insertions(+), 101 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 7c66e4a..609691f 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -169,81 +169,28 @@ done:
 }
 
 /*
- * stpg_endio - Evaluate SET TARGET GROUP STATES
- * @sdev: the device to be evaluated
- * @state: the new target group state
- *
- * Evaluate a SET TARGET GROUP STATES command response.
- */
-static void stpg_endio(struct request *req, int error)
-{
-   struct alua_dh_data *h = req->end_io_data;
-   struct scsi_sense_hdr sense_hdr;
-   unsigned err = SCSI_DH_OK;
-
-   if (host_byte(req->errors) != DID_OK ||
-   msg_byte(req->errors) != COMMAND_COMPLETE) {
-   err = SCSI_DH_IO;
-   goto done;
-   }
-
-   if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
-_hdr)) {
-   if (sense_hdr.sense_key == NOT_READY &&
-   sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) {
-   /* ALUA state transition already in progress */
-   err = SCSI_DH_OK;
-   goto done;
-   }
-   if (sense_hdr.sense_key == UNIT_ATTENTION) {
-   err = SCSI_DH_RETRY;
-   goto done;
-   }
-   sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
-   ALUA_DH_NAME);
-   scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, _hdr);
-   err = SCSI_DH_IO;
-   } else if (error)
-   err = SCSI_DH_IO;
-
-   if (err == SCSI_DH_OK) {
-   h->state = TPGS_STATE_OPTIMIZED;
-   sdev_printk(KERN_INFO, h->sdev,
-   "%s: port group %02x switched to state %c\n",
-   ALUA_DH_NAME, h->group_id,
-   print_alua_state(h->state));
-   }
-done:
-   req->end_io_data = NULL;
-   __blk_put_request(req->q, req);
-   if (h->callback_fn) {
-   h->callback_fn(h->callback_data, err);
-   h->callback_fn = h->callback_data = NULL;
-   }
-   return;
-}
-
-/*
  * submit_stpg - Issue a SET TARGET GROUP STATES command
  *
  * Currently we're only setting the current target port group state
  * to 'active/optimized' and let the array firmware figure out
  * the states of the remaining groups.
  */
-static unsigned submit_stpg(struct alua_dh_data *h)
+static unsigned submit_stpg(struct scsi_device *sdev, int group_id,
+   unsigned char *sense)
 {
struct request *rq;
+   unsigned char stpg_data[8];
int stpg_len = 8;
-   struct scsi_device *sdev = h->sdev;
+   int err = 0;
 
/* Prepare the data buffer */
-   memset(h->buff, 0, stpg_len);
-   h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
-   put_unaligned_be16(h->group_id, >buff[6]);
+   memset(stpg_data, 0, stpg_len);
+   stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
+   put_unaligned_be16(group_id, _data[6]);
 
-   rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
+   rq = get_alua_req(sdev, stpg_data, stpg_len, WRITE);
if (!rq)
-   return SCSI_DH_RES_TEMP_UNAVAIL;
+   return DRIVER_BUSY << 24;
 
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_OUT;
@@ -251,13 +198,17 @@ static unsigned submit_stpg(struct alua_dh_data *h)
put_unaligned_be32(stpg_len, >cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
 
-   rq->sense = h->sense;
+   rq->sense = sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;
-   rq->end_io_data = h;
 
-   blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
-   return SCSI_DH_OK;
+   blk_execute_rq(rq->q, NULL, rq, 1);
+   if (rq->errors)
+   err = rq->errors;
+
+   blk_put_request(rq);
+
+   return err;
 }
 
 /*
@@ -582,59 +533,63 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_dh_data *h, int wait_
  * alua_stpg - Issue a SET TARGET GROUP STATES command
  *
  * Issue a SET TARGET GROUP STATES command and evaluate the
- * response. Returns SCSI_DH_RETRY if the target port group
- * state is found to be in 'transitioning'.
- * If SCSI_DH_OK is returned the passed-in 'fn' function
- * this function will take care of executing 'fn'.
- * Otherwise 'fn' should be executed by the caller with the
- * returned error code.
+ * response. Returns SCSI_DH_RETRY per default to trigger
+ * a re-evaluation of the target 

[PATCH 06/20] scsi_dh_alua: Use separate alua_port_group structure

2015-12-07 Thread Hannes Reinecke
The port group needs to be a separate structure as several
LUNs might belong to the same group.

Reviewed-by: Ewan Milne 
Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 221 -
 include/scsi/scsi_dh.h |   1 +
 2 files changed, 151 insertions(+), 71 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 063c03a..f3191f7 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -64,9 +64,13 @@
 #define ALUA_OPTIMIZE_STPG 1
 #define ALUA_RTPG_EXT_HDR_UNSUPP   2
 
-struct alua_dh_data {
+static LIST_HEAD(port_group_list);
+static DEFINE_SPINLOCK(port_group_lock);
+
+struct alua_port_group {
+   struct kref kref;
+   struct list_headnode;
int group_id;
-   int rel_port;
int tpgs;
int state;
int pref;
@@ -75,6 +79,12 @@ struct alua_dh_data {
unsigned char   *buff;
int bufflen;
unsigned char   transition_tmo;
+};
+
+struct alua_dh_data {
+   struct alua_port_group  *pg;
+   int group_id;
+   int rel_port;
struct scsi_device  *sdev;
activate_complete   callback_fn;
void*callback_data;
@@ -85,21 +95,34 @@ struct alua_dh_data {
 
 static char print_alua_state(int);
 
-static int realloc_buffer(struct alua_dh_data *h, unsigned len)
+static int realloc_buffer(struct alua_port_group *pg, unsigned len)
 {
-   if (h->buff && h->buff != h->inq)
-   kfree(h->buff);
+   if (pg->buff && pg->buff != pg->inq)
+   kfree(pg->buff);
 
-   h->buff = kmalloc(len, GFP_NOIO);
-   if (!h->buff) {
-   h->buff = h->inq;
-   h->bufflen = ALUA_INQUIRY_SIZE;
+   pg->buff = kmalloc(len, GFP_NOIO);
+   if (!pg->buff) {
+   pg->buff = pg->inq;
+   pg->bufflen = ALUA_INQUIRY_SIZE;
return 1;
}
-   h->bufflen = len;
+   pg->bufflen = len;
return 0;
 }
 
+static void release_port_group(struct kref *kref)
+{
+   struct alua_port_group *pg;
+
+   pg = container_of(kref, struct alua_port_group, kref);
+   spin_lock(_group_lock);
+   list_del(>node);
+   spin_unlock(_group_lock);
+   if (pg->buff && pg->inq != pg->buff)
+   kfree(pg->buff);
+   kfree(pg);
+}
+
 /*
  * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
  * @sdev: sdev the command should be sent to
@@ -160,6 +183,37 @@ static int submit_stpg(struct scsi_device *sdev, int 
group_id,
 }
 
 /*
+ * alua_get_pg - Allocate a new port_group structure
+ * @sdev: scsi device
+ * @h: alua device_handler data
+ * @group_id: port group id
+ *
+ * Allocate a new port_group structure for a given
+ * device.
+ */
+struct alua_port_group *alua_get_pg(struct scsi_device *sdev,
+   int group_id, int tpgs)
+{
+   struct alua_port_group *pg = NULL;
+
+   pg = kzalloc(sizeof(struct alua_port_group), GFP_KERNEL);
+   if (!pg)
+   return NULL;
+
+   pg->group_id = group_id;
+   pg->buff = pg->inq;
+   pg->bufflen = ALUA_INQUIRY_SIZE;
+   pg->tpgs = tpgs;
+   pg->state = TPGS_STATE_OPTIMIZED;
+   kref_init(>kref);
+   spin_lock(_group_lock);
+   list_add(>node, _group_list);
+   spin_unlock(_group_lock);
+
+   return pg;
+}
+
+/*
  * alua_check_tpgs - Evaluate TPGS setting
  * @sdev: device to be checked
  *
@@ -330,7 +384,7 @@ static int alua_check_sense(struct scsi_device *sdev,
  * Returns SCSI_DH_DEV_OFFLINED if the path is
  * found to be unusable.
  */
-static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int 
wait_for_transition)
+static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg, int 
wait_for_transition)
 {
struct scsi_sense_hdr sense_hdr;
int len, k, off, valid_states = 0;
@@ -340,13 +394,14 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_dh_data *h, int wait_
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
 
-   if (!h->transition_tmo)
+   if (!pg->transition_tmo)
expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT * HZ);
else
-   expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
+   expiry = round_jiffies_up(jiffies + pg->transition_tmo * HZ);
 
  retry:
-   retval = submit_rtpg(sdev, h->buff, h->bufflen, _hdr, h->flags);
+   retval = submit_rtpg(sdev, pg->buff, pg->bufflen,
+_hdr, pg->flags);
 
if (retval) {
if 

[PATCH 05/20] scsi_dh_alua: switch to scsi_execute_req_flags()

2015-12-07 Thread Hannes Reinecke
All commands are issued synchronously, so no need to open-code
scsi_execute_req_flags() anymore. And we can get rid of the
static sense code structure element. scsi_execute_req_flags()
will be setting REQ_QUIET and REQ_PREEMPT, but that is
perfectly fine as we're evaluating and logging any errors
ourselves and we really need to send the command even if
the device is quiesced.

Reviewed-by: Christoph Hellwig 
Reviewed-by: Ewan Milne 
Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 125 +
 1 file changed, 36 insertions(+), 89 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index ba3d23e..063c03a 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -75,7 +75,6 @@ struct alua_dh_data {
unsigned char   *buff;
int bufflen;
unsigned char   transition_tmo;
-   unsigned char   sense[SCSI_SENSE_BUFFERSIZE];
struct scsi_device  *sdev;
activate_complete   callback_fn;
void*callback_data;
@@ -101,71 +100,30 @@ static int realloc_buffer(struct alua_dh_data *h, 
unsigned len)
return 0;
 }
 
-static struct request *get_alua_req(struct scsi_device *sdev,
-   void *buffer, unsigned buflen, int rw)
-{
-   struct request *rq;
-   struct request_queue *q = sdev->request_queue;
-
-   rq = blk_get_request(q, rw, GFP_NOIO);
-
-   if (IS_ERR(rq)) {
-   sdev_printk(KERN_INFO, sdev,
-   "%s: blk_get_request failed\n", __func__);
-   return NULL;
-   }
-   blk_rq_set_block_pc(rq);
-
-   if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
-   blk_put_request(rq);
-   sdev_printk(KERN_INFO, sdev,
-   "%s: blk_rq_map_kern failed\n", __func__);
-   return NULL;
-   }
-
-   rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
-REQ_FAILFAST_DRIVER;
-   rq->retries = ALUA_FAILOVER_RETRIES;
-   rq->timeout = ALUA_FAILOVER_TIMEOUT * HZ;
-
-   return rq;
-}
-
 /*
  * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
  * @sdev: sdev the command should be sent to
  */
-static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
-   int bufflen, unsigned char *sense, int flags)
+static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
+  int bufflen, struct scsi_sense_hdr *sshdr, int flags)
 {
-   struct request *rq;
-   int err = 0;
-
-   rq = get_alua_req(sdev, buff, bufflen, READ);
-   if (!rq) {
-   err = DRIVER_BUSY << 24;
-   goto done;
-   }
+   u8 cdb[COMMAND_SIZE(MAINTENANCE_IN)];
+   int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+   REQ_FAILFAST_DRIVER;
 
/* Prepare the command. */
-   rq->cmd[0] = MAINTENANCE_IN;
+   memset(cdb, 0x0, COMMAND_SIZE(MAINTENANCE_IN));
+   cdb[0] = MAINTENANCE_IN;
if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
-   rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
+   cdb[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
else
-   rq->cmd[1] = MI_REPORT_TARGET_PGS;
-   put_unaligned_be32(bufflen, >cmd[6]);
-   rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
-
-   rq->sense = sense;
-   memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-   rq->sense_len = 0;
-
-   blk_execute_rq(rq->q, NULL, rq, 1);
-   if (rq->errors)
-   err = rq->errors;
-   blk_put_request(rq);
-done:
-   return err;
+   cdb[1] = MI_REPORT_TARGET_PGS;
+   put_unaligned_be32(bufflen, [6]);
+
+   return scsi_execute_req_flags(sdev, cdb, DMA_FROM_DEVICE,
+ buff, bufflen, sshdr,
+ ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, NULL, req_flags);
 }
 
 /*
@@ -175,40 +133,30 @@ done:
  * to 'active/optimized' and let the array firmware figure out
  * the states of the remaining groups.
  */
-static unsigned submit_stpg(struct scsi_device *sdev, int group_id,
-   unsigned char *sense)
+static int submit_stpg(struct scsi_device *sdev, int group_id,
+  struct scsi_sense_hdr *sshdr)
 {
-   struct request *rq;
+   u8 cdb[COMMAND_SIZE(MAINTENANCE_OUT)];
unsigned char stpg_data[8];
int stpg_len = 8;
-   int err = 0;
+   int req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
+   REQ_FAILFAST_DRIVER;
 
/* Prepare the data buffer */
memset(stpg_data, 0, stpg_len);

[PATCH 15/20] scsi_dh_alua: Send TEST UNIT READY to poll for transitioning

2015-12-07 Thread Hannes Reinecke
Sending a 'REPORT TARGET PORT GROUP' command is a costly operation,
as the array has to gather information about all ports.
So instead of using RTPG to poll for a status update when a port
is in transitioning we should be sending a TEST UNIT READY, and
wait for the sense code to report success.

Signed-off-by: Hannes Reinecke 
Reviewed-by: Ewan Milne 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 37 ++
 1 file changed, 37 insertions(+)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6ddbb88..6014750 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -489,6 +489,30 @@ static int alua_check_sense(struct scsi_device *sdev,
 }
 
 /*
+ * alua_tur - Send a TEST UNIT READY
+ * @sdev: device to which the TEST UNIT READY command should be send
+ *
+ * Send a TEST UNIT READY to @sdev to figure out the device state
+ * Returns SCSI_DH_RETRY if the sense code is NOT READY/ALUA TRANSITIONING,
+ * SCSI_DH_OK if no error occurred, and SCSI_DH_IO otherwise.
+ */
+static int alua_tur(struct scsi_device *sdev)
+{
+   struct scsi_sense_hdr sense_hdr;
+   int retval;
+
+   retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ,
+ ALUA_FAILOVER_RETRIES, _hdr);
+   if (sense_hdr.sense_key == NOT_READY &&
+   sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+   return SCSI_DH_RETRY;
+   else if (retval)
+   return SCSI_DH_IO;
+   else
+   return SCSI_DH_OK;
+}
+
+/*
  * alua_rtpg - Evaluate REPORT TARGET GROUP STATES
  * @sdev: the device to be evaluated.
  *
@@ -752,7 +776,20 @@ static void alua_rtpg_work(struct work_struct *work)
}
pg->flags |= ALUA_PG_RUNNING;
if (pg->flags & ALUA_PG_RUN_RTPG) {
+   int state = pg->state;
+
spin_unlock_irqrestore(>lock, flags);
+   if (state == TPGS_STATE_TRANSITIONING) {
+   if (alua_tur(sdev) == SCSI_DH_RETRY) {
+   spin_lock_irqsave(>lock, flags);
+   pg->flags &= ~ALUA_PG_RUNNING;
+   spin_unlock_irqrestore(>lock, flags);
+   queue_delayed_work(kaluad_wq, >rtpg_work,
+  pg->interval * HZ);
+   return;
+   }
+   /* Send RTPG on failure or if TUR indicates SUCCESS */
+   }
err = alua_rtpg(sdev, pg);
spin_lock_irqsave(>lock, flags);
if (err == SCSI_DH_RETRY) {
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 14/20] scsi_dh_alua: update all port states

2015-12-07 Thread Hannes Reinecke
When we read in the target port group state we should be
updating all affected port groups, otherwise we risk
running out of sync.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 31 +-
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 04a3a543..6ddbb88 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -499,11 +499,13 @@ static int alua_check_sense(struct scsi_device *sdev,
 static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
 {
struct scsi_sense_hdr sense_hdr;
+   struct alua_port_group *tmp_pg;
int len, k, off, valid_states = 0, bufflen = ALUA_RTPG_SIZE;
-   unsigned char *ucp, *buff;
+   unsigned char *desc, *buff;
unsigned err, retval;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
+   unsigned long flags;
 
if (!pg->expiry) {
unsigned long transition_tmo = ALUA_FAILOVER_TIMEOUT * HZ;
@@ -605,16 +607,27 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg)
else
tpg_desc_tbl_off = 4;
 
-   for (k = tpg_desc_tbl_off, ucp = buff + tpg_desc_tbl_off;
+   for (k = tpg_desc_tbl_off, desc = buff + tpg_desc_tbl_off;
 k < len;
-k += off, ucp += off) {
-
-   if (pg->group_id == get_unaligned_be16([2])) {
-   pg->state = ucp[0] & 0x0f;
-   pg->pref = ucp[0] >> 7;
-   valid_states = ucp[1];
+k += off, desc += off) {
+   u16 group_id = get_unaligned_be16([2]);
+
+   spin_lock_irqsave(_group_lock, flags);
+   list_for_each_entry(tmp_pg, _group_list, node) {
+   if (tmp_pg->group_id != group_id)
+   continue;
+   if (tmp_pg->device_id_len != pg->device_id_len)
+   continue;
+   if (strncmp(tmp_pg->device_id_str, pg->device_id_str,
+   tmp_pg->device_id_len))
+   continue;
+   tmp_pg->state = desc[0] & 0x0f;
+   tmp_pg->pref = desc[0] >> 7;
+   if (tmp_pg == pg)
+   valid_states = desc[1];
}
-   off = 8 + (ucp[7] * 4);
+   spin_unlock_irqrestore(_group_lock, flags);
+   off = 8 + (desc[7] * 4);
}
 
sdev_printk(KERN_INFO, sdev,
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 02/20] scsi_dh_alua: separate out alua_stpg()

2015-12-07 Thread Hannes Reinecke
Separate out SET TARGET PORT GROUP functionality into a separate
function alua_stpg().

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 95 +++---
 1 file changed, 61 insertions(+), 34 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index df71e85..7c66e4a 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -579,6 +579,65 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_dh_data *h, int wait_
 }
 
 /*
+ * alua_stpg - Issue a SET TARGET GROUP STATES command
+ *
+ * Issue a SET TARGET GROUP STATES command and evaluate the
+ * response. Returns SCSI_DH_RETRY if the target port group
+ * state is found to be in 'transitioning'.
+ * If SCSI_DH_OK is returned the passed-in 'fn' function
+ * this function will take care of executing 'fn'.
+ * Otherwise 'fn' should be executed by the caller with the
+ * returned error code.
+ */
+static unsigned alua_stpg(struct scsi_device *sdev, struct alua_dh_data *h,
+ activate_complete fn, void *data)
+{
+   int err = SCSI_DH_OK;
+   int stpg = 0;
+
+   if (!(h->tpgs & TPGS_MODE_EXPLICIT))
+   /* Only implicit ALUA supported */
+   goto out;
+
+   switch (h->state) {
+   case TPGS_STATE_NONOPTIMIZED:
+   stpg = 1;
+   if ((h->flags & ALUA_OPTIMIZE_STPG) &&
+   !h->pref &&
+   (h->tpgs & TPGS_MODE_IMPLICIT))
+   stpg = 0;
+   break;
+   case TPGS_STATE_STANDBY:
+   case TPGS_STATE_UNAVAILABLE:
+   stpg = 1;
+   break;
+   case TPGS_STATE_OFFLINE:
+   err = SCSI_DH_IO;
+   break;
+   case TPGS_STATE_TRANSITIONING:
+   err = SCSI_DH_RETRY;
+   break;
+   default:
+   break;
+   }
+
+   if (stpg) {
+   h->callback_fn = fn;
+   h->callback_data = data;
+   err = submit_stpg(h);
+   if (err != SCSI_DH_OK)
+   h->callback_fn = h->callback_data = NULL;
+   else
+   fn = NULL;
+   }
+out:
+   if (fn)
+   fn(data, err);
+
+   return err;
+}
+
+/*
  * alua_initialize - Initialize ALUA state
  * @sdev: the device to be initialized
  *
@@ -655,7 +714,6 @@ static int alua_activate(struct scsi_device *sdev,
 {
struct alua_dh_data *h = sdev->handler_data;
int err = SCSI_DH_OK;
-   int stpg = 0;
 
err = alua_rtpg(sdev, h, 1);
if (err != SCSI_DH_OK)
@@ -664,41 +722,10 @@ static int alua_activate(struct scsi_device *sdev,
if (optimize_stpg)
h->flags |= ALUA_OPTIMIZE_STPG;
 
-   if (h->tpgs & TPGS_MODE_EXPLICIT) {
-   switch (h->state) {
-   case TPGS_STATE_NONOPTIMIZED:
-   stpg = 1;
-   if ((h->flags & ALUA_OPTIMIZE_STPG) &&
-   (!h->pref) &&
-   (h->tpgs & TPGS_MODE_IMPLICIT))
-   stpg = 0;
-   break;
-   case TPGS_STATE_STANDBY:
-   case TPGS_STATE_UNAVAILABLE:
-   stpg = 1;
-   break;
-   case TPGS_STATE_OFFLINE:
-   err = SCSI_DH_IO;
-   break;
-   case TPGS_STATE_TRANSITIONING:
-   err = SCSI_DH_RETRY;
-   break;
-   default:
-   break;
-   }
-   }
-
-   if (stpg) {
-   h->callback_fn = fn;
-   h->callback_data = data;
-   err = submit_stpg(h);
-   if (err == SCSI_DH_OK)
-   return 0;
-   h->callback_fn = h->callback_data = NULL;
-   }
+   err = alua_stpg(sdev, h, fn, data);
 
 out:
-   if (fn)
+   if (err != SCSI_DH_OK && fn)
fn(data, err);
return 0;
 }
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 18/20] scsi_dh_alua: use common definitions for ALUA state

2015-12-07 Thread Hannes Reinecke
scsi_proto.h now contains definitions for the ALUA state,
so we don't have to carry them in the device handler.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 62 +-
 1 file changed, 27 insertions(+), 35 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 58c51ad..6c6ff0b 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -31,14 +31,6 @@
 #define ALUA_DH_NAME "alua"
 #define ALUA_DH_VER "1.3"
 
-#define TPGS_STATE_OPTIMIZED   0x0
-#define TPGS_STATE_NONOPTIMIZED0x1
-#define TPGS_STATE_STANDBY 0x2
-#define TPGS_STATE_UNAVAILABLE 0x3
-#define TPGS_STATE_LBA_DEPENDENT   0x4
-#define TPGS_STATE_OFFLINE 0xe
-#define TPGS_STATE_TRANSITIONING   0xf
-
 #define TPGS_SUPPORT_NONE  0x00
 #define TPGS_SUPPORT_OPTIMIZED 0x01
 #define TPGS_SUPPORT_NONOPTIMIZED  0x02
@@ -180,7 +172,7 @@ static int submit_stpg(struct scsi_device *sdev, int 
group_id,
 
/* Prepare the data buffer */
memset(stpg_data, 0, stpg_len);
-   stpg_data[4] = TPGS_STATE_OPTIMIZED & 0x0f;
+   stpg_data[4] = SCSI_ACCESS_STATE_OPTIMAL & 0x0f;
put_unaligned_be16(group_id, _data[6]);
 
/* Prepare the command. */
@@ -244,7 +236,7 @@ struct alua_port_group *alua_get_pg(struct scsi_device 
*sdev,
pg->device_id_len = id_size;
pg->group_id = group_id;
pg->tpgs = tpgs;
-   pg->state = TPGS_STATE_OPTIMIZED;
+   pg->state = SCSI_ACCESS_STATE_OPTIMAL;
if (optimize_stpg)
pg->flags |= ALUA_OPTIMIZE_STPG;
kref_init(>kref);
@@ -401,22 +393,22 @@ static int alua_check_vpd(struct scsi_device *sdev, 
struct alua_dh_data *h,
return SCSI_DH_OK;
 }
 
-static char print_alua_state(int state)
+static char print_alua_state(enum scsi_access_state state)
 {
switch (state) {
-   case TPGS_STATE_OPTIMIZED:
+   case SCSI_ACCESS_STATE_OPTIMAL:
return 'A';
-   case TPGS_STATE_NONOPTIMIZED:
+   case SCSI_ACCESS_STATE_ACTIVE:
return 'N';
-   case TPGS_STATE_STANDBY:
+   case SCSI_ACCESS_STATE_STANDBY:
return 'S';
-   case TPGS_STATE_UNAVAILABLE:
+   case SCSI_ACCESS_STATE_UNAVAILABLE:
return 'U';
-   case TPGS_STATE_LBA_DEPENDENT:
+   case SCSI_ACCESS_STATE_LBA:
return 'L';
-   case TPGS_STATE_OFFLINE:
+   case SCSI_ACCESS_STATE_OFFLINE:
return 'O';
-   case TPGS_STATE_TRANSITIONING:
+   case SCSI_ACCESS_STATE_TRANSITIONING:
return 'T';
default:
return 'X';
@@ -667,7 +659,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg)
valid_states_SUPPORT_OPTIMIZED?'A':'a');
 
switch (pg->state) {
-   case TPGS_STATE_TRANSITIONING:
+   case SCSI_ACCESS_STATE_TRANSITIONING:
if (time_before(jiffies, pg->expiry)) {
/* State transition, retry */
pg->interval = 2;
@@ -675,11 +667,11 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_port_group *pg)
} else {
/* Transitioning time exceeded, set port to standby */
err = SCSI_DH_IO;
-   pg->state = TPGS_STATE_STANDBY;
+   pg->state = SCSI_ACCESS_STATE_STANDBY;
pg->expiry = 0;
}
break;
-   case TPGS_STATE_OFFLINE:
+   case SCSI_ACCESS_STATE_OFFLINE:
/* Path unusable */
err = SCSI_DH_DEV_OFFLINED;
pg->expiry = 0;
@@ -712,21 +704,21 @@ static unsigned alua_stpg(struct scsi_device *sdev, 
struct alua_port_group *pg)
return SCSI_DH_RETRY;
}
switch (pg->state) {
-   case TPGS_STATE_OPTIMIZED:
+   case SCSI_ACCESS_STATE_OPTIMAL:
return SCSI_DH_OK;
-   case TPGS_STATE_NONOPTIMIZED:
+   case SCSI_ACCESS_STATE_ACTIVE:
if ((pg->flags & ALUA_OPTIMIZE_STPG) &&
!pg->pref &&
(pg->tpgs & TPGS_MODE_IMPLICIT))
return SCSI_DH_OK;
break;
-   case TPGS_STATE_STANDBY:
-   case TPGS_STATE_UNAVAILABLE:
+   case SCSI_ACCESS_STATE_STANDBY:
+   case SCSI_ACCESS_STATE_UNAVAILABLE:
break;
-   case TPGS_STATE_OFFLINE:
+   case SCSI_ACCESS_STATE_OFFLINE:
return SCSI_DH_IO;
break;
-   case TPGS_STATE_TRANSITIONING:
+   case SCSI_ACCESS_STATE_TRANSITIONING:
break;
default:
sdev_printk(KERN_INFO, sdev,
@@ -736,7 +728,7 @@ static unsigned alua_stpg(struct scsi_device 

[PATCH 17/20] scsi: Add 'access_state' attribute

2015-12-07 Thread Hannes Reinecke
Add an 'access_state' attribute to struct scsi_device to
display the asymmetric LUN access state.

Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/scsi_scan.c   |  1 +
 drivers/scsi/scsi_sysfs.c  | 49 ++
 include/scsi/scsi_device.h |  1 +
 include/scsi/scsi_proto.h  | 13 
 4 files changed, 64 insertions(+)

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 05dc1aa..9fc1531 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -231,6 +231,7 @@ static struct scsi_device *scsi_alloc_sdev(struct 
scsi_target *starget,
sdev->lun = lun;
sdev->channel = starget->channel;
sdev->sdev_state = SDEV_CREATED;
+   sdev->access_state = SCSI_ACCESS_STATE_UNKNOWN;
INIT_LIST_HEAD(>siblings);
INIT_LIST_HEAD(>same_target_siblings);
INIT_LIST_HEAD(>cmd_list);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index ef36053..80b4c67 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -81,6 +81,34 @@ const char *scsi_host_state_name(enum scsi_host_state state)
return name;
 }
 
+static const struct {
+   enum scsi_access_state  value;
+   char*name;
+} sdev_access_states[] = {
+   { SCSI_ACCESS_STATE_OPTIMAL, "active/optimized" },
+   { SCSI_ACCESS_STATE_ACTIVE, "active/non-optimized" },
+   { SCSI_ACCESS_STATE_STANDBY, "standby" },
+   { SCSI_ACCESS_STATE_UNAVAILABLE, "unavailable" },
+   { SCSI_ACCESS_STATE_LBA, "lba-dependent" },
+   { SCSI_ACCESS_STATE_OFFLINE, "offline" },
+   { SCSI_ACCESS_STATE_TRANSITIONING, "transitioning" },
+   { SCSI_ACCESS_STATE_UNKNOWN, "unknown" },
+};
+
+const char *scsi_access_state_name(enum scsi_access_state state)
+{
+   int i;
+   char *name = NULL;
+
+   for (i = 0; i < ARRAY_SIZE(sdev_access_states); i++) {
+   if (sdev_access_states[i].value == state) {
+   name = sdev_access_states[i].name;
+   break;
+   }
+   }
+   return name;
+}
+
 static int check_set(unsigned long long *val, char *src)
 {
char *last;
@@ -973,6 +1001,26 @@ sdev_store_dh_state(struct device *dev, struct 
device_attribute *attr,
 
 static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state,
   sdev_store_dh_state);
+
+static ssize_t
+sdev_show_access_state(struct device *dev,
+  struct device_attribute *attr,
+  char *buf)
+{
+   struct scsi_device *sdev = to_scsi_device(dev);
+   enum scsi_access_state access_state;
+   bool pref = false;
+
+   if (sdev->access_state & SCSI_ACCESS_STATE_PREFERRED)
+   pref = true;
+
+   access_state = (sdev->access_state & SCSI_ACCESS_STATE_MASK);
+
+   return snprintf(buf, 32, "%s%s\n",
+   scsi_access_state_name(access_state),
+   pref ? " preferred" : "");
+}
+static DEVICE_ATTR(access_state, S_IRUGO, sdev_show_access_state, NULL);
 #endif
 
 static ssize_t
@@ -1047,6 +1095,7 @@ static struct attribute *scsi_sdev_attrs[] = {
_attr_wwid.attr,
 #ifdef CONFIG_SCSI_DH
_attr_dh_state.attr,
+   _attr_access_state.attr,
 #endif
_attr_queue_ramp_up_period.attr,
REF_EVT(media_change),
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index f63a167..5dd00e9f 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -200,6 +200,7 @@ struct scsi_device {
struct scsi_device_handler *handler;
void*handler_data;
 
+   enum scsi_access_state  access_state;
enum scsi_device_state sdev_state;
unsigned long   sdev_data[0];
 } __attribute__((aligned(sizeof(unsigned long;
diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h
index a9fbf1b..80e85e7 100644
--- a/include/scsi/scsi_proto.h
+++ b/include/scsi/scsi_proto.h
@@ -277,5 +277,18 @@ struct scsi_lun {
__u8 scsi_lun[8];
 };
 
+/* SPC asymmetric access states */
+enum scsi_access_state {
+   SCSI_ACCESS_STATE_OPTIMAL = 0,
+   SCSI_ACCESS_STATE_ACTIVE,
+   SCSI_ACCESS_STATE_STANDBY,
+   SCSI_ACCESS_STATE_UNAVAILABLE,
+   SCSI_ACCESS_STATE_LBA,
+   SCSI_ACCESS_STATE_OFFLINE = 0xe,
+   SCSI_ACCESS_STATE_TRANSITIONING = 0xf,
+   SCSI_ACCESS_STATE_UNKNOWN = 0x70,
+};
+#define SCSI_ACCESS_STATE_MASK 0x0f
+#define SCSI_ACCESS_STATE_PREFERRED 0x80
 
 #endif /* _SCSI_PROTO_H_ */
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 00/20] ALUA device handler update, part II

2015-12-07 Thread Hannes Reinecke
Hi all,

as promised here is now the second part of my ALUA device handler update.
This contains a major rework of the ALUA device handler as execution is
moved onto a workqueue. This has the advantage that we avoid having to
do multiple calls to the same LUN (as happens frequently when failing
over a LUN with several paths) and finally retries are handled correctly.
As some arrays are only capable of handling one STPG at a time I've added
a module parameter 'sync_stpg' which switches to a singlethreaded
workqueue, thereby effectively synchronize STPG handling.
Thanks to Bart for this suggestion.

As usual, comments and reviews are welcome.

Hannes Reinecke (20):
  scsi_dh_alua: Pass buffer as function argument
  scsi_dh_alua: separate out alua_stpg()
  scsi_dh_alua: Make stpg synchronous
  scsi_dh_alua: call alua_rtpg() if stpg fails
  scsi_dh_alua: switch to scsi_execute_req_flags()
  scsi_dh_alua: Use separate alua_port_group structure
  scsi_dh_alua: allocate RTPG buffer separately
  scsi_dh_alua: use unique device id
  scsi_dh_alua: simplify alua_initialize()
  revert commit a8e5a2d593cb ("[SCSI] scsi_dh_alua: ALUA handler attach
should succeed while TPG is transitioning")
  scsi_dh_alua: Use workqueue for RTPG
  scsi_dh_alua: Allow workqueue to run synchronously
  scsi_dh_alua: Recheck state on unit attention
  scsi_dh_alua: update all port states
  scsi_dh_alua: Send TEST UNIT READY to poll for transitioning
  scsi_dh: add 'rescan' callback
  scsi: Add 'access_state' attribute
  scsi_dh_alua: use common definitions for ALUA state
  scsi_dh_alua: update 'access_state' field
  scsi_dh_alua: Update version to 2.0

 drivers/scsi/device_handler/scsi_dh_alua.c | 977 -
 drivers/scsi/scsi_lib.c|   1 +
 drivers/scsi/scsi_scan.c   |   9 +-
 drivers/scsi/scsi_sysfs.c  |  49 ++
 include/scsi/scsi_device.h |   1 +
 include/scsi/scsi_dh.h |   2 +
 include/scsi/scsi_proto.h  |  13 +
 7 files changed, 745 insertions(+), 307 deletions(-)

-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 01/20] scsi_dh_alua: Pass buffer as function argument

2015-12-07 Thread Hannes Reinecke
Pass in the buffer as a function argument for submit_rtpg().

Reviewed-by: Martin K. Petersen 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Bart Van Assche 
Signed-off-by: Hannes Reinecke 
---
 drivers/scsi/device_handler/scsi_dh_alua.c | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c 
b/drivers/scsi/device_handler/scsi_dh_alua.c
index 5a328bf..df71e85 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -135,12 +135,13 @@ static struct request *get_alua_req(struct scsi_device 
*sdev,
  * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
  * @sdev: sdev the command should be sent to
  */
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
+static unsigned submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
+   int bufflen, unsigned char *sense, int flags)
 {
struct request *rq;
int err = 0;
 
-   rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
+   rq = get_alua_req(sdev, buff, bufflen, READ);
if (!rq) {
err = DRIVER_BUSY << 24;
goto done;
@@ -148,14 +149,14 @@ static unsigned submit_rtpg(struct scsi_device *sdev, 
struct alua_dh_data *h)
 
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_IN;
-   if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP))
+   if (!(flags & ALUA_RTPG_EXT_HDR_UNSUPP))
rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
else
rq->cmd[1] = MI_REPORT_TARGET_PGS;
-   put_unaligned_be32(h->bufflen, >cmd[6]);
+   put_unaligned_be32(bufflen, >cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
 
-   rq->sense = h->sense;
+   rq->sense = sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;
 
@@ -446,7 +447,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct 
alua_dh_data *h, int wait_
expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
 
  retry:
-   retval = submit_rtpg(sdev, h);
+   retval = submit_rtpg(sdev, h->buff, h->bufflen, h->sense, h->flags);
if (retval) {
if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
  _hdr)) {
-- 
1.8.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Bug 108771] scsi: ses: kasan: ses_enclosure_data_process use after free on boot SAS2X28

2015-12-07 Thread bugzilla-daemon
https://bugzilla.kernel.org/show_bug.cgi?id=108771

--- Comment #1 from Pavel Tikhomirov  ---
Aditional info about enclosue(from that node, but older 3.10 based kernel):

[root@p9 crash]# modprobe sg
[root@p9 crash]#  sg_map -i
/dev/sg0  LSI   SAS2X28   0e12
/dev/sg1  /dev/sda  LSI  MR9260-4i  2.13
[root@p9 crash]# lsscsi -gs
[1:0:16:0]   enclosu LSI  SAS2X28  0e12  -  /dev/sg0   
-
[1:2:0:0]diskLSI  MR9260-4i2.13  /dev/sda   /dev/sg1  
3.99TB
[root@p9 crash]#  sg_ses /dev/sg0
  LSI   SAS2X28   0e12
Supported diagnostic pages:
  Supported Diagnostic Pages [sdp] [0x0]
  Configuration (SES) [cf] [0x1]
  Enclosure Status/Control (SES) [ec,es] [0x2]
  Element Descriptor (SES) [ed] [0x7]
  Additional Element Status (SES-2) [aes] [0xa]
  Download Microcode (SES-2) [dm] [0xe]
[root@p9 crash]#  sg_ses /dev/sg1
  LSI  MR9260-4i  2.13
disk device (not an enclosure)
Supported diagnostic pages:

-- 
You are receiving this mail because:
You are watching the assignee of the bug.
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 04/10] aacraid: Fix memory leak in aac_fib_map_free

2015-12-07 Thread Tomas Henzl
On 5.12.2015 01:40, Raghava Aditya Renukunta wrote:
> Hello Tomas,
>
>
>> -Original Message-
>> From: Tomas Henzl [mailto:the...@redhat.com]
>> Sent: Friday, December 4, 2015 6:35 AM
>> To: Raghava Aditya Renukunta; jbottom...@parallels.com; linux-
>> s...@vger.kernel.org
>> Cc: Mahesh Rajashekhara; Murthy Bhat; Santosh Akula; Gana Sridaran;
>> aacr...@pmc-sierra.com; Rich Bono
>> Subject: Re: [PATCH 04/10] aacraid: Fix memory leak in aac_fib_map_free
>>
>> On 1.12.2015 13:39, Raghava Aditya Renukunta wrote:
>>> From: Raghava Aditya Renukunta 
>>>
>>> aac_fib_map_free() calls pci_free_consistent() without checking that
>>> dev->hw_fib_va is not NULL and dev->max_fib_size is not zero.If they
>>> are indeed NULL/0, this will result in a hang as pci_free_consistent()
>>> will attempt to invalidate cache for the entire 64-bit address space
>>> (which would take a very long time).
>>>
>>> Fixed by adding a check to make sure that dev->hw_fib_va and
>>> dev->max_fib_size are not NULL and 0 respectively.
>>>
>>> Signed-off-by: Raghava Aditya Renukunta
>> 
>>
>> Reviewed-by: Tomas Henzl 
>>
>> Is the can_queue constant during the driver's life, or is it possible
>> to manipulate it (aac_change_queue_depth)?
>>
>> Tomas
> can_queue is only changed in aac_init_adapter. Do you want to save 
>  (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) in a variable
> So that the whole can_queue dereference need not be used?

It's fine as it is, (I thought it may change elsewhere in your code
but now I think that I was wrong).

--tm

>
> Regards,
> Raghava Aditya
>
>>> ---
>>>  drivers/scsi/aacraid/commsup.c | 9 ++---
>>>  1 file changed, 6 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/scsi/aacraid/commsup.c
>> b/drivers/scsi/aacraid/commsup.c
>>> index b257d3b..9533f47 100644
>>> --- a/drivers/scsi/aacraid/commsup.c
>>> +++ b/drivers/scsi/aacraid/commsup.c
>>> @@ -83,9 +83,12 @@ static int fib_map_alloc(struct aac_dev *dev)
>>>
>>>  void aac_fib_map_free(struct aac_dev *dev)
>>>  {
>>> -   pci_free_consistent(dev->pdev,
>>> - dev->max_fib_size * (dev->scsi_host_ptr->can_queue +
>> AAC_NUM_MGT_FIB),
>>> - dev->hw_fib_va, dev->hw_fib_pa);
>>> +   if (dev->hw_fib_va && dev->max_fib_size) {
>>> +   pci_free_consistent(dev->pdev,
>>> +   (dev->max_fib_size *
>>> +   (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)),
>>> +   dev->hw_fib_va, dev->hw_fib_pa);
>>> +   }
>>> dev->hw_fib_va = NULL;
>>> dev->hw_fib_pa = 0;
>>>  }
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] scsi_transport_fc: cancel scan work always before freeing fc_rport.

2015-12-07 Thread Arkadiusz Bubała

Hello,

on my FC environment target machine hanged always while rebooting the 
initiator machine. I was able to capture the following call trace:


[19236.146988]  rport-11:0-0: blocked FC remote port time out: removing 
target and saving binding
[19236.157185]  rport-10:0-0: blocked FC remote port time out: removing 
target and saving binding
[19236.157288] scsi scan: 37 byte inquiry failed.  Consider 
BLIST_INQUIRY_36 for this device
[19236.157290] scsi scan: 37 byte inquiry failed.  Consider 
BLIST_INQUIRY_36 for this device
[19236.157412] BUG: unable to handle kernel NULL pointer dereference 
at   (null)

[19236.157416] IP: [] scsi_device_put+0xf/0x50
[19236.157423] PGD 0
[19236.157425] Oops:  [#1] SMP
[19236.157427] Modules linked in: iscsi_scst(O) scst_vdisk(O) 
qla2x00tgt(O) scst(O) sch_htb rpcsec_gss_krb5 nls_iso8859_1 nls_cp437 
vfat fat zfs(PO) zunicode(PO) zavl(PO) zcommon(PO) znvpair(PO) spl(O) 
crc32c_intel sg qla2xxx(O) scsi_transport_fc mpt2sas(O) raid_class 
scsi_transport_sas button acpi_cpufreq mperf processor ixgbe(O) igb(O) 
ptp pps_core aufs [last unloaded: scst]
[19236.157449] CPU: 0 PID: 28914 Comm: kworker/0:0 Tainted: P   
O 3.10.92-oe64-ge331686 #15

[19236.157451] Hardware name: Supermicro X8DTS/X8DTS, BIOS 2.1 06/25/2012
[19236.157457] Workqueue: fc_wq_10 fc_starget_delete [scsi_transport_fc]
[19236.157459] task: 88030d8741a0 ti: 8802ec38e000 task.ti: 
8802ec38e000
[19236.157461] RIP: 0010:[] [] 
scsi_device_put+0xf/0x50

[19236.157464] RSP: 0018:8802ec38fdf0  EFLAGS: 00010202
[19236.157466] RAX:  RBX: 88030be48800 RCX: 
000181ba
[19236.157467] RDX: 000181bb RSI: 88030e4b0860 RDI: 
88030be48800
[19236.157469] RBP: 88032ca8d000 R08:  R09: 
ea000c392c00
[19236.157470] R10: 880332803d00 R11: 8142992c R12: 
88032b951860
[19236.157472] R13: 88032ca8d010 R14: 8802ef3e0c00 R15: 
88030be48800
[19236.157474] FS:  () GS:880332e0() 
knlGS:

[19236.157475] CS:  0010 DS:  ES:  CR0: 8005003b
[19236.157477] CR2:  CR3: 0195e000 CR4: 
07f0
[19236.157478] DR0:  DR1:  DR2: 

[19236.157480] DR3:  DR6: 0ff0 DR7: 
0400

[19236.157481] Stack:
[19236.157482]  88032ca8d000 88032ca8d000 81429aba 
0286
[19236.157484]  8802dd800800 88032b951b08 880332e11680 

[19236.157487]  e8a05900 0001 8105ce4d 
8105a4a7

[19236.157489] Call Trace:
[19236.157494]  [] ? scsi_remove_target+0x16a/0x250
[19236.157499]  [] ? process_one_work+0x13d/0x3b0
[19236.157502]  [] ? pwq_activate_delayed_work+0x27/0x40
[19236.157504]  [] ? worker_thread+0x121/0x3d0
[19236.157507]  [] ? manage_workers.isra.26+0x280/0x280
[19236.157510]  [] ? kthread+0xc2/0xd0
[19236.157514]  [] ? sched_clock_cpu+0x30/0x100
[19236.157517]  [] ? kthread_create_on_node+0x110/0x110
[19236.157521]  [] ? ret_from_fork+0x58/0x90
[19236.157524]  [] ? kthread_create_on_node+0x110/0x110
[19236.157525] Code: 7d 58 4c 89 fe e8 92 a2 27 00 48 89 d8 5b 5d 41 5c 
41 5d 41 5e 41 5f c3 0f 1f 40 00 55 53 48 89 fb 48 8b 07 48 8b 80 c0 00 
00 00 <48> 8b 28 48 85 ed 74 0d 48 89 ef e8 71 c4 c6 ff 48 85 c0 75 14

[19236.157548] RIP  [] scsi_device_put+0xf/0x50
[19236.157551]  RSP 
[19236.157552] CR2: 
[19236.157555] ---[ end trace 37bfa3906f93d93a ]---
[19236.157578] BUG: unable to handle kernel paging request at 
ffd8

[19236.157580] IP: [] kthread_data+0x7/0x10
[19236.157583] PGD 1961067 PUD 1963067 PMD 0
[19236.157586] Oops:  [#2] SMP
[19236.157587] Modules linked in: iscsi_scst(O) scst_vdisk(O) 
qla2x00tgt(O) scst(O) sch_htb rpcsec_gss_krb5 nls_iso8859_1 nls_cp437 
vfat fat zfs(PO) zunicode(PO) zavl(PO) zcommon(PO) znvpair(PO) spl(O) 
crc32c_intel sg qla2xxx(O) scsi_transport_fc mpt2sas(O) raid_class 
scsi_transport_sas button acpi_cpufreq mperf processor ixgbe(O) igb(O) 
ptp pps_core aufs [last unloaded: scst]
[19236.157605] CPU: 0 PID: 28914 Comm: kworker/0:0 Tainted: P DO 
3.10.92-oe64-ge331686 #15

[19236.157606] Hardware name: Supermicro X8DTS/X8DTS, BIOS 2.1 06/25/2012
[19236.157617] task: 88030d8741a0 ti: 8802ec38e000 task.ti: 
8802ec38e000
[19236.157618] RIP: 0010:[] [] 
kthread_data+0x7/0x10

[19236.157621] RSP: 0018:8802ec38fa48  EFLAGS: 00010002
[19236.157623] RAX:  RBX:  RCX: 
0001
[19236.157624] RDX:  RSI:  RDI: 
88030d8741a0
[19236.157626] RBP: 88030d8741a0 R08:  R09: 
880332803a00
[19236.157627] R10: 880332e14a80 R11: ea000b862a00 R12: 

[19236.157629] R13: 88030d874490 R14: 88030d874190 R15: 
0246
[19236.157630] FS:  () 

Re: [PATCH v2 77/71] ncr5380: Fix wait for 53C80 registers registers after PDMA

2015-12-07 Thread Ondrej Zary
On Monday 07 December 2015 04:16:14 Finn Thain wrote:
> 
> On Mon, 7 Dec 2015, Ondrej Zary wrote:
> 
> > The check for 53C80 registers accessibility was commented out because
> > it was broken (inverted). Fix and enable it.
> > 
> > Signed-off-by: Ondrej Zary 
> > ---
> >  drivers/scsi/g_NCR5380.c |   37 ++---
> >  1 file changed, 6 insertions(+), 31 deletions(-)
> > 
> > diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
> > index 038dddf..a7479c6 100644
> > --- a/drivers/scsi/g_NCR5380.c
> > +++ b/drivers/scsi/g_NCR5380.c
> > @@ -603,14 +603,10 @@ static inline int NCR5380_pread(struct Scsi_Host 
> > *instance, unsigned char *dst,
> > if (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ))
> > printk("53C400r: no 53C80 gated irq after transfer");
> >  
> > -#if 0
> > -   /*
> > -*  DON'T DO THIS - THEY NEVER ARRIVE!
> > -*/
> > -   printk("53C400r: Waiting for 53C80 registers\n");
> > -   while (NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)
> > +   /* wait for 53C80 registers to be available */
> > +   while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG))
> > ;
> 
> In the previous patch, udelay(4) was added to a CSR_GATED_53C80_IRQ 
> polling loop. It is interesting that you don't need it here when polling 
> CSR_53C80_REG.

Yes, it's weird. Reads work fine without the delay. Small writes work most of
the time without the delay but crash sometimes. Large writes crash the chip
consistently without the delay.

> > -#endif
> > +
> > if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
> > printk(KERN_ERR "53C400r: no end dma signal\n");
> > 
> > @@ -632,7 +628,6 @@ static inline int NCR5380_pwrite(struct Scsi_Host 
> > *instance, unsigned char *src,
> > struct NCR5380_hostdata *hostdata = shost_priv(instance);
> > int blocks = len / 128;
> > int start = 0;
> > -   int i;
> >  
> > NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
> > NCR5380_write(hostdata->c400_blk_cnt, blocks);
> > @@ -681,36 +676,16 @@ static inline int NCR5380_pwrite(struct Scsi_Host 
> > *instance, unsigned char *src,
> > blocks--;
> > }
> >  
> > -#if 0
> > -   printk("53C400w: waiting for registers to be available\n");
> > -   THEY NEVER DO ! while (NCR5380_read(hostdata->c400_ctl_status) & 
> > CSR_53C80_REG);
> > -   printk("53C400w: Got em\n");
> > -#endif
> > -
> > -   /* Let's wait for this instead - could be ugly */
> > -   /* All documentation says to check for this. Maybe my hardware is too
> > -* fast. Waiting for it seems to work fine! KLL
> > -*/
> > -   while (!(i = NCR5380_read(hostdata->c400_ctl_status) & 
> > CSR_GATED_53C80_IRQ)) {
> > +   /* wait for 53C80 registers to be available */
> > +   while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
> > udelay(4); /* DTC436 chip hangs without this */
> 
> ... based on the above, this udelay is probably not needed.
> 
> (Or perhaps it is only needed once, in between the final host_buf register 
> access and the first ctl_status access??)

I guess that the delay is needed when the chip does write in the background.
But why only on the last block?
Adding delays inside the while(1) loop does not help, it crashes anyway.
Single delay before the first ctl_status does not help either (perhaps only
if it's long enough for the write to complete).

The chip also crashes in transfer_pio during bigger transfers in a similar
way. With Quantum HDD, it did not crash once I got PDMA working.
But with a faster IBM HDD, it crashes even with smaller PIO trasnfers.

> Is there any reference in the docs to timing sensitivity?

Haven't found anything in NCR docs. Unfortunately, we don't have any DTC
docs.

> > /* FIXME - no timeout */
> > }
> >  
> > -   /*
> > -* I know. i is certainly != 0 here but the loop is new. See previous
> > -* comment.
> > -*/
> 
> Thanks for cleaning up this mess!
> 


-- 
Ondrej Zary
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


transakce~

2015-12-07 Thread Juin



napiste mi na e-mailovou adresu pro podrobnosti o vzájemne spoluprace.

jng.ch...@gmail.com

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver.

2015-12-07 Thread kbuild test robot
Hi Himanshu,

[auto build test WARNING on target/master]
[also build test WARNING on v4.4-rc4 next-20151207]
[cannot apply to scsi/for-next]

url:
https://github.com/0day-ci/linux/commits/Himanshu-Madhani/qla2xxx-Patches-for-target-pending-branch/20151208-093328
base:   https://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git 
master


coccinelle warnings: (new ones prefixed by >>)

>> drivers/scsi/qla2xxx/qla_iocb.c:2022:2-7: WARNING: NULL check before freeing 
>> functions like kfree, debugfs_remove, debugfs_remove_recursive or 
>> usb_free_urb is not needed. Maybe consider reorganizing relevant code to 
>> avoid passing NULL values.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructureOpen Source Technology Center
https://lists.01.org/pipermail/kbuild-all   Intel Corporation
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] qla2xxx: fix ifnullfree.cocci warnings

2015-12-07 Thread kbuild test robot
drivers/scsi/qla2xxx/qla_iocb.c:2022:2-7: WARNING: NULL check before freeing 
functions like kfree, debugfs_remove, debugfs_remove_recursive or usb_free_urb 
is not needed. Maybe consider reorganizing relevant code to avoid passing NULL 
values.

 NULL check before some freeing functions is not needed.

 Based on checkpatch warning
 "kfree(NULL) is safe this check is probably not required"
 and kfreeaddr.cocci by Julia Lawall.

Generated by: scripts/coccinelle/free/ifnullfree.cocci

CC: Himanshu Madhani 
Signed-off-by: Fengguang Wu 
---

 qla_iocb.c |3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2018,8 +2018,7 @@ qla2x00_els_dcmd_sp_free(void *ptr, void
srb_t *sp = (srb_t *)data;
struct srb_iocb *elsio = >u.iocb_cmd;
 
-   if (sp->fcport)
-   kfree(sp->fcport);
+   kfree(sp->fcport);
 
if (elsio->u.els_logo.els_logo_pyld)
dma_free_coherent(>pdev->dev, DMA_POOL_SIZE,
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 13/20] qla2xxx: Remove dependency on hardware_lock to reduce lock contention.

2015-12-07 Thread Julia Lawall
Looks suspicious.  Please check.

julia

On Tue, 8 Dec 2015, kbuild test robot wrote:

> CC: kbuild-...@01.org
> In-Reply-To: <1449535747-2850-14-git-send-email-himanshu.madh...@qlogic.com>
> TO: Himanshu Madhani <himanshu.madh...@qlogic.com>
> CC: target-de...@vger.kernel.org, n...@linux-iscsi.org
> CC: giridhar.malav...@qlogic.com, linux-scsi@vger.kernel.org, 
> himanshu.madh...@qlogic.com
>
> Hi Quinn,
>
> [auto build test WARNING on target/master]
> [also build test WARNING on v4.4-rc4 next-20151207]
> [cannot apply to scsi/for-next]
>
> url:
> https://github.com/0day-ci/linux/commits/Himanshu-Madhani/qla2xxx-Patches-for-target-pending-branch/20151208-093328
> base:   
> https://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
> :: branch date: 47 minutes ago
> :: commit date: 47 minutes ago
>
> >> drivers/scsi/qla2xxx/qla_target.c:1091:2-8: preceding lock on line 1074
>
> git remote add linux-review https://github.com/0day-ci/linux
> git remote update linux-review
> git checkout 13bfc932c19778c08e1fc8908c4f0825fd70583f
> vim +1091 drivers/scsi/qla2xxx/qla_target.c
>
> 2d70c103 Nicholas Bellinger 2012-05-15  1068  if 
> (!vha->hw->tgt.tgt_ops)
> 2d70c103 Nicholas Bellinger 2012-05-15  1069  return;
> 2d70c103 Nicholas Bellinger 2012-05-15  1070
> b2032fd5 Roland Dreier  2015-07-14  1071  if (!tgt)
> 2d70c103 Nicholas Bellinger 2012-05-15  1072  return;
> 2d70c103 Nicholas Bellinger 2012-05-15  1073
> 13bfc932 Quinn Tran 2015-12-07 @1074  
> spin_lock_irqsave(>hw->tgt.sess_lock, flags);
> 2d70c103 Nicholas Bellinger 2012-05-15  1075  if (tgt->tgt_stop) {
> 13bfc932 Quinn Tran 2015-12-07  1076  
> spin_unlock_irqrestore(>hw->tgt.sess_lock, flags);
> 2d70c103 Nicholas Bellinger 2012-05-15  1077  return;
> 2d70c103 Nicholas Bellinger 2012-05-15  1078  }
> 2d70c103 Nicholas Bellinger 2012-05-15  1079  sess = 
> qlt_find_sess_by_port_name(tgt, fcport->port_name);
> 2d70c103 Nicholas Bellinger 2012-05-15  1080  if (!sess) {
> 13bfc932 Quinn Tran 2015-12-07  1081  
> spin_unlock_irqrestore(>hw->tgt.sess_lock, flags);
> 2d70c103 Nicholas Bellinger 2012-05-15  1082  return;
> 2d70c103 Nicholas Bellinger 2012-05-15  1083  }
> 2d70c103 Nicholas Bellinger 2012-05-15  1084
> df673274 Alexei Potashnik   2015-07-14  1085  if (max_gen - 
> sess->generation < 0) {
> df673274 Alexei Potashnik   2015-07-14  1086  
> ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092,
> df673274 Alexei Potashnik   2015-07-14  1087  "Ignoring 
> stale deletion request for se_sess %p / sess %p"
> df673274 Alexei Potashnik   2015-07-14  1088  " for port 
> %8phC, req_gen %d, sess_gen %d\n",
> df673274 Alexei Potashnik   2015-07-14  1089  
> sess->se_sess, sess, sess->port_name, max_gen,
> df673274 Alexei Potashnik   2015-07-14  1090  
> sess->generation);
> df673274 Alexei Potashnik   2015-07-14 @1091  return;
> df673274 Alexei Potashnik   2015-07-14  1092  }
> df673274 Alexei Potashnik   2015-07-14  1093
> 2d70c103 Nicholas Bellinger 2012-05-15  1094  ql_dbg(ql_dbg_tgt_mgt, 
> vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess);
>
> :: The code at line 1091 was first introduced by commit
> :: df673274fa4896f25f0bf348d2a3535d74b4cbec qla2xxx: added sess 
> generations to detect RSCN update races
>
> :: TO: Alexei Potashnik <ale...@purestorage.com>
> :: CC: Nicholas Bellinger <n...@linux-iscsi.org>
>
> ---
> 0-DAY kernel test infrastructureOpen Source Technology Center
> https://lists.01.org/pipermail/kbuild-all   Intel Corporation
>
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 09/20] qla2xxx: Change check_stop_free to always return 1

2015-12-07 Thread Christoph Hellwig
On Mon, Dec 07, 2015 at 07:48:56PM -0500, Himanshu Madhani wrote:
> From: Quinn Tran 
> 
> change tcm_qla2xxx_check_stop_free to always return 1
> to prevent transport_cmd_finish_abort from accidently
> taking extra kref_put.

This looks a bit fishy.  Even if this was the right behavior it's
something all something all drivers returning the value of
target_put_sess_cmd in their check_stop_free would need to do.

Can you explain the issue you're trying to address in a little more
detail?

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module

2015-12-07 Thread Christoph Hellwig
> -void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
> +int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
>  {
>   struct qla_tgt *tgt = cmd->tgt;
>   struct scsi_qla_host *vha = tgt->vha;
>   struct se_cmd *se_cmd = >se_cmd;
> + unsigned long flags,refcount;
>  
>   ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
>   "qla_target(%d): terminating exchange for aborted cmd=%p "
>   "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, >se_cmd,
>   se_cmd->tag);
>  
> +spin_lock_irqsave(>cmd_lock, flags);
> +if (cmd->aborted) {
> +spin_unlock_irqrestore(>cmd_lock, flags);
> +
> +/* It's normal to see 2 calls in this path:
> + *  1) XFER Rdy completion + CMD_T_ABORT
> + *  2) TCM TMR - drain_state_list
> + */
> +refcount = atomic_read(>se_cmd.cmd_kref.refcount);
> +ql_dbg(ql_dbg_tgt_mgt, vha, 0x,
> +   "multiple abort. %p refcount %lx"
> +   "transport_state %x, t_state %x, se_cmd_flags %x \n",
> +   cmd, refcount,cmd->se_cmd.transport_state,
> +   cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
> +
> +return EIO;
> +}

Err, no.  Looking into the refcount inside a kref is never the
right thing to do.

> +typedef enum {
> + /*
> +  * BIT_0 - Atio Arrival / schedule to work
> +  * BIT_1 - qlt_do_work
> +  * BIT_2 - qlt_do work failed
> +  * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
> +  * BIT_4 - read respond/tcm_qla2xx_queue_data_in
> +  * BIT_5 - status respond / tcm_qla2xx_queue_status
> +  * BIT_6 - tcm request to abort/Term exchange.
> +  *  pre_xmit_response->qlt_send_term_exchange
> +  * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
> +  * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
> +  * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
> +  * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
> +
> +  * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
> +  * BIT_13 - Bad completion -
> +  *  qlt_ctio_do_completion --> qlt_term_ctio_exchange
> +  * BIT_14 - Back end data received/sent.
> +  * BIT_15 - SRR prepare ctio
> +  * BIT_16 - complete free
> +  * BIT_17 - flush - qlt_abort_cmd_on_host_reset
> +  * BIT_18 - completion w/abort status
> +  * BIT_19 - completion w/unknown status
> +  * BIT_20 - tcm_qla2xxx_free_cmd

Please use descriptive names for these flags in the source code!

> + BUG_ON(cmd->cmd_flags & BIT_20);
> + cmd->cmd_flags |= BIT_20;
> +

And no crazieness like this.  While we're at it: what synchronizes
access to ->cmd_flags?

> @@ -466,13 +484,25 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, 
> struct qla_tgt_cmd *cmd,
>  static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
>  {
>   struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
> + unsigned long flags;
>  
>   /*
>* Ensure that the complete FCP WRITE payload has been received.
>* Otherwise return an exception via CHECK_CONDITION status.
>*/
>   cmd->cmd_in_wq = 0;
> - cmd->cmd_flags |= BIT_11;
> +
> + spin_lock_irqsave(>cmd_lock, flags);
> + cmd->cmd_flags |= CMD_FLAG_DATA_WORK;
> + if (cmd->aborted) {
> + cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
> + spin_unlock_irqrestore(>cmd_lock, flags);
> +
> + tcm_qla2xxx_free_cmd(cmd);
> + return;
> + }
> + spin_unlock_irqrestore(>cmd_lock, flags);

All these abort flag hacks look very suspicios.  Can you explain the
exact theory of operation behind them?

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer

2015-12-07 Thread Christoph Hellwig
> diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c 
> b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> index 842fcca..2e9c194 100644
> --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
> @@ -617,6 +617,26 @@ static int tcm_qla2xxx_queue_status(struct se_cmd 
> *se_cmd)
>   struct qla_tgt_cmd, se_cmd);
>   int xmit_type = QLA_TGT_XMIT_STATUS;
>  
> + if (se_cmd->transport_state & CMD_T_ABORTED) {
> + /* For TCM TAS support n kernel >= 3.15:
> +  * This cmd is attempting to respond with "Task Aborted Status".
> +  */
> + if (cmd->aborted) {
> + return 0;
> + } else if ((cmd->state == QLA_TGT_STATE_NEED_DATA) &&
> + cmd->cmd_sent_to_fw) {
> + qlt_abort_cmd(cmd);
> + return 0;
> + } else if (cmd->state == QLA_TGT_STATE_PROCESSED) {
> + if (cmd->cmd_sent_to_fw) {
> + qlt_abort_cmd(cmd);
> + return 0;
> + } else {/* about to be free */
> + return 0;
> + }
> + }
> + }
> +

This is really something that should be explicitly communicated
from the core instead of having to second guess it.
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH 12/20] target/tmr: LUN reset cause cmd premature free.

2015-12-07 Thread Christoph Hellwig
On Mon, Dec 07, 2015 at 07:48:59PM -0500, Himanshu Madhani wrote:
> From: Quinn Tran 
> 
> During LUN/Target reset, the TMR code attempt to intercept
> cmds and try to aborted them.  Current code assume cmds are
> always intercepted at the back end device.  The cleanup code
> would issue a "queue_status() & check_stop_free()" to terminate
> the command.  However, when a cmd is intercepted at the front
> end/Fabric layer, current code introduce premature free or
> cause Fabric to double free.
> 
> When command is intercepted at Fabric layer, it means a
> check_stop_free(cmd_kref--) has been called.  The extra
> check_stop_free in the Lun Reset cleanup code causes early
> free.  When a cmd in the Fabric layer is completed, the normal
> free code adds another another free which introduce a double free.
> 
> To fix the issue:
> - add a new flag/CMD_T_SENT_STATUS to track command that have
>  made it down to fabric layer after back end good/bad completion.
> - if cmd reach Fabric Layer at Lun Reset time, add an extra
>  cmd_kref count to prevent premature free.

This seems lke something solved by Bart's abort rewrite in a much nicer
way.  All this special casing based on magic flags isn't maintainable
in the long run.
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 1/3] badblocks: Add core badblock management code

2015-12-07 Thread Vishal Verma
Take the core badblocks implementation from md, and make it generally
available. This follows the same style as kernel implementations of
linked lists, rb-trees etc, where you can have a structure that can be
embedded anywhere, and accessor functions to manipulate the data.

The only changes in this copy of the code are ones to generalize
function/variable names from md-specific ones. Also add init and free
functions.

Signed-off-by: Vishal Verma 
---
 block/Makefile|   2 +-
 block/badblocks.c | 576 ++
 include/linux/badblocks.h |  53 +
 3 files changed, 630 insertions(+), 1 deletion(-)
 create mode 100644 block/badblocks.c
 create mode 100644 include/linux/badblocks.h

diff --git a/block/Makefile b/block/Makefile
index 00ecc97..db5f622 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-tag.o 
blk-sysfs.o \
blk-iopoll.o blk-lib.o blk-mq.o blk-mq-tag.o \
blk-mq-sysfs.o blk-mq-cpu.o blk-mq-cpumap.o ioctl.o \
genhd.o scsi_ioctl.o partition-generic.o ioprio.o \
-   partitions/
+   badblocks.o partitions/
 
 obj-$(CONFIG_BOUNCE)   += bounce.o
 obj-$(CONFIG_BLK_DEV_BSG)  += bsg.o
diff --git a/block/badblocks.c b/block/badblocks.c
new file mode 100644
index 000..f0ac279
--- /dev/null
+++ b/block/badblocks.c
@@ -0,0 +1,576 @@
+/*
+ * Bad block management
+ *
+ * - Heavily based on MD badblocks code from Neil Brown
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * badblocks_check() - check a given range for bad sectors
+ * @bb:the badblocks structure that holds all badblock 
information
+ * @s: sector (start) at which to check for badblocks
+ * @sectors:   number of sectors to check for badblocks
+ * @first_bad: pointer to store location of the first badblock
+ * @bad_sectors: pointer to store number of badblocks after @first_bad
+ *
+ * We can record which blocks on each device are 'bad' and so just
+ * fail those blocks, or that stripe, rather than the whole device.
+ * Entries in the bad-block table are 64bits wide.  This comprises:
+ * Length of bad-range, in sectors: 0-511 for lengths 1-512
+ * Start of bad-range, sector offset, 54 bits (allows 8 exbibytes)
+ *  A 'shift' can be set so that larger blocks are tracked and
+ *  consequently larger devices can be covered.
+ * 'Acknowledged' flag - 1 bit. - the most significant bit.
+ *
+ * Locking of the bad-block table uses a seqlock so badblocks_check
+ * might need to retry if it is very unlucky.
+ * We will sometimes want to check for bad blocks in a bi_end_io function,
+ * so we use the write_seqlock_irq variant.
+ *
+ * When looking for a bad block we specify a range and want to
+ * know if any block in the range is bad.  So we binary-search
+ * to the last range that starts at-or-before the given endpoint,
+ * (or "before the sector after the target range")
+ * then see if it ends after the given start.
+ *
+ * Return:
+ *  0: there are no known bad blocks in the range
+ *  1: there are known bad block which are all acknowledged
+ * -1: there are bad blocks which have not yet been acknowledged in metadata.
+ * plus the start/length of the first bad section we overlap.
+ */
+int badblocks_check(struct badblocks *bb, sector_t s, int sectors,
+   sector_t *first_bad, int *bad_sectors)
+{
+   int hi;
+   int lo;
+   u64 *p = bb->page;
+   int rv;
+   sector_t target = s + sectors;
+   unsigned seq;
+
+   if (bb->shift > 0) {
+   /* round the start down, and the end up */
+   s >>= bb->shift;
+   target += (1>= bb->shift;
+   sectors = target - s;
+   }
+   /* 'target' is now the first block after the bad range */
+
+retry:
+   seq = read_seqbegin(>lock);
+   lo = 0;
+   rv = 0;
+   hi = bb->count;
+
+   /* Binary search between lo and hi for 'target'
+* i.e. for the last range that starts before 'target'
+*/
+   /* INVARIANT: ranges before 'lo' and at-or-after 'hi'
+* are known not to be the last range before target.
+* VARIANT: hi-lo is the number of possible
+* ranges, and decreases until it reaches 1
+*/
+ 

[PATCH v2 3/3] md: convert to use the generic badblocks code

2015-12-07 Thread Vishal Verma
Retain badblocks as part of rdev, but use the accessor functions from
include/linux/badblocks for all manipulation.

Signed-off-by: Vishal Verma 
---
 drivers/md/md.c | 516 +++-
 drivers/md/md.h |  40 +
 2 files changed, 28 insertions(+), 528 deletions(-)

diff --git a/drivers/md/md.c b/drivers/md/md.c
index c702de1..afdc3ea 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -34,6 +34,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -707,8 +708,7 @@ void md_rdev_clear(struct md_rdev *rdev)
put_page(rdev->bb_page);
rdev->bb_page = NULL;
}
-   kfree(rdev->badblocks.page);
-   rdev->badblocks.page = NULL;
+   badblocks_free(>badblocks);
 }
 EXPORT_SYMBOL_GPL(md_rdev_clear);
 
@@ -1358,8 +1358,6 @@ static __le32 calc_sb_1_csum(struct mdp_superblock_1 *sb)
return cpu_to_le32(csum);
 }
 
-static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
-   int acknowledged);
 static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int 
minor_version)
 {
struct mdp_superblock_1 *sb;
@@ -1484,8 +1482,7 @@ static int super_1_load(struct md_rdev *rdev, struct 
md_rdev *refdev, int minor_
count <<= sb->bblog_shift;
if (bb + 1 == 0)
break;
-   if (md_set_badblocks(>badblocks,
-sector, count, 1) == 0)
+   if (badblocks_set(>badblocks, sector, count, 1))
return -EINVAL;
}
} else if (sb->bblog_offset != 0)
@@ -2226,7 +2223,7 @@ repeat:
rdev_for_each(rdev, mddev) {
if (rdev->badblocks.changed) {
rdev->badblocks.changed = 0;
-   md_ack_all_badblocks(>badblocks);
+   ack_all_badblocks(>badblocks);
md_error(mddev, rdev);
}
clear_bit(Blocked, >flags);
@@ -2352,7 +2349,7 @@ repeat:
clear_bit(Blocked, >flags);
 
if (any_badblocks_changed)
-   md_ack_all_badblocks(>badblocks);
+   ack_all_badblocks(>badblocks);
clear_bit(BlockedBadBlocks, >flags);
wake_up(>blocked_wait);
}
@@ -2944,11 +2941,17 @@ static ssize_t recovery_start_store(struct md_rdev 
*rdev, const char *buf, size_
 static struct rdev_sysfs_entry rdev_recovery_start =
 __ATTR(recovery_start, S_IRUGO|S_IWUSR, recovery_start_show, 
recovery_start_store);
 
-static ssize_t
-badblocks_show(struct badblocks *bb, char *page, int unack);
-static ssize_t
-badblocks_store(struct badblocks *bb, const char *page, size_t len, int unack);
-
+/* sysfs access to bad-blocks list.
+ * We present two files.
+ * 'bad-blocks' lists sector numbers and lengths of ranges that
+ *are recorded as bad.  The list is truncated to fit within
+ *the one-page limit of sysfs.
+ *Writing "sector length" to this file adds an acknowledged
+ *bad block list.
+ * 'unacknowledged-bad-blocks' lists bad blocks that have not yet
+ *been acknowledged.  Writing to this file adds bad blocks
+ *without acknowledging them.  This is largely for testing.
+ */
 static ssize_t bb_show(struct md_rdev *rdev, char *page)
 {
return badblocks_show(>badblocks, page, 0);
@@ -3063,14 +3066,7 @@ int md_rdev_init(struct md_rdev *rdev)
 * This reserves the space even on arrays where it cannot
 * be used - I wonder if that matters
 */
-   rdev->badblocks.count = 0;
-   rdev->badblocks.shift = -1; /* disabled until explicitly enabled */
-   rdev->badblocks.page = kmalloc(PAGE_SIZE, GFP_KERNEL);
-   seqlock_init(>badblocks.lock);
-   if (rdev->badblocks.page == NULL)
-   return -ENOMEM;
-
-   return 0;
+   return badblocks_init(>badblocks, 0);
 }
 EXPORT_SYMBOL_GPL(md_rdev_init);
 /*
@@ -8348,254 +8344,9 @@ void md_finish_reshape(struct mddev *mddev)
 }
 EXPORT_SYMBOL(md_finish_reshape);
 
-/* Bad block management.
- * We can record which blocks on each device are 'bad' and so just
- * fail those blocks, or that stripe, rather than the whole device.
- * Entries in the bad-block table are 64bits wide.  This comprises:
- * Length of bad-range, in sectors: 0-511 for lengths 1-512
- * Start of bad-range, sector offset, 54 bits (allows 8 exbibytes)
- *  A 'shift' can be set so that larger blocks are tracked and
- *  consequently larger devices can be covered.
- * 'Acknowledged' flag - 1 bit. - the most significant bit.
- *
- * Locking of the bad-block table uses a seqlock so md_is_badblock
- * might need to retry if 

[PATCH v2 0/3] Badblock tracking for gendisks

2015-12-07 Thread Vishal Verma
v3:
  - Add kernel-doc style comments to all exported functions in badblocks.c 
(James)
  - Make return values from badblocks functions consistent with themselves
and the kernel style. Change the polarity of badblocks_set, and update
all callers accordingly (James)
  - In gendisk, don't unconditionally allocate badblocks, export the 
initializer.
This also allows the initializer to be a non-void return type, so that the
badblocks user can act upon failures better (James)


v2:
  - In badblocks_free, make 'page' NULL (patch 1)
  - Move the core badblocks code to a new .c file (patch 1) (Jens)
  - Fix a sizeof usage in disk_alloc_badblocks (patch 2) (Dan)
  - Since disk_alloc_badblocks can fail, check disk->bb for NULL in the
genhd wrappers (patch 2) (Jeff)
  - Update the md conversion to also ise the badblocks init and free
functions (patch 3)
  - Remove the BB_* macros from md.h as they are now in badblocks.h (patch 3)

Patch 1 copies badblock management code into a header of its own,
making it generally available. It follows common libraries of code
such as linked lists, where anyone may embed a core data structure
in another place, and use the provided accessor functions to
manipulate the data.

Patch 2 adds badblock tracking to gendisks (in preparation for use
by NVDIMM devices).

Patch 3 converts md over to use the new badblocks 'library'. I have
done some pretty simple testing on this - created a raid 1 device,
made sure the sysfs entries show up, and can be used to add and view
badblocks. A closer look by the md folks would be nice here.

Vishal Verma (3):
  badblocks: Add core badblock management code
  block: Add badblock management for gendisks
  md: convert to use the generic badblocks code

 block/Makefile|   2 +-
 block/badblocks.c | 576 ++
 block/genhd.c |  76 ++
 drivers/md/md.c   | 516 ++---
 drivers/md/md.h   |  40 +---
 include/linux/badblocks.h |  53 +
 include/linux/genhd.h |   7 +
 7 files changed, 741 insertions(+), 529 deletions(-)
 create mode 100644 block/badblocks.c
 create mode 100644 include/linux/badblocks.h

-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 2/3] block: Add badblock management for gendisks

2015-12-07 Thread Vishal Verma
NVDIMM devices, which can behave more like DRAM rather than block
devices, may develop bad cache lines, or 'poison'. A block device
exposed by the pmem driver can then consume poison via a read (or
write), and cause a machine check. On platforms without machine
check recovery features, this would mean a crash.

The block device maintaining a runtime list of all known sectors that
have poison can directly avoid this, and also provide a path forward
to enable proper handling/recovery for DAX faults on such a device.

Use the new badblock management interfaces to add a badblocks list to
gendisks.

Signed-off-by: Vishal Verma 
---
 block/genhd.c | 76 +++
 include/linux/genhd.h |  7 +
 2 files changed, 83 insertions(+)

diff --git a/block/genhd.c b/block/genhd.c
index 0c706f3..809e3e2 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "blk.h"
 
@@ -505,6 +506,16 @@ static int exact_lock(dev_t devt, void *data)
return 0;
 }
 
+int disk_alloc_badblocks(struct gendisk *disk)
+{
+   disk->bb = kzalloc(sizeof(*(disk->bb)), GFP_KERNEL);
+   if (!disk->bb)
+   return -ENOMEM;
+
+   return badblocks_init(disk->bb, 1);
+}
+EXPORT_SYMBOL(disk_alloc_badblocks);
+
 static void register_disk(struct gendisk *disk)
 {
struct device *ddev = disk_to_dev(disk);
@@ -657,6 +668,11 @@ void del_gendisk(struct gendisk *disk)
blk_unregister_queue(disk);
blk_unregister_region(disk_devt(disk), disk->minors);
 
+   if (disk->bb) {
+   badblocks_free(disk->bb);
+   kfree(disk->bb);
+   }
+
part_stat_set_all(>part0, 0);
disk->part0.stamp = 0;
 
@@ -670,6 +686,63 @@ void del_gendisk(struct gendisk *disk)
 }
 EXPORT_SYMBOL(del_gendisk);
 
+/*
+ * The gendisk usage of badblocks does not track acknowledgements for
+ * badblocks. We always assume they are acknowledged.
+ */
+int disk_check_badblocks(struct gendisk *disk, sector_t s, int sectors,
+  sector_t *first_bad, int *bad_sectors)
+{
+   if (!disk->bb)
+   return 0;
+
+   return badblocks_check(disk->bb, s, sectors, first_bad, bad_sectors);
+}
+EXPORT_SYMBOL(disk_check_badblocks);
+
+int disk_set_badblocks(struct gendisk *disk, sector_t s, int sectors)
+{
+   if (!disk->bb)
+   return 0;
+
+   return badblocks_set(disk->bb, s, sectors, 1);
+}
+EXPORT_SYMBOL(disk_set_badblocks);
+
+int disk_clear_badblocks(struct gendisk *disk, sector_t s, int sectors)
+{
+   if (!disk->bb)
+   return 0;
+
+   return badblocks_clear(disk->bb, s, sectors);
+}
+EXPORT_SYMBOL(disk_clear_badblocks);
+
+/* sysfs access to bad-blocks list. */
+static ssize_t disk_badblocks_show(struct device *dev,
+   struct device_attribute *attr,
+   char *page)
+{
+   struct gendisk *disk = dev_to_disk(dev);
+
+   if (!disk->bb)
+   return 0;
+
+   return badblocks_show(disk->bb, page, 0);
+}
+
+static ssize_t disk_badblocks_store(struct device *dev,
+   struct device_attribute *attr,
+   const char *page, size_t len)
+{
+   struct gendisk *disk = dev_to_disk(dev);
+
+   if (!disk->bb)
+   return 0;
+
+   return badblocks_store(disk->bb, page, len, 0);
+}
+
 /**
  * get_gendisk - get partitioning information for a given device
  * @devt: device to get partitioning information for
@@ -988,6 +1061,8 @@ static DEVICE_ATTR(discard_alignment, S_IRUGO, 
disk_discard_alignment_show,
 static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
 static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
 static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
+static DEVICE_ATTR(badblocks, S_IRUGO | S_IWUSR, disk_badblocks_show,
+   disk_badblocks_store);
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 static struct device_attribute dev_attr_fail =
__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
@@ -1009,6 +1084,7 @@ static struct attribute *disk_attrs[] = {
_attr_capability.attr,
_attr_stat.attr,
_attr_inflight.attr,
+   _attr_badblocks.attr,
 #ifdef CONFIG_FAIL_MAKE_REQUEST
_attr_fail.attr,
 #endif
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 2adbfa6..985eb94 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -162,6 +162,7 @@ struct disk_part_tbl {
 };
 
 struct disk_events;
+struct badblocks;
 
 struct gendisk {
/* major, first_minor and minors are input parameters only,
@@ -201,6 +202,7 @@ struct gendisk {
struct blk_integrity *integrity;
 #endif
int node_id;
+   struct badblocks *bb;
 };
 
 static inline struct gendisk *part_to_disk(struct hd_struct *part)
@@ -421,6 

Re: [PATCH v2 0/3] Badblock tracking for gendisks

2015-12-07 Thread Verma, Vishal L
Oops, sorry, should've been PATCH v3..
The contents are right, just the subject line is off.

-Vishal


On Mon, 2015-12-07 at 19:52 -0700, Vishal Verma wrote:
> v3:
>   - Add kernel-doc style comments to all exported functions in
> badblocks.c (James)
>   - Make return values from badblocks functions consistent with
> themselves
> and the kernel style. Change the polarity of badblocks_set, and
> update
> all callers accordingly (James)
>   - In gendisk, don't unconditionally allocate badblocks, export the
> initializer.
> This also allows the initializer to be a non-void return type, so
> that the
> badblocks user can act upon failures better (James)
> 
> 
> v2:
>   - In badblocks_free, make 'page' NULL (patch 1)
>   - Move the core badblocks code to a new .c file (patch 1) (Jens)
>   - Fix a sizeof usage in disk_alloc_badblocks (patch 2) (Dan)
>   - Since disk_alloc_badblocks can fail, check disk->bb for NULL in
> the
> genhd wrappers (patch 2) (Jeff)
>   - Update the md conversion to also ise the badblocks init and free
> functions (patch 3)
>   - Remove the BB_* macros from md.h as they are now in badblocks.h
> (patch 3)
> 
> Patch 1 copies badblock management code into a header of its own,
> making it generally available. It follows common libraries of code
> such as linked lists, where anyone may embed a core data structure
> in another place, and use the provided accessor functions to
> manipulate the data.
> 
> Patch 2 adds badblock tracking to gendisks (in preparation for use
> by NVDIMM devices).
> 
> Patch 3 converts md over to use the new badblocks 'library'. I have
> done some pretty simple testing on this - created a raid 1 device,
> made sure the sysfs entries show up, and can be used to add and view
> badblocks. A closer look by the md folks would be nice here.
> 
> Vishal Verma (3):
>   badblocks: Add core badblock management code
>   block: Add badblock management for gendisks
>   md: convert to use the generic badblocks code
> 
>  block/Makefile|   2 +-
>  block/badblocks.c | 576
> ++
>  block/genhd.c |  76 ++
>  drivers/md/md.c   | 516 ++---
> 
>  drivers/md/md.h   |  40 +---
>  include/linux/badblocks.h |  53 +
>  include/linux/genhd.h |   7 +
>  7 files changed, 741 insertions(+), 529 deletions(-)
>  create mode 100644 block/badblocks.c
>  create mode 100644 include/linux/badblocks.h
> N�r��yb�X��ǧv�^�)޺{.n�+{���"�{ay�ʇڙ�,j��f���h���z��w���
> ���j:+v���w�j�mzZ+�ݢj"��!�i

[PATCH 10/13] IB/srp: use the new CQ API

2015-12-07 Thread Christoph Hellwig
This also moves recv completion handling from hardirq context into
softirq context.

Signed-off-by: Christoph Hellwig 
---
 drivers/infiniband/ulp/srp/ib_srp.c | 173 +---
 drivers/infiniband/ulp/srp/ib_srp.h |   7 +-
 2 files changed, 86 insertions(+), 94 deletions(-)

diff --git a/drivers/infiniband/ulp/srp/ib_srp.c 
b/drivers/infiniband/ulp/srp/ib_srp.c
index 784dd97..d61489e 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -132,8 +132,9 @@ MODULE_PARM_DESC(ch_count,
 
 static void srp_add_one(struct ib_device *device);
 static void srp_remove_one(struct ib_device *device, void *client_data);
-static void srp_recv_completion(struct ib_cq *cq, void *ch_ptr);
-static void srp_send_completion(struct ib_cq *cq, void *ch_ptr);
+static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc);
+static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc,
+   const char *opname);
 static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
 
 static struct scsi_transport_template *ib_srp_transport_template;
@@ -445,6 +446,17 @@ static struct srp_fr_pool *srp_alloc_fr_pool(struct 
srp_target_port *target)
  dev->max_pages_per_mr);
 }
 
+static void srp_drain_done(struct ib_cq *cq, struct ib_wc *wc)
+{
+   struct srp_rdma_ch *ch = cq->cq_context;
+
+   complete(>done);
+}
+
+static struct ib_cqe srp_drain_cqe = {
+   .done   = srp_drain_done,
+};
+
 /**
  * srp_destroy_qp() - destroy an RDMA queue pair
  * @ch: SRP RDMA channel.
@@ -461,7 +473,7 @@ static void srp_destroy_qp(struct srp_rdma_ch *ch)
struct ib_recv_wr *bad_wr;
int ret;
 
-   wr.wr_id = SRP_LAST_WR_ID;
+   wr.wr_cqe = _drain_cqe;
/* Destroying a QP and reusing ch->done is only safe if not connected */
WARN_ON_ONCE(ch->connected);
 
@@ -490,34 +502,27 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch)
struct ib_fmr_pool *fmr_pool = NULL;
struct srp_fr_pool *fr_pool = NULL;
const int m = 1 + dev->use_fast_reg;
-   struct ib_cq_init_attr cq_attr = {};
int ret;
 
init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL);
if (!init_attr)
return -ENOMEM;
 
-   /* + 1 for SRP_LAST_WR_ID */
-   cq_attr.cqe = target->queue_size + 1;
-   cq_attr.comp_vector = ch->comp_vector;
-   recv_cq = ib_create_cq(dev->dev, srp_recv_completion, NULL, ch,
-  _attr);
+   /* queue_size + 1 for ib_drain_qp */
+   recv_cq = ib_alloc_cq(dev->dev, ch, target->queue_size + 1,
+   ch->comp_vector, IB_POLL_SOFTIRQ);
if (IS_ERR(recv_cq)) {
ret = PTR_ERR(recv_cq);
goto err;
}
 
-   cq_attr.cqe = m * target->queue_size;
-   cq_attr.comp_vector = ch->comp_vector;
-   send_cq = ib_create_cq(dev->dev, srp_send_completion, NULL, ch,
-  _attr);
+   send_cq = ib_alloc_cq(dev->dev, ch, m * target->queue_size,
+   ch->comp_vector, IB_POLL_DIRECT);
if (IS_ERR(send_cq)) {
ret = PTR_ERR(send_cq);
goto err_recv_cq;
}
 
-   ib_req_notify_cq(recv_cq, IB_CQ_NEXT_COMP);
-
init_attr->event_handler   = srp_qp_event;
init_attr->cap.max_send_wr = m * target->queue_size;
init_attr->cap.max_recv_wr = target->queue_size + 1;
@@ -559,9 +564,9 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch)
if (ch->qp)
srp_destroy_qp(ch);
if (ch->recv_cq)
-   ib_destroy_cq(ch->recv_cq);
+   ib_free_cq(ch->recv_cq);
if (ch->send_cq)
-   ib_destroy_cq(ch->send_cq);
+   ib_free_cq(ch->send_cq);
 
ch->qp = qp;
ch->recv_cq = recv_cq;
@@ -581,13 +586,13 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch)
return 0;
 
 err_qp:
-   ib_destroy_qp(qp);
+   srp_destroy_qp(ch);
 
 err_send_cq:
-   ib_destroy_cq(send_cq);
+   ib_free_cq(send_cq);
 
 err_recv_cq:
-   ib_destroy_cq(recv_cq);
+   ib_free_cq(recv_cq);
 
 err:
kfree(init_attr);
@@ -623,9 +628,10 @@ static void srp_free_ch_ib(struct srp_target_port *target,
if (ch->fmr_pool)
ib_destroy_fmr_pool(ch->fmr_pool);
}
+
srp_destroy_qp(ch);
-   ib_destroy_cq(ch->send_cq);
-   ib_destroy_cq(ch->recv_cq);
+   ib_free_cq(ch->send_cq);
+   ib_free_cq(ch->recv_cq);
 
/*
 * Avoid that the SCSI error handler tries to use this channel after
@@ -1038,7 +1044,13 @@ static int srp_connect_ch(struct srp_rdma_ch *ch, bool 
multich)
}
 }
 
-static int srp_inv_rkey(struct srp_rdma_ch *ch, u32 rkey)
+static void srp_inv_rkey_err_done(struct ib_cq *cq, struct ib_wc *wc)
+{
+   

[PATCH 09/13] IB/srpt: use the new CQ API

2015-12-07 Thread Christoph Hellwig
Signed-off-by: Christoph Hellwig 
---
 drivers/infiniband/ulp/srpt/ib_srpt.c | 327 +-
 drivers/infiniband/ulp/srpt/ib_srpt.h |  28 +--
 2 files changed, 88 insertions(+), 267 deletions(-)

diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c 
b/drivers/infiniband/ulp/srpt/ib_srpt.c
index b5544b2..98282e9 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -93,6 +93,8 @@ MODULE_PARM_DESC(srpt_service_guid,
 static struct ib_client srpt_client;
 static void srpt_release_channel(struct srpt_rdma_ch *ch);
 static int srpt_queue_status(struct se_cmd *cmd);
+static void srpt_recv_done(struct ib_cq *cq, struct ib_wc *wc);
+static void srpt_send_done(struct ib_cq *cq, struct ib_wc *wc);
 
 /**
  * opposite_dma_dir() - Swap DMA_TO_DEVICE and DMA_FROM_DEVICE.
@@ -778,12 +780,12 @@ static int srpt_post_recv(struct srpt_device *sdev,
struct ib_recv_wr wr, *bad_wr;
 
BUG_ON(!sdev);
-   wr.wr_id = encode_wr_id(SRPT_RECV, ioctx->ioctx.index);
-
list.addr = ioctx->ioctx.dma;
list.length = srp_max_req_size;
list.lkey = sdev->pd->local_dma_lkey;
 
+   ioctx->ioctx.cqe.done = srpt_recv_done;
+   wr.wr_cqe = >ioctx.cqe;
wr.next = NULL;
wr.sg_list = 
wr.num_sge = 1;
@@ -819,8 +821,9 @@ static int srpt_post_send(struct srpt_rdma_ch *ch,
list.length = len;
list.lkey = sdev->pd->local_dma_lkey;
 
+   ioctx->ioctx.cqe.done = srpt_send_done;
wr.next = NULL;
-   wr.wr_id = encode_wr_id(SRPT_SEND, ioctx->ioctx.index);
+   wr.wr_cqe = >ioctx.cqe;
wr.sg_list = 
wr.num_sge = 1;
wr.opcode = IB_WR_SEND;
@@ -1383,116 +1386,44 @@ out:
 }
 
 /**
- * srpt_handle_send_err_comp() - Process an IB_WC_SEND error completion.
- */
-static void srpt_handle_send_err_comp(struct srpt_rdma_ch *ch, u64 wr_id)
-{
-   struct srpt_send_ioctx *ioctx;
-   enum srpt_command_state state;
-   u32 index;
-
-   atomic_inc(>sq_wr_avail);
-
-   index = idx_from_wr_id(wr_id);
-   ioctx = ch->ioctx_ring[index];
-   state = srpt_get_cmd_state(ioctx);
-
-   WARN_ON(state != SRPT_STATE_CMD_RSP_SENT
-   && state != SRPT_STATE_MGMT_RSP_SENT
-   && state != SRPT_STATE_NEED_DATA
-   && state != SRPT_STATE_DONE);
-
-   /* If SRP_RSP sending failed, undo the ch->req_lim change. */
-   if (state == SRPT_STATE_CMD_RSP_SENT
-   || state == SRPT_STATE_MGMT_RSP_SENT)
-   atomic_dec(>req_lim);
-
-   srpt_abort_cmd(ioctx);
-}
-
-/**
- * srpt_handle_send_comp() - Process an IB send completion notification.
- */
-static void srpt_handle_send_comp(struct srpt_rdma_ch *ch,
- struct srpt_send_ioctx *ioctx)
-{
-   enum srpt_command_state state;
-
-   atomic_inc(>sq_wr_avail);
-
-   state = srpt_set_cmd_state(ioctx, SRPT_STATE_DONE);
-
-   if (WARN_ON(state != SRPT_STATE_CMD_RSP_SENT
-   && state != SRPT_STATE_MGMT_RSP_SENT
-   && state != SRPT_STATE_DONE))
-   pr_debug("state = %d\n", state);
-
-   if (state != SRPT_STATE_DONE) {
-   srpt_unmap_sg_to_ib_sge(ch, ioctx);
-   transport_generic_free_cmd(>cmd, 0);
-   } else {
-   pr_err("IB completion has been received too late for"
-  " wr_id = %u.\n", ioctx->ioctx.index);
-   }
-}
-
-/**
- * srpt_handle_rdma_comp() - Process an IB RDMA completion notification.
- *
  * XXX: what is now target_execute_cmd used to be asynchronous, and unmapping
  * the data that has been transferred via IB RDMA had to be postponed until the
  * check_stop_free() callback.  None of this is necessary anymore and needs to
  * be cleaned up.
  */
-static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
- struct srpt_send_ioctx *ioctx,
- enum srpt_opcode opcode)
+static void srpt_rdma_read_done(struct ib_cq *cq, struct ib_wc *wc)
 {
+   struct srpt_rdma_ch *ch = cq->cq_context;
+   struct srpt_send_ioctx *ioctx =
+   container_of(wc->wr_cqe, struct srpt_send_ioctx, ioctx.cqe);
+
WARN_ON(ioctx->n_rdma <= 0);
atomic_add(ioctx->n_rdma, >sq_wr_avail);
 
-   if (opcode == SRPT_RDMA_READ_LAST) {
-   if (srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA,
-   SRPT_STATE_DATA_IN))
-   target_execute_cmd(>cmd);
-   else
-   pr_err("%s[%d]: wrong state = %d\n", __func__,
-  __LINE__, srpt_get_cmd_state(ioctx));
-   } else {
-   WARN(true, "unexpected opcode %d\n", opcode);
+   if (unlikely(wc->status != IB_WC_SUCCESS)) {
+   pr_info("RDMA_READ for ioctx 0x%p failed with status %d\n",
+   ioctx, 

[PATCH 08/13] IB/srpt: chain RDMA READ/WRITE requests

2015-12-07 Thread Christoph Hellwig
Remove struct rdma_iu and instead allocate the struct ib_rdma_wr array
early and fill out directly.  This allows us to chain the WRs, and thus
archive both less lock contention on the HCA workqueue as well as much
simpler error handling.

Signed-off-by: Christoph Hellwig 
---
 drivers/infiniband/ulp/srpt/ib_srpt.c | 100 +-
 drivers/infiniband/ulp/srpt/ib_srpt.h |  14 +
 2 files changed, 39 insertions(+), 75 deletions(-)

diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c 
b/drivers/infiniband/ulp/srpt/ib_srpt.c
index b8b654c..b5544b2 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -1055,7 +1055,7 @@ static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch 
*ch,
BUG_ON(ioctx->n_rdma && !ioctx->rdma_ius);
 
while (ioctx->n_rdma)
-   kfree(ioctx->rdma_ius[--ioctx->n_rdma].sge);
+   kfree(ioctx->rdma_ius[--ioctx->n_rdma].wr.sg_list);
 
kfree(ioctx->rdma_ius);
ioctx->rdma_ius = NULL;
@@ -1082,7 +1082,7 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
struct scatterlist *sg, *sg_orig;
int sg_cnt;
enum dma_data_direction dir;
-   struct rdma_iu *riu;
+   struct ib_rdma_wr *riu;
struct srp_direct_buf *db;
dma_addr_t dma_addr;
struct ib_sge *sge;
@@ -1115,7 +1115,8 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
nrdma = (count + SRPT_DEF_SG_PER_WQE - 1) / SRPT_DEF_SG_PER_WQE
+ ioctx->n_rbuf;
 
-   ioctx->rdma_ius = kzalloc(nrdma * sizeof *riu, GFP_KERNEL);
+   ioctx->rdma_ius = kcalloc(nrdma, sizeof(*ioctx->rdma_ius),
+   GFP_KERNEL);
if (!ioctx->rdma_ius)
goto free_mem;
 
@@ -1139,9 +1140,9 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
 j < count && i < ioctx->n_rbuf && tsize > 0; ++i, ++riu, ++db) {
rsize = be32_to_cpu(db->len);
raddr = be64_to_cpu(db->va);
-   riu->raddr = raddr;
+   riu->remote_addr = raddr;
riu->rkey = be32_to_cpu(db->key);
-   riu->sge_cnt = 0;
+   riu->wr.num_sge = 0;
 
/* calculate how many sge required for this remote_buf */
while (rsize > 0 && tsize > 0) {
@@ -1165,27 +1166,29 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch 
*ch,
rsize = 0;
}
 
-   ++riu->sge_cnt;
+   ++riu->wr.num_sge;
 
-   if (rsize > 0 && riu->sge_cnt == SRPT_DEF_SG_PER_WQE) {
+   if (rsize > 0 &&
+   riu->wr.num_sge == SRPT_DEF_SG_PER_WQE) {
++ioctx->n_rdma;
-   riu->sge =
-   kmalloc(riu->sge_cnt * sizeof *riu->sge,
-   GFP_KERNEL);
-   if (!riu->sge)
+   riu->wr.sg_list = kmalloc_array(riu->wr.num_sge,
+   sizeof(*riu->wr.sg_list),
+   GFP_KERNEL);
+   if (!riu->wr.sg_list)
goto free_mem;
 
++riu;
-   riu->sge_cnt = 0;
-   riu->raddr = raddr;
+   riu->wr.num_sge = 0;
+   riu->remote_addr = raddr;
riu->rkey = be32_to_cpu(db->key);
}
}
 
++ioctx->n_rdma;
-   riu->sge = kmalloc(riu->sge_cnt * sizeof *riu->sge,
-  GFP_KERNEL);
-   if (!riu->sge)
+   riu->wr.sg_list = kmalloc_array(riu->wr.num_sge,
+   sizeof(*riu->wr.sg_list),
+   GFP_KERNEL);
+   if (!riu->wr.sg_list)
goto free_mem;
}
 
@@ -1200,7 +1203,7 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
for (i = 0, j = 0;
 j < count && i < ioctx->n_rbuf && tsize > 0; ++i, ++riu, ++db) {
rsize = be32_to_cpu(db->len);
-   sge = riu->sge;
+   sge = riu->wr.sg_list;
k = 0;
 
while (rsize > 0 && tsize > 0) {
@@ -1232,9 +1235,9 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
}
 
++k;
-   if (k == riu->sge_cnt && rsize > 0 && tsize > 0) {
+   if (k == riu->wr.num_sge && rsize > 0 && tsize > 0) {
++riu;
- 

[PATCH 11/13] IB/iser: Use a dedicated descriptor for login

2015-12-07 Thread Christoph Hellwig
From: Sagi Grimberg 

We'll need it later with the new CQ abstraction. also switch
login bufs to void pointers.

Signed-off-by: Sagi Grimberg 
Signed-off-by: Christoph Hellwig 
---
 drivers/infiniband/ulp/iser/iscsi_iser.h |  30 +--
 drivers/infiniband/ulp/iser/iser_initiator.c | 128 +--
 drivers/infiniband/ulp/iser/iser_verbs.c |  14 +--
 3 files changed, 89 insertions(+), 83 deletions(-)

diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h 
b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 502063b..5648409 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -326,6 +326,25 @@ struct iser_rx_desc {
char pad[ISER_RX_PAD_SIZE];
 } __attribute__((packed));
 
+
+/**
+ * struct iser_login_desc - iSER login descriptor
+ *
+ * @req:   pointer to login request buffer
+ * @resp:  pointer to login response buffer
+ * @req_dma:   DMA address of login request buffer
+ * @rsp_dma:  DMA address of login response buffer
+ * @sge:   IB sge for login post recv
+ */
+struct iser_login_desc {
+   void *req;
+   void *rsp;
+   u64  req_dma;
+   u64  rsp_dma;
+   struct ib_sgesge;
+} __attribute__((packed));
+
+
 struct iser_conn;
 struct ib_conn;
 struct iscsi_iser_task;
@@ -512,11 +531,7 @@ struct ib_conn {
  * @up_completion:connection establishment completed
  *(state is ISER_CONN_UP)
  * @conn_list:entry in ig conn list
- * @login_buf:login data buffer (stores login parameters)
- * @login_req_buf:login request buffer
- * @login_req_dma:login request buffer dma address
- * @login_resp_buf:   login response buffer
- * @login_resp_dma:   login response buffer dma address
+ * @login_desc:   login descriptor
  * @rx_desc_head: head of rx_descs cyclic buffer
  * @rx_descs: rx buffers array (cyclic buffer)
  * @num_rx_descs: number of rx descriptors
@@ -539,10 +554,7 @@ struct iser_conn {
struct completionib_completion;
struct completionup_completion;
struct list_head conn_list;
-
-   char *login_buf;
-   char *login_req_buf, *login_resp_buf;
-   u64  login_req_dma, login_resp_dma;
+   struct iser_login_desc   login_desc;
unsigned int rx_desc_head;
struct iser_rx_desc  *rx_descs;
u32  num_rx_descs;
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c 
b/drivers/infiniband/ulp/iser/iser_initiator.c
index ffd00c4..21f28c8 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -174,73 +174,63 @@ static void iser_create_send_desc(struct iser_conn
*iser_conn,
 static void iser_free_login_buf(struct iser_conn *iser_conn)
 {
struct iser_device *device = iser_conn->ib_conn.device;
+   struct iser_login_desc *desc = _conn->login_desc;
 
-   if (!iser_conn->login_buf)
+   if (!desc->req)
return;
 
-   if (iser_conn->login_req_dma)
-   ib_dma_unmap_single(device->ib_device,
-   iser_conn->login_req_dma,
-   ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_TO_DEVICE);
+   ib_dma_unmap_single(device->ib_device, desc->req_dma,
+   ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_TO_DEVICE);
 
-   if (iser_conn->login_resp_dma)
-   ib_dma_unmap_single(device->ib_device,
-   iser_conn->login_resp_dma,
-   ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE);
+   ib_dma_unmap_single(device->ib_device, desc->rsp_dma,
+   ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE);
 
-   kfree(iser_conn->login_buf);
+   kfree(desc->req);
+   kfree(desc->rsp);
 
/* make sure we never redo any unmapping */
-   iser_conn->login_req_dma = 0;
-   iser_conn->login_resp_dma = 0;
-   iser_conn->login_buf = NULL;
+   desc->req = NULL;
+   desc->rsp = NULL;
 }
 
 static int iser_alloc_login_buf(struct iser_conn *iser_conn)
 {
struct iser_device *device = iser_conn->ib_conn.device;
-   int req_err, resp_err;
-
-   BUG_ON(device == NULL);
-
-   iser_conn->login_buf = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN +
-ISER_RX_LOGIN_SIZE, GFP_KERNEL);
-   if (!iser_conn->login_buf)
-   goto out_err;
-
-   iser_conn->login_req_buf  = iser_conn->login_buf;
-   iser_conn->login_resp_buf = iser_conn->login_buf +
-   

[PATCH 13/13] IB/iser: Convert to CQ abstraction

2015-12-07 Thread Christoph Hellwig
From: Sagi Grimberg 

Use the new CQ abstraction to simplify completions in the iSER
initiator.

Signed-off-by: Sagi Grimberg 
Signed-off-by: Christoph Hellwig 
---
 drivers/infiniband/ulp/iser/iscsi_iser.h |  72 +---
 drivers/infiniband/ulp/iser/iser_initiator.c | 142 ++-
 drivers/infiniband/ulp/iser/iser_memory.c|  21 ++-
 drivers/infiniband/ulp/iser/iser_verbs.c | 258 ++-
 4 files changed, 210 insertions(+), 283 deletions(-)

diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h 
b/drivers/infiniband/ulp/iser/iscsi_iser.h
index cf4c4ce..d3f5255 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -151,16 +151,12 @@
 - ISER_MAX_RX_MISC_PDUS) / \
 (1 + ISER_INFLIGHT_DATAOUTS))
 
-#define ISER_WC_BATCH_COUNT   16
 #define ISER_SIGNAL_CMD_COUNT 32
 
 #define ISER_VER   0x10
 #define ISER_WSV   0x08
 #define ISER_RSV   0x04
 
-#define ISER_FASTREG_LI_WRID   0xULL
-#define ISER_BEACON_WRID   0xfffeULL
-
 /**
  * struct iser_hdr - iSER header
  *
@@ -269,7 +265,7 @@ enum iser_desc_type {
 #define ISER_MAX_WRS 7
 
 /**
- * struct iser_tx_desc - iSER TX descriptor (for send wr_id)
+ * struct iser_tx_desc - iSER TX descriptor
  *
  * @iser_header:   iser header
  * @iscsi_header:  iscsi header
@@ -293,6 +289,7 @@ struct iser_tx_desc {
u64  dma_addr;
struct ib_sgetx_sg[2];
int  num_sge;
+   struct ib_cqecqe;
bool mapped;
u8   wr_idx;
union iser_wr {
@@ -306,9 +303,10 @@ struct iser_tx_desc {
 };
 
 #define ISER_RX_PAD_SIZE   (256 - (ISER_RX_PAYLOAD_SIZE + \
-   sizeof(u64) + sizeof(struct ib_sge)))
+sizeof(u64) + sizeof(struct ib_sge) + \
+sizeof(struct ib_cqe)))
 /**
- * struct iser_rx_desc - iSER RX descriptor (for recv wr_id)
+ * struct iser_rx_desc - iSER RX descriptor
  *
  * @iser_header:   iser header
  * @iscsi_header:  iscsi header
@@ -323,9 +321,9 @@ struct iser_rx_desc {
char data[ISER_RECV_DATA_SEG_LEN];
u64  dma_addr;
struct ib_sgerx_sg;
+   struct ib_cqecqe;
char pad[ISER_RX_PAD_SIZE];
-} __attribute__((packed));
-
+} __packed;
 
 /**
  * struct iser_login_desc - iSER login descriptor
@@ -335,6 +333,7 @@ struct iser_rx_desc {
  * @req_dma:   DMA address of login request buffer
  * @rsp_dma:  DMA address of login response buffer
  * @sge:   IB sge for login post recv
+ * @cqe:   completion handler
  */
 struct iser_login_desc {
void *req;
@@ -342,9 +341,9 @@ struct iser_login_desc {
u64  req_dma;
u64  rsp_dma;
struct ib_sgesge;
+   struct ib_cqecqe;
 } __attribute__((packed));
 
-
 struct iser_conn;
 struct ib_conn;
 struct iscsi_iser_task;
@@ -352,18 +351,12 @@ struct iscsi_iser_task;
 /**
  * struct iser_comp - iSER completion context
  *
- * @device: pointer to device handle
  * @cq: completion queue
- * @wcs:work completion array
- * @tasklet:Tasklet handle
  * @active_qps: Number of active QPs attached
  *  to completion context
  */
 struct iser_comp {
-   struct iser_device  *device;
struct ib_cq*cq;
-   struct ib_wc wcs[ISER_WC_BATCH_COUNT];
-   struct tasklet_structtasklet;
int  active_qps;
 };
 
@@ -492,10 +485,11 @@ struct iser_fr_pool {
  * @rx_wr:   receive work request for batch posts
  * @device:  reference to iser device
  * @comp:iser completion context
- * @pi_support:  Indicate device T10-PI support
- * @beacon:  beacon send wr to signal all flush errors were drained
- * @flush_comp:  completes when all connection completions consumed
  * @fr_pool: connection fast registration poool
+ * @pi_support:  Indicate device T10-PI support
+ * @last:last send wr to signal all flush errors were drained
+ * @last_cqe:cqe handler for last wr
+ * @last_comp:   completes when all connection completions consumed
  */
 struct ib_conn {
struct rdma_cm_id   *cma_id;
@@ -505,10 +499,12 @@ struct ib_conn {
struct ib_recv_wrrx_wr[ISER_MIN_POSTED_RX];
struct iser_device  *device;
struct 

[PATCH 12/13] IB/iser: Use helper for container_of

2015-12-07 Thread Christoph Hellwig
From: Sagi Grimberg 

Nicer this way.

Signed-off-by: Sagi Grimberg 
Signed-off-by: Christoph Hellwig 
---
 drivers/infiniband/ulp/iser/iscsi_iser.h | 6 ++
 drivers/infiniband/ulp/iser/iser_initiator.c | 3 +--
 drivers/infiniband/ulp/iser/iser_verbs.c | 6 ++
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h 
b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 5648409..cf4c4ce 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -729,4 +729,10 @@ iser_tx_next_wr(struct iser_tx_desc *tx_desc)
return cur_wr;
 }
 
+static inline struct iser_conn *
+to_iser_conn(struct ib_conn *ib_conn)
+{
+   return container_of(ib_conn, struct iser_conn, ib_conn);
+}
+
 #endif
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c 
b/drivers/infiniband/ulp/iser/iser_initiator.c
index 21f28c8..21148b6 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -559,8 +559,7 @@ void iser_rcv_completion(struct iser_rx_desc *rx_desc,
 unsigned long rx_xfer_len,
 struct ib_conn *ib_conn)
 {
-   struct iser_conn *iser_conn = container_of(ib_conn, struct iser_conn,
-  ib_conn);
+   struct iser_conn *iser_conn = to_iser_conn(ib_conn);
struct iscsi_hdr *hdr;
char *data;
u64 rx_dma;
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c 
b/drivers/infiniband/ulp/iser/iser_verbs.c
index ee4cebc..f75ef0c 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -455,8 +455,7 @@ void iser_free_fastreg_pool(struct ib_conn *ib_conn)
  */
 static int iser_create_ib_conn_res(struct ib_conn *ib_conn)
 {
-   struct iser_conn *iser_conn = container_of(ib_conn, struct iser_conn,
-  ib_conn);
+   struct iser_conn *iser_conn = to_iser_conn(ib_conn);
struct iser_device  *device;
struct ib_device*ib_dev;
struct ib_qp_init_attr  init_attr;
@@ -1160,9 +1159,8 @@ static void
 iser_handle_comp_error(struct ib_conn *ib_conn,
   struct ib_wc *wc)
 {
+   struct iser_conn *iser_conn = to_iser_conn(ib_conn);
void *wr_id = (void *)(uintptr_t)wc->wr_id;
-   struct iser_conn *iser_conn = container_of(ib_conn, struct iser_conn,
-  ib_conn);
 
if (wc->status != IB_WC_WR_FLUSH_ERR)
if (iser_conn->iscsi_conn)
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 05/13] irq_poll: mark __irq_poll_complete static

2015-12-07 Thread Christoph Hellwig
Signed-off-by: Christoph Hellwig 
---
 include/linux/irq_poll.h | 1 -
 lib/irq_poll.c   | 3 +--
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/include/linux/irq_poll.h b/include/linux/irq_poll.h
index c3145c7..ce9e1db 100644
--- a/include/linux/irq_poll.h
+++ b/include/linux/irq_poll.h
@@ -21,7 +21,6 @@ enum {
 extern void irq_poll_sched(struct irq_poll *);
 extern void irq_poll_init(struct irq_poll *, int, irq_poll_fn *);
 extern void irq_poll_complete(struct irq_poll *);
-extern void __irq_poll_complete(struct irq_poll *);
 extern void irq_poll_enable(struct irq_poll *);
 extern void irq_poll_disable(struct irq_poll *);
 
diff --git a/lib/irq_poll.c b/lib/irq_poll.c
index 2c7b8e6..652ef4d 100644
--- a/lib/irq_poll.c
+++ b/lib/irq_poll.c
@@ -47,13 +47,12 @@ EXPORT_SYMBOL(irq_poll_sched);
  * See irq_poll_complete(). This function must be called with interrupts
  * disabled.
  **/
-void __irq_poll_complete(struct irq_poll *iop)
+static void __irq_poll_complete(struct irq_poll *iop)
 {
list_del(>list);
smp_mb__before_atomic();
clear_bit_unlock(IRQ_POLL_F_SCHED, >state);
 }
-EXPORT_SYMBOL(__irq_poll_complete);
 
 /**
  * irq_poll_complete - Mark this @iop as un-polled again
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 06/13] irq_poll: remove unused data and max fields

2015-12-07 Thread Christoph Hellwig
Signed-off-by: Christoph Hellwig 
---
 include/linux/irq_poll.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/include/linux/irq_poll.h b/include/linux/irq_poll.h
index ce9e1db..7527c03 100644
--- a/include/linux/irq_poll.h
+++ b/include/linux/irq_poll.h
@@ -7,9 +7,7 @@ typedef int (irq_poll_fn)(struct irq_poll *, int);
 struct irq_poll {
struct list_head list;
unsigned long state;
-   unsigned long data;
int weight;
-   int max;
irq_poll_fn *poll;
 };
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 02/13] irq_poll: don't disable new irq_poll instances

2015-12-07 Thread Christoph Hellwig
There is no good reason to start out disabled - drivers can control if
the poll instance can be scheduled by simply not scheduling it yet.

Signed-off-by: Christoph Hellwig 
---
 drivers/scsi/be2iscsi/be_main.c | 2 --
 drivers/scsi/ipr.c  | 2 --
 lib/irq_poll.c  | 4 +---
 3 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 1d879ef..471e2b9 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -5581,7 +5581,6 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
pbe_eq = _context->be_eq[i];
irq_poll_init(_eq->iopoll, be_iopoll_budget,
be_iopoll);
-   irq_poll_enable(_eq->iopoll);
}
 
i = (phba->msix_enabled) ? i : 0;
@@ -5754,7 +5753,6 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
pbe_eq = _context->be_eq[i];
irq_poll_init(_eq->iopoll, be_iopoll_budget,
be_iopoll);
-   irq_poll_enable(_eq->iopoll);
}
 
i = (phba->msix_enabled) ? i : 0;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 6b9c738..402e4ca 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3708,7 +3708,6 @@ static ssize_t ipr_store_iopoll_weight(struct device *dev,
for (i = 1; i < ioa_cfg->hrrq_num; i++) {
irq_poll_init(_cfg->hrrq[i].iopoll,
ioa_cfg->iopoll_weight, ipr_iopoll);
-   irq_poll_enable(_cfg->hrrq[i].iopoll);
}
}
spin_unlock_irqrestore(shost->host_lock, lock_flags);
@@ -10407,7 +10406,6 @@ static int ipr_probe(struct pci_dev *pdev, const struct 
pci_device_id *dev_id)
for (i = 1; i < ioa_cfg->hrrq_num; i++) {
irq_poll_init(_cfg->hrrq[i].iopoll,
ioa_cfg->iopoll_weight, ipr_iopoll);
-   irq_poll_enable(_cfg->hrrq[i].iopoll);
}
}
 
diff --git a/lib/irq_poll.c b/lib/irq_poll.c
index e6fd1dc..88af879 100644
--- a/lib/irq_poll.c
+++ b/lib/irq_poll.c
@@ -170,8 +170,7 @@ EXPORT_SYMBOL(irq_poll_enable);
  * @poll_fn:  The handler to invoke
  *
  * Description:
- * Initialize this irq_poll structure. Before being actively used, the
- * driver must call irq_poll_enable().
+ * Initialize and enable this irq_poll structure.
  **/
 void irq_poll_init(struct irq_poll *iop, int weight, irq_poll_fn *poll_fn)
 {
@@ -179,7 +178,6 @@ void irq_poll_init(struct irq_poll *iop, int weight, 
irq_poll_fn *poll_fn)
INIT_LIST_HEAD(>list);
iop->weight = weight;
iop->poll = poll_fn;
-   set_bit(IRQ_POLL_F_SCHED, >state);
 }
 EXPORT_SYMBOL(irq_poll_init);
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 03/13] irq_poll: fold irq_poll_sched_prep into irq_poll_sched

2015-12-07 Thread Christoph Hellwig
There is no good reason to keep them apart, and this makes using the API
a bit simpler.

Signed-off-by: Christoph Hellwig 
---
 drivers/scsi/be2iscsi/be_main.c |  6 ++
 drivers/scsi/ipr.c  |  3 +--
 include/linux/irq_poll.h| 13 -
 lib/irq_poll.c  | 10 +++---
 4 files changed, 10 insertions(+), 22 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 471e2b9..cb9072a8 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -910,8 +910,7 @@ static irqreturn_t be_isr_msix(int irq, void *dev_id)
num_eq_processed = 0;
while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
& EQE_VALID_MASK) {
-   if (!irq_poll_sched_prep(_eq->iopoll))
-   irq_poll_sched(_eq->iopoll);
+   irq_poll_sched(_eq->iopoll);
 
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
queue_tail_inc(eq);
@@ -972,8 +971,7 @@ static irqreturn_t be_isr(int irq, void *dev_id)
spin_unlock_irqrestore(>isr_lock, flags);
num_mcceq_processed++;
} else {
-   if (!irq_poll_sched_prep(_eq->iopoll))
-   irq_poll_sched(_eq->iopoll);
+   irq_poll_sched(_eq->iopoll);
num_ioeq_processed++;
}
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 402e4ca..82031e0 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -5692,8 +5692,7 @@ static irqreturn_t ipr_isr_mhrrq(int irq, void *devp)
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
if ((be32_to_cpu(*hrrq->hrrq_curr) & IPR_HRRQ_TOGGLE_BIT) ==
   hrrq->toggle_bit) {
-   if (!irq_poll_sched_prep(>iopoll))
-   irq_poll_sched(>iopoll);
+   irq_poll_sched(>iopoll);
spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
return IRQ_HANDLED;
}
diff --git a/include/linux/irq_poll.h b/include/linux/irq_poll.h
index 0cf7c26..73d7c20 100644
--- a/include/linux/irq_poll.h
+++ b/include/linux/irq_poll.h
@@ -18,19 +18,6 @@ enum {
IRQ_POLL_F_DISABLE  = 1,
 };
 
-/*
- * Returns 0 if we successfully set the IRQ_POLL_F_SCHED bit, indicating
- * that we were the first to acquire this iop for scheduling. If this iop
- * is currently disabled, return "failure".
- */
-static inline int irq_poll_sched_prep(struct irq_poll *iop)
-{
-   if (!test_bit(IRQ_POLL_F_DISABLE, >state))
-   return test_and_set_bit(IRQ_POLL_F_SCHED, >state);
-
-   return 1;
-}
-
 static inline int irq_poll_disable_pending(struct irq_poll *iop)
 {
return test_bit(IRQ_POLL_F_DISABLE, >state);
diff --git a/lib/irq_poll.c b/lib/irq_poll.c
index 88af879..13cb149 100644
--- a/lib/irq_poll.c
+++ b/lib/irq_poll.c
@@ -21,13 +21,17 @@ static DEFINE_PER_CPU(struct list_head, blk_cpu_iopoll);
  *
  * Description:
  * Add this irq_poll structure to the pending poll list and trigger the
- * raise of the blk iopoll softirq. The driver must already have gotten a
- * successful return from irq_poll_sched_prep() before calling this.
+ * raise of the blk iopoll softirq.
  **/
 void irq_poll_sched(struct irq_poll *iop)
 {
unsigned long flags;
 
+   if (test_bit(IRQ_POLL_F_DISABLE, >state))
+   return;
+   if (!test_and_set_bit(IRQ_POLL_F_SCHED, >state))
+   return;
+
local_irq_save(flags);
list_add_tail(>list, this_cpu_ptr(_cpu_iopoll));
__raise_softirq_irqoff(IRQ_POLL_SOFTIRQ);
@@ -58,7 +62,7 @@ EXPORT_SYMBOL(__irq_poll_complete);
  * Description:
  * If a driver consumes less than the assigned budget in its run of the
  * iopoll handler, it'll end the polled mode by calling this function. The
- * iopoll handler will not be invoked again before irq_poll_sched_prep()
+ * iopoll handler will not be invoked again before irq_poll_schedp()
  * is called.
  **/
 void irq_poll_complete(struct irq_poll *iop)
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 04/13] irq_poll: fold irq_poll_disable_pending into irq_poll_softirq

2015-12-07 Thread Christoph Hellwig
Signed-off-by: Christoph Hellwig 
---
 include/linux/irq_poll.h | 5 -
 lib/irq_poll.c   | 2 +-
 2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/include/linux/irq_poll.h b/include/linux/irq_poll.h
index 73d7c20..c3145c7 100644
--- a/include/linux/irq_poll.h
+++ b/include/linux/irq_poll.h
@@ -18,11 +18,6 @@ enum {
IRQ_POLL_F_DISABLE  = 1,
 };
 
-static inline int irq_poll_disable_pending(struct irq_poll *iop)
-{
-   return test_bit(IRQ_POLL_F_DISABLE, >state);
-}
-
 extern void irq_poll_sched(struct irq_poll *);
 extern void irq_poll_init(struct irq_poll *, int, irq_poll_fn *);
 extern void irq_poll_complete(struct irq_poll *);
diff --git a/lib/irq_poll.c b/lib/irq_poll.c
index 13cb149..2c7b8e6 100644
--- a/lib/irq_poll.c
+++ b/lib/irq_poll.c
@@ -122,7 +122,7 @@ static void irq_poll_softirq(struct softirq_action *h)
 * move the instance around on the list at-will.
 */
if (work >= weight) {
-   if (irq_poll_disable_pending(iop))
+   if (test_bit(IRQ_POLL_F_DISABLE, >state))
__irq_poll_complete(iop);
else
list_move_tail(>list, list);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 01/13] irq_poll: make blk-iopoll available outside the block layer

2015-12-07 Thread Christoph Hellwig
The new name is irq_poll as iopoll is already taken.  Better suggestions
welcome.

Signed-off-by: Christoph Hellwig 
---
 Documentation/kernel-per-CPU-kthreads.txt |   2 +-
 block/Makefile|   2 +-
 block/blk-iopoll.c| 224 --
 drivers/scsi/Kconfig  |   1 +
 drivers/scsi/be2iscsi/Kconfig |   1 +
 drivers/scsi/be2iscsi/be.h|   4 +-
 drivers/scsi/be2iscsi/be_iscsi.c  |   4 +-
 drivers/scsi/be2iscsi/be_main.c   |  24 ++--
 drivers/scsi/ipr.c|  28 ++--
 drivers/scsi/ipr.h|   4 +-
 include/linux/blk-iopoll.h|  46 --
 include/linux/interrupt.h |   2 +-
 include/linux/irq_poll.h  |  46 ++
 include/trace/events/irq.h|   2 +-
 lib/Kconfig   |   5 +
 lib/Makefile  |   1 +
 lib/irq_poll.c| 221 +
 tools/lib/traceevent/event-parse.c|   2 +-
 tools/perf/util/trace-event-parse.c   |   2 +-
 19 files changed, 313 insertions(+), 308 deletions(-)
 delete mode 100644 block/blk-iopoll.c
 delete mode 100644 include/linux/blk-iopoll.h
 create mode 100644 include/linux/irq_poll.h
 create mode 100644 lib/irq_poll.c

diff --git a/Documentation/kernel-per-CPU-kthreads.txt 
b/Documentation/kernel-per-CPU-kthreads.txt
index f4cbfe0..edec3a3 100644
--- a/Documentation/kernel-per-CPU-kthreads.txt
+++ b/Documentation/kernel-per-CPU-kthreads.txt
@@ -90,7 +90,7 @@ BLOCK_SOFTIRQ:  Do all of the following:
from being initiated from tasks that might run on the CPU to
be de-jittered.  (It is OK to force this CPU offline and then
bring it back online before you start your application.)
-BLOCK_IOPOLL_SOFTIRQ:  Do all of the following:
+IRQ_POLL_SOFTIRQ:  Do all of the following:
 1. Force block-device interrupts onto some other CPU.
 2. Initiate any block I/O and block-I/O polling on other CPUs.
 3. Once your application has started, prevent CPU-hotplug operations
diff --git a/block/Makefile b/block/Makefile
index 00ecc97..e850474 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -5,7 +5,7 @@
 obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-tag.o blk-sysfs.o \
blk-flush.o blk-settings.o blk-ioc.o blk-map.o \
blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \
-   blk-iopoll.o blk-lib.o blk-mq.o blk-mq-tag.o \
+   blk-lib.o blk-mq.o blk-mq-tag.o \
blk-mq-sysfs.o blk-mq-cpu.o blk-mq-cpumap.o ioctl.o \
genhd.o scsi_ioctl.o partition-generic.o ioprio.o \
partitions/
diff --git a/block/blk-iopoll.c b/block/blk-iopoll.c
deleted file mode 100644
index 0736729..000
--- a/block/blk-iopoll.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Functions related to interrupt-poll handling in the block layer. This
- * is similar to NAPI for network devices.
- */
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "blk.h"
-
-static unsigned int blk_iopoll_budget __read_mostly = 256;
-
-static DEFINE_PER_CPU(struct list_head, blk_cpu_iopoll);
-
-/**
- * blk_iopoll_sched - Schedule a run of the iopoll handler
- * @iop:  The parent iopoll structure
- *
- * Description:
- * Add this blk_iopoll structure to the pending poll list and trigger the
- * raise of the blk iopoll softirq. The driver must already have gotten a
- * successful return from blk_iopoll_sched_prep() before calling this.
- **/
-void blk_iopoll_sched(struct blk_iopoll *iop)
-{
-   unsigned long flags;
-
-   local_irq_save(flags);
-   list_add_tail(>list, this_cpu_ptr(_cpu_iopoll));
-   __raise_softirq_irqoff(BLOCK_IOPOLL_SOFTIRQ);
-   local_irq_restore(flags);
-}
-EXPORT_SYMBOL(blk_iopoll_sched);
-
-/**
- * __blk_iopoll_complete - Mark this @iop as un-polled again
- * @iop:  The parent iopoll structure
- *
- * Description:
- * See blk_iopoll_complete(). This function must be called with interrupts
- * disabled.
- **/
-void __blk_iopoll_complete(struct blk_iopoll *iop)
-{
-   list_del(>list);
-   smp_mb__before_atomic();
-   clear_bit_unlock(IOPOLL_F_SCHED, >state);
-}
-EXPORT_SYMBOL(__blk_iopoll_complete);
-
-/**
- * blk_iopoll_complete - Mark this @iop as un-polled again
- * @iop:  The parent iopoll structure
- *
- * Description:
- * If a driver consumes less than the assigned budget in its run of the
- * iopoll handler, it'll end the polled mode by calling this function. The
- * iopoll handler will not be invoked again before blk_iopoll_sched_prep()
- * is called.
- **/
-void blk_iopoll_complete(struct blk_iopoll *iop)
-{
-   unsigned long flags;
-
-   

RE: [PATCH 08/10] aacraid: Disable device ID wildcard

2015-12-07 Thread Raghava Aditya Renukunta
Hello Christoph,

> -Original Message-
> From: Christoph Hellwig [mailto:h...@infradead.org]
> Sent: Friday, December 4, 2015 12:33 AM
> To: Raghava Aditya Renukunta
> Cc: Tomas Henzl; jbottom...@parallels.com; linux-scsi@vger.kernel.org;
> Mahesh Rajashekhara; Murthy Bhat; Santosh Akula; Gana Sridaran;
> aacr...@pmc-sierra.com; Rich Bono
> Subject: Re: [PATCH 08/10] aacraid: Disable device ID wildcard
> 
> On Thu, Dec 03, 2015 at 09:32:18PM +, Raghava Aditya Renukunta wrote:
> > This will enable us to prevent aacraid from loading for PCI devices that
> match
> > device ID wildcards. Enabling us to use say a new driver for future devices.
> 
> This looks like a bogus reason.  The same PCI ID should always be
> compatible and mathed by the same driver.  Even if you add a new driver
> to expose additional feature and break these semantics there is no point
> to do a) reject them conditionally on a module option and b) do this
> before said driver is merged.

I have spoken with my team and  it does make more sense to submit
it when the new driver is merged. I will withdraw this patch.

Regards,
Raghava Aditya
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH 04/10] aacraid: Fix memory leak in aac_fib_map_free

2015-12-07 Thread Raghava Aditya Renukunta
Hello Tomas,

> -Original Message-
> From: Tomas Henzl [mailto:the...@redhat.com]
> Sent: Monday, December 7, 2015 6:06 AM
> To: Raghava Aditya Renukunta; jbottom...@parallels.com; linux-
> s...@vger.kernel.org
> Cc: Mahesh Rajashekhara; Murthy Bhat; Santosh Akula; Gana Sridaran;
> aacr...@pmc-sierra.com; Rich Bono
> Subject: Re: [PATCH 04/10] aacraid: Fix memory leak in aac_fib_map_free
> 
> On 5.12.2015 01:40, Raghava Aditya Renukunta wrote:
> > Hello Tomas,
> >
> >
> >> -Original Message-
> >> From: Tomas Henzl [mailto:the...@redhat.com]
> >> Sent: Friday, December 4, 2015 6:35 AM
> >> To: Raghava Aditya Renukunta; jbottom...@parallels.com; linux-
> >> s...@vger.kernel.org
> >> Cc: Mahesh Rajashekhara; Murthy Bhat; Santosh Akula; Gana Sridaran;
> >> aacr...@pmc-sierra.com; Rich Bono
> >> Subject: Re: [PATCH 04/10] aacraid: Fix memory leak in aac_fib_map_free
> >>
> >> On 1.12.2015 13:39, Raghava Aditya Renukunta wrote:
> >>> From: Raghava Aditya Renukunta
> 
> >>>
> >>> aac_fib_map_free() calls pci_free_consistent() without checking that
> >>> dev->hw_fib_va is not NULL and dev->max_fib_size is not zero.If they
> >>> are indeed NULL/0, this will result in a hang as pci_free_consistent()
> >>> will attempt to invalidate cache for the entire 64-bit address space
> >>> (which would take a very long time).
> >>>
> >>> Fixed by adding a check to make sure that dev->hw_fib_va and
> >>> dev->max_fib_size are not NULL and 0 respectively.
> >>>
> >>> Signed-off-by: Raghava Aditya Renukunta
> >> 
> >>
> >> Reviewed-by: Tomas Henzl 
> >>
> >> Is the can_queue constant during the driver's life, or is it possible
> >> to manipulate it (aac_change_queue_depth)?
> >>
> >> Tomas
> > can_queue is only changed in aac_init_adapter. Do you want to save
> >  (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) in a variable
> > So that the whole can_queue dereference need not be used?
> 
> It's fine as it is, (I thought it may change elsewhere in your code
> but now I think that I was wrong).
> 
> --tm

I will leave it as it is then.


> 
> >
> > Regards,
> > Raghava Aditya
> >
> >>> ---
> >>>  drivers/scsi/aacraid/commsup.c | 9 ++---
> >>>  1 file changed, 6 insertions(+), 3 deletions(-)
> >>>
> >>> diff --git a/drivers/scsi/aacraid/commsup.c
> >> b/drivers/scsi/aacraid/commsup.c
> >>> index b257d3b..9533f47 100644
> >>> --- a/drivers/scsi/aacraid/commsup.c
> >>> +++ b/drivers/scsi/aacraid/commsup.c
> >>> @@ -83,9 +83,12 @@ static int fib_map_alloc(struct aac_dev *dev)
> >>>
> >>>  void aac_fib_map_free(struct aac_dev *dev)
> >>>  {
> >>> - pci_free_consistent(dev->pdev,
> >>> -   dev->max_fib_size * (dev->scsi_host_ptr->can_queue +
> >> AAC_NUM_MGT_FIB),
> >>> -   dev->hw_fib_va, dev->hw_fib_pa);
> >>> + if (dev->hw_fib_va && dev->max_fib_size) {
> >>> + pci_free_consistent(dev->pdev,
> >>> + (dev->max_fib_size *
> >>> + (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)),
> >>> + dev->hw_fib_va, dev->hw_fib_pa);
> >>> + }
> >>>   dev->hw_fib_va = NULL;
> >>>   dev->hw_fib_pa = 0;
> >>>  }
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> > the body of a message to majord...@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] scsi_dh_alua: Remove stale variables

2015-12-07 Thread Martin K. Petersen
> "Hannes" == Hannes Reinecke  writes:

Hannes> With commit 83ea0e5e3501 these variables became obsolete, but
Hannes> weren't removed.

Applied to 4.5/scsi-queue.

-- 
Martin K. Petersen  Oracle Linux Engineering
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 09/20] qla2xxx: Change check_stop_free to always return 1

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

change tcm_qla2xxx_check_stop_free to always return 1
to prevent transport_cmd_finish_abort from accidently
taking extra kref_put.

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

diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c 
b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 74c6e9b..366142a 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -314,7 +314,8 @@ static int tcm_qla2xxx_check_stop_free(struct se_cmd 
*se_cmd)
cmd->cmd_flags |= BIT_14;
}
 
-   return target_put_sess_cmd(se_cmd);
+   target_put_sess_cmd(se_cmd);
+   return 1;
 }
 
 /* tcm_qla2xxx_release_cmd - Callback from TCM Core to release underlying
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 06/20] qla2xxx: Delete session if initiator is gone from FW

2015-12-07 Thread Himanshu Madhani
From: Alexei Potashnik 

1. Initiator A is logged in with fc_id(1)/loop_id(1)
2. Initiator A re-logs in with fc_id(2)/loop_id(2)
3. Part of old session deletion async logoout for 1/1 is queued
4. Initiator B logs in with fc_id(1)/loop_id(1), starts
   passing data and creates session.
5. Async logo from 3 is processed by DPC and sent to FW

Now initiator B has the session but is logged out from FW.

This condition is detected first with CTIO error 29 at which
point we should delete current session. During session
deletion we will send LOGO to initiator to force re-login.

Under rare circumstances initiator might be logged out of FW,
not have driver session, but still think it's logged in.
E.g. the above sequence plus session deletion due to re-config.
Incoming commands will fail to create local session because
initiator is not found in FW. In this case we also issue LOGO
to initiator to force him re-login.

Finally this patch fixes exchange leak when commands where
received in logged out state. In this case loop_id must be
set to  when corresponding exchange is terminated. The
patch modifies exchange termination to always use ,
since in certain scenarios it's impossible to tell whether
command was received in logged in or logged out state.

Signed-off-by: Alexei Potashnik 
Acked-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_def.h|2 +
 drivers/scsi/qla2xxx/qla_os.c |1 +
 drivers/scsi/qla2xxx/qla_target.c |  108 +++--
 drivers/scsi/qla2xxx/qla_target.h |9 +++
 4 files changed, 104 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 366f65b..1050fc2 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3652,6 +3652,8 @@ typedef struct scsi_qla_host {
atomic_tgeneration_tick;
/* Time when global fcport update has been scheduled */
int total_fcport_update_gen;
+   /* List of pending LOGOs, protected by tgt_mutex */
+   struct list_headlogo_list;
 
uint32_tvp_abort_cnt;
 
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index a63ce6e..c02cbc6 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3918,6 +3918,7 @@ struct scsi_qla_host *qla2x00_create_host(struct 
scsi_host_template *sht,
INIT_LIST_HEAD(>list);
INIT_LIST_HEAD(>qla_cmd_list);
INIT_LIST_HEAD(>qla_sess_op_cmd_list);
+   INIT_LIST_HEAD(>logo_list);
 
spin_lock_init(>work_lock);
spin_lock_init(>cmd_list_lock);
diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 661124a..5ef9d4c 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -389,6 +389,52 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, 
response_t *pkt)
 
 }
 
+typedef struct {
+   /* These fields must be initialized by the caller */
+   port_id_t id;
+   /*
+* number of cmds dropped while we were waiting for
+* initiator to ack LOGO initialize to 1 if LOGO is
+* triggered by a command, otherwise, to 0
+*/
+   int cmd_count;
+
+   /* These fields are used by callee */
+   struct list_head list;
+} qlt_port_logo_t;
+
+static void
+qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo)
+{
+   qlt_port_logo_t *tmp;
+   int res;
+
+   mutex_lock(>vha_tgt.tgt_mutex);
+
+   list_for_each_entry(tmp, >logo_list, list) {
+   if (tmp->id.b24 == logo->id.b24) {
+   tmp->cmd_count += logo->cmd_count;
+   mutex_unlock(>vha_tgt.tgt_mutex);
+   return;
+   }
+   }
+
+   list_add_tail(>list, >logo_list);
+
+   mutex_unlock(>vha_tgt.tgt_mutex);
+
+   res = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, logo->id);
+
+   mutex_lock(>vha_tgt.tgt_mutex);
+   list_del(>list);
+   mutex_unlock(>vha_tgt.tgt_mutex);
+
+   dev_info(>hw->pdev->dev,
+"Finished LOGO to %02x:%02x:%02x, dropped %d cmds, res = 
%#x\n",
+logo->id.b.domain, logo->id.b.area, logo->id.b.al_pa,
+logo->cmd_count, res);
+}
+
 static void qlt_free_session_done(struct work_struct *work)
 {
struct qla_tgt_sess *sess = container_of(work, struct qla_tgt_sess,
@@ -402,14 +448,21 @@ static void qlt_free_session_done(struct work_struct 
*work)
 
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
"%s: se_sess %p / sess %p from port %8phC loop_id %#04x"
-   " s_id %02x:%02x:%02x logout %d keep %d plogi %d\n",
+   " s_id %02x:%02x:%02x logout %d keep %d plogi %d els_logo %d\n",
__func__, sess->se_sess, sess, 

[PATCH 10/20] qla2xxx: Fix interaction issue between qla2xxx and Target Core Module

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

During lun reset, TMR thread from TCM would issue abort
to qla driver.  At abort time, each command is in different
state.  Depending on the state, qla will use the TMR thread
to trigger a command free(cmd_kref--) if command is not
down at firmware.

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_target.c  |   60 +
 drivers/scsi/qla2xxx/qla_target.h  |   59 +
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |   73 ++-
 3 files changed, 147 insertions(+), 45 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 638940f..4d42b79 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -105,7 +105,7 @@ static void qlt_response_pkt(struct scsi_qla_host *ha, 
response_t *pkt);
 static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
int fn, void *iocb, int flags);
 static void qlt_send_term_exchange(struct scsi_qla_host *ha, struct qla_tgt_cmd
-   *cmd, struct atio_from_isp *atio, int ha_locked);
+   *cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort);
 static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha,
struct qla_tgt_srr_imm *imm, int ha_lock);
 static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
@@ -2646,7 +2646,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int 
xmit_type,
/* no need to terminate. FW already freed exchange. */
qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
else
-   qlt_send_term_exchange(vha, cmd, >atio, 1);
+   qlt_send_term_exchange(vha, cmd, >atio, 1, 0);
spin_unlock_irqrestore(>hardware_lock, flags);
return 0;
}
@@ -3154,7 +3154,8 @@ static int __qlt_send_term_exchange(struct scsi_qla_host 
*vha,
 }
 
 static void qlt_send_term_exchange(struct scsi_qla_host *vha,
-   struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked)
+   struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked,
+   int ul_abort)
 {
unsigned long flags = 0;
int rc;
@@ -3174,8 +3175,7 @@ static void qlt_send_term_exchange(struct scsi_qla_host 
*vha,
qlt_alloc_qfull_cmd(vha, atio, 0, 0);
 
 done:
-   if (cmd && (!cmd->aborted ||
-   !cmd->cmd_sent_to_fw)) {
+   if (cmd && !ul_abort && !cmd->aborted) {
if (cmd->sg_mapped)
qlt_unmap_sg(vha, cmd);
vha->hw->tgt.tgt_ops->free_cmd(cmd);
@@ -3234,21 +3234,43 @@ static void qlt_chk_exch_leak_thresh_hold(struct 
scsi_qla_host *vha)
 
 }
 
-void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
+int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
 {
struct qla_tgt *tgt = cmd->tgt;
struct scsi_qla_host *vha = tgt->vha;
struct se_cmd *se_cmd = >se_cmd;
+   unsigned long flags,refcount;
 
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
"qla_target(%d): terminating exchange for aborted cmd=%p "
"(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, >se_cmd,
se_cmd->tag);
 
+spin_lock_irqsave(>cmd_lock, flags);
+if (cmd->aborted) {
+spin_unlock_irqrestore(>cmd_lock, flags);
+
+/* It's normal to see 2 calls in this path:
+ *  1) XFER Rdy completion + CMD_T_ABORT
+ *  2) TCM TMR - drain_state_list
+ */
+refcount = atomic_read(>se_cmd.cmd_kref.refcount);
+ql_dbg(ql_dbg_tgt_mgt, vha, 0x,
+   "multiple abort. %p refcount %lx"
+   "transport_state %x, t_state %x, se_cmd_flags %x \n",
+   cmd, refcount,cmd->se_cmd.transport_state,
+   cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
+
+return EIO;
+}
+
cmd->aborted = 1;
cmd->cmd_flags |= BIT_6;
+spin_unlock_irqrestore(>cmd_lock, flags);
+
+   qlt_send_term_exchange(vha, cmd, >atio, 0, 1);
 
-   qlt_send_term_exchange(vha, cmd, >atio, 0);
+   return 0;
 }
 EXPORT_SYMBOL(qlt_abort_cmd);
 
@@ -3263,6 +3285,9 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd)
 
BUG_ON(cmd->cmd_in_wq);
 
+   if (cmd->sg_mapped)
+   qlt_unmap_sg(cmd->vha, cmd);
+
if (!cmd->q_full)
qlt_decr_num_pend_cmds(cmd->vha);
 
@@ -3380,7 +3405,7 @@ static int qlt_term_ctio_exchange(struct scsi_qla_host 
*vha, void *ctio,
term = 1;
 
if (term)
-   qlt_send_term_exchange(vha, cmd, >atio, 1);
+   qlt_send_term_exchange(vha, cmd, >atio, 1, 0);
 
return term;
 }
@@ -3735,6 +3760,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
goto out_term;
}
 
+   spin_lock_init(>cmd_lock);
cdb = >u.isp24.fcp_cmnd.cdb[0];
  

[PATCH 03/20] qla2xxx: Enable Target counters in DebugFS.

2015-12-07 Thread Himanshu Madhani
Following counters are added in target mode to help debugging efforts.

Target Counters

qla_core_sbt_cmd = 0
qla_core_ret_sta_ctio = 0
qla_core_ret_ctio = 0
core_qla_que_buf = 0
core_qla_snd_status = 0
core_qla_free_cmd = 0
num alloc iocb failed = 0
num term exchange sent = 0
num Q full sent = 0

Signed-off-by: Himanshu Madhani 
Signed-off-by: Giridhar Malavali 
---
 drivers/scsi/qla2xxx/qla_dbg.c |2 +-
 drivers/scsi/qla2xxx/qla_def.h |   15 +
 drivers/scsi/qla2xxx/qla_dfs.c |   56 
 drivers/scsi/qla2xxx/qla_iocb.c|1 +
 drivers/scsi/qla2xxx/qla_target.c  |7 
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |4 ++
 6 files changed, 84 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index e25f5ac..07451bb 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -60,7 +60,7 @@
  * |  || 0xb13c-0xb140  |
  * |  || 0xb149
|
  * | MultiQ   |   0xc00c   |   |
- * | Misc |   0xd300   | 0xd031-0xd0ff |
+ * | Misc |   0xd301   | 0xd031-0xd0ff |
  * |  || 0xd101-0xd1fe |
  * |  || 0xd214-0xd2fe |
  * | Target Mode |   0xe080   ||
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index be9a674..1d2a51a 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3342,6 +3342,8 @@ struct qla_hw_data {
uint32_tchain_offset;
struct dentry *dfs_dir;
struct dentry *dfs_fce;
+   struct dentry *dfs_tgt_counters;
+
dma_addr_t  fce_dma;
void*fce;
uint32_tfce_bufs;
@@ -3499,6 +3501,18 @@ struct qla_hw_data {
int allow_cna_fw_dump;
 };
 
+struct qla_tgt_counters {
+   uint64_t qla_core_sbt_cmd;
+   uint64_t core_qla_que_buf;
+   uint64_t qla_core_ret_ctio;
+   uint64_t core_qla_snd_status;
+   uint64_t qla_core_ret_sta_ctio;
+   uint64_t core_qla_free_cmd;
+   uint64_t num_q_full_sent;
+   uint64_t num_alloc_iocb_failed;
+   uint64_t num_term_xchg_sent;
+};
+
 /*
  * Qlogic scsi host structure
  */
@@ -3651,6 +3665,7 @@ typedef struct scsi_qla_host {
 
atomic_tvref_count;
struct qla8044_reset_template reset_tmplt;
+   struct qla_tgt_counters tgt_counters;
 } scsi_qla_host_t;
 
 #define SET_VP_IDX 1
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 15cf074..449541f 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -13,6 +13,48 @@ static struct dentry *qla2x00_dfs_root;
 static atomic_t qla2x00_dfs_root_count;
 
 static int
+qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
+{
+   struct scsi_qla_host *vha = s->private;
+
+   seq_puts(s, "Target Counters\n");
+   seq_printf(s, "qla_core_sbt_cmd = %lld\n",
+   vha->tgt_counters.qla_core_sbt_cmd);
+   seq_printf(s, "qla_core_ret_sta_ctio = %lld\n",
+   vha->tgt_counters.qla_core_ret_sta_ctio);
+   seq_printf(s, "qla_core_ret_ctio = %lld\n",
+   vha->tgt_counters.qla_core_ret_ctio);
+   seq_printf(s, "core_qla_que_buf = %lld\n",
+   vha->tgt_counters.core_qla_que_buf);
+   seq_printf(s, "core_qla_snd_status = %lld\n",
+   vha->tgt_counters.core_qla_snd_status);
+   seq_printf(s, "core_qla_free_cmd = %lld\n",
+   vha->tgt_counters.core_qla_free_cmd);
+   seq_printf(s, "num alloc iocb failed = %lld\n",
+   vha->tgt_counters.num_alloc_iocb_failed);
+   seq_printf(s, "num term exchange sent = %lld\n",
+   vha->tgt_counters.num_term_xchg_sent);
+   seq_printf(s, "num Q full sent = %lld\n",
+   vha->tgt_counters.num_q_full_sent);
+
+   return 0;
+}
+
+static int
+qla_dfs_tgt_counters_open(struct inode *inode, struct file *file)
+{
+   struct scsi_qla_host *vha = inode->i_private;
+   return single_open(file, qla_dfs_tgt_counters_show, vha);
+}
+
+static const struct file_operations dfs_tgt_counters_ops = {
+   .open   = qla_dfs_tgt_counters_open,
+   .read   = seq_read,
+   .llseek = seq_lseek,
+   .release= single_release,
+};
+
+static int
 qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
 {
scsi_qla_host_t *vha = s->private;
@@ -146,6 +188,14 @@ create_dir:
atomic_inc(_dfs_root_count);
 
 create_nodes:
+   ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
+   ha->dfs_dir, vha, 

[PATCH 18/20] qla2xxx: Set all queues to 4k

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

set ATIO/Request/Response Queues and Default number
of outstanding command to 4k.

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

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 0ddb2de..141a6ba 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -259,7 +259,7 @@
 #define LOOP_DOWN_TIME 255 /* 240 */
 #defineLOOP_DOWN_RESET (LOOP_DOWN_TIME - 30)
 
-#define DEFAULT_OUTSTANDING_COMMANDS   1024
+#define DEFAULT_OUTSTANDING_COMMANDS   4096
 #define MIN_OUTSTANDING_COMMANDS   128
 
 /* ISP request and response entry counts (37-65535) */
@@ -267,6 +267,7 @@
 #define REQUEST_ENTRY_CNT_2200 2048/* Number of request entries. */
 #define REQUEST_ENTRY_CNT_24XX 2048/* Number of request entries. */
 #define REQUEST_ENTRY_CNT_83XX 8192/* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_83XX4096/* Number of response 
entries.*/
 #define RESPONSE_ENTRY_CNT_210064  /* Number of response 
entries.*/
 #define RESPONSE_ENTRY_CNT_2300512 /* Number of response 
entries.*/
 #define RESPONSE_ENTRY_CNT_MQ  128 /* Number of response entries.*/
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index b350905..0fcc838 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2483,7 +2483,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct 
pci_device_id *id)
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
req_length = REQUEST_ENTRY_CNT_83XX;
-   rsp_length = RESPONSE_ENTRY_CNT_2300;
+   rsp_length = RESPONSE_ENTRY_CNT_83XX;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
@@ -2513,8 +2513,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct 
pci_device_id *id)
ha->portnum = PCI_FUNC(ha->pdev->devfn);
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
-   req_length = REQUEST_ENTRY_CNT_24XX;
-   rsp_length = RESPONSE_ENTRY_CNT_2300;
+   req_length = REQUEST_ENTRY_CNT_83XX;
+   rsp_length = RESPONSE_ENTRY_CNT_83XX;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 19/20] qla2xxx: Add bulk send for atio & ctio completion paths.

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

At high traffic, the work queue can become a bottle neck.
Instead of putting each command on the work queue as 1 work
element, the fix would daisy chain a list of commands that came
from FW/interrupt under 1 work element to reduce lock contention.

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_def.h |3 +
 drivers/scsi/qla2xxx/qla_isr.c |3 +
 drivers/scsi/qla2xxx/qla_target.c  |   65 ++-
 drivers/scsi/qla2xxx/qla_target.h  |2 +
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |   75 +--
 5 files changed, 133 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 141a6ba..b731eef 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2937,6 +2937,9 @@ struct qlt_hw_data {
uint32_t leak_exchg_thresh_hold;
spinlock_t sess_lock;
int rspq_vector_cpuid;
+
+   void *ctio_for_bulk_process;
+   void *atio_for_bulk_process;
spinlock_t atio_lock cacheline_aligned;
 };
 
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 72d1cdc..d2bbcbb 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -2646,6 +2646,9 @@ process_err:
WRT_REG_DWORD(>rsp_q_out[0], rsp->ring_index);
} else
WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
+
+   if (ha->tgt.ctio_for_bulk_process)
+   vha->hw->tgt.tgt_ops->handle_bulk(vha);
 }
 
 static void
diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index f8f2b8a..9cf812f 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -3834,12 +3834,23 @@ static void qlt_do_work(struct work_struct *work)
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
scsi_qla_host_t *vha = cmd->vha;
unsigned long flags;
+   struct list_head h;
+   struct qla_tgt_cmd *c = NULL, *tc = NULL;
 
spin_lock_irqsave(>cmd_list_lock, flags);
list_del(>cmd_list);
spin_unlock_irqrestore(>cmd_list_lock, flags);
 
+   INIT_LIST_HEAD();
+   if (!list_empty(>bulk_process_list))
+   list_splice_init(>bulk_process_list, );
+
__qlt_do_work(cmd);
+
+   list_for_each_entry_safe(c, tc, , bulk_process_list) {
+   list_del_init(>bulk_process_list);
+   c->work.func(>work);
+   }
 }
 
 static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
@@ -3871,6 +3882,7 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t 
*vha,
cmd->jiffies_at_alloc = get_jiffies_64();
 
cmd->reset_count = vha->hw->chip_reset;
+   INIT_LIST_HEAD(>bulk_process_list);
 
return cmd;
 }
@@ -3930,6 +3942,7 @@ static void qlt_create_sess_from_atio(struct work_struct 
*work)
kfree(op);
return;
}
+
/*
 * __qlt_do_work() will call ha->tgt.tgt_ops->put_sess() to release
 * the extra reference taken above by qlt_make_local_sess()
@@ -3946,6 +3959,40 @@ out_term:
 
 }
 
+static void qlt_add_cmd_to_bulk_list(struct qla_tgt_cmd *cmd)
+{
+   struct qla_hw_data *ha = cmd->tgt->ha;
+   struct qla_tgt_cmd *hc = (struct qla_tgt_cmd *)
+   ha->tgt.atio_for_bulk_process;
+
+   if (IS_QLA27XX(ha) || IS_QLA83XX(ha))
+   /* We are running under atio_lock protection here. */
+   assert_spin_locked(>tgt.atio_lock);
+   else
+   assert_spin_locked(>hardware_lock);
+
+   if (hc)
+   list_add_tail(>bulk_process_list, >bulk_process_list);
+   else
+   ha->tgt.atio_for_bulk_process = (void *)cmd;
+}
+
+static void qlt_send_atio_bulk(struct qla_hw_data *ha)
+{
+   struct qla_tgt_cmd *cmd =
+   (struct qla_tgt_cmd *)ha->tgt.atio_for_bulk_process;
+
+   if (IS_QLA27XX(ha) || IS_QLA83XX(ha))
+   /*We are running under atio_lock protection here */
+   assert_spin_locked(>tgt.atio_lock);
+   else
+   assert_spin_locked(>hardware_lock);
+
+   ha->tgt.atio_for_bulk_process = NULL;
+   queue_work_on(smp_processor_id(), qla_tgt_wq, >work);
+}
+
+
 /* ha->hardware_lock supposed to be held on entry */
 static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
struct atio_from_isp *atio)
@@ -4011,17 +4058,11 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host 
*vha,
spin_unlock(>cmd_list_lock);
 
INIT_WORK(>work, qlt_do_work);
-   if (ha->msix_count) {
+   if (ha->msix_count)
cmd->se_cmd.cpuid = ha->tgt.rspq_vector_cpuid;
-   if (cmd->atio.u.isp24.fcp_cmnd.rddata)
-   queue_work_on(smp_processor_id(), 

[PATCH 14/20] qla2xxx: Add irq affinity notification

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

Register to receive notification of when irq setting change
occured.

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

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 7c6369b..9165732 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2714,11 +2714,16 @@ struct isp_operations {
 
 struct scsi_qla_host;
 
+
+#define QLA83XX_RSPQ_MSIX_ENTRY_NUMBER 1 /* refer to qla83xx_msix_entries */
+
 struct qla_msix_entry {
int have_irq;
uint32_t vector;
uint16_t entry;
struct rsp_que *rsp;
+   struct irq_affinity_notify irq_notify;
+   int cpuid;
 };
 
 #defineWATCH_INTERVAL  1   /* number of seconds */
@@ -2930,6 +2935,7 @@ struct qlt_hw_data {
spinlock_t q_full_lock;
uint32_t leak_exchg_thresh_hold;
spinlock_t sess_lock;
+   int rspq_vector_cpuid;
 };
 
 #define MAX_QFULL_CMDS_ALLOC   8192
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index ea7e8e8..e879802d 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -18,6 +18,10 @@ static void qla2x00_status_entry(scsi_qla_host_t *, struct 
rsp_que *, void *);
 static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
 static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
sts_entry_t *);
+static void qla_irq_affinity_notify(struct irq_affinity_notify *,
+const cpumask_t *);
+static void qla_irq_affinity_release(struct kref *);
+
 
 /**
  * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -2548,6 +2552,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host 
*vha,
if (!vha->flags.online)
return;
 
+   if (rsp->msix->cpuid != smp_processor_id()) {
+   /* if kernel does not notify qla of IRQ's CPU change,
+* then set it here.
+*/
+   rsp->msix->cpuid = smp_processor_id();
+   ha->tgt.rspq_vector_cpuid = rsp->msix->cpuid;
+   }
+
while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
 
@@ -2979,8 +2991,11 @@ qla24xx_disable_msix(struct qla_hw_data *ha)
 
for (i = 0; i < ha->msix_count; i++) {
qentry = >msix_entries[i];
-   if (qentry->have_irq)
+   if (qentry->have_irq) {
+   /* un-register irq cpu affinity notification */
+   irq_set_affinity_notifier(qentry->vector, NULL);
free_irq(qentry->vector, qentry->rsp);
+   }
}
pci_disable_msix(ha->pdev);
kfree(ha->msix_entries);
@@ -3043,6 +3058,9 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct 
rsp_que *rsp)
qentry->entry = entries[i].entry;
qentry->have_irq = 0;
qentry->rsp = NULL;
+   qentry->irq_notify.notify  = qla_irq_affinity_notify;
+   qentry->irq_notify.release = qla_irq_affinity_release;
+   qentry->cpuid = -1;
}
 
/* Enable MSI-X vectors for the base queue */
@@ -3061,6 +3079,18 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct 
rsp_que *rsp)
qentry->have_irq = 1;
qentry->rsp = rsp;
rsp->msix = qentry;
+
+   /* Register for CPU affinity notification. */
+   irq_set_affinity_notifier(qentry->vector, >irq_notify);
+
+   /* Schedule work (ie. trigger a notification) to read cpu
+* mask for this specific irq.
+* kref_get is required because
+   * irq_affinity_notify() will do
+   * kref_put().
+   */
+   kref_get(>irq_notify.kref);
+   schedule_work(>irq_notify.work);
}
 
/*
@@ -3240,3 +3270,47 @@ int qla25xx_request_irq(struct rsp_que *rsp)
msix->rsp = rsp;
return ret;
 }
+
+
+/* irq_set_affinity/irqbalance will trigger notification of cpu mask update */
+static void qla_irq_affinity_notify(struct irq_affinity_notify *notify,
+   const cpumask_t *mask)
+{
+   struct qla_msix_entry *e =
+   container_of(notify, struct qla_msix_entry, irq_notify);
+   struct qla_hw_data *ha;
+   struct scsi_qla_host *base_vha;
+
+   /* user is recommended to set mask to just 1 cpu */
+   e->cpuid = cpumask_first(mask);
+
+   ha = e->rsp->hw;
+   base_vha = pci_get_drvdata(ha->pdev);
+
+   ql_dbg(ql_dbg_init, base_vha, 0x,
+   "%s: 

[PATCH 07/20] qla2xxx: Wait for all conflicts before ack'ing PLOGI

2015-12-07 Thread Himanshu Madhani
From: Alexei Potashnik 

Until now ack'ing of a new PLOGI has only been delayed if there
was an existing session for the same WWN. Ack was released when
the session deletion completed.

If there was another WWN session with the same fc_id/loop_id pair
(aka "conflicting session"), PLOGI was still ack'ed immediately.
This potentially caused a problem when old session deletion logged
fc_id/loop_id out of FW after new session has been established.

Two work-arounds were attempted before:
1. Dropping PLOGIs until conflicting session goes away.
2. Detecting initiator being logged out of FW and issuing LOGO
to force re-login.

This patch introduces proper solution to the problem where PLOGI
is held until either existing session with same WWN or any
conflicting session goes away. Mechanism supports one session holding
two PLOGI acks as well as one PLOGI ack being held by many sessions.

Signed-off-by: Alexei Potashnik 
Acked-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_dbg.c|4 +-
 drivers/scsi/qla2xxx/qla_def.h|2 +
 drivers/scsi/qla2xxx/qla_os.c |1 +
 drivers/scsi/qla2xxx/qla_target.c |  202 +
 drivers/scsi/qla2xxx/qla_target.h |   18 +++-
 5 files changed, 177 insertions(+), 50 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 02f01be..b303027 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -26,7 +26,7 @@
  * |  || 0x3036,0x3038  |
  * |  || 0x303a
|
  * | DPC Thread   |   0x4023   | 0x4002,0x4013  |
- * | Async Events |   0x508a   | 0x502b-0x502f  |
+ * | Async Events |   0x5089   | 0x502b-0x502f  |
  * |  || 0x5084,0x5075 |
  * |  || 0x503d,0x5044  |
  * |  || 0x507b,0x505f |
@@ -63,7 +63,7 @@
  * |  || 0xd101-0xd1fe |
  * |  || 0xd214-0xd2fe |
  * | Target Mode |   0xe080   ||
- * | Target Mode Management  |   0xf096   | 0xf002 |
+ * | Target Mode Management  |   0xf09b   | 0xf002 |
  * |  || 0xf046-0xf049  |
  * | Target Mode Task Management  |  0x1000d  ||
  * --
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 1050fc2..46abba8 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3654,6 +3654,8 @@ typedef struct scsi_qla_host {
int total_fcport_update_gen;
/* List of pending LOGOs, protected by tgt_mutex */
struct list_headlogo_list;
+   /* List of pending PLOGI acks, protected by hw lock */
+   struct list_headplogi_ack_list;
 
uint32_tvp_abort_cnt;
 
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index c02cbc6..eb47272 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3919,6 +3919,7 @@ struct scsi_qla_host *qla2x00_create_host(struct 
scsi_host_template *sht,
INIT_LIST_HEAD(>qla_cmd_list);
INIT_LIST_HEAD(>qla_sess_op_cmd_list);
INIT_LIST_HEAD(>logo_list);
+   INIT_LIST_HEAD(>plogi_ack_list);
 
spin_lock_init(>work_lock);
spin_lock_init(>cmd_list_lock);
diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 5ef9d4c..57b4294 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -118,10 +118,13 @@ static void qlt_send_notify_ack(struct scsi_qla_host *vha,
struct imm_ntfy_from_isp *ntfy,
uint32_t add_flags, uint16_t resp_code, int resp_code_valid,
uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan);
+static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
+   struct imm_ntfy_from_isp *imm, int ha_locked);
 /*
  * Global Variables
  */
 static struct kmem_cache *qla_tgt_mgmt_cmd_cachep;
+static struct kmem_cache *qla_tgt_plogi_cachep;
 static mempool_t *qla_tgt_mgmt_cmd_mempool;
 static struct workqueue_struct *qla_tgt_wq;
 static DEFINE_MUTEX(qla_tgt_mutex);
@@ -389,6 +392,85 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, 
response_t *pkt)
 
 }
 
+/*
+ * All qlt_plogi_ack_t operations are protected by hardware_lock
+ */
+
+/*
+ * This is a zero-base ref-counting solution, since hardware_lock
+ * guarantees that ref_count is 

[PATCH 05/20] qla2xxx: Added interface to send ELS commands from driver.

2015-12-07 Thread Himanshu Madhani
Signed-off-by: Himanshu Madhani 
Signed-off-by: Giridhar Malavali 
---
 drivers/scsi/qla2xxx/qla_attr.c   |   36 +++
 drivers/scsi/qla2xxx/qla_dbg.c|5 +-
 drivers/scsi/qla2xxx/qla_def.h|   19 -
 drivers/scsi/qla2xxx/qla_gbl.h|2 +
 drivers/scsi/qla2xxx/qla_inline.h |2 +
 drivers/scsi/qla2xxx/qla_iocb.c   |  189 +
 drivers/scsi/qla2xxx/qla_isr.c|6 +
 7 files changed, 255 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 6b942d9..6992ebc 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -824,6 +824,41 @@ static struct bin_attribute sysfs_reset_attr = {
 };
 
 static ssize_t
+qla2x00_issue_logo(struct file *filp, struct kobject *kobj,
+   struct bin_attribute *bin_attr,
+   char *buf, loff_t off, size_t count)
+{
+   struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+   struct device, kobj)));
+   int type;
+   int rval = 0;
+   port_id_t did;
+
+   type = simple_strtol(buf, NULL, 10);
+
+   did.b.domain = (type & 0x00ff) >> 16;
+   did.b.area = (type & 0xff00) >> 8;
+   did.b.al_pa = (type & 0x00ff);
+
+   ql_log(ql_log_info, vha, 0x70e3, "portid=%02x%02x%02x done\n",
+   did.b.domain, did.b.area, did.b.al_pa);
+
+   ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type);
+
+   rval = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
+   return count;
+}
+
+static struct bin_attribute sysfs_issue_logo_attr = {
+   .attr = {
+   .name = "issue_logo",
+   .mode = S_IWUSR,
+   },
+   .size = 0,
+   .write = qla2x00_issue_logo,
+};
+
+static ssize_t
 qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
   struct bin_attribute *bin_attr,
   char *buf, loff_t off, size_t count)
@@ -937,6 +972,7 @@ static struct sysfs_entry {
{ "vpd", _vpd_attr, 1 },
{ "sfp", _sfp_attr, 1 },
{ "reset", _reset_attr, },
+   { "issue_logo", _issue_logo_attr, },
{ "xgmac_stats", _xgmac_stats_attr, 3 },
{ "dcbx_tlv", _dcbx_tlv_attr, 3 },
{ NULL },
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 07451bb..02f01be 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -19,7 +19,7 @@
  * | Device Discovery |   0x2016   | 0x2020-0x2022, |
  * |  || 0x2011-0x2012, |
  * |  || 0x2099-0x20a4  |
- * | Queue Command and IO tracing |   0x3075   | 0x300b |
+ * | Queue Command and IO tracing |   0x3074   | 0x300b |
  * |  || 0x3027-0x3028  |
  * |  || 0x303d-0x3041  |
  * |  || 0x302d,0x3033  |
@@ -27,12 +27,11 @@
  * |  || 0x303a
|
  * | DPC Thread   |   0x4023   | 0x4002,0x4013  |
  * | Async Events |   0x508a   | 0x502b-0x502f  |
- * |  || 0x5047
|
  * |  || 0x5084,0x5075 |
  * |  || 0x503d,0x5044  |
  * |  || 0x507b,0x505f |
  * | Timer Routines   |   0x6012   ||
- * | User Space Interactions  |   0x70e2   | 0x7018,0x702e  |
+ * | User Space Interactions  |   0x70e65  | 0x7018,0x702e  |
  * | || 0x7020,0x7024  |
  * |  || 0x7039,0x7045  |
  * |  || 0x7073-0x7075  |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index cf32fb9..366f65b 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -310,6 +310,14 @@ struct srb_cmd {
 /* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
 #define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID)
 
+struct els_logo_payload {
+   uint8_t opcode;
+   uint8_t rsvd[3];
+   uint8_t s_id[3];
+   uint8_t rsvd1[1];
+   uint8_t wwpn[WWN_SIZE];
+};
+
 /*
  * SRB extensions.
  */
@@ -323,6 +331,15 @@ struct srb_iocb {
uint16_t data[2];
} logio;
struct {
+#define ELS_DCMD_TIMEOUT 20
+#define ELS_DCMD_LOGO 0x5
+   uint32_t flags;
+   uint32_t els_cmd;
+ 

[PATCH 04/20] qla2xxx: Add FW resource count in DebugFS.

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

DebugFS now will show fw_resource_count node.

FW Resource count

Original TGT exchg count[0]
current TGT exchg count[0]
original Initiator Exchange count[2048]
Current Initiator Exchange count[2048]
Original IOCB count[2078]
Current IOCB count[2067]
MAX VP count[254]
MAX FCF count[0]

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_def.h |   13 +++--
 drivers/scsi/qla2xxx/qla_dfs.c |   50 
 drivers/scsi/qla2xxx/qla_gbl.h |3 +-
 drivers/scsi/qla2xxx/qla_init.c|   12 +++-
 drivers/scsi/qla2xxx/qla_mbx.c |   28 ---
 drivers/scsi/qla2xxx/qla_target.c  |4 +-
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |2 +-
 7 files changed, 81 insertions(+), 31 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 1d2a51a..cf32fb9 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2917,7 +2917,7 @@ struct qlt_hw_data {
 #define MAX_QFULL_CMDS_ALLOC   8192
 #define Q_FULL_THRESH_HOLD_PERCENT 90
 #define Q_FULL_THRESH_HOLD(ha) \
-   ((ha->fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
+   ((ha->cur_fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
 
 #define LEAK_EXCHG_THRESH_HOLD_PERCENT 75  /* 75 percent */
 
@@ -3298,8 +3298,14 @@ struct qla_hw_data {
 #define RISC_START_ADDRESS_2100 0x1000
 #define RISC_START_ADDRESS_2300 0x800
 #define RISC_START_ADDRESS_2400 0x10
-   uint16_tfw_xcb_count;
-   uint16_tfw_iocb_count;
+
+   uint16_torig_fw_tgt_xcb_count;
+   uint16_tcur_fw_tgt_xcb_count;
+   uint16_torig_fw_xcb_count;
+   uint16_tcur_fw_xcb_count;
+   uint16_torig_fw_iocb_count;
+   uint16_tcur_fw_iocb_count;
+   uint16_tfw_max_fcf_count;
 
uint32_tfw_shared_ram_start;
uint32_tfw_shared_ram_end;
@@ -3343,6 +3349,7 @@ struct qla_hw_data {
struct dentry *dfs_dir;
struct dentry *dfs_fce;
struct dentry *dfs_tgt_counters;
+   struct dentry *dfs_fw_resource_cnt;
 
dma_addr_t  fce_dma;
void*fce;
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 449541f..cd8b96a 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -13,6 +13,43 @@ static struct dentry *qla2x00_dfs_root;
 static atomic_t qla2x00_dfs_root_count;
 
 static int
+qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
+{
+   struct scsi_qla_host *vha = s->private;
+   struct qla_hw_data *ha = vha->hw;
+
+   seq_puts(s, "FW Resource count\n\n");
+   seq_printf(s, "Original TGT exchg count[%d]\n",
+   ha->orig_fw_tgt_xcb_count);
+   seq_printf(s, "current TGT exchg count[%d]\n",
+   ha->cur_fw_tgt_xcb_count);
+   seq_printf(s, "original Initiator Exchange count[%d]\n",
+   ha->orig_fw_xcb_count);
+   seq_printf(s, "Current Initiator Exchange count[%d]\n",
+   ha->cur_fw_xcb_count);
+   seq_printf(s, "Original IOCB count[%d]\n", ha->orig_fw_iocb_count);
+   seq_printf(s, "Current IOCB count[%d]\n", ha->cur_fw_iocb_count);
+   seq_printf(s, "MAX VP count[%d]\n", ha->max_npiv_vports);
+   seq_printf(s, "MAX FCF count[%d]\n", ha->fw_max_fcf_count);
+
+   return 0;
+}
+
+static int
+qla_dfs_fw_resource_cnt_open(struct inode *inode, struct file *file)
+{
+   struct scsi_qla_host *vha = inode->i_private;
+   return single_open(file, qla_dfs_fw_resource_cnt_show, vha);
+}
+
+static const struct file_operations dfs_fw_resource_cnt_ops = {
+   .open   = qla_dfs_fw_resource_cnt_open,
+   .read   = seq_read,
+   .llseek = seq_lseek,
+   .release= single_release,
+};
+
+static int
 qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
 {
struct scsi_qla_host *vha = s->private;
@@ -188,6 +225,14 @@ create_dir:
atomic_inc(_dfs_root_count);
 
 create_nodes:
+   ha->dfs_fw_resource_cnt = debugfs_create_file("fw_resource_count",
+   S_IRUSR, ha->dfs_dir, vha, _fw_resource_cnt_ops);
+   if (!ha->dfs_fw_resource_cnt) {
+   ql_log(ql_log_warn, vha, 0x00fd,
+   "Unable to create debugFS fw_resource_count node.\n");
+   goto out;
+   }
+
ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
ha->dfs_dir, vha, _tgt_counters_ops);
if (!ha->dfs_tgt_counters) {
@@ -212,6 +257,11 @@ qla2x00_dfs_remove(scsi_qla_host_t *vha)
 {
struct qla_hw_data *ha = vha->hw;
 
+   if (ha->dfs_fw_resource_cnt) {
+   debugfs_remove(ha->dfs_fw_resource_cnt);
+   ha->dfs_fw_resource_cnt = NULL;
+   }
+
if (ha->dfs_tgt_counters) {

[PATCH 01/20] qla2xxx: Enable Extended Login support

2015-12-07 Thread Himanshu Madhani
Signed-off-by: Himanshu Madhani 
Signed-off-by: Giridhar Malavali 
---
 drivers/scsi/qla2xxx/qla_dbg.c  |9 +--
 drivers/scsi/qla2xxx/qla_def.h  |   13 -
 drivers/scsi/qla2xxx/qla_gbl.h  |7 ++
 drivers/scsi/qla2xxx/qla_init.c |7 ++
 drivers/scsi/qla2xxx/qla_mbx.c  |  119 +++
 drivers/scsi/qla2xxx/qla_os.c   |   76 +
 6 files changed, 224 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 34dc9a3..5766640 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -14,7 +14,7 @@
  * | Module Init and Probe|   0x017f   | 0x0146 |
  * |  || 0x015b-0x0160 |
  * |  || 0x016e-0x0170  |
- * | Mailbox commands |   0x118d   | 0x1115-0x1116 |
+ * | Mailbox commands |   0x1192   | 0x1018-0x1019 |
  * |  || 0x111a-0x111b  |
  * | Device Discovery |   0x2016   | 0x2020-0x2022, |
  * |  || 0x2011-0x2012, |
@@ -60,10 +60,9 @@
  * |  || 0xb13c-0xb140  |
  * |  || 0xb149
|
  * | MultiQ   |   0xc00c   |   |
- * | Misc |   0xd300   | 0xd016-0xd017 |
- * |  || 0xd021,0xd024 |
- * |  || 0xd025,0xd029 |
- * |  || 0xd02a,0xd02e |
+ * | Misc |   0xd300   | 0xd012-0xd014 |
+ * |  || 0xd016-0xd017 |
+ * |  || 0xd02e
|
  * |  || 0xd031-0xd0ff |
  * |  || 0xd101-0xd1fe |
  * |  || 0xd214-0xd2fe |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 388d790..8f465b7 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -891,6 +891,7 @@ struct mbx_cmd_32 {
 #define MBC_DISABLE_VI 0x24/* Disable VI operation. */
 #define MBC_ENABLE_VI  0x25/* Enable VI operation. */
 #define MBC_GET_FIRMWARE_OPTION0x28/* Get Firmware 
Options. */
+#define MBC_GET_MEM_OFFLOAD_CNTRL_STAT 0x34/* Memory Offload ctrl/Stat*/
 #define MBC_SET_FIRMWARE_OPTION0x38/* Set Firmware 
Options. */
 #define MBC_LOOP_PORT_BYPASS   0x40/* Loop Port Bypass. */
 #define MBC_LOOP_PORT_ENABLE   0x41/* Loop Port Enable. */
@@ -2962,11 +2963,12 @@ struct qla_hw_data {
uint32_tisp82xx_no_md_cap:1;
uint32_thost_shutting_down:1;
uint32_tidc_compl_status:1;
-
uint32_tmr_reset_hdlr_active:1;
uint32_tmr_intr_valid:1;
+
uint32_tfawwpn_enabled:1;
-   /* 35 bits */
+   uint32_texlogins_enabled:1;
+   /* 34 bits */
} flags;
 
/* This spinlock is used to protect "io transactions", you must
@@ -3237,6 +3239,13 @@ struct qla_hw_data {
void*async_pd;
dma_addr_t  async_pd_dma;
 
+#define ENABLE_EXTENDED_LOGIN  BIT_7
+
+   /* Extended Logins  */
+   void*exlogin_buf;
+   dma_addr_t  exlogin_buf_dma;
+   int exlogin_size;
+
void*swl;
 
/* These are used by mailbox operations. */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 7686bfe..d396c49 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -117,6 +117,7 @@ extern int ql2xdontresethba;
 extern uint64_t ql2xmaxlun;
 extern int ql2xmdcapmask;
 extern int ql2xmdenable;
+extern int ql2xexlogins;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -135,6 +136,8 @@ extern int qla2x00_post_async_adisc_work(struct 
scsi_qla_host *, fc_port_t *,
 uint16_t *);
 extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
 fc_port_t *, uint16_t *);
+extern int qla2x00_set_exlogins_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exlogin_buffer(struct qla_hw_data *);
 
 extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
 
@@ -766,4 +769,8 @@ extern int qla8044_abort_isp(scsi_qla_host_t *);
 extern int 

[PATCH 20/20] qla2xxx: Check for online flag instead of active reset when transmitting responses

2015-12-07 Thread Himanshu Madhani
From: Dilip Kumar Uppugandla 

Driver has following initialization sequence for Target mode

1. Driver initialization starts

2. ISP Abort is scheduled when the target is enabled.

qla2xxx [:04:00.0]-4807:25: ISP abort scheduled
qla2xxx [:04:00.0]-00af:25: Performing ISP error recovery - 
ha=880caa9e.

3. DPC thread starts the ISP Abort

4. While DPC is resetting the chip and initializing the firmware, we get
   async events from the firmware about P2P mode, LOOP UP and PORT UPDATE.

5. PRLI from a initiator is delivered to us followed by a PLOGI and then a
   SCSI command which creates a session.

6. If the SCSI command is a WRITE in this case, we issue XFR RDY and it
   gets dropped as can be seen with messages RESET-XFR because ISP Abort
   is still active

qla2xxx [:04:00.0]-e902:25: RESET-XFR active/old-count/new-count = 1/1/1.

7. If the SCSI command is a READ, we issue RESPONSE and they get dropped
   as well because Abort is still active.

qla2xxx [:04:00.0]-e901:25: RESET-RSP active/old-count/new-count = 1/1/1

8. Now eventually, ISP Abort finishes clearing the DPC flags.

qla2xxx [:04:00.0]-8822:25: qla2x00_abort_isp succeeded.
qla2xxx [:04:00.0]-4808:25: ISP abort end.

9. Since we dropped SCSI commands silently (without any responses sent
   to the initiator) initiator waits for a SCSI timeout (which is 60
   seconds in our case), Sends an ABTS which fails since there
   no se_cmd found for the tag that ABTS is referencing as the
   commands were cleaned up in Step 6 and 7.

10. Initiator send an IO after the ABTS which succeed fine.

To fix the above case, the following changes have been made:
  - To prevent target from dropping commands silently, use the online flag
instead to check for an active chip reset. Once the port is online during
a chip reset phase, we are good to process the commands.
  - Clean up qla2x00_restart_isp to not set the online flag and process ATIO
as it is unnecessary. During a chip reset, interrupts are enabled only
after setting the online flag to 1, so ATIO's won't be missed and hence
no need to process ATIO's after setting the online flag.

Signed-off-by: Dilip Kumar Uppugandla 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_init.c   |   34 --
 drivers/scsi/qla2xxx/qla_target.c |   34 +-
 2 files changed, 37 insertions(+), 31 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 993dd25..52a8765 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3065,6 +3065,26 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
atomic_set(>loop_state, LOOP_READY);
ql_dbg(ql_dbg_disc, vha, 0x2069,
"LOOP READY.\n");
+
+   /*
+* Process any ATIO queue entries that came in
+* while we weren't online.
+*/
+   if (qla_tgt_mode_enabled(vha)) {
+   if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
+   spin_lock_irqsave(>tgt.atio_lock,
+   flags);
+   qlt_24xx_process_atio_queue(vha, 0);
+   spin_unlock_irqrestore(
+   >tgt.atio_lock, flags);
+   } else {
+   spin_lock_irqsave(>hardware_lock,
+   flags);
+   qlt_24xx_process_atio_queue(vha, 1);
+   spin_unlock_irqrestore(
+   >hardware_lock, flags);
+   }
+   }
}
}
 
@@ -4919,7 +4939,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0];
-   unsigned long flags, flags2;
 
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(vha)) {
@@ -4941,19 +4960,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
/* Issue a marker after FW becomes ready. */
qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
 
-   vha->flags.online = 1;
-
-   /*
-* Process any ATIO queue entries that came in
-* while we weren't online.
-*/
-   spin_lock_irqsave(>hardware_lock, flags);
-   spin_lock_irqsave(>tgt.atio_lock, flags2);
-   if 

[PATCH 02/20] qla2xxx: Enable Exchange offload support.

2015-12-07 Thread Himanshu Madhani
Signed-off-by: Himanshu Madhani 
Signed-off-by: Giridhar Malavali 
---
 drivers/scsi/qla2xxx/qla_dbg.c  |9 +--
 drivers/scsi/qla2xxx/qla_def.h  |   12 -
 drivers/scsi/qla2xxx/qla_gbl.h  |6 ++
 drivers/scsi/qla2xxx/qla_init.c |7 ++
 drivers/scsi/qla2xxx/qla_mbx.c  |  117 +++
 drivers/scsi/qla2xxx/qla_os.c   |   76 +
 6 files changed, 220 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 5766640..e25f5ac 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -14,8 +14,8 @@
  * | Module Init and Probe|   0x017f   | 0x0146 |
  * |  || 0x015b-0x0160 |
  * |  || 0x016e-0x0170  |
- * | Mailbox commands |   0x1192   | 0x1018-0x1019 |
- * |  || 0x111a-0x111b  |
+ * | Mailbox commands |   0x1192   |   |
+ * |  ||   |
  * | Device Discovery |   0x2016   | 0x2020-0x2022, |
  * |  || 0x2011-0x2012, |
  * |  || 0x2099-0x20a4  |
@@ -60,10 +60,7 @@
  * |  || 0xb13c-0xb140  |
  * |  || 0xb149
|
  * | MultiQ   |   0xc00c   |   |
- * | Misc |   0xd300   | 0xd012-0xd014 |
- * |  || 0xd016-0xd017 |
- * |  || 0xd02e
|
- * |  || 0xd031-0xd0ff |
+ * | Misc |   0xd300   | 0xd031-0xd0ff |
  * |  || 0xd101-0xd1fe |
  * |  || 0xd214-0xd2fe |
  * | Target Mode |   0xe080   ||
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 8f465b7..be9a674 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -272,6 +272,7 @@
 #define RESPONSE_ENTRY_CNT_MQ  128 /* Number of response entries.*/
 #define ATIO_ENTRY_CNT_24XX4096/* Number of ATIO entries. */
 #define RESPONSE_ENTRY_CNT_FX00256 /* Number of response 
entries.*/
+#define EXTENDED_EXCH_ENTRY_CNT32768   /* Reuqest Entries for 
offload case*/
 
 struct req_que;
 struct qla_tgt_sess;
@@ -2968,7 +2969,8 @@ struct qla_hw_data {
 
uint32_tfawwpn_enabled:1;
uint32_texlogins_enabled:1;
-   /* 34 bits */
+   uint32_texchoffld_enabled:1;
+   /* 35 bits */
} flags;
 
/* This spinlock is used to protect "io transactions", you must
@@ -3246,6 +3248,14 @@ struct qla_hw_data {
dma_addr_t  exlogin_buf_dma;
int exlogin_size;
 
+#define ENABLE_EXCHANGE_OFFLD  BIT_2
+
+   /* Exchange Offload */
+   void*exchoffld_buf;
+   dma_addr_t  exchoffld_buf_dma;
+   int exchoffld_size;
+   int exchoffld_count;
+
void*swl;
 
/* These are used by mailbox operations. */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index d396c49..f9ebfcf 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -118,6 +118,7 @@ extern uint64_t ql2xmaxlun;
 extern int ql2xmdcapmask;
 extern int ql2xmdenable;
 extern int ql2xexlogins;
+extern int ql2xexchoffld;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -138,6 +139,8 @@ extern int qla2x00_post_async_adisc_done_work(struct 
scsi_qla_host *,
 fc_port_t *, uint16_t *);
 extern int qla2x00_set_exlogins_buffer(struct scsi_qla_host *);
 extern void qla2x00_free_exlogin_buffer(struct qla_hw_data *);
+extern int qla2x00_set_exchoffld_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exchoffld_buffer(struct qla_hw_data *);
 
 extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
 
@@ -772,5 +775,8 @@ extern void qlt_host_reset_handler(struct qla_hw_data *ha);
 extern int qla_get_exlogin_status(scsi_qla_host_t *, uint16_t *,
uint16_t *);
 extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr);
+extern int qla_get_exchoffld_status(scsi_qla_host_t *, uint16_t *, uint16_t *);
+extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha,
+dma_addr_t phys_addr);

[PATCH 00/20] qla2xxx: Patches for target-pending branch

2015-12-07 Thread Himanshu Madhani
Hi Nic,

This patch series adds performance improvement for qla2xxx target mode driver.

Please apply this series to target-pending for next mainline merge window.

Thanks,
Himanshu

Alexei Potashnik (2):
  qla2xxx: Delete session if initiator is gone from FW
  qla2xxx: Wait for all conflicts before ack'ing PLOGI

Dilip Kumar Uppugandla (1):
  qla2xxx: Check for online flag instead of active reset when
transmitting responses

Himanshu Madhani (4):
  qla2xxx: Enable Extended Login support
  qla2xxx: Enable Exchange offload support.
  qla2xxx: Enable Target counters in DebugFS.
  qla2xxx: Added interface to send ELS commands from driver.

Quinn Tran (13):
  qla2xxx: Add FW resource count in DebugFS.
  qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit.
  qla2xxx: Change check_stop_free to always return 1
  qla2xxx: Fix interaction issue between qla2xxx and Target Core Module
  qla2xxx: Add TAS detection for kernel 3.15 n newer
  target/tmr: LUN reset cause cmd premature free.
  qla2xxx: Remove dependency on hardware_lock to reduce lock
contention.
  qla2xxx: Add irq affinity notification
  qla2xxx: Add selective command queuing
  qla2xxx: Move atioq to a different lock to reduce lock contention
  qla2xxx: Disable ZIO at start time.
  qla2xxx: Set all queues to 4k
  qla2xxx: Add bulk send for atio & ctio completion paths.

 drivers/scsi/qla2xxx/qla_attr.c|   36 ++
 drivers/scsi/qla2xxx/qla_dbg.c |   19 +-
 drivers/scsi/qla2xxx/qla_def.h |   86 -
 drivers/scsi/qla2xxx/qla_dfs.c |  106 +
 drivers/scsi/qla2xxx/qla_gbl.h |   19 +-
 drivers/scsi/qla2xxx/qla_init.c|   58 ++-
 drivers/scsi/qla2xxx/qla_inline.h  |2 +
 drivers/scsi/qla2xxx/qla_iocb.c|  190 
 drivers/scsi/qla2xxx/qla_isr.c |  129 +-
 drivers/scsi/qla2xxx/qla_mbx.c |  264 +++-
 drivers/scsi/qla2xxx/qla_os.c  |  163 +++-
 drivers/scsi/qla2xxx/qla_target.c  |  737 +---
 drivers/scsi/qla2xxx/qla_target.h  |   95 +++--
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |  205 -
 drivers/target/target_core_tmr.c   |   33 ++-
 drivers/target/target_core_transport.c |   35 ++-
 include/target/target_core_base.h  |2 +
 17 files changed, 1894 insertions(+), 285 deletions(-)

-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 17/20] qla2xxx: Disable ZIO at start time.

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

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

diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 69f88d3..f8f2b8a 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -6563,10 +6563,21 @@ qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha,
 {
struct qla_hw_data *ha = vha->hw;
 
+   if (!QLA_TGT_MODE_ENABLED())
+   return;
+
if (ha->tgt.node_name_set) {
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
+
+   /* disable ZIO at start time. */
+   if (!vha->flags.init_done) {
+   uint32_t tmp;
+   tmp = le32_to_cpu(icb->firmware_options_2);
+   tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+   icb->firmware_options_2 = cpu_to_le32(tmp);
+   }
 }
 
 void
@@ -6657,6 +6668,15 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha,
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
+
+   /* disable ZIO at start time. */
+   if (!vha->flags.init_done) {
+   uint32_t tmp;
+   tmp = le32_to_cpu(icb->firmware_options_2);
+   tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+   icb->firmware_options_2 = cpu_to_le32(tmp);
+   }
+
 }
 
 void
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 12/20] target/tmr: LUN reset cause cmd premature free.

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

During LUN/Target reset, the TMR code attempt to intercept
cmds and try to aborted them.  Current code assume cmds are
always intercepted at the back end device.  The cleanup code
would issue a "queue_status() & check_stop_free()" to terminate
the command.  However, when a cmd is intercepted at the front
end/Fabric layer, current code introduce premature free or
cause Fabric to double free.

When command is intercepted at Fabric layer, it means a
check_stop_free(cmd_kref--) has been called.  The extra
check_stop_free in the Lun Reset cleanup code causes early
free.  When a cmd in the Fabric layer is completed, the normal
free code adds another another free which introduce a double free.

To fix the issue:
- add a new flag/CMD_T_SENT_STATUS to track command that have
 made it down to fabric layer after back end good/bad completion.
- if cmd reach Fabric Layer at Lun Reset time, add an extra
 cmd_kref count to prevent premature free.

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/target/target_core_tmr.c   |   33 +++-
 drivers/target/target_core_transport.c |   30 +
 include/target/target_core_base.h  |1 +
 3 files changed, 63 insertions(+), 1 deletions(-)

diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 28fb301..41f8b57 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -243,7 +243,9 @@ static void core_tmr_drain_state_list(
 {
LIST_HEAD(drain_task_list);
struct se_cmd *cmd, *next;
-   unsigned long flags;
+   unsigned long flags, flags2;
+   int rmkref;
+   struct se_session *se_sess;
 
/*
 * Complete outstanding commands with TASK_ABORTED SAM status.
@@ -282,6 +284,16 @@ static void core_tmr_drain_state_list(
if (prout_cmd == cmd)
continue;
 
+   se_sess = cmd->se_sess;
+   /* take an extra kref to prevent cmd free race condition. */
+   spin_lock_irqsave(_sess->sess_cmd_lock, flags2);
+   if (!kref_get_unless_zero(>cmd_kref)) {
+   /* cmd is already in the free process */
+   spin_unlock_irqrestore(_sess->sess_cmd_lock, flags2);
+   continue;
+   }
+   spin_unlock_irqrestore(_sess->sess_cmd_lock, flags2);
+
list_move_tail(>state_list, _task_list);
cmd->state_active = false;
}
@@ -320,9 +332,28 @@ static void core_tmr_drain_state_list(
target_stop_cmd(cmd, );
 
cmd->transport_state |= CMD_T_ABORTED;
+
+   /* CMD_T_SENT_STATUS: cmd is down in fabric layer.
+* A check stop has been called.  Keep the extra kref
+* from above because core_tmr_handle_tas_abort will
+* generate another check_stop.
+*
+* !CMD_T_SENT_STATUS: cmd intercepted at back end.
+* Remove the extra kref from above because only
+* 1 check_stop is required or generated by
+* core_tmr_handle_tas_abort()
+*/
+   rmkref = 0;
+   if (!((cmd->t_state == TRANSPORT_COMPLETE) &&
+   (cmd->transport_state & CMD_T_SENT_STATUS)))
+   rmkref = 1;
+
spin_unlock_irqrestore(>t_state_lock, flags);
 
core_tmr_handle_tas_abort(tmr_nacl, cmd, tas);
+
+   if (rmkref)
+   target_put_sess_cmd(cmd);
}
 }
 
diff --git a/drivers/target/target_core_transport.c 
b/drivers/target/target_core_transport.c
index 4fdcee2..cdd18bf 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -639,9 +639,14 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int 
remove)
 static void target_complete_failure_work(struct work_struct *work)
 {
struct se_cmd *cmd = container_of(work, struct se_cmd, work);
+   unsigned long flags;
 
transport_generic_request_failure(cmd,
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE);
+
+   spin_lock_irqsave(>t_state_lock, flags);
+   cmd->transport_state |= CMD_T_SENT_STATUS;
+   spin_unlock_irqrestore(>t_state_lock, flags);
 }
 
 /*
@@ -1659,6 +1664,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
sense_reason_t sense_reason)
 {
int ret = 0, post_ret = 0;
+   unsigned long flags;
 
pr_debug("-[ Storage Engine Exception for cmd: %p ITT: 0x%08llx"
" CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]);
@@ -1670,6 +1676,10 @@ void transport_generic_request_failure(struct se_cmd 
*cmd,
(cmd->transport_state & CMD_T_STOP) != 0,

[PATCH 15/20] qla2xxx: Add selective command queuing

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

queue work element to specific process lessen cache miss

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_isr.c |2 +-
 drivers/scsi/qla2xxx/qla_target.c  |   13 -
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |4 ++--
 drivers/target/target_core_transport.c |5 -
 include/target/target_core_base.h  |1 +
 5 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index e879802d..26fa4d8 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -3302,7 +3302,7 @@ static void qla_irq_affinity_notify(struct 
irq_affinity_notify *notify,
}
 }
 
-void qla_irq_affinity_release(struct kref *ref)
+static void qla_irq_affinity_release(struct kref *ref)
 {
struct irq_affinity_notify *notify =
container_of(ref, struct irq_affinity_notify, kref);
diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index dc6ac4e..b33c018 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -4004,13 +4004,24 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host 
*vha,
 
cmd->cmd_in_wq = 1;
cmd->cmd_flags |= BIT_0;
+   cmd->se_cmd.cpuid = -1;
 
spin_lock(>cmd_list_lock);
list_add_tail(>cmd_list, >qla_cmd_list);
spin_unlock(>cmd_list_lock);
 
INIT_WORK(>work, qlt_do_work);
-   queue_work(qla_tgt_wq, >work);
+   if (ha->msix_count) {
+   cmd->se_cmd.cpuid = ha->tgt.rspq_vector_cpuid;
+   if (cmd->atio.u.isp24.fcp_cmnd.rddata)
+   queue_work_on(smp_processor_id(), qla_tgt_wq,
+   >work);
+   else
+   queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq,
+   >work);
+   } else {
+   queue_work(qla_tgt_wq, >work);
+   }
return 0;
 
 }
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c 
b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 833dec2..d7a34d1 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -303,7 +303,7 @@ static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
cmd->cmd_flags |= BIT_20;
 
INIT_WORK(>work, tcm_qla2xxx_complete_free);
-   queue_work(tcm_qla2xxx_free_wq, >work);
+   queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, >work);
 }
 
 /*
@@ -535,7 +535,7 @@ static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd)
cmd->cmd_flags |= BIT_10;
cmd->cmd_in_wq = 1;
INIT_WORK(>work, tcm_qla2xxx_handle_data_work);
-   queue_work(tcm_qla2xxx_free_wq, >work);
+   queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, >work);
 }
 
 static void tcm_qla2xxx_handle_dif_work(struct work_struct *work)
diff --git a/drivers/target/target_core_transport.c 
b/drivers/target/target_core_transport.c
index cdd18bf..a37db6d 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -720,7 +720,10 @@ void target_complete_cmd(struct se_cmd *cmd, u8 
scsi_status)
cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE);
spin_unlock_irqrestore(>t_state_lock, flags);
 
-   queue_work(target_completion_wq, >work);
+   if (cmd->cpuid == -1)
+   queue_work(target_completion_wq, >work);
+   else
+   queue_work_on(cmd->cpuid, target_completion_wq, >work);
 }
 EXPORT_SYMBOL(target_complete_cmd);
 
diff --git a/include/target/target_core_base.h 
b/include/target/target_core_base.h
index efccd71..ce26a3a 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -527,6 +527,7 @@ struct se_cmd {
unsigned intt_prot_nents;
sense_reason_t  pi_err;
sector_tbad_sector;
+   int cpuid;
 };
 
 struct se_ua {
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 11/20] qla2xxx: Add TAS detection for kernel 3.15 n newer

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

For kernel 3.15 and newer with TCM API change, add detection
for TCM support of TAS.  Instead of default command terminate
for LUN/TARGET reset error handling, allow SCSI status to go
out if we know sequece Initiative is own by FW (cmd_sent_to_fw=0)

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_target.c  |   36 +---
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |   20 
 2 files changed, 37 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 4d42b79..5fca846 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -3239,36 +3239,34 @@ int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
struct qla_tgt *tgt = cmd->tgt;
struct scsi_qla_host *vha = tgt->vha;
struct se_cmd *se_cmd = >se_cmd;
-   unsigned long flags,refcount;
+   unsigned long flags, refcount;
 
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
"qla_target(%d): terminating exchange for aborted cmd=%p "
"(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, >se_cmd,
se_cmd->tag);
 
-spin_lock_irqsave(>cmd_lock, flags);
-if (cmd->aborted) {
-spin_unlock_irqrestore(>cmd_lock, flags);
+   spin_lock_irqsave(>cmd_lock, flags);
 
-/* It's normal to see 2 calls in this path:
- *  1) XFER Rdy completion + CMD_T_ABORT
- *  2) TCM TMR - drain_state_list
- */
-refcount = atomic_read(>se_cmd.cmd_kref.refcount);
-ql_dbg(ql_dbg_tgt_mgt, vha, 0x,
-   "multiple abort. %p refcount %lx"
-   "transport_state %x, t_state %x, se_cmd_flags %x \n",
-   cmd, refcount,cmd->se_cmd.transport_state,
-   cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
+   if (cmd->aborted) {
+   spin_unlock_irqrestore(>cmd_lock, flags);
+   /* It's normal to see 2 calls in this path:
+*  1) XFER Rdy completion + CMD_T_ABORT
+*  2) TCM TMR - drain_state_list
+*/
+   refcount = atomic_read(>se_cmd.cmd_kref.refcount);
+   ql_dbg(ql_dbg_tgt_mgt, vha, 0x,
+   "multiple abort. %p refcount %lx"
+   "transport_state %x, t_state %x, se_cmd_flags %x \n",
+   cmd, refcount, cmd->se_cmd.transport_state,
+   cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags);
 
-return EIO;
-}
+   return EIO;
+   }
 
cmd->aborted = 1;
cmd->cmd_flags |= BIT_6;
-spin_unlock_irqrestore(>cmd_lock, flags);
-
-   qlt_send_term_exchange(vha, cmd, >atio, 0, 1);
+   spin_unlock_irqrestore(>cmd_lock, flags);
 
return 0;
 }
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c 
b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 842fcca..2e9c194 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -617,6 +617,26 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
struct qla_tgt_cmd, se_cmd);
int xmit_type = QLA_TGT_XMIT_STATUS;
 
+   if (se_cmd->transport_state & CMD_T_ABORTED) {
+   /* For TCM TAS support n kernel >= 3.15:
+* This cmd is attempting to respond with "Task Aborted Status".
+*/
+   if (cmd->aborted) {
+   return 0;
+   } else if ((cmd->state == QLA_TGT_STATE_NEED_DATA) &&
+   cmd->cmd_sent_to_fw) {
+   qlt_abort_cmd(cmd);
+   return 0;
+   } else if (cmd->state == QLA_TGT_STATE_PROCESSED) {
+   if (cmd->cmd_sent_to_fw) {
+   qlt_abort_cmd(cmd);
+   return 0;
+   } else {/* about to be free */
+   return 0;
+   }
+   }
+   }
+
cmd->bufflen = se_cmd->data_length;
cmd->sg = NULL;
cmd->sg_cnt = 0;
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 16/20] qla2xxx: Move atioq to a different lock to reduce lock contention

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

99% of the time the ATIOQ has SCSI command.  The other 1% of time
is something else.  Most of the time this interrupt does not need
to hold the hardware_lock.  We're moving the ATIO interrupt thread
to a different lock to reduce lock contention.

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_def.h|1 +
 drivers/scsi/qla2xxx/qla_gbl.h|1 +
 drivers/scsi/qla2xxx/qla_init.c   |6 ++-
 drivers/scsi/qla2xxx/qla_isr.c|   44 +
 drivers/scsi/qla2xxx/qla_os.c |2 +
 drivers/scsi/qla2xxx/qla_target.c |   97 +++--
 drivers/scsi/qla2xxx/qla_target.h |4 +-
 7 files changed, 127 insertions(+), 28 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 9165732..0ddb2de 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2936,6 +2936,7 @@ struct qlt_hw_data {
uint32_t leak_exchg_thresh_hold;
spinlock_t sess_lock;
int rspq_vector_cpuid;
+   spinlock_t atio_lock cacheline_aligned;
 };
 
 #define MAX_QFULL_CMDS_ALLOC   8192
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 2e91966..5496e0a 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -779,5 +779,6 @@ extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, 
dma_addr_t phys_addr);
 extern int qla_get_exchoffld_status(scsi_qla_host_t *, uint16_t *, uint16_t *);
 extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha,
 dma_addr_t phys_addr);
+extern void qlt_handle_abts_recv(struct scsi_qla_host *, response_t *);
 
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 35d1ea8..993dd25 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -4919,7 +4919,7 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0];
-   unsigned long flags;
+   unsigned long flags, flags2;
 
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(vha)) {
@@ -4948,8 +4948,10 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
 * while we weren't online.
 */
spin_lock_irqsave(>hardware_lock, flags);
+   spin_lock_irqsave(>tgt.atio_lock, flags2);
if (qla_tgt_mode_enabled(vha))
-   qlt_24xx_process_atio_queue(vha);
+   qlt_24xx_process_atio_queue(vha, 1);
+   spin_unlock_irqrestore(>tgt.atio_lock, flags2);
spin_unlock_irqrestore(>hardware_lock, flags);
 
set_bit(LOOP_RESYNC_NEEDED, >dpc_flags);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 26fa4d8..72d1cdc 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -2605,8 +2605,14 @@ process_err:
qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
break;
case ABTS_RECV_24XX:
-   /* ensure that the ATIO queue is empty */
-   qlt_24xx_process_atio_queue(vha);
+   if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+   /* ensure that the ATIO queue is empty */
+   qlt_handle_abts_recv(vha, (response_t *)pkt);
+   break;
+   } else {
+   /* drop through */
+   qlt_24xx_process_atio_queue(vha, 1);
+   }
case ABTS_RESP_24XX:
case CTIO_TYPE7:
case NOTIFY_ACK_TYPE:
@@ -2773,13 +2779,22 @@ qla24xx_intr_handler(int irq, void *dev_id)
case INTR_RSP_QUE_UPDATE_83XX:
qla24xx_process_response_queue(vha, rsp);
break;
-   case INTR_ATIO_QUE_UPDATE:
-   qlt_24xx_process_atio_queue(vha);
+   case INTR_ATIO_QUE_UPDATE:{
+   unsigned long flags2;
+   spin_lock_irqsave(>tgt.atio_lock, flags2);
+   qlt_24xx_process_atio_queue(vha, 1);
+   spin_unlock_irqrestore(>tgt.atio_lock, flags2);
break;
-   case INTR_ATIO_RSP_QUE_UPDATE:
-   qlt_24xx_process_atio_queue(vha);
+   }
+   case INTR_ATIO_RSP_QUE_UPDATE: {
+   unsigned long flags2;
+   spin_lock_irqsave(>tgt.atio_lock, flags2);
+   

[PATCH 08/20] qla2xxx: Replace QLA_TGT_STATE_ABORTED with a bit.

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

Replace QLA_TGT_STATE_ABORTED state with a bit because
the current state of the command is lost when an abort
is requested by upper layer.

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

diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 57b4294..638940f 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -1468,7 +1468,7 @@ static int abort_cmd_for_tag(struct scsi_qla_host *vha, 
uint32_t tag)
 
list_for_each_entry(cmd, >qla_cmd_list, cmd_list) {
if (tag == cmd->atio.u.isp24.exchange_addr) {
-   cmd->state = QLA_TGT_STATE_ABORTED;
+   cmd->aborted = 1;
spin_unlock(>cmd_list_lock);
return 1;
}
@@ -1510,7 +1510,7 @@ static void abort_cmds_for_lun(struct scsi_qla_host *vha,
cmd_lun = scsilun_to_int(
(struct scsi_lun *)>atio.u.isp24.fcp_cmnd.lun);
if (cmd_key == key && cmd_lun == lun)
-   cmd->state = QLA_TGT_STATE_ABORTED;
+   cmd->aborted = 1;
}
spin_unlock(>cmd_list_lock);
 }
@@ -3174,7 +3174,7 @@ static void qlt_send_term_exchange(struct scsi_qla_host 
*vha,
qlt_alloc_qfull_cmd(vha, atio, 0, 0);
 
 done:
-   if (cmd && ((cmd->state != QLA_TGT_STATE_ABORTED) ||
+   if (cmd && (!cmd->aborted ||
!cmd->cmd_sent_to_fw)) {
if (cmd->sg_mapped)
qlt_unmap_sg(vha, cmd);
@@ -3245,7 +3245,7 @@ void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
"(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, >se_cmd,
se_cmd->tag);
 
-   cmd->state = QLA_TGT_STATE_ABORTED;
+   cmd->aborted = 1;
cmd->cmd_flags |= BIT_6;
 
qlt_send_term_exchange(vha, cmd, >atio, 0);
@@ -3465,9 +3465,6 @@ qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, 
struct qla_tgt_cmd *cmd)
 
ha->tgt.tgt_ops->handle_data(cmd);
return;
-   } else if (cmd->state == QLA_TGT_STATE_ABORTED) {
-   ql_dbg(ql_dbg_io, vha, 0xff02,
-   "HOST-ABORT: handle=%d, state=ABORTED.\n", handle);
} else {
ql_dbg(ql_dbg_io, vha, 0xff03,
"HOST-ABORT: handle=%d, state=BAD(%d).\n", handle,
@@ -3632,14 +3629,14 @@ static void qlt_do_ctio_completion(struct scsi_qla_host 
*vha, uint32_t handle,
}
 
 
-   /* "cmd->state == QLA_TGT_STATE_ABORTED" means
+   /* "cmd->aborted" means
 * cmd is already aborted/terminated, we don't
 * need to terminate again.  The exchange is already
 * cleaned up/freed at FW level.  Just cleanup at driver
 * level.
 */
if ((cmd->state != QLA_TGT_STATE_NEED_DATA) &&
-   (cmd->state != QLA_TGT_STATE_ABORTED)) {
+   (!cmd->aborted)) {
cmd->cmd_flags |= BIT_13;
if (qlt_term_ctio_exchange(vha, ctio, cmd, status))
return;
@@ -3657,7 +3654,7 @@ skip_term:
 
ha->tgt.tgt_ops->handle_data(cmd);
return;
-   } else if (cmd->state == QLA_TGT_STATE_ABORTED) {
+   } else if (cmd->aborted) {
cmd->cmd_flags |= BIT_18;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e,
  "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag);
@@ -3669,7 +3666,7 @@ skip_term:
}
 
if (unlikely(status != CTIO_SUCCESS) &&
-   (cmd->state != QLA_TGT_STATE_ABORTED)) {
+   !cmd->aborted) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01f, "Finishing failed CTIO\n");
dump_stack();
}
@@ -3731,7 +3728,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
if (tgt->tgt_stop)
goto out_term;
 
-   if (cmd->state == QLA_TGT_STATE_ABORTED) {
+   if (cmd->aborted) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082,
"cmd with tag %u is aborted\n",
cmd->atio.u.isp24.exchange_addr);
@@ -4289,7 +4286,7 @@ static int abort_cmds_for_s_id(struct scsi_qla_host *vha, 
port_id_t *s_id)
list_for_each_entry(cmd, >qla_cmd_list, cmd_list) {
uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
if (cmd_key == key) {
-   cmd->state = QLA_TGT_STATE_ABORTED;
+   cmd->aborted = 1;
count++;
}
}
diff --git 

[PATCH 13/20] qla2xxx: Remove dependency on hardware_lock to reduce lock contention.

2015-12-07 Thread Himanshu Madhani
From: Quinn Tran 

Sessions management (add, deleted, modify) currently are serialized
through the hardware_lock.  Hardware_lock is a high traffic lock.
This lock is accessed by both the transmit & receive sides.

Sessions management is now moved off to another lock call sess_lock.
This is done to reduce lock contention and increase traffic throughput.

Signed-off-by: Quinn Tran 
Signed-off-by: Himanshu Madhani 
---
 drivers/scsi/qla2xxx/qla_def.h |1 +
 drivers/scsi/qla2xxx/qla_os.c  |1 +
 drivers/scsi/qla2xxx/qla_target.c  |  131 
 drivers/scsi/qla2xxx/tcm_qla2xxx.c |   28 
 4 files changed, 105 insertions(+), 56 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 46abba8..7c6369b 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2929,6 +2929,7 @@ struct qlt_hw_data {
uint32_t num_qfull_cmds_dropped;
spinlock_t q_full_lock;
uint32_t leak_exchg_thresh_hold;
+   spinlock_t sess_lock;
 };
 
 #define MAX_QFULL_CMDS_ALLOC   8192
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index eb47272..8b45642 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2336,6 +2336,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct 
pci_device_id *id)
ha->tgt.enable_class_2 = ql2xenableclass2;
INIT_LIST_HEAD(>tgt.q_full_list);
spin_lock_init(>tgt.q_full_lock);
+   spin_lock_init(>tgt.sess_lock);
 
/* Clear our data area */
ha->bars = bars;
diff --git a/drivers/scsi/qla2xxx/qla_target.c 
b/drivers/scsi/qla2xxx/qla_target.c
index 5fca846..d4b7e25 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -635,7 +635,7 @@ static void qlt_free_session_done(struct work_struct *work)
wake_up_all(>waitQ);
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 void qlt_unreg_sess(struct qla_tgt_sess *sess)
 {
struct scsi_qla_host *vha = sess->vha;
@@ -651,7 +651,7 @@ void qlt_unreg_sess(struct qla_tgt_sess *sess)
 }
 EXPORT_SYMBOL(qlt_unreg_sess);
 
-/* ha->hardware_lock supposed to be held on entry */
+
 static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
 {
struct qla_hw_data *ha = vha->hw;
@@ -661,12 +661,15 @@ static int qlt_reset(struct scsi_qla_host *vha, void 
*iocb, int mcmd)
int res = 0;
struct imm_ntfy_from_isp *n = (struct imm_ntfy_from_isp *)iocb;
struct atio_from_isp *a = (struct atio_from_isp *)iocb;
+   unsigned long flags;
 
loop_id = le16_to_cpu(n->u.isp24.nport_handle);
if (loop_id == 0x) {
/* Global event */
atomic_inc(>vha_tgt.qla_tgt->tgt_global_resets_count);
+   spin_lock_irqsave(>tgt.sess_lock, flags);
qlt_clear_tgt_db(vha->vha_tgt.qla_tgt);
+   spin_unlock_irqrestore(>tgt.sess_lock, flags);
 #if 0 /* FIXME: do we need to choose a session here? */
if (!list_empty(>tgt.qla_tgt->sess_list)) {
sess = list_entry(ha->tgt.qla_tgt->sess_list.next,
@@ -693,7 +696,9 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, 
int mcmd)
sess = NULL;
 #endif
} else {
+   spin_lock_irqsave(>tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+   spin_unlock_irqrestore(>tgt.sess_lock, flags);
}
 
ql_dbg(ql_dbg_tgt, vha, 0xe000,
@@ -715,7 +720,7 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, 
int mcmd)
iocb, QLA24XX_MGMT_SEND_NACK);
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
bool immediate)
 {
@@ -759,7 +764,7 @@ static void qlt_schedule_sess_for_deletion(struct 
qla_tgt_sess *sess,
sess->expires - jiffies);
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 static void qlt_clear_tgt_db(struct qla_tgt *tgt)
 {
struct qla_tgt_sess *sess;
@@ -819,7 +824,7 @@ out_free_id_list:
return res;
 }
 
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
 static void qlt_undelete_sess(struct qla_tgt_sess *sess)
 {
BUG_ON(sess->deleted != QLA_SESS_DELETION_PENDING);
@@ -837,7 +842,7 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
struct qla_tgt_sess *sess;
unsigned long flags, elapsed;
 
-   spin_lock_irqsave(>hardware_lock, flags);
+   spin_lock_irqsave(>tgt.sess_lock, flags);
while 

Re: [PATCH 06/20] qla2xxx: Delete session if initiator is gone from FW

2015-12-07 Thread kbuild test robot
Hi Alexei,

[auto build test WARNING on target/master]
[also build test WARNING on v4.4-rc4 next-20151207]
[cannot apply to scsi/for-next]

url:
https://github.com/0day-ci/linux/commits/Himanshu-Madhani/qla2xxx-Patches-for-target-pending-branch/20151208-093328
base:   https://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git 
master
config: i386-randconfig-x007-12070758 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386 

All warnings (new ones prefixed by >>):

   drivers/scsi/qla2xxx/qla_target.c: In function 'qlt_do_ctio_completion':
>> drivers/scsi/qla2xxx/qla_target.c:3465:20: warning: comparison of constant 
>> '41' with boolean expression is always false [-Wbool-compare]
   (logged_out == CTIO_PORT_LOGGED_OUT) ?
   ^

vim +/41 +3465 drivers/scsi/qla2xxx/qla_target.c

  3449  /* They are OK */
  3450  ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058,
  3451  "qla_target(%d): CTIO with "
  3452  "status %#x received, state %x, se_cmd %p, "
  3453  "(LIP_RESET=e, ABORTED=2, TARGET_RESET=17, "
  3454  "TIMEOUT=b, INVALID_RX_ID=8)\n", 
vha->vp_idx,
  3455  status, cmd->state, se_cmd);
  3456  break;
  3457  
  3458  case CTIO_PORT_LOGGED_OUT:
  3459  case CTIO_PORT_UNAVAILABLE:
  3460  {
  3461  bool logged_out = (status & 0x);
  3462  ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059,
  3463  "qla_target(%d): CTIO with %s status %x "
  3464  "received (state %x, se_cmd %p)\n", 
vha->vp_idx,
> 3465  (logged_out == CTIO_PORT_LOGGED_OUT) ?
  3466  "PORT LOGGED OUT" : "PORT UNAVAILABLE",
  3467  status, cmd->state, se_cmd);
  3468  
  3469  if (logged_out && cmd->sess) {
  3470  /*
  3471   * Session is already logged out, but 
we need
  3472   * to notify initiator, who's not aware 
of this
  3473   */

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


.config.gz
Description: Binary data


Re: [PATCH v2 74/71] ncr5380: Enable PDMA for NCR53C400A

2015-12-07 Thread Finn Thain

On Sun, 6 Dec 2015, Ondrej Zary wrote:

> Add I/O register mapping for NCR53C400A and enable PDMA mode to
> improve performance and fix non-working IRQ.
> 
> Tested with HP C2502 (and user-space enabler).
> 
> Signed-off-by: Ondrej Zary 
> ---
>  drivers/scsi/g_NCR5380.c |   14 +++---
>  1 file changed, 11 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
> index 86740fd..099fdac 100644
> --- a/drivers/scsi/g_NCR5380.c
> +++ b/drivers/scsi/g_NCR5380.c
> @@ -324,7 +324,7 @@ static int __init generic_NCR5380_detect(struct 
> scsi_host_template *tpnt)
>  #endif
>   break;
>   case BOARD_NCR53C400A:
> - flags = FLAG_NO_PSEUDO_DMA;
> + flags = FLAG_NO_DMA_FIXUP;
>   ports = ncr_53c400a_ports;
>   break;
>   case BOARD_DTC3181E:
> @@ -406,11 +406,18 @@ static int __init generic_NCR5380_detect(struct 
> scsi_host_template *tpnt)
>* On NCR53C400 boards, NCR5380 registers are mapped 8 past
>* the base address.
>*/
> - if (overrides[current_override].board == BOARD_NCR53C400) {
> + switch (overrides[current_override].board) {
> + case BOARD_NCR53C400:
>   instance->io_port += 8;
>   hostdata->c400_ctl_status = 0;
>   hostdata->c400_blk_cnt = 1;
>   hostdata->c400_host_buf = 4;
> + break;
> + case BOARD_NCR53C400A:
> + hostdata->c400_ctl_status = 9;
> + hostdata->c400_blk_cnt = 10;
> + hostdata->c400_host_buf = 8;
> + break;
>   }
>  #else
>   instance->base = overrides[current_override].NCR5380_map_name;


For SCSI_G_NCR5380_MEM and BOARD_NCR53C400A (or BOARD_DTC3181E), you have 
not assigned c400_ctl_status, c400_blk_cnt and c400_host_buf. Perhaps we 
should throw an error, something like this?

hostdata->iomem = iomem;
-   if (overrides[current_override].board == BOARD_NCR53C400) {
+   switch (overrides[current_override].board) {
+   case BOARD_NCR53C400:
hostdata->c400_ctl_status = 0x100;
hostdata->c400_blk_cnt = 0x101;
hostdata->c400_host_buf = 0x104;
+   break;
+   case BOARD_NCR53C400A:
+   pr_err(DRV_MODULE_NAME ": unknown register offsets\n");
+   goto out_unregister;
}
 #endif
 
-- 

> @@ -425,7 +432,8 @@ static int __init generic_NCR5380_detect(struct 
> scsi_host_template *tpnt)
>   if (NCR5380_init(instance, flags))
>   goto out_unregister;
>  
> - if (overrides[current_override].board == BOARD_NCR53C400)
> + if (overrides[current_override].board == BOARD_NCR53C400 ||
> + overrides[current_override].board == BOARD_NCR53C400A)
>   NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
>  
>   NCR5380_maybe_reset_bus(instance);
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html