[PATCH] mac_esp: fix to pass correct device identity to free_irq()

2017-04-25 Thread Finn Thain
From: Wei Yongjun 

free_irq() expects the same device identity that was passed to
corresponding request_irq(), otherwise the IRQ is not freed.

Signed-off-by: Wei Yongjun 
Signed-off-by: Finn Thain 
---

Rebased on jejb-scsi/misc.

diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index 26c67c4..999699d 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -587,7 +587,7 @@ static int esp_mac_probe(struct platform_device *dev)
esp_chips[dev->id] = NULL;
if (esp_chips[!dev->id] == NULL) {
spin_unlock(_chips_lock);
-   free_irq(host->irq, esp);
+   free_irq(host->irq, NULL);
} else
spin_unlock(_chips_lock);
 fail_free_priv:


Re: [PATCH] qla4xxx: fix spelling mistake: "Tempalate" -> "Template"

2017-04-25 Thread Rangankar, Manish

On 26/04/17 3:07 AM, "Colin King"  wrote:

>From: Colin Ian King 
>
>trivial fix to spelling mistake in DEBUG2 debug message
>
>Signed-off-by: Colin Ian King 
>---
> drivers/scsi/qla4xxx/ql4_init.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
>diff --git a/drivers/scsi/qla4xxx/ql4_init.c
>b/drivers/scsi/qla4xxx/ql4_init.c
>index 4180d6d9fe78..5d6d158bbfd6 100644
>--- a/drivers/scsi/qla4xxx/ql4_init.c
>+++ b/drivers/scsi/qla4xxx/ql4_init.c
>@@ -389,7 +389,7 @@ void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha)
>   goto alloc_cleanup;
> 
>   DEBUG2(ql4_printk(KERN_INFO, ha,
>-"Minidump Tempalate Size = 0x%x KB\n",
>+"Minidump Template Size = 0x%x KB\n",
> ha->fw_dump_tmplt_size));
>   DEBUG2(ql4_printk(KERN_INFO, ha,
> "Total Minidump size = 0x%x KB\n", ha->fw_dump_size));
>-- 
>2.11.0

Acked-by: Manish Rangankar 




[PATCH] mpt3sas_base:fix memory leak in _base_request_irq

2017-04-25 Thread Heloise
Signed-off-by: Heloise 

In function _base_request_irq, variable reply_q applies for memory
space 'reply_q=kzalloc()', but does not release it before the function
returns, fix it.
---
 drivers/scsi/mpt3sas/mpt3sas_base.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c 
b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 5b7aec5..801dfab 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -1884,6 +1884,7 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index)
 
INIT_LIST_HEAD(_q->list);
list_add_tail(_q->list, >reply_queue_list);
+   kfree(reply_q);
return 0;
 }
 
-- 
2.1.0




Re: [PATCH] scsi: stex: make S6flag static

2017-04-25 Thread Charles Chiou

Looks good to me.
Thanks for the improvement.

On 4/26/2017 1:36 AM, Colin King wrote:

From: Colin Ian King 

This module specific flag can be made static as it does
not need to be in global scope.


> Reviewed-by: Charles Chiou 

Signed-off-by: Colin Ian King 
---
  drivers/scsi/stex.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 0751561b59da..9b20643ab49d 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -363,7 +363,7 @@ struct st_card_info {
u16 sts_count;
  };
  
-int S6flag;

+static int S6flag;
  static int stex_halt(struct notifier_block *nb, ulong event, void *buf);
  static struct notifier_block stex_notifier = {
stex_halt, NULL, 0



Re: [RFC] scsi: reduce protection of scan_mutex in scsi_remove_device

2017-04-25 Thread Song Liu

> On Apr 25, 2017, at 3:17 PM, Bart Van Assche  
> wrote:
> 
> On Tue, 2017-04-25 at 21:17 +, Song Liu wrote:
>> I am not sure I fully understand the problem here. If I understand the logic 
>> correctly, when a device is being removed, it will stay in 
>> scsi_host->__devices
>> until fully the remove routine is finished. And LUN scanning in parallel will
>> find the device with scsi_device_lookup_by_target(), and thus it would not 
>> rescan the device until the device is fully removed? Did I miss anything 
>> here?
> 
> Hello Song,
> 
> The SCSI core is already complicated enough. Please don't complicate it 
> further
> by making subtle changes to the semantics of scan_mutex. Please also note that
> I have proposed an alternative, namely to make the START STOP UNIT command
> asynchronous.
> 

Hello Bart, 

I total agree with your concern in making SCSI core more complicated. However, 
I am
not sure whether how asynchronous START STOP UNIT command makes multiple 
deletes run
in parallel. If I understand correctly, each device delete has the following 
steps:
  1. lock scan_mutex
  2. issue async START STOP UNIT 
  3. wait START STOP UNIT to complete
  4. unlock scan_mutex

scan_mutex will prevent multiple device deletes to run in parallel. 

On the other hand, maybe the problem is simpler than I thought? Once we ensure 
all
slave_destroy() holds proper lock to access host level data, something as 
follows
might just work. In this way, echoing into delete handle is not protected by 
scan_mutex. However, when the sysfs entry exists, the device should be fully 
added 
to the system. And before delete operation finishes, future scan should not 
re-add 
the device (as the device can be found by scsi_device_lookup_by_target). 

Am I too optimistic here?

Thanks,
Song


diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 82dfe07..d1c3338 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -710,7 +710,7 @@ sdev_store_delete(struct device *dev, struct 
device_attribute *attr,
  const char *buf, size_t count)
 {
if (device_remove_file_self(dev, attr))
-   scsi_remove_device(to_scsi_device(dev));
+   __scsi_remove_device(to_scsi_device(dev));
return count;
 }; 



RE: [PATCH v2 1/1] aacraid: pci_alloc_consistent() failures on ARM64

2017-04-25 Thread Dave Carroll
> -Original Message-
> From: Christoph Hellwig [mailto:h...@infradead.org]
> Sent: Tuesday, April 25, 2017 12:07 AM
> To: Mahesh Rajashekhara 
> Cc: Dave Carroll ; linux-scsi@vger.kernel.org;
> j...@linux.vnet.ibm.com; martin.peter...@oracle.com; dl-esc-Aacraid Linux
> Driver 
> Subject: Re: [PATCH v2 1/1] aacraid: pci_alloc_consistent() failures on ARM64
> 
> On Wed, Apr 05, 2017 at 04:14:16PM +0530, Mahesh Rajashekhara wrote:
> > There were pci_alloc_consistent() failures on ARM64 platform.
> > Use dma_alloc_coherent() with GFP_KERNEL flag DMA memory allocations.
> >
> > Signed-off-by: Mahesh Rajashekhara 
> > ---
> > v2:
> >  - Removed platform specific MACRO and call dma_*_coherent routines
> directly.
> >  - Removed all the casts to and from void * in the arguments and
> > return values
> 
> The indentation is weird, and you're also adding memsets of the allocations
> which is a behavior change.  Please take a look at the the attached version 
> that
> fixes this up.
> 
> If you really need the zeroing please send an additional patch to switch to
> dma_zalloc_coherent.
> 
> ---
> From 522b355c4fe021822d385332de525c7de5c2b290 Mon Sep 17 00:00:00
> 2001
> From: Mahesh Rajashekhara 
> Date: Wed, 5 Apr 2017 16:14:16 +0530
> Subject: aacraid: pci_alloc_consistent() failures on ARM64
> 
> There were pci_alloc_consistent() failures on ARM64 platform.
> Use dma_alloc_coherent() with GFP_KERNEL flag DMA memory allocations.
> 
> Signed-off-by: Mahesh Rajashekhara 
> [hch: tweaked indentation, removed memsets]
> Signed-off-by: Christoph Hellwig 
> ---
Acked-by: Dave Carroll 


Re: [RFC] scsi: reduce protection of scan_mutex in scsi_remove_device

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 21:17 +, Song Liu wrote:
> I am not sure I fully understand the problem here. If I understand the logic 
> correctly, when a device is being removed, it will stay in 
> scsi_host->__devices
> until fully the remove routine is finished. And LUN scanning in parallel will
> find the device with scsi_device_lookup_by_target(), and thus it would not 
> rescan the device until the device is fully removed? Did I miss anything here?

Hello Song,

The SCSI core is already complicated enough. Please don't complicate it further
by making subtle changes to the semantics of scan_mutex. Please also note that
I have proposed an alternative, namely to make the START STOP UNIT command
asynchronous.

Bart.

Re: [PATCH v5 10/10] scsi: Implement blk_mq_ops.show_rq()

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 14:39 -0700, Omar Sandoval wrote:
> On Tue, Apr 25, 2017 at 01:37:45PM -0700, Bart Van Assche wrote:
> > Show the SCSI CDB, .eh_eflags and .result for pending SCSI commands
> > in /sys/kernel/debug/block/*/mq/*/dispatch and */rq_list.
> 
> Only thing I noticed was that the only other caller I see has buf[70].
> No idea if that's a meaningful number. For the sake of this not getting
> bike-shedded to death,

Neither length is sufficient to avoid truncation of e.g. ATA pass-through
commands or commands with variable length CDBs. However, from the point of
view of debugging queue lockups the most useful information in a SCSI
command are the first two bytes of the CDB. The chosen buffer length is
definitely enough to make sure that these two bytes will be reported.

Bart.

Re: [PATCH v5 10/10] scsi: Implement blk_mq_ops.show_rq()

2017-04-25 Thread Omar Sandoval
On Tue, Apr 25, 2017 at 01:37:45PM -0700, Bart Van Assche wrote:
> Show the SCSI CDB, .eh_eflags and .result for pending SCSI commands
> in /sys/kernel/debug/block/*/mq/*/dispatch and */rq_list.

Only thing I noticed was that the only other caller I see has buf[70].
No idea if that's a meaningful number. For the sake of this not getting
bike-shedded to death,

Reviewed-by: Omar Sandoval 

> Signed-off-by: Bart Van Assche 
> Cc: Martin K. Petersen 
> Cc: James Bottomley 
> Cc: Omar Sandoval 
> Cc: Hannes Reinecke 
> Cc: 
> ---
>  drivers/scsi/Makefile   |  1 +
>  drivers/scsi/scsi_debugfs.c | 13 +
>  drivers/scsi/scsi_debugfs.h |  4 
>  drivers/scsi/scsi_lib.c |  4 
>  4 files changed, 22 insertions(+)
>  create mode 100644 drivers/scsi/scsi_debugfs.c
>  create mode 100644 drivers/scsi/scsi_debugfs.h
> 
> diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
> index fc2855565a51..93dbe58c47c8 100644
> --- a/drivers/scsi/Makefile
> +++ b/drivers/scsi/Makefile
> @@ -166,6 +166,7 @@ scsi_mod-y+= scsi_scan.o 
> scsi_sysfs.o scsi_devinfo.o
>  scsi_mod-$(CONFIG_SCSI_NETLINK)  += scsi_netlink.o
>  scsi_mod-$(CONFIG_SYSCTL)+= scsi_sysctl.o
>  scsi_mod-$(CONFIG_SCSI_PROC_FS)  += scsi_proc.o
> +scsi_mod-$(CONFIG_BLK_DEBUG_FS)  += scsi_debugfs.o
>  scsi_mod-y   += scsi_trace.o scsi_logging.o
>  scsi_mod-$(CONFIG_PM)+= scsi_pm.o
>  scsi_mod-$(CONFIG_SCSI_DH)   += scsi_dh.o
> diff --git a/drivers/scsi/scsi_debugfs.c b/drivers/scsi/scsi_debugfs.c
> new file mode 100644
> index ..f831c23fdee3
> --- /dev/null
> +++ b/drivers/scsi/scsi_debugfs.c
> @@ -0,0 +1,13 @@
> +#include 
> +#include 
> +#include 
> +#include "scsi_debugfs.h"
> +
> +void scsi_show_rq(struct seq_file *m, struct request *rq)
> +{
> + struct scsi_cmnd *cmd = container_of(scsi_req(rq), typeof(*cmd), req);
> + char buf[64];
> +
> + __scsi_format_command(buf, sizeof(buf), cmd->cmnd, cmd->cmd_len);
> + seq_printf(m, ", .cmd=%s", buf);
> +}
> diff --git a/drivers/scsi/scsi_debugfs.h b/drivers/scsi/scsi_debugfs.h
> new file mode 100644
> index ..951b043e82d0
> --- /dev/null
> +++ b/drivers/scsi/scsi_debugfs.h
> @@ -0,0 +1,4 @@
> +struct request;
> +struct seq_file;
> +
> +void scsi_show_rq(struct seq_file *m, struct request *rq);
> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
> index abc391e00f7d..1c3e87d6c48f 100644
> --- a/drivers/scsi/scsi_lib.c
> +++ b/drivers/scsi/scsi_lib.c
> @@ -34,6 +34,7 @@
>  
>  #include 
>  
> +#include "scsi_debugfs.h"
>  #include "scsi_priv.h"
>  #include "scsi_logging.h"
>  
> @@ -2157,6 +2158,9 @@ static const struct blk_mq_ops scsi_mq_ops = {
>   .queue_rq   = scsi_queue_rq,
>   .complete   = scsi_softirq_done,
>   .timeout= scsi_timeout,
> +#ifdef CONFIG_BLK_DEBUG_FS
> + .show_rq= scsi_show_rq,
> +#endif
>   .init_request   = scsi_init_request,
>   .exit_request   = scsi_exit_request,
>   .map_queues = scsi_map_queues,
> -- 
> 2.12.2
> 


[PATCH] qla4xxx: fix spelling mistake: "Tempalate" -> "Template"

2017-04-25 Thread Colin King
From: Colin Ian King 

trivial fix to spelling mistake in DEBUG2 debug message

Signed-off-by: Colin Ian King 
---
 drivers/scsi/qla4xxx/ql4_init.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 4180d6d9fe78..5d6d158bbfd6 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -389,7 +389,7 @@ void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha)
goto alloc_cleanup;
 
DEBUG2(ql4_printk(KERN_INFO, ha,
- "Minidump Tempalate Size = 0x%x KB\n",
+ "Minidump Template Size = 0x%x KB\n",
  ha->fw_dump_tmplt_size));
DEBUG2(ql4_printk(KERN_INFO, ha,
  "Total Minidump size = 0x%x KB\n", ha->fw_dump_size));
-- 
2.11.0



Re: [RFC] scsi: reduce protection of scan_mutex in scsi_remove_device

2017-04-25 Thread Song Liu

> On Apr 25, 2017, at 1:59 PM, Bart Van Assche  
> wrote:
> 
> On Fri, 2017-04-21 at 22:31 +, Song Liu wrote:
>> On Apr 21, 2017, at 2:20 PM, Bart Van Assche  
>> wrote:
>>> On Fri, 2017-04-21 at 14:13 -0700, Song Liu wrote:
 On the other hand, some devices do long latency IO during deletion,
 for example, sd_shutdown() may do sync cache and/or start_stop.
 It is not necessary for these commands to run in series.
>>> 
>>> Have you noticed my patch series that makes sd_shutdown() submit the
>>> SYNCHRONIZE CACHE command asynchronously? Have you tried whether that
>>> patch series would be a good alternative?
>> 
>> The asynchronous SYNCHRONIZE CACHE will not help our use case, where the 
>> latency comes from sd_start_stop_device(). Seems it is not easy to make 
>> the START STOP UNIT command async. 
> 
> Hello Song,
> 
> It should be possible to make the START STOP UNIT command asynchronous too
> by issuing it asynchronously from inside sd_sync_cache_done(). To avoid
> dereferencing a stale struct scsi_disk pointer you will either have to hold
> an additional reference as long as the SYNCHRONIZE CACHE command is in
> progress or copy the data needed from struct scsi_disk into the SCSI request.
> 

Hello Bart, 

As you stated in the patch: blk_cleanup_queue() in __scsi_remove_device() 
will wait for async SYNCHRONIZE CACHE and START STOP UNIT command to complete. 
Since __scsi_remove_device() is called with scan_mutex held, simultaneous 
START STOP UNIT requires are still serialized by the scan_mutex. 

Song



Re: [RFC 0/8] Copy Offload with Peer-to-Peer PCI Memory

2017-04-25 Thread Stephen Bates
>> Yes, that's why I used 'significant'. One good thing is that given resources 
>> it can easily be done in parallel with other development, and will give 
>> additional
>> insight of some form.
>
>Yup, well if someone wants to start working on an emulated RDMA device
>that actually simulates proper DMA transfers that would be great!

Give that each RDMA vendor’s devices expose a different MMIO I don’t expect 
this to happen anytime soon.

> Yes, the nvme device in qemu has a CMB buffer which is a good choice to
> test with but we don't have code to use it for p2p transfers in the
>kernel so it is a bit awkward.

Note the CMB code is not in upstream QEMU, it’s in Keith’s fork [1]. I will see 
if I can push this upstream.

Stephen

[1] git://git.infradead.org/users/kbusch/qemu-nvme.git




Re: [RFC 0/8] Copy Offload with Peer-to-Peer PCI Memory

2017-04-25 Thread Stephen Bates

> My first reflex when reading this thread was to think that this whole domain
> lends it self excellently to testing via Qemu. Could it be that doing this in 
> the opposite direction might be a safer approach in the long run even though 
> (significant) more work up-front?

While the idea of QEMU for this work is attractive it will be a long time 
before QEMU is in a position to support this development. 

Another approach is to propose a common development platform for p2pmem work 
using a platform we know is going to work. This an extreme version of the 
whitelisting approach that was discussed on this thread. We can list a very 
specific set of hardware (motherboard, PCIe end-points and (possibly) PCIe 
switch enclosure) that has been shown to work that others can copy for their 
development purposes.

p2pmem.io perhaps ;-)?

Stephen




Re: [RFC] scsi: reduce protection of scan_mutex in scsi_remove_device

2017-04-25 Thread Song Liu

> On Apr 25, 2017, at 10:52 AM, Bart Van Assche  
> wrote:
> 
> On Tue, 2017-04-25 at 17:42 +, Song Liu wrote:
>> I have been studying the code recently. I am wondering whether the following 
>> would work:
>> 
>> 1. Introduce a new mutex for scsi_device to protect most operations in the 
>>   list you gathered above;
>> 
>> 2. For operations like host->slave_destroy(), ensure they access scsi_host 
>>   data with host_lock (or another spin lock). 
>> 
>>   I looked into all instances of slave_destroy, only 2 of them: 
>>   dc395x_slave_destroy() and visorhba_slave_destroy() access scsi_host data 
>>   without protection of spin lock. 
>> 
>> 3. Once 1 and 2 is ready, __scsi_remove_device() only need to hold the mutex
>>   for the scsi_device. scan_mutex is no longer required. 
>> 
>> Is this a valid path?
> 
> Sorry but I don't think so. Unlocking and reacquiring scan_mutex would create
> the potential that LUN scanning occurs in the meantime and hence that it fails
> because LUN removal is incomplete.
> 


Hello Bart, 

I am not sure I fully understand the problem here. If I understand the logic 
correctly, when a device is being removed, it will stay in scsi_host->__devices
until fully the remove routine is finished. And LUN scanning in parallel will
find the device with scsi_device_lookup_by_target(), and thus it would not 
rescan the device until the device is fully removed? Did I miss anything here?

Thanks,
Song



Re: [RFC] scsi: reduce protection of scan_mutex in scsi_remove_device

2017-04-25 Thread Bart Van Assche
On Fri, 2017-04-21 at 22:31 +, Song Liu wrote:
> On Apr 21, 2017, at 2:20 PM, Bart Van Assche  
> wrote:
> > On Fri, 2017-04-21 at 14:13 -0700, Song Liu wrote:
> > > On the other hand, some devices do long latency IO during deletion,
> > > for example, sd_shutdown() may do sync cache and/or start_stop.
> > > It is not necessary for these commands to run in series.
> > 
> > Have you noticed my patch series that makes sd_shutdown() submit the
> > SYNCHRONIZE CACHE command asynchronously? Have you tried whether that
> > patch series would be a good alternative?
> 
> The asynchronous SYNCHRONIZE CACHE will not help our use case, where the 
> latency comes from sd_start_stop_device(). Seems it is not easy to make 
> the START STOP UNIT command async. 

Hello Song,

It should be possible to make the START STOP UNIT command asynchronous too
by issuing it asynchronously from inside sd_sync_cache_done(). To avoid
dereferencing a stale struct scsi_disk pointer you will either have to hold
an additional reference as long as the SYNCHRONIZE CACHE command is in
progress or copy the data needed from struct scsi_disk into the SCSI request.

Bart.

[PATCH v5 1/4] Introduce scsi_start_queue()

2017-04-25 Thread Bart Van Assche
This patch does not change any functionality.

Signed-off-by: Bart Van Assche 
Cc: Israel Rukshin 
Cc: Max Gurtovoy 
Cc: Hannes Reinecke 
Cc: Song Liu 
---
 drivers/scsi/scsi_lib.c  | 25 +++--
 drivers/scsi/scsi_priv.h |  1 +
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index eecc005099b2..ffa6e61299a9 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2987,6 +2987,20 @@ scsi_internal_device_block(struct scsi_device *sdev, 
bool wait)
 }
 EXPORT_SYMBOL_GPL(scsi_internal_device_block);
  
+void scsi_start_queue(struct scsi_device *sdev)
+{
+   struct request_queue *q = sdev->request_queue;
+   unsigned long flags;
+
+   if (q->mq_ops) {
+   blk_mq_start_stopped_hw_queues(q, false);
+   } else {
+   spin_lock_irqsave(q->queue_lock, flags);
+   blk_start_queue(q);
+   spin_unlock_irqrestore(q->queue_lock, flags);
+   }
+}
+
 /**
  * scsi_internal_device_unblock - resume a device after a block request
  * @sdev:  device to resume
@@ -3007,9 +3021,6 @@ int
 scsi_internal_device_unblock(struct scsi_device *sdev,
 enum scsi_device_state new_state)
 {
-   struct request_queue *q = sdev->request_queue; 
-   unsigned long flags;
-
/*
 * Try to transition the scsi device to SDEV_RUNNING or one of the
 * offlined states and goose the device queue if successful.
@@ -3027,13 +3038,7 @@ scsi_internal_device_unblock(struct scsi_device *sdev,
 sdev->sdev_state != SDEV_OFFLINE)
return -EINVAL;
 
-   if (q->mq_ops) {
-   blk_mq_start_stopped_hw_queues(q, false);
-   } else {
-   spin_lock_irqsave(q->queue_lock, flags);
-   blk_start_queue(q);
-   spin_unlock_irqrestore(q->queue_lock, flags);
-   }
+   scsi_start_queue(sdev);
 
return 0;
 }
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index f11bd102d6d5..c7629e31a75b 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -89,6 +89,7 @@ extern void scsi_run_host_queues(struct Scsi_Host *shost);
 extern void scsi_requeue_run_queue(struct work_struct *work);
 extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
 extern struct request_queue *scsi_mq_alloc_queue(struct scsi_device *sdev);
+extern void scsi_start_queue(struct scsi_device *sdev);
 extern int scsi_mq_setup_tags(struct Scsi_Host *shost);
 extern void scsi_mq_destroy_tags(struct Scsi_Host *shost);
 extern int scsi_init_queue(void);
-- 
2.12.2



Re: [PATCH] nvme-scsi: Use correct byte ordering for eui64 in Dev ID VPD

2017-04-25 Thread Jon Derrick
On 04/25/2017 02:18 PM, Jon Derrick wrote:
> NVME specifies an EUI64/NGUID in little-endian format, while SCSI
> specifies that the Device Identification VPD use big-endian for EUI
> formats. The current code copies this bytestream directly from the
> Identification Namespace page, meaning we just need to reverse the
> bytestream when passing it on to the VPD.
> 

This seems to hold true for NGUID devices, but Keith just pointed out to
me that it may not hold true for EUI64 devices. It seems like that case
needs byte swiveling within each field. So I'll NAK for now until I can
figure out if that's the case.


[PATCH v5 4/4] Avoid that __scsi_remove_device() hangs

2017-04-25 Thread Bart Van Assche
Since scsi_target_unblock() uses starget_for_each_device(), since
starget_for_each_device() uses scsi_device_get(), since
scsi_device_get() fails after unloading of the LLD kernel module
has been started scsi_target_unblock() may skip devices that were
affected by scsi_target_block(). Ensure that __scsi_remove_device()
does not hang for blocked SCSI devices. This patch avoids that
unloading the ib_srp kernel module can trigger the following hang:

Call Trace:
 schedule+0x35/0x80
 schedule_timeout+0x237/0x2d0
 io_schedule_timeout+0xa6/0x110
 wait_for_completion_io+0xa3/0x110
 blk_execute_rq+0xdf/0x120
 scsi_execute+0xce/0x150 [scsi_mod]
 scsi_execute_req_flags+0x8f/0xf0 [scsi_mod]
 sd_sync_cache+0xa9/0x190 [sd_mod]
 sd_shutdown+0x6a/0x100 [sd_mod]
 sd_remove+0x64/0xc0 [sd_mod]
 __device_release_driver+0x8d/0x120
 device_release_driver+0x1e/0x30
 bus_remove_device+0xf9/0x170
 device_del+0x127/0x240
 __scsi_remove_device+0xc1/0xd0 [scsi_mod]
 scsi_forget_host+0x57/0x60 [scsi_mod]
 scsi_remove_host+0x72/0x110 [scsi_mod]
 srp_remove_work+0x8b/0x200 [ib_srp]

Reported-by: Israel Rukshin 
Signed-off-by: Bart Van Assche 
Cc: Max Gurtovoy 
Cc: Hannes Reinecke 
Cc: Song Liu 
---
 drivers/scsi/scsi_sysfs.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 82dfe07b1d47..e090c35ba6ee 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1299,6 +1299,15 @@ void __scsi_remove_device(struct scsi_device *sdev)
 * device.
 */
scsi_device_set_state(sdev, SDEV_DEL);
+   /*
+* Since scsi_target_unblock() is a no-op after unloading of the SCSI
+* LLD has started, explicitly restart the queue. Do this after the
+* device state has been changed into SDEV_DEL because
+* scsi_prep_state_check() returns BLKPREP_KILL for the SDEV_DEL state
+* Do this before calling blk_cleanup_queue() to avoid that that
+* function encounters a stopped queue.
+*/
+   scsi_start_queue(sdev);
blk_cleanup_queue(sdev->request_queue);
cancel_work_sync(>requeue_work);
 
-- 
2.12.2



[PATCH v5 3/4] sd: Make synchronize cache upon shutdown asynchronous

2017-04-25 Thread Bart Van Assche
This patch avoids that sd_shutdown() hangs on the SYNCHRONIZE CACHE
command if the block layer queue has been stopped by
scsi_target_block().

Signed-off-by: Bart Van Assche 
Cc: Israel Rukshin 
Cc: Max Gurtovoy 
Cc: Hannes Reinecke 
Cc: Benjamin Block 
Cc: Song Liu 
---
 drivers/scsi/sd.c | 45 -
 1 file changed, 40 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index fe0f7997074e..75575fc1b2d8 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1489,6 +1489,33 @@ static unsigned int sd_check_events(struct gendisk 
*disk, unsigned int clearing)
return retval;
 }
 
+/*
+ * Callback function called indirectly by scsi_end_request() after the
+ * SYNCHRONIZE CACHE command has finished.
+ */
+static void sd_sync_cache_done(struct request *rq, int e)
+{
+   struct request_queue *q = rq->q;
+
+   __blk_put_request(q, rq);
+}
+
+/*
+ * Issue a SYNCHRONIZE CACHE command asynchronously. Since blk_cleanup_queue()
+ * waits for all commands to finish, __scsi_remove_device() will wait for the
+ * SYNCHRONIZE CACHE command to finish.
+ */
+static int sd_sync_cache_async(struct scsi_disk *sdkp)
+{
+   const struct scsi_device *sdp = sdkp->device;
+   const int timeout = sdp->request_queue->rq_timeout *
+   SD_FLUSH_TIMEOUT_MULTIPLIER;
+   const unsigned char cmd[10] = { SYNCHRONIZE_CACHE };
+
+   return scsi_execute_async(sdp, NULL, cmd, DMA_NONE, NULL, 0, timeout,
+ SD_MAX_RETRIES, 0, 0, sd_sync_cache_done);
+}
+
 static int sd_sync_cache(struct scsi_disk *sdkp)
 {
int retries, res;
@@ -3349,13 +3376,15 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, 
int start)
 }
 
 /*
- * Send a SYNCHRONIZE CACHE instruction down to the device through
- * the normal SCSI command structure.  Wait for the command to
- * complete.
+ * Send a SYNCHRONIZE CACHE instruction down to the device through the normal
+ * SCSI command structure. When stopping the disk, wait for the command to
+ * complete. When not stopping the disk, the blk_cleanup_queue() call in
+ * __scsi_remove_device() will wait for this command to complete.
  */
 static void sd_shutdown(struct device *dev)
 {
struct scsi_disk *sdkp = dev_get_drvdata(dev);
+   bool stop_disk;
 
if (!sdkp)
return; /* this can happen */
@@ -3363,12 +3392,18 @@ static void sd_shutdown(struct device *dev)
if (pm_runtime_suspended(dev))
return;
 
+   stop_disk = system_state != SYSTEM_RESTART &&
+   sdkp->device->manage_start_stop;
+
if (sdkp->WCE && sdkp->media_present) {
sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
-   sd_sync_cache(sdkp);
+   if (stop_disk)
+   sd_sync_cache(sdkp);
+   else
+   sd_sync_cache_async(sdkp);
}
 
-   if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) {
+   if (stop_disk) {
sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
sd_start_stop_device(sdkp, 0);
}
-- 
2.12.2



[PATCH v5 2/4] Introduce scsi_execute_async()

2017-04-25 Thread Bart Van Assche
Move the code for submitting a SCSI command from scsi_execute()
into scsi_build_rq(). Introduce scsi_execute_async(). This patch
does not change any functionality.

Signed-off-by: Bart Van Assche 
Cc: Israel Rukshin 
Cc: Max Gurtovoy 
Cc: Hannes Reinecke 
Cc: Song Liu 
---
 drivers/scsi/scsi_lib.c| 89 +-
 include/scsi/scsi_device.h |  5 +++
 2 files changed, 77 insertions(+), 17 deletions(-)

diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ffa6e61299a9..7f9c70fd0acd 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -213,6 +213,73 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
__scsi_queue_insert(cmd, reason, 1);
 }
 
+static struct request *scsi_build_rq(const struct scsi_device *sdev,
+   const unsigned char *cmd, int data_direction, void *buffer,
+   unsigned bufflen, int timeout, int retries, u64 flags,
+   req_flags_t rq_flags)
+{
+   struct request *req;
+   struct scsi_request *rq;
+   int ret;
+
+   req = blk_get_request(sdev->request_queue,
+   data_direction == DMA_TO_DEVICE ?
+   REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, __GFP_RECLAIM);
+   if (IS_ERR(req))
+   return req;
+   rq = scsi_req(req);
+   scsi_req_init(req);
+
+   if (bufflen) {
+   ret = blk_rq_map_kern(sdev->request_queue, req,
+ buffer, bufflen, __GFP_RECLAIM);
+   if (ret) {
+   blk_put_request(req);
+   return ERR_PTR(ret);
+   }
+   }
+
+   rq->cmd_len = COMMAND_SIZE(cmd[0]);
+   memcpy(rq->cmd, cmd, rq->cmd_len);
+   req->retries = retries;
+   req->timeout = timeout;
+   req->cmd_flags |= flags;
+   req->rq_flags |= rq_flags | RQF_QUIET | RQF_PREEMPT;
+
+   return req;
+}
+
+/**
+ * scsi_execute_async - insert a SCSI request
+ * @sdev:  scsi device
+ * @disk:   gendisk pointer that will be stored in the request structure
+ * @cmd:   scsi command
+ * @data_direction: data direction
+ * @buffer:data buffer
+ * @bufflen:   length of buffer
+ * @timeout:   request timeout in seconds
+ * @retries:   number of times to retry request
+ * @flags: flags for ->cmd_flags
+ * @rq_flags:  flags for ->rq_flags
+ * @done:   I/O completion function
+ */
+int scsi_execute_async(const struct scsi_device *sdev, struct gendisk *disk,
+   const unsigned char *cmd, int data_direction, void *buffer,
+   unsigned bufflen, int timeout, int retries, u64 flags,
+   req_flags_t rq_flags, rq_end_io_fn *done)
+{
+   struct request *req;
+
+   req = scsi_build_rq(sdev, cmd, data_direction, buffer, bufflen, timeout,
+   retries, flags, rq_flags);
+   if (IS_ERR(req))
+   return PTR_ERR(req);
+   /* head injection *required* here otherwise quiesce won't work */
+   blk_execute_rq_nowait(req->q, disk, req, 1, done);
+
+   return 0;
+}
+EXPORT_SYMBOL(scsi_execute_async);
 
 /**
  * scsi_execute - insert request and wait for the result
@@ -242,24 +309,12 @@ int scsi_execute(struct scsi_device *sdev, const unsigned 
char *cmd,
struct scsi_request *rq;
int ret = DRIVER_ERROR << 24;
 
-   req = blk_get_request(sdev->request_queue,
-   data_direction == DMA_TO_DEVICE ?
-   REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, __GFP_RECLAIM);
+   req = scsi_build_rq(sdev, cmd, data_direction, buffer, bufflen,
+   timeout, retries, flags, rq_flags);
if (IS_ERR(req))
-   return ret;
-   rq = scsi_req(req);
-   scsi_req_init(req);
+   return PTR_ERR(req);
 
-   if (bufflen &&  blk_rq_map_kern(sdev->request_queue, req,
-   buffer, bufflen, __GFP_RECLAIM))
-   goto out;
-
-   rq->cmd_len = COMMAND_SIZE(cmd[0]);
-   memcpy(rq->cmd, cmd, rq->cmd_len);
-   req->retries = retries;
-   req->timeout = timeout;
-   req->cmd_flags |= flags;
-   req->rq_flags |= rq_flags | RQF_QUIET | RQF_PREEMPT;
+   rq = scsi_req(req);
 
/*
 * head injection *required* here otherwise quiesce won't work
@@ -282,7 +337,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned 
char *cmd,
if (sshdr)
scsi_normalize_sense(rq->sense, rq->sense_len, sshdr);
ret = req->errors;
- out:
+
blk_put_request(req);
 
return ret;
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 080c7ce9bae8..38c73ee0a929 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -408,6 +408,11 @@ extern const char *scsi_device_state_name(enum 

[PATCH v5 0/4] Avoid that __scsi_remove_device() hangs

2017-04-25 Thread Bart Van Assche
__scsi_remove_device() hangs if it is waiting for the SYNCHRONIZE CACHE
command submitted by the sd driver to finish if the block layer queue is
stopped and does not get restarted. This patch series avoids that that
hang occurs.

Changes compared to v4:
- Fixed the deadlock reported by the 0-day bot by changing a blk_put_request()
  call into __blk_put_request().

Changes compared to v3:
- Removed the logging statements from sd_sync_cache_done() that triggered
  a crash due to a use-after-free.

Changes compared to v2:
- Moved the "stop_disk" assignment after the sdkp check in the sd driver.
- Added a completion function for asynchronous SYNCHRONIZE CACHE commands.
- Added "disk" and "done" arguments to scsi_execute_async().

Changes compared to v1:
- Reworked the approach of this patch series.

Bart Van Assche (4):
  Introduce scsi_start_queue()
  Introduce scsi_execute_async()
  sd: Make synchronize cache upon shutdown asynchronous
  Avoid that __scsi_remove_device() hangs

 drivers/scsi/scsi_lib.c| 114 ++---
 drivers/scsi/scsi_priv.h   |   1 +
 drivers/scsi/scsi_sysfs.c  |   9 
 drivers/scsi/sd.c  |  45 --
 include/scsi/scsi_device.h |   5 ++
 5 files changed, 142 insertions(+), 32 deletions(-)

-- 
2.12.2


[PATCH v5 10/10] scsi: Implement blk_mq_ops.show_rq()

2017-04-25 Thread Bart Van Assche
Show the SCSI CDB, .eh_eflags and .result for pending SCSI commands
in /sys/kernel/debug/block/*/mq/*/dispatch and */rq_list.

Signed-off-by: Bart Van Assche 
Cc: Martin K. Petersen 
Cc: James Bottomley 
Cc: Omar Sandoval 
Cc: Hannes Reinecke 
Cc: 
---
 drivers/scsi/Makefile   |  1 +
 drivers/scsi/scsi_debugfs.c | 13 +
 drivers/scsi/scsi_debugfs.h |  4 
 drivers/scsi/scsi_lib.c |  4 
 4 files changed, 22 insertions(+)
 create mode 100644 drivers/scsi/scsi_debugfs.c
 create mode 100644 drivers/scsi/scsi_debugfs.h

diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index fc2855565a51..93dbe58c47c8 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -166,6 +166,7 @@ scsi_mod-y  += scsi_scan.o scsi_sysfs.o 
scsi_devinfo.o
 scsi_mod-$(CONFIG_SCSI_NETLINK)+= scsi_netlink.o
 scsi_mod-$(CONFIG_SYSCTL)  += scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)+= scsi_proc.o
+scsi_mod-$(CONFIG_BLK_DEBUG_FS)+= scsi_debugfs.o
 scsi_mod-y += scsi_trace.o scsi_logging.o
 scsi_mod-$(CONFIG_PM)  += scsi_pm.o
 scsi_mod-$(CONFIG_SCSI_DH) += scsi_dh.o
diff --git a/drivers/scsi/scsi_debugfs.c b/drivers/scsi/scsi_debugfs.c
new file mode 100644
index ..f831c23fdee3
--- /dev/null
+++ b/drivers/scsi/scsi_debugfs.c
@@ -0,0 +1,13 @@
+#include 
+#include 
+#include 
+#include "scsi_debugfs.h"
+
+void scsi_show_rq(struct seq_file *m, struct request *rq)
+{
+   struct scsi_cmnd *cmd = container_of(scsi_req(rq), typeof(*cmd), req);
+   char buf[64];
+
+   __scsi_format_command(buf, sizeof(buf), cmd->cmnd, cmd->cmd_len);
+   seq_printf(m, ", .cmd=%s", buf);
+}
diff --git a/drivers/scsi/scsi_debugfs.h b/drivers/scsi/scsi_debugfs.h
new file mode 100644
index ..951b043e82d0
--- /dev/null
+++ b/drivers/scsi/scsi_debugfs.h
@@ -0,0 +1,4 @@
+struct request;
+struct seq_file;
+
+void scsi_show_rq(struct seq_file *m, struct request *rq);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index abc391e00f7d..1c3e87d6c48f 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -34,6 +34,7 @@
 
 #include 
 
+#include "scsi_debugfs.h"
 #include "scsi_priv.h"
 #include "scsi_logging.h"
 
@@ -2157,6 +2158,9 @@ static const struct blk_mq_ops scsi_mq_ops = {
.queue_rq   = scsi_queue_rq,
.complete   = scsi_softirq_done,
.timeout= scsi_timeout,
+#ifdef CONFIG_BLK_DEBUG_FS
+   .show_rq= scsi_show_rq,
+#endif
.init_request   = scsi_init_request,
.exit_request   = scsi_exit_request,
.map_queues = scsi_map_queues,
-- 
2.12.2



[PATCH 3/3] scsi: ufs: Delete an unnecessary return statement in ufshcd_exception_event_handler()

2017-04-25 Thread SF Markus Elfring
From: Markus Elfring 
Date: Tue, 25 Apr 2017 22:00:05 +0200

The script "checkpatch.pl" pointed information out like the following.

WARNING: void function return statements are not generally useful

Thus remove such a statement here.

Signed-off-by: Markus Elfring 
---
 drivers/scsi/ufs/ufshcd.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5216e33e61a3..9018f26a5667 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4966,7 +4966,6 @@ static void ufshcd_exception_event_handler(struct 
work_struct *work)
 
 out:
pm_runtime_put_sync(hba->dev);
-   return;
 }
 
 /* Complete requests that have door-bell cleared */
-- 
2.12.2



[PATCH 2/3] scsi: ufs: Delete an error message for a failed memory allocation in ufshcd_memory_alloc()

2017-04-25 Thread SF Markus Elfring
From: Markus Elfring 
Date: Tue, 25 Apr 2017 21:50:43 +0200

The script "checkpatch.pl" pointed information out like the following.

WARNING: Possible unnecessary 'out of memory' message

Thus remove such a statement here.

Link: 
http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf
Signed-off-by: Markus Elfring 
---
 drivers/scsi/ufs/ufshcd.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ce385911a20e..5216e33e61a3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3274,8 +3274,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
GFP_KERNEL);
-   if (!hba->lrb) {
-   dev_err(hba->dev, "LRB Memory allocation failed\n");
+   if (!hba->lrb)
goto out;
-   }
+
return 0;
 out:
return -ENOMEM;
-- 
2.12.2



Get back to me

2017-04-25 Thread Ashraf Basit
Good day. Did you receive the business proposal I sent to you yesterday? I was 
waiting for your reply but I am not sure if you receive the message.  If for 
some reason you did not receive my previous email, I can resend the message to 
you. Please confirm as this is very urgent and important.

Regards,

Ashraf.
ashraf...@secsuremailer.com


[PATCH 1/3] scsi: ufs: Use devm_kcalloc() in ufshcd_memory_alloc()

2017-04-25 Thread SF Markus Elfring
From: Markus Elfring 
Date: Tue, 25 Apr 2017 21:45:25 +0200

* A multiplication for the size determination of a memory allocation
  indicated that an array data structure should be processed.
  Thus use the corresponding function "devm_kcalloc".

* Replace the specification of a data structure by a pointer dereference
  to make the corresponding size determination a bit safer according to
  the Linux coding style convention.

Signed-off-by: Markus Elfring 
---
 drivers/scsi/ufs/ufshcd.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9ef8ce7f01a2..ce385911a20e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3270,8 +3270,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba)
}
 
/* Allocate memory for local reference block */
-   hba->lrb = devm_kzalloc(hba->dev,
-   hba->nutrs * sizeof(struct ufshcd_lrb),
+   hba->lrb = devm_kcalloc(hba->dev, hba->nutrs, sizeof(*hba->lrb),
GFP_KERNEL);
if (!hba->lrb) {
dev_err(hba->dev, "LRB Memory allocation failed\n");
-- 
2.12.2



[PATCH 0/3] SCSI-UFSHCD: Fine-tuning for two function implementations

2017-04-25 Thread SF Markus Elfring
From: Markus Elfring 
Date: Tue, 25 Apr 2017 22:20:02 +0200

Three update suggestions were taken into account
from static source code analysis.

Markus Elfring (3):
  Use devm_kcalloc() in ufshcd_memory_alloc()
  Delete an error message for a failed memory allocation in 
ufshcd_memory_alloc()
  Delete an unnecessary return statement in ufshcd_exception_event_handler()

 drivers/scsi/ufs/ufshcd.c | 9 +++--
 1 file changed, 3 insertions(+), 6 deletions(-)

-- 
2.12.2



[PATCH] nvme-scsi: Use correct byte ordering for eui64 in Dev ID VPD

2017-04-25 Thread Jon Derrick
NVME specifies an EUI64/NGUID in little-endian format, while SCSI
specifies that the Device Identification VPD use big-endian for EUI
formats. The current code copies this bytestream directly from the
Identification Namespace page, meaning we just need to reverse the
bytestream when passing it on to the VPD.

This results in the correct values being parsed by sg-tools, eg:
$ sg_inq -e -p 0x83 /dev/nvme1n1 -vvv
open /dev/nvme1n1 with flags=0x800
VPD INQUIRY: Device Identification page
inquiry cdb: 12 01 83 00 fc 00
  duration=0 ms
  Designation descriptor number 1, descriptor length: 20
designator_type: EUI-64 based,  code_set: Binary
associated with the addressed logical unit
  EUI-64 based 16 byte identifier
  Identifier extension: 0x10001
  IEEE Company_id: 0x5cd2e4
  Vendor Specific Extension Identifier: 0x0
  [0x000100015cd2e400]

Signed-off-by: Jon Derrick 
---
 drivers/nvme/host/scsi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/host/scsi.c b/drivers/nvme/host/scsi.c
index f49ae27..8f94e77 100644
--- a/drivers/nvme/host/scsi.c
+++ b/drivers/nvme/host/scsi.c
@@ -598,6 +598,7 @@ static int nvme_fill_device_id_eui64(struct nvme_ns *ns, 
struct sg_io_hdr *hdr,
int nvme_sc, res;
size_t len;
void *eui;
+   int i;
 
nvme_sc = nvme_identify_ns(ns->ctrl, ns->ns_id, _ns);
res = nvme_trans_status_code(hdr, nvme_sc);
@@ -628,7 +629,8 @@ static int nvme_fill_device_id_eui64(struct nvme_ns *ns, 
struct sg_io_hdr *hdr,
inq_response[5] = 0x02; /* PIV=0b | Asso=00b | Designator Type=2h */
inq_response[6] = 0x00; /* Rsvd */
inq_response[7] = len;  /* Designator Length */
-   memcpy(_response[8], eui, len);
+   for (i = 0; i < len; i++)
+   inq_response[8 + i] = ((char *)eui)[len - (i + 1)];
 
res = nvme_trans_copy_to_user(hdr, inq_response, alloc_len);
 out_free_id:
-- 
2.9.3



Re: [PATCH] ibmvscsis: Do not send aborted task response

2017-04-25 Thread Tyrel Datwyler
On 04/10/2017 11:52 AM, Bryant G. Ly wrote:
> The driver is sending a response to the aborted task response
> along with LIO sending the tmr response.

I think this could be better worded. Something like the driver is sending a 
response to
the actual ***scsi op*** that was aborted by an abort task TM, while LIO is 
sending a
response to the abort task TM.

> ibmvscsis_tgt does not send the response to the client until
> release_cmd time. The reason for this was because if we did it
> at queue_status time, then the client would be free to reuse the
> tag for that command, but we're still using the tag until the
> command is released at release_cmd time, so we chose to delay
> sending the response until then. That then caused this issue, because
> release_cmd is always called, even if queue_status is not.

The above portion of the commit message is little convoluted in my opinion, and 
a bit hard
to follow. Otherwise,

Reviewed-by: Tyrel Datwyler 

> 
> SCSI spec says that the initiator that sends the abort task
> TM NEVER gets a response to the aborted op and with the current
> code it will send a response. Thus this fix will remove that response
> if the TAS bit is set.
> 
> Cc:  # v4.8+
> Signed-off-by: Bryant G. Ly 
> ---
>  drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 60 
> +---
>  1 file changed, 40 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c 
> b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
> index 4bb5635..f75948a 100644
> --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
> +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
> @@ -1758,33 +1758,42 @@ static void ibmvscsis_send_messages(struct scsi_info 
> *vscsi)
>  
>   if (!(vscsi->flags & RESPONSE_Q_DOWN)) {
>   list_for_each_entry_safe(cmd, nxt, >waiting_rsp, list) {
> - iue = cmd->iue;
> + /*
> +  * If Task Abort Status Bit is set, then dont send a
> +  * response.
> +  */
> + if (cmd->se_cmd.transport_state & CMD_T_TAS) {
> + list_del(>list);
> + ibmvscsis_free_cmd_resources(vscsi, cmd);
> + } else {
> + iue = cmd->iue;
>  
> - crq->valid = VALID_CMD_RESP_EL;
> - crq->format = cmd->rsp.format;
> + crq->valid = VALID_CMD_RESP_EL;
> + crq->format = cmd->rsp.format;
>  
> - if (cmd->flags & CMD_FAST_FAIL)
> - crq->status = VIOSRP_ADAPTER_FAIL;
> + if (cmd->flags & CMD_FAST_FAIL)
> + crq->status = VIOSRP_ADAPTER_FAIL;
>  
> - crq->IU_length = cpu_to_be16(cmd->rsp.len);
> + crq->IU_length = cpu_to_be16(cmd->rsp.len);
>  
> - rc = h_send_crq(vscsi->dma_dev->unit_address,
> - be64_to_cpu(msg_hi),
> - be64_to_cpu(cmd->rsp.tag));
> + rc = h_send_crq(vscsi->dma_dev->unit_address,
> + be64_to_cpu(msg_hi),
> + be64_to_cpu(cmd->rsp.tag));
>  
> - pr_debug("send_messages: cmd %p, tag 0x%llx, rc %ld\n",
> -  cmd, be64_to_cpu(cmd->rsp.tag), rc);
> + pr_debug("send_messages: cmd %p, tag 0x%llx, rc 
> %ld\n",
> +  cmd, be64_to_cpu(cmd->rsp.tag), rc);
>  
> - /* if all ok free up the command element resources */
> - if (rc == H_SUCCESS) {
> - /* some movement has occurred */
> - vscsi->rsp_q_timer.timer_pops = 0;
> - list_del(>list);
> + /* if all ok free up the command element 
> resources */
> + if (rc == H_SUCCESS) {
> + /* some movement has occurred */
> + vscsi->rsp_q_timer.timer_pops = 0;
> + list_del(>list);
>  
> - ibmvscsis_free_cmd_resources(vscsi, cmd);
> - } else {
> - srp_snd_msg_failed(vscsi, rc);
> - break;
> + ibmvscsis_free_cmd_resources(vscsi, 
> cmd);
> + } else {
> + srp_snd_msg_failed(vscsi, rc);
> + break;
> + }
>   }
>   }
> 

Re: [PATCH 20/37] smartpqi: add ptraid support

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 14:47 -0500, Don Brace wrote:
> +static inline bool pqi_is_external_raid_device(struct pqi_scsi_dev *device)
> +{
> + return device->is_external_raid_device;
> +}

The name of this function is almost as long as its implementation. Please drop
this function definition and inline the function into its callers.

Thanks,

Bart.

Re: [PATCH 18/37] smartpqi: cleanup messages

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 14:47 -0500, Don Brace wrote:
>   case CISS_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
>   status =
> - "Encrypted volume inaccessible - disabled on ctrl";
> + "Volume encrypted but encryption disabled on controller";
>   break;

This indentation style is confusing. Please don't do this.

Thanks,

Bart.

Re: [PATCH 16/37] smartpqi: minor driver cleanup

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 14:47 -0500, Don Brace wrote:
> From: Kevin Barnett 
> 
> - align with in-house driver

This is not an appropriate patch description. A patch description should
explain what has been changed and also what the purpose is of these changes.

Thanks,

Bart.

Re: [PATCH 12/37] smartpqi: change functions to inline

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 14:47 -0500, Don Brace wrote:
> From: Kevin Barnett 
> 
> Reviewed-by: Scott Benesh 
> Signed-off-by: Kevin Barnett 
> Signed-off-by: Don Brace 
> ---
>  drivers/scsi/smartpqi/smartpqi_init.c |2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
> b/drivers/scsi/smartpqi/smartpqi_init.c
> index 728db8f..523b730 100644
> --- a/drivers/scsi/smartpqi/smartpqi_init.c
> +++ b/drivers/scsi/smartpqi/smartpqi_init.c
> @@ -432,7 +432,7 @@ static struct pqi_io_request *pqi_alloc_io_request(
>   return io_request;
>  }
>  
> -static void pqi_free_io_request(struct pqi_io_request *io_request)
> +static inline void pqi_free_io_request(struct pqi_io_request *io_request)
>  {
>   atomic_dec(_request->refcount);
>  }

A patch description should not only explain what has been changed but also
why a change has been made. What is the reason that this function has been
declared inline? Why do you think that the compiler is not smart enough to
decide on its own to inline this function?

Thanks,

Bart.

Re: [PATCH 08/37] smartpqi: add suspend and resume support

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 14:46 -0500, Don Brace wrote:
> +static int pqi_device_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info,
> +   struct pqi_scsi_dev *device)
> +{
> +   while (atomic_read(>scsi_cmds_outstanding)) {
> +   pqi_check_ctrl_health(ctrl_info);
> +   if (pqi_ctrl_offline(ctrl_info))
> +   return -ENXIO;
> +   usleep_range(1000, 2000);
> +   }
> +
> +   return 0;
> +}
> +
> +static int pqi_ctrl_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info)
> +{
> +   bool io_pending;
> +   unsigned long flags;
> +   struct pqi_scsi_dev *device;
> +
> +   while (1) {
> +   io_pending = false;
> +
> +   spin_lock_irqsave(_info->scsi_device_list_lock, flags);
> +   list_for_each_entry(device, _info->scsi_device_list,
> +   scsi_device_list_entry) {
> +   if (atomic_read(>scsi_cmds_outstanding)) {
> +   io_pending = true;
> +   break;
> +   }
> +   }
> +   spin_unlock_irqrestore(_info->scsi_device_list_lock,
> +   flags);
> +
> +   if (!io_pending)
> +   break;
> +
> +   pqi_check_ctrl_health(ctrl_info);
> +   if (pqi_ctrl_offline(ctrl_info))
> +   return -ENXIO;
> +
> +   usleep_range(1000, 2000);
> +   }
> +
> +   return 0;
> +}

The same comment applies here that applies to the previous patch: please use
scsi_target_block() / scsi_target_unblock() instead of reimplementing these
functions.

Thanks,

Bart.

Re: [PATCH 07/37] smartpqi: enhance resets

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 14:46 -0500, Don Brace wrote:
> @@ -4655,23 +4860,46 @@ static int pqi_device_reset(struct pqi_ctrl_info 
> *ctrl_info,
>  static int pqi_eh_device_reset_handler(struct scsi_cmnd *scmd)
>  {
>   int rc;
> + struct Scsi_Host *shost;
>   struct pqi_ctrl_info *ctrl_info;
>   struct pqi_scsi_dev *device;
>  
> - ctrl_info = shost_to_hba(scmd->device->host);
> + shost = scmd->device->host;
> + ctrl_info = shost_to_hba(shost);
>   device = scmd->device->hostdata;
>  
>   dev_err(_info->pci_dev->dev,
>   "resetting scsi %d:%d:%d:%d\n",
> - ctrl_info->scsi_host->host_no,
> - device->bus, device->target, device->lun);
> + shost->host_no, device->bus, device->target, device->lun);
>  
> - rc = pqi_device_reset(ctrl_info, device);
> + pqi_check_ctrl_health(ctrl_info);
> + if (pqi_ctrl_offline(ctrl_info)) {
> + rc = FAILED;
> + goto out;
> + }
>  
> + mutex_lock(_info->lun_reset_mutex);
> +
> + pqi_ctrl_block_requests(ctrl_info);
> + pqi_ctrl_wait_until_quiesced(ctrl_info);
> + pqi_fail_io_queued_for_device(ctrl_info, device);
> + rc = pqi_wait_until_inbound_queues_empty(ctrl_info);
> + pqi_device_reset_start(device);
> + pqi_ctrl_unblock_requests(ctrl_info);
> +
> + if (rc)
> + rc = FAILED;
> + else
> + rc = pqi_device_reset(ctrl_info, device);
> +
> + pqi_device_reset_done(device);
> +
> + mutex_unlock(_info->lun_reset_mutex);
> +
> +out:
>   dev_err(_info->pci_dev->dev,
>   "reset of scsi %d:%d:%d:%d: %s\n",
> - ctrl_info->scsi_host->host_no,
> - device->bus, device->target, device->lun,
> + shost->host_no, device->bus, device->target, device->lun,
>   rc == SUCCESS ? "SUCCESS" : "FAILED");
>  
>   return rc;

Please use scsi_target_block() / scsi_target_unblock() instead of reimplementing
these functions.

Thanks,

Bart.


Re: [PATCH 05/37] smartpqi: ensure controller is in SIS mode at init

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 14:46 -0500, Don Brace wrote:
> +bool sis_is_kernel_up(struct pqi_ctrl_info *ctrl_info)
> +{
> + u32 status;
> + bool kernel_up;
> +
> + status = readl(_info->registers->sis_firmware_status);
> +
> + if (status & SIS_CTRL_KERNEL_UP)
> + kernel_up = true;
> + else
> + kernel_up = false;
> +
> + return kernel_up;
> +}

Since bool is a synonym for the C11 type _Bool, it is not necessary to
convert explicitly to a truth value. The above code can be simplified into:

bool sis_is_kernel_up(struct pqi_ctrl_info *ctrl_info)
{
return readl(_info->registers->sis_firmware_status) &
SIS_CTRL_KERNEL_UP;
}

Re: [PATCH 02/37] smartpqi: cleanup interrupt management

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 14:46 -0500, Don Brace wrote:
>  static int pqi_request_irqs(struct pqi_ctrl_info *ctrl_info)
>  {
> - struct pci_dev *pdev = ctrl_info->pci_dev;
>   int i;
>   int rc;
> + struct pci_dev *pdev = ctrl_info->pci_dev;

Was this change necessary? If not, please leave it out.

Thanks,

Bart.

[PATCH 36/37] smartpqi: remove writeq/readq function definitions

2017-04-25 Thread Don Brace
From: Corentin Labbe 

Instead of rewriting write/readq, use existing functions

Reviewed-by: Scott Benesh 
Signed-off-by: Corentin Labbe 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h |   29 -
 1 file changed, 29 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index e9f113a..446e17b 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -1175,33 +1175,4 @@ void pqi_prep_for_scsi_done(struct scsi_cmnd *scmd);
 
 extern struct sas_function_template pqi_sas_transport_functions;
 
-#if !defined(readq)
-#define readq readq
-static inline u64 readq(const volatile void __iomem *addr)
-{
-   u32 lower32;
-   u32 upper32;
-
-   lower32 = readl(addr);
-   upper32 = readl(addr + 4);
-
-   return ((u64)upper32 << 32) | lower32;
-}
-#endif
-
-#if !defined(writeq)
-#define writeq writeq
-static inline void writeq(u64 value, volatile void __iomem *addr)
-{
-   u32 lower32;
-   u32 upper32;
-
-   lower32 = lower_32_bits(value);
-   upper32 = upper_32_bits(value);
-
-   writel(lower32, addr);
-   writel(upper32, addr + 4);
-}
-#endif
-
 #endif /* _SMARTPQI_H */



[PATCH 37/37] smartpqi: bump driver version

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Reviewed-by: Scott Benesh 
Reviewed-by: Gerry Morong 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   15 ---
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index cf13f3e..ef5ccb2 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -40,13 +40,14 @@
 #define BUILD_TIMESTAMP
 #endif
 
-#define DRIVER_VERSION "0.9.13-370"
-#define DRIVER_MAJOR   0
-#define DRIVER_MINOR   9
-#define DRIVER_RELEASE 13
-#define DRIVER_REVISION370
-
-#define DRIVER_NAME"Microsemi PQI Driver (v" DRIVER_VERSION ")"
+#define DRIVER_VERSION "1.0.4-100"
+#define DRIVER_MAJOR   1
+#define DRIVER_MINOR   0
+#define DRIVER_RELEASE 4
+#define DRIVER_REVISION100
+
+#define DRIVER_NAME"Microsemi PQI Driver (v" \
+   DRIVER_VERSION BUILD_TIMESTAMP ")"
 #define DRIVER_NAME_SHORT  "smartpqi"
 
 #define PQI_EXTRA_SGL_MEMORY   (12 * sizeof(struct pqi_sg_descriptor))



[PATCH 31/37] smartpqi: enhance device add and remove messages

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Improved formatting of information displayed when devices
are added/removed from the system.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   90 +
 1 file changed, 69 insertions(+), 21 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 52ad6e7..c20d731 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -1454,24 +1454,66 @@ static enum pqi_find_result pqi_scsi_find_entry(struct 
pqi_ctrl_info *ctrl_info,
return DEVICE_NOT_FOUND;
 }
 
+#define PQI_DEV_INFO_BUFFER_LENGTH 128
+
 static void pqi_dev_info(struct pqi_ctrl_info *ctrl_info,
char *action, struct pqi_scsi_dev *device)
 {
-   dev_info(_info->pci_dev->dev,
-   "%s scsi %d:%d:%d:%d: %s %.8s %.16s %-12s SSDSmartPathCap%c 
En%c qd=%d\n",
-   action,
-   ctrl_info->scsi_host->host_no,
-   device->bus,
-   device->target,
-   device->lun,
+   ssize_t count;
+   char buffer[PQI_DEV_INFO_BUFFER_LENGTH];
+
+   count = snprintf(buffer, PQI_DEV_INFO_BUFFER_LENGTH,
+   "%d:%d:", ctrl_info->scsi_host->host_no, device->bus);
+
+   if (device->target_lun_valid)
+   count += snprintf(buffer + count,
+   PQI_DEV_INFO_BUFFER_LENGTH - count,
+   "%d:%d",
+   device->target,
+   device->lun);
+   else
+   count += snprintf(buffer + count,
+   PQI_DEV_INFO_BUFFER_LENGTH - count,
+   "-:-");
+
+   if (pqi_is_logical_device(device))
+   count += snprintf(buffer + count,
+   PQI_DEV_INFO_BUFFER_LENGTH - count,
+   " %08x%08x",
+   *((u32 *)>scsi3addr),
+   *((u32 *)>scsi3addr[4]));
+   else
+   count += snprintf(buffer + count,
+   PQI_DEV_INFO_BUFFER_LENGTH - count,
+   " %016llx", device->sas_address);
+
+   count += snprintf(buffer + count, PQI_DEV_INFO_BUFFER_LENGTH - count,
+   " %s %.8s %.16s ",
scsi_device_type(device->devtype),
device->vendor,
-   device->model,
-   pqi_is_logical_device(device) ?
-   pqi_raid_level_to_string(device->raid_level) : "",
-   device->offload_configured ? '+' : '-',
-   device->offload_enabled_pending ? '+' : '-',
-   device->queue_depth);
+   device->model);
+
+   if (pqi_is_logical_device(device)) {
+   if (device->devtype == TYPE_DISK)
+   count += snprintf(buffer + count,
+   PQI_DEV_INFO_BUFFER_LENGTH - count,
+   "SSDSmartPathCap%c En%c %-12s",
+   device->offload_configured ? '+' : '-',
+   (device->offload_enabled ||
+   device->offload_enabled_pending) ? '+' : '-',
+   pqi_raid_level_to_string(device->raid_level));
+   } else {
+   count += snprintf(buffer + count,
+   PQI_DEV_INFO_BUFFER_LENGTH - count,
+   "AIO%c", device->aio_enabled ? '+' : '-');
+   if (device->devtype == TYPE_DISK ||
+   device->devtype == TYPE_ZBC)
+   count += snprintf(buffer + count,
+   PQI_DEV_INFO_BUFFER_LENGTH - count,
+   " qd=%-6d", device->queue_depth);
+   }
+
+   dev_info(_info->pci_dev->dev, "%s %s\n", action, buffer);
 }
 
 /* Assumes the SCSI device list lock is held. */
@@ -1644,14 +1686,14 @@ static void pqi_update_device_list(struct pqi_ctrl_info 
*ctrl_info,
/* Remove all devices that have gone away. */
list_for_each_entry_safe(device, next, _list,
delete_list_entry) {
-   if (device->sdev)
-   pqi_remove_device(ctrl_info, device);
if (device->volume_offline) {
pqi_dev_info(ctrl_info, "offline", device);
pqi_show_volume_status(ctrl_info, device);
} else {
pqi_dev_info(ctrl_info, "removed", device);
}
+   if (device->sdev)
+   pqi_remove_device(ctrl_info, device);
list_del(>delete_list_entry);
pqi_free_device(device);
}
@@ -1673,6 +1715,7 @@ static void pqi_update_device_list(struct pqi_ctrl_info 
*ctrl_info,
/* 

[PATCH 34/37] smartpqi: cleanup list initialization

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Better initialization of linked list heads.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   11 +++
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 8b285ad..13d3ed5 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -1597,11 +1597,8 @@ static void pqi_update_device_list(struct pqi_ctrl_info 
*ctrl_info,
struct pqi_scsi_dev *device;
struct pqi_scsi_dev *next;
struct pqi_scsi_dev *matching_device;
-   struct list_head add_list;
-   struct list_head delete_list;
-
-   INIT_LIST_HEAD(_list);
-   INIT_LIST_HEAD(_list);
+   LIST_HEAD(add_list);
+   LIST_HEAD(delete_list);
 
/*
 * The idea here is to do as little work as possible while holding the
@@ -1761,7 +1758,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info 
*ctrl_info)
 {
int i;
int rc;
-   struct list_head new_device_list_head;
+   LIST_HEAD(new_device_list_head);
struct report_phys_lun_extended *physdev_list = NULL;
struct report_log_lun_extended *logdev_list = NULL;
struct report_phys_lun_extended_entry *phys_lun_ext_entry;
@@ -1779,8 +1776,6 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info 
*ctrl_info)
static char *out_of_memory_msg =
"failed to allocate memory, device discovery stopped";
 
-   INIT_LIST_HEAD(_device_list_head);
-
rc = pqi_get_device_lists(ctrl_info, _list, _list);
if (rc)
goto out;



[PATCH 35/37] smartpqi: add module parameters

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Add module parameters to disable heartbeat support and to disable
shutting down the controller when a controller is taken offline.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   29 -
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 13d3ed5..cf13f3e 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -122,6 +122,18 @@ module_param_named(disable_device_id_wildcards,
 MODULE_PARM_DESC(disable_device_id_wildcards,
"Disable device ID wildcards.");
 
+static int pqi_disable_heartbeat;
+module_param_named(disable_heartbeat,
+   pqi_disable_heartbeat, int, 0644);
+MODULE_PARM_DESC(disable_heartbeat,
+   "Disable heartbeat.");
+
+static int pqi_disable_ctrl_shutdown;
+module_param_named(disable_ctrl_shutdown,
+   pqi_disable_ctrl_shutdown, int, 0644);
+MODULE_PARM_DESC(disable_ctrl_shutdown,
+   "Disable controller shutdown when controller locked up.");
+
 static char *pqi_lockup_action_param;
 module_param_named(lockup_action,
pqi_lockup_action_param, charp, 0644);
@@ -5969,10 +5981,16 @@ static int pqi_process_config_table(struct 
pqi_ctrl_info *ctrl_info)
 
switch (get_unaligned_le16(>section_id)) {
case PQI_CONFIG_TABLE_SECTION_HEARTBEAT:
-   ctrl_info->heartbeat_counter = table_iomem_addr +
-   section_offset +
-   offsetof(struct pqi_config_table_heartbeat,
-   heartbeat_counter);
+   if (pqi_disable_heartbeat)
+   dev_warn(_info->pci_dev->dev,
+   "heartbeat disabled by module parameter\n");
+   else
+   ctrl_info->heartbeat_counter =
+   table_iomem_addr +
+   section_offset +
+   offsetof(
+   struct pqi_config_table_heartbeat,
+   heartbeat_counter);
break;
}
 
@@ -6557,7 +6575,8 @@ static void pqi_take_ctrl_offline(struct pqi_ctrl_info 
*ctrl_info)
ctrl_info->controller_online = false;
ctrl_info->pqi_mode_enabled = false;
pqi_ctrl_block_requests(ctrl_info);
-   sis_shutdown_ctrl(ctrl_info);
+   if (!pqi_disable_ctrl_shutdown)
+   sis_shutdown_ctrl(ctrl_info);
pci_disable_device(ctrl_info->pci_dev);
dev_err(_info->pci_dev->dev, "controller offline\n");
schedule_work(_info->ctrl_offline_work);



[PATCH 33/37] smartpqi: add raid level show

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Display the RAID level via sysfs

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   30 +-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 23d4686..8b285ad 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -144,7 +144,7 @@ static char *pqi_raid_level_to_string(u8 raid_level)
if (raid_level < ARRAY_SIZE(raid_levels))
return raid_levels[raid_level];
 
-   return "";
+   return "RAID UNKNOWN";
 }
 
 #define SA_RAID_0  0
@@ -5761,13 +5761,41 @@ static ssize_t pqi_ssd_smart_path_enabled_show(struct 
device *dev,
return 2;
 }
 
+static ssize_t pqi_raid_level_show(struct device *dev,
+   struct device_attribute *attr, char *buffer)
+{
+   struct pqi_ctrl_info *ctrl_info;
+   struct scsi_device *sdev;
+   struct pqi_scsi_dev *device;
+   unsigned long flags;
+   char *raid_level;
+
+   sdev = to_scsi_device(dev);
+   ctrl_info = shost_to_hba(sdev->host);
+
+   spin_lock_irqsave(_info->scsi_device_list_lock, flags);
+
+   device = sdev->hostdata;
+
+   if (pqi_is_logical_device(device))
+   raid_level = pqi_raid_level_to_string(device->raid_level);
+   else
+   raid_level = "N/A";
+
+   spin_unlock_irqrestore(_info->scsi_device_list_lock, flags);
+
+   return snprintf(buffer, PAGE_SIZE, "%s\n", raid_level);
+}
+
 static DEVICE_ATTR(sas_address, 0444, pqi_sas_address_show, NULL);
 static DEVICE_ATTR(ssd_smart_path_enabled, 0444,
pqi_ssd_smart_path_enabled_show, NULL);
+static DEVICE_ATTR(raid_level, 0444, pqi_raid_level_show, NULL);
 
 static struct device_attribute *pqi_sdev_attrs[] = {
_attr_sas_address,
_attr_ssd_smart_path_enabled,
+   _attr_raid_level,
NULL
 };
 



[PATCH 30/37] smartpqi: update timeout on admin commands

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Increase the timeout on admin commands from 3 seconds to 60
seconds and added a check for controller crash in the loop
where the driver polls for admin command completion.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index e841c1b..52ad6e7 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -3432,6 +3432,8 @@ static void pqi_submit_admin_request(struct pqi_ctrl_info 
*ctrl_info,
writel(iq_pi, admin_queues->iq_pi);
 }
 
+#define PQI_ADMIN_REQUEST_TIMEOUT_SECS 60
+
 static int pqi_poll_for_admin_response(struct pqi_ctrl_info *ctrl_info,
struct pqi_general_admin_response *response)
 {
@@ -3443,7 +3445,7 @@ static int pqi_poll_for_admin_response(struct 
pqi_ctrl_info *ctrl_info,
admin_queues = _info->admin_queues;
oq_ci = admin_queues->oq_ci_copy;
 
-   timeout = (3 * HZ) + jiffies;
+   timeout = (PQI_ADMIN_REQUEST_TIMEOUT_SECS * HZ) + jiffies;
 
while (1) {
oq_pi = *admin_queues->oq_pi;
@@ -3454,6 +3456,8 @@ static int pqi_poll_for_admin_response(struct 
pqi_ctrl_info *ctrl_info,
"timed out waiting for admin response\n");
return -ETIMEDOUT;
}
+   if (!sis_is_firmware_running(ctrl_info))
+   return -ENXIO;
usleep_range(1000, 2000);
}
 



[PATCH 32/37] smartpqi: make raid bypass references consistent

2017-04-25 Thread Don Brace
From: Kevin Barnett 

- make all references to RAID bypass consistent throughout driver.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |   13 
 drivers/scsi/smartpqi/smartpqi_init.c |   56 ++---
 2 files changed, 30 insertions(+), 39 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 2ed15cf..e9f113a 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -805,12 +805,11 @@ struct pqi_scsi_dev {
u8  bay;
u8  box[8];
u16 phys_connector[8];
-   int offload_configured; /* I/O accel RAID offload configured */
-   int offload_enabled;/* I/O accel RAID offload enabled */
-   int offload_enabled_pending;
-   int offload_to_mirror;  /* Send next I/O accelerator RAID */
-   /* offload request to mirror drive. */
-   struct raid_map *raid_map;  /* I/O accelerator RAID map */
+   boolraid_bypass_configured; /* RAID bypass configured */
+   boolraid_bypass_enabled;/* RAID bypass enabled */
+   int offload_to_mirror;  /* Send next RAID bypass request */
+   /* to mirror drive. */
+   struct raid_map *raid_map;  /* RAID bypass map */
 
struct pqi_sas_port *sas_port;
struct scsi_device *sdev;
@@ -827,7 +826,7 @@ struct pqi_scsi_dev {
 #define SCSI_VPD_SUPPORTED_PAGES   0x0 /* standard page */
 #define SCSI_VPD_DEVICE_ID 0x83/* standard page */
 #define CISS_VPD_LV_DEVICE_GEOMETRY0xc1/* vendor-specific page */
-#define CISS_VPD_LV_OFFLOAD_STATUS 0xc2/* vendor-specific page */
+#define CISS_VPD_LV_BYPASS_STATUS  0xc2/* vendor-specific page */
 #define CISS_VPD_LV_STATUS 0xc3/* vendor-specific page */
 
 #define VPD_PAGE   (1 << 8)
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index c20d731..23d4686 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -1117,35 +1117,33 @@ static int pqi_get_raid_map(struct pqi_ctrl_info 
*ctrl_info,
return rc;
 }
 
-static void pqi_get_offload_status(struct pqi_ctrl_info *ctrl_info,
+static void pqi_get_raid_bypass_status(struct pqi_ctrl_info *ctrl_info,
struct pqi_scsi_dev *device)
 {
int rc;
u8 *buffer;
-   u8 offload_status;
+   u8 bypass_status;
 
buffer = kmalloc(64, GFP_KERNEL);
if (!buffer)
return;
 
rc = pqi_scsi_inquiry(ctrl_info, device->scsi3addr,
-   VPD_PAGE | CISS_VPD_LV_OFFLOAD_STATUS, buffer, 64);
+   VPD_PAGE | CISS_VPD_LV_BYPASS_STATUS, buffer, 64);
if (rc)
goto out;
 
-#define OFFLOAD_STATUS_BYTE4
-#define OFFLOAD_CONFIGURED_BIT 0x1
-#define OFFLOAD_ENABLED_BIT0x2
+#define RAID_BYPASS_STATUS 4
+#define RAID_BYPASS_CONFIGURED 0x1
+#define RAID_BYPASS_ENABLED0x2
 
-   offload_status = buffer[OFFLOAD_STATUS_BYTE];
-   device->offload_configured =
-   !!(offload_status & OFFLOAD_CONFIGURED_BIT);
-   if (device->offload_configured) {
-   device->offload_enabled_pending =
-   !!(offload_status & OFFLOAD_ENABLED_BIT);
-   if (pqi_get_raid_map(ctrl_info, device))
-   device->offload_enabled_pending = false;
-   }
+   bypass_status = buffer[RAID_BYPASS_STATUS];
+   device->raid_bypass_configured =
+   (bypass_status & RAID_BYPASS_CONFIGURED) != 0;
+   if (device->raid_bypass_configured &&
+   (bypass_status & RAID_BYPASS_ENABLED) &&
+   pqi_get_raid_map(ctrl_info, device) == 0)
+   device->raid_bypass_enabled = true;
 
 out:
kfree(buffer);
@@ -1219,7 +1217,7 @@ static int pqi_get_device_info(struct pqi_ctrl_info 
*ctrl_info,
device->volume_offline = false;
} else {
pqi_get_raid_level(ctrl_info, device);
-   pqi_get_offload_status(ctrl_info, device);
+   pqi_get_raid_bypass_status(ctrl_info, device);
pqi_get_volume_status(ctrl_info, device);
}
}
@@ -1498,9 +1496,8 @@ static void pqi_dev_info(struct pqi_ctrl_info *ctrl_info,
count += snprintf(buffer + count,
PQI_DEV_INFO_BUFFER_LENGTH - count,
"SSDSmartPathCap%c En%c %-12s",
-   device->offload_configured ? '+' : '-',
-   (device->offload_enabled ||
-

[PATCH 29/37] smartpqi: map more raid errors to SCSI errors

2017-04-25 Thread Don Brace
From: Kevin Barnett 

enhance mapping of RAID path errors to Linux SCSI host
error codes.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   32 +++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 790dfc4..e841c1b 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -2447,13 +2447,43 @@ static void pqi_process_raid_io_error(struct 
pqi_io_request *io_request)
scsi_status = error_info->status;
host_byte = DID_OK;
 
-   if (error_info->data_out_result == PQI_DATA_IN_OUT_UNDERFLOW) {
+   switch (error_info->data_out_result) {
+   case PQI_DATA_IN_OUT_GOOD:
+   break;
+   case PQI_DATA_IN_OUT_UNDERFLOW:
xfer_count =
get_unaligned_le32(_info->data_out_transferred);
residual_count = scsi_bufflen(scmd) - xfer_count;
scsi_set_resid(scmd, residual_count);
if (xfer_count < scmd->underflow)
host_byte = DID_SOFT_ERROR;
+   break;
+   case PQI_DATA_IN_OUT_UNSOLICITED_ABORT:
+   case PQI_DATA_IN_OUT_ABORTED:
+   host_byte = DID_ABORT;
+   break;
+   case PQI_DATA_IN_OUT_TIMEOUT:
+   host_byte = DID_TIME_OUT;
+   break;
+   case PQI_DATA_IN_OUT_BUFFER_OVERFLOW:
+   case PQI_DATA_IN_OUT_PROTOCOL_ERROR:
+   case PQI_DATA_IN_OUT_BUFFER_ERROR:
+   case PQI_DATA_IN_OUT_BUFFER_OVERFLOW_DESCRIPTOR_AREA:
+   case PQI_DATA_IN_OUT_BUFFER_OVERFLOW_BRIDGE:
+   case PQI_DATA_IN_OUT_ERROR:
+   case PQI_DATA_IN_OUT_HARDWARE_ERROR:
+   case PQI_DATA_IN_OUT_PCIE_FABRIC_ERROR:
+   case PQI_DATA_IN_OUT_PCIE_COMPLETION_TIMEOUT:
+   case PQI_DATA_IN_OUT_PCIE_COMPLETER_ABORT_RECEIVED:
+   case PQI_DATA_IN_OUT_PCIE_UNSUPPORTED_REQUEST_RECEIVED:
+   case PQI_DATA_IN_OUT_PCIE_ECRC_CHECK_FAILED:
+   case PQI_DATA_IN_OUT_PCIE_UNSUPPORTED_REQUEST:
+   case PQI_DATA_IN_OUT_PCIE_ACS_VIOLATION:
+   case PQI_DATA_IN_OUT_PCIE_TLP_PREFIX_BLOCKED:
+   case PQI_DATA_IN_OUT_PCIE_POISONED_MEMORY_READ:
+   default:
+   host_byte = DID_ERROR;
+   break;
}
 
sense_data_length = get_unaligned_le16(_info->sense_data_length);



[PATCH 28/37] smartpqi: cleanup controller branding

2017-04-25 Thread Don Brace
From: Kevin Barnett 

- Improve controller branding support.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   18 +++---
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 66f02f4..790dfc4 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -58,9 +58,6 @@ MODULE_SUPPORTED_DEVICE("Microsemi Smart Family Controllers");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
-static char *hpe_branded_controller = "HPE Smart Array Controller";
-static char *microsemi_branded_controller = "Microsemi Smart Family 
Controller";
-
 static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info);
 static void pqi_ctrl_offline_worker(struct work_struct *work);
 static void pqi_retry_raid_bypass_requests(struct pqi_ctrl_info *ctrl_info);
@@ -6474,19 +6471,10 @@ static void pqi_print_ctrl_info(struct pci_dev *pci_dev,
 {
char *ctrl_description;
 
-   if (id->driver_data) {
+   if (id->driver_data)
ctrl_description = (char *)id->driver_data;
-   } else {
-   switch (id->subvendor) {
-   case PCI_VENDOR_ID_HP:
-   ctrl_description = hpe_branded_controller;
-   break;
-   case PCI_VENDOR_ID_ADAPTEC2:
-   default:
-   ctrl_description = microsemi_branded_controller;
-   break;
-   }
-   }
+   else
+   ctrl_description = "Microsemi Smart Family Controller";
 
dev_info(_dev->dev, "%s found\n", ctrl_description);
 }



[PATCH 27/37] smartpqi: controller offline improvements

2017-04-25 Thread Don Brace
From: Kevin Barnett 

improve support for taking controller offline.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |2 
 drivers/scsi/smartpqi/smartpqi_init.c |  141 ++---
 2 files changed, 77 insertions(+), 66 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 94b92ae..2ed15cf 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -994,7 +994,6 @@ struct pqi_ctrl_info {
u8  inbound_spanning_supported : 1;
u8  outbound_spanning_supported : 1;
u8  pqi_mode_enabled : 1;
-   u8  update_time_worker_scheduled : 1;
 
struct list_head scsi_device_list;
spinlock_t  scsi_device_list_lock;
@@ -1016,6 +1015,7 @@ struct pqi_ctrl_info {
u32 previous_heartbeat_count;
__le32 __iomem  *heartbeat_counter;
struct timer_list heartbeat_timer;
+   struct work_struct ctrl_offline_work;
 
struct semaphore sync_request_sem;
atomic_tnum_busy_threads;
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 8a0a486..66f02f4 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -61,10 +61,8 @@ MODULE_LICENSE("GPL");
 static char *hpe_branded_controller = "HPE Smart Array Controller";
 static char *microsemi_branded_controller = "Microsemi Smart Family 
Controller";
 
-static void pqi_perform_lockup_action(void);
 static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info);
-static void pqi_complete_all_queued_raid_bypass_retries(
-   struct pqi_ctrl_info *ctrl_info, int result);
+static void pqi_ctrl_offline_worker(struct work_struct *work);
 static void pqi_retry_raid_bypass_requests(struct pqi_ctrl_info *ctrl_info);
 static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info);
 static void pqi_scan_start(struct Scsi_Host *shost);
@@ -224,7 +222,6 @@ static inline void pqi_save_ctrl_mode(struct pqi_ctrl_info 
*ctrl_info,
sis_write_driver_scratch(ctrl_info, mode);
 }
 
-#define PQI_RESCAN_WORK_INTERVAL   (10 * HZ)
 static inline void pqi_ctrl_block_requests(struct pqi_ctrl_info *ctrl_info)
 {
ctrl_info->block_requests = true;
@@ -310,10 +307,26 @@ static inline bool pqi_device_in_reset(struct 
pqi_scsi_dev *device)
return device->in_reset;
 }
 
+static inline void pqi_schedule_rescan_worker_with_delay(
+   struct pqi_ctrl_info *ctrl_info, unsigned long delay)
+{
+   if (pqi_ctrl_offline(ctrl_info))
+   return;
+
+   schedule_delayed_work(_info->rescan_work, delay);
+}
+
 static inline void pqi_schedule_rescan_worker(struct pqi_ctrl_info *ctrl_info)
 {
-   schedule_delayed_work(_info->rescan_work,
-   PQI_RESCAN_WORK_INTERVAL);
+   pqi_schedule_rescan_worker_with_delay(ctrl_info, 0);
+}
+
+#define PQI_RESCAN_WORK_DELAY  (10 * HZ)
+
+static inline void pqi_schedule_rescan_worker_delayed(
+   struct pqi_ctrl_info *ctrl_info)
+{
+   pqi_schedule_rescan_worker_with_delay(ctrl_info, PQI_RESCAN_WORK_DELAY);
 }
 
 static inline void pqi_cancel_rescan_worker(struct pqi_ctrl_info *ctrl_info)
@@ -746,6 +759,9 @@ static void pqi_update_time_worker(struct work_struct *work)
ctrl_info = container_of(to_delayed_work(work), struct pqi_ctrl_info,
update_time_work);
 
+   if (pqi_ctrl_offline(ctrl_info))
+   return;
+
rc = pqi_write_current_time_to_host_wellness(ctrl_info);
if (rc)
dev_warn(_info->pci_dev->dev,
@@ -758,21 +774,13 @@ static void pqi_update_time_worker(struct work_struct 
*work)
 static inline void pqi_schedule_update_time_worker(
struct pqi_ctrl_info *ctrl_info)
 {
-   if (ctrl_info->update_time_worker_scheduled)
-   return;
-
schedule_delayed_work(_info->update_time_work, 0);
-   ctrl_info->update_time_worker_scheduled = true;
 }
 
 static inline void pqi_cancel_update_time_worker(
struct pqi_ctrl_info *ctrl_info)
 {
-   if (!ctrl_info->update_time_worker_scheduled)
-   return;
-
cancel_delayed_work_sync(_info->update_time_work);
-   ctrl_info->update_time_worker_scheduled = false;
 }
 
 static int pqi_report_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd,
@@ -1939,7 +1947,7 @@ static int pqi_scan_scsi_devices(struct pqi_ctrl_info 
*ctrl_info)
 
rc = pqi_update_scsi_devices(ctrl_info);
if (rc)
-   pqi_schedule_rescan_worker(ctrl_info);
+   pqi_schedule_rescan_worker_delayed(ctrl_info);
 
mutex_unlock(_info->scan_mutex);
 
@@ -2762,6 +2770,10 @@ static void pqi_event_worker(struct work_struct *work)
 

[PATCH 26/37] smartpqi: update device offline

2017-04-25 Thread Don Brace
From: Kevin Barnett 

- Improve handling of offline devices.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   30 +-
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 36cf8cd..8a0a486 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -290,6 +290,11 @@ static inline void pqi_ctrl_wait_until_quiesced(struct 
pqi_ctrl_info *ctrl_info)
usleep_range(1000, 2000);
 }
 
+static inline bool pqi_device_offline(struct pqi_scsi_dev *device)
+{
+   return device->device_offline;
+}
+
 static inline void pqi_device_reset_start(struct pqi_scsi_dev *device)
 {
device->in_reset = true;
@@ -2405,15 +2410,17 @@ static inline void pqi_take_device_offline(struct 
scsi_device *sdev, char *path)
struct pqi_ctrl_info *ctrl_info;
struct pqi_scsi_dev *device;
 
-   if (scsi_device_online(sdev)) {
-   scsi_device_set_state(sdev, SDEV_OFFLINE);
-   ctrl_info = shost_to_hba(sdev->host);
-   schedule_delayed_work(_info->rescan_work, 0);
-   device = sdev->hostdata;
-   dev_err(_info->pci_dev->dev, "offlined %s scsi 
%d:%d:%d:%d\n",
-   path, ctrl_info->scsi_host->host_no, device->bus,
-   device->target, device->lun);
-   }
+   device = sdev->hostdata;
+   if (device->device_offline)
+   return;
+
+   device->device_offline = true;
+   scsi_device_set_state(sdev, SDEV_OFFLINE);
+   ctrl_info = shost_to_hba(sdev->host);
+   pqi_schedule_rescan_worker(ctrl_info);
+   dev_err(_info->pci_dev->dev, "offlined %s scsi %d:%d:%d:%d\n",
+   path, ctrl_info->scsi_host->host_no, device->bus,
+   device->target, device->lun);
 }
 
 static void pqi_process_raid_io_error(struct pqi_io_request *io_request)
@@ -4605,6 +4612,7 @@ static inline void pqi_schedule_bypass_retry(struct 
pqi_ctrl_info *ctrl_info)
 static bool pqi_raid_bypass_retry_needed(struct pqi_io_request *io_request)
 {
struct scsi_cmnd *scmd;
+   struct pqi_scsi_dev *device;
struct pqi_ctrl_info *ctrl_info;
 
if (!io_request->raid_bypass)
@@ -4616,6 +4624,10 @@ static bool pqi_raid_bypass_retry_needed(struct 
pqi_io_request *io_request)
if (host_byte(scmd->result) == DID_NO_CONNECT)
return false;
 
+   device = scmd->device->hostdata;
+   if (pqi_device_offline(device))
+   return false;
+
ctrl_info = shost_to_hba(scmd->device->host);
if (pqi_ctrl_offline(ctrl_info))
return false;



[PATCH 25/37] smartpqi: correct aio error path

2017-04-25 Thread Don Brace
From: Kevin Barnett 

set the internal flag that causes I/O to be sent down the
RAID path when the AIO path is disabled

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |8 +
 drivers/scsi/smartpqi/smartpqi_init.c |  345 +++--
 2 files changed, 285 insertions(+), 68 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 857d1be..94b92ae 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -785,11 +785,11 @@ struct pqi_scsi_dev {
u8  is_physical_device : 1;
u8  is_external_raid_device : 1;
u8  target_lun_valid : 1;
-   u8  aio_enabled : 1;/* only valid for physical disks */
u8  device_gone : 1;
u8  new_device : 1;
u8  keep_device : 1;
u8  volume_offline : 1;
+   boolaio_enabled;/* only valid for physical disks */
boolin_reset;
booldevice_offline;
u8  vendor[8];  /* bytes 8-15 of inquiry data */
@@ -911,7 +911,9 @@ struct pqi_io_request {
void (*io_complete_callback)(struct pqi_io_request *io_request,
void *context);
void*context;
+   u8  raid_bypass : 1;
int status;
+   struct pqi_queue_group *queue_group;
struct scsi_cmnd *scmd;
void*error_info;
struct pqi_sg_descriptor *sg_chain_buffer;
@@ -1019,6 +1021,10 @@ struct pqi_ctrl_info {
atomic_tnum_busy_threads;
atomic_tnum_blocked_threads;
wait_queue_head_t block_requests_wait;
+
+   struct list_head raid_bypass_retry_list;
+   spinlock_t  raid_bypass_retry_list_lock;
+   struct work_struct raid_bypass_retry_work;
 };
 
 enum pqi_ctrl_mode {
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 132a419..36cf8cd 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -63,6 +63,9 @@ static char *microsemi_branded_controller = "Microsemi Smart 
Family Controller";
 
 static void pqi_perform_lockup_action(void);
 static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info);
+static void pqi_complete_all_queued_raid_bypass_retries(
+   struct pqi_ctrl_info *ctrl_info, int result);
+static void pqi_retry_raid_bypass_requests(struct pqi_ctrl_info *ctrl_info);
 static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info);
 static void pqi_scan_start(struct Scsi_Host *shost);
 static void pqi_start_io(struct pqi_ctrl_info *ctrl_info,
@@ -74,7 +77,7 @@ static int pqi_submit_raid_request_synchronous(struct 
pqi_ctrl_info *ctrl_info,
 static int pqi_aio_submit_io(struct pqi_ctrl_info *ctrl_info,
struct scsi_cmnd *scmd, u32 aio_handle, u8 *cdb,
unsigned int cdb_length, struct pqi_queue_group *queue_group,
-   struct pqi_encryption_info *encryption_info);
+   struct pqi_encryption_info *encryption_info, bool raid_bypass);
 
 /* for flags argument to pqi_submit_raid_request_synchronous() */
 #define PQI_SYNC_FLAGS_INTERRUPTABLE   0x1
@@ -232,6 +235,7 @@ static inline void pqi_ctrl_unblock_requests(struct 
pqi_ctrl_info *ctrl_info)
 {
ctrl_info->block_requests = false;
wake_up_all(_info->block_requests_wait);
+   pqi_retry_raid_bypass_requests(ctrl_info);
scsi_unblock_requests(ctrl_info->scsi_host);
 }
 
@@ -450,6 +454,14 @@ static int pqi_build_raid_path_request(struct 
pqi_ctrl_info *ctrl_info,
buffer, buffer_length, pci_dir);
 }
 
+static inline void pqi_reinit_io_request(struct pqi_io_request *io_request)
+{
+   io_request->scmd = NULL;
+   io_request->status = 0;
+   io_request->error_info = NULL;
+   io_request->raid_bypass = false;
+}
+
 static struct pqi_io_request *pqi_alloc_io_request(
struct pqi_ctrl_info *ctrl_info)
 {
@@ -467,9 +479,7 @@ static struct pqi_io_request *pqi_alloc_io_request(
/* benignly racy */
ctrl_info->next_io_request_slot = (i + 1) % ctrl_info->max_io_slots;
 
-   io_request->scmd = NULL;
-   io_request->status = 0;
-   io_request->error_info = NULL;
+   pqi_reinit_io_request(io_request);
 
return io_request;
 }
@@ -1684,8 +1694,8 @@ static bool pqi_is_supported_device(struct pqi_scsi_dev 
*device)
/*
 * Only support the HBA controller itself as a RAID
 * controller.  If it's a RAID controller other than
-* the HBA itself (an external RAID controller, MSA500
-* or similar), we don't support it.
+* the HBA itself (an external RAID controller, for
+* example), we don't support it.

[PATCH 23/37] smartpqi: remove qdepth calculations for logical volumes

2017-04-25 Thread Don Brace
From: Kevin Barnett 

make the queue depth for LVs the same as the maximum
I/Os supported by the controller

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |6 -
 drivers/scsi/smartpqi/smartpqi_init.c |  140 ++---
 2 files changed, 8 insertions(+), 138 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 400d1fb..857d1be 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -726,7 +726,6 @@ struct report_phys_lun_extended_entry {
 };
 
 /* for device_flags field of struct report_phys_lun_extended_entry */
-#define REPORT_PHYS_LUN_DEV_FLAG_NON_DISK  0x1
 #define REPORT_PHYS_LUN_DEV_FLAG_AIO_ENABLED   0x8
 
 struct report_phys_lun_extended {
@@ -786,8 +785,6 @@ struct pqi_scsi_dev {
u8  is_physical_device : 1;
u8  is_external_raid_device : 1;
u8  target_lun_valid : 1;
-   u8  expose_device : 1;
-   u8  no_uld_attach : 1;
u8  aio_enabled : 1;/* only valid for physical disks */
u8  device_gone : 1;
u8  new_device : 1;
@@ -1034,9 +1031,6 @@ enum pqi_ctrl_mode {
  */
 #define PQI_PHYSICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH  27
 
-/* 0 = no limit */
-#define PQI_LOGICAL_DRIVE_DEFAULT_MAX_QUEUE_DEPTH  0
-
 /* CISS commands */
 #define CISS_READ  0xc0
 #define CISS_REPORT_LOG0xc2/* Report Logical LUNs */
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 6235b6d..2b667b5 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -1308,87 +1308,6 @@ static void pqi_show_volume_status(struct pqi_ctrl_info 
*ctrl_info,
device->bus, device->target, device->lun, status);
 }
 
-static struct pqi_scsi_dev *pqi_find_disk_by_aio_handle(
-   struct pqi_ctrl_info *ctrl_info, u32 aio_handle)
-{
-   struct pqi_scsi_dev *device;
-
-   list_for_each_entry(device, _info->scsi_device_list,
-   scsi_device_list_entry) {
-   if (device->devtype != TYPE_DISK && device->devtype != TYPE_ZBC)
-   continue;
-   if (pqi_is_logical_device(device))
-   continue;
-   if (device->aio_handle == aio_handle)
-   return device;
-   }
-
-   return NULL;
-}
-
-static void pqi_update_logical_drive_queue_depth(
-   struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *logical_drive)
-{
-   unsigned int i;
-   struct raid_map *raid_map;
-   struct raid_map_disk_data *disk_data;
-   struct pqi_scsi_dev *phys_disk;
-   unsigned int num_phys_disks;
-   unsigned int num_raid_map_entries;
-   unsigned int queue_depth;
-
-   logical_drive->queue_depth = PQI_LOGICAL_DRIVE_DEFAULT_MAX_QUEUE_DEPTH;
-
-   raid_map = logical_drive->raid_map;
-   if (!raid_map)
-   return;
-
-   disk_data = raid_map->disk_data;
-   num_phys_disks = get_unaligned_le16(_map->layout_map_count) *
-   (get_unaligned_le16(_map->data_disks_per_row) +
-   get_unaligned_le16(_map->metadata_disks_per_row));
-   num_raid_map_entries = num_phys_disks *
-   get_unaligned_le16(_map->row_cnt);
-
-   queue_depth = 0;
-   for (i = 0; i < num_raid_map_entries; i++) {
-   phys_disk = pqi_find_disk_by_aio_handle(ctrl_info,
-   disk_data[i].aio_handle);
-
-   if (!phys_disk) {
-   dev_warn(_info->pci_dev->dev,
-   "failed to find physical disk for logical drive 
%016llx\n",
-   get_unaligned_be64(logical_drive->scsi3addr));
-   logical_drive->offload_enabled = false;
-   logical_drive->offload_enabled_pending = false;
-   kfree(raid_map);
-   logical_drive->raid_map = NULL;
-   return;
-   }
-
-   queue_depth += phys_disk->queue_depth;
-   }
-
-   logical_drive->queue_depth = queue_depth;
-}
-
-static void pqi_update_all_logical_drive_queue_depths(
-   struct pqi_ctrl_info *ctrl_info)
-{
-   struct pqi_scsi_dev *device;
-
-   list_for_each_entry(device, _info->scsi_device_list,
-   scsi_device_list_entry) {
-   if (device->devtype != TYPE_DISK && device->devtype != TYPE_ZBC)
-   continue;
-   if (!pqi_is_logical_device(device))
-   continue;
-   if (pqi_is_external_raid_device(device))
-   continue;
-   pqi_update_logical_drive_queue_depth(ctrl_info, device);
-  

[PATCH 22/37] smartpqi: enhance kdump

2017-04-25 Thread Don Brace
From: Kevin Barnett 

constrain resource usage during kdump to avoid kdump failures

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |6 +++-
 drivers/scsi/smartpqi/smartpqi_init.c |   45 +++--
 2 files changed, 36 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index be04bcb..400d1fb 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -686,8 +686,10 @@ struct pqi_config_table_heartbeat {
__le32  heartbeat_counter;
 };
 
-#define PQI_MAX_OUTSTANDING_REQUESTS   ((u32)~0)
-#define PQI_MAX_TRANSFER_SIZE  (4 * 1024U * 1024U)
+#define PQI_MAX_OUTSTANDING_REQUESTS   ((u32)~0)
+#define PQI_MAX_OUTSTANDING_REQUESTS_KDUMP 32
+#define PQI_MAX_TRANSFER_SIZE  (4 * 1024U * 1024U)
+#define PQI_MAX_TRANSFER_SIZE_KDUMP(512 * 1024U)
 
 #define RAID_MAP_MAX_ENTRIES   1024
 
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 5678b6a..6235b6d 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -4360,8 +4360,12 @@ static void pqi_calculate_io_resources(struct 
pqi_ctrl_info *ctrl_info)
ctrl_info->error_buffer_length =
ctrl_info->max_io_slots * PQI_ERROR_BUFFER_ELEMENT_LENGTH;
 
-   max_transfer_size =
-   min(ctrl_info->max_transfer_size, PQI_MAX_TRANSFER_SIZE);
+   if (reset_devices)
+   max_transfer_size = min(ctrl_info->max_transfer_size,
+   PQI_MAX_TRANSFER_SIZE_KDUMP);
+   else
+   max_transfer_size = min(ctrl_info->max_transfer_size,
+   PQI_MAX_TRANSFER_SIZE);
 
max_sg_entries = max_transfer_size / PAGE_SIZE;
 
@@ -4381,19 +4385,24 @@ static void pqi_calculate_io_resources(struct 
pqi_ctrl_info *ctrl_info)
 
 static void pqi_calculate_queue_resources(struct pqi_ctrl_info *ctrl_info)
 {
-   int num_cpus;
-   int max_queue_groups;
int num_queue_groups;
u16 num_elements_per_iq;
u16 num_elements_per_oq;
 
-   max_queue_groups = min(ctrl_info->max_inbound_queues / 2,
-   ctrl_info->max_outbound_queues - 1);
-   max_queue_groups = min(max_queue_groups, PQI_MAX_QUEUE_GROUPS);
+   if (reset_devices) {
+   num_queue_groups = 1;
+   } else {
+   int num_cpus;
+   int max_queue_groups;
+
+   max_queue_groups = min(ctrl_info->max_inbound_queues / 2,
+   ctrl_info->max_outbound_queues - 1);
+   max_queue_groups = min(max_queue_groups, PQI_MAX_QUEUE_GROUPS);
 
-   num_cpus = num_online_cpus();
-   num_queue_groups = min(num_cpus, ctrl_info->max_msix_vectors);
-   num_queue_groups = min(num_queue_groups, max_queue_groups);
+   num_cpus = num_online_cpus();
+   num_queue_groups = min(num_cpus, ctrl_info->max_msix_vectors);
+   num_queue_groups = min(num_queue_groups, max_queue_groups);
+   }
 
ctrl_info->num_queue_groups = num_queue_groups;
ctrl_info->max_hw_queue_index = num_queue_groups - 1;
@@ -5834,9 +5843,17 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
return rc;
}
 
-   if (ctrl_info->max_outstanding_requests > PQI_MAX_OUTSTANDING_REQUESTS)
-   ctrl_info->max_outstanding_requests =
-   PQI_MAX_OUTSTANDING_REQUESTS;
+   if (reset_devices) {
+   if (ctrl_info->max_outstanding_requests >
+   PQI_MAX_OUTSTANDING_REQUESTS_KDUMP)
+   ctrl_info->max_outstanding_requests =
+   PQI_MAX_OUTSTANDING_REQUESTS_KDUMP;
+   } else {
+   if (ctrl_info->max_outstanding_requests >
+   PQI_MAX_OUTSTANDING_REQUESTS)
+   ctrl_info->max_outstanding_requests =
+   PQI_MAX_OUTSTANDING_REQUESTS;
+   }
 
pqi_calculate_io_resources(ctrl_info);
 
@@ -7117,4 +7134,6 @@ static void __attribute__((unused)) 
verify_structures(void)
PQI_QUEUE_ELEMENT_LENGTH_ALIGNMENT != 0);
 
BUILD_BUG_ON(PQI_RESERVED_IO_SLOTS >= PQI_MAX_OUTSTANDING_REQUESTS);
+   BUILD_BUG_ON(PQI_RESERVED_IO_SLOTS >=
+   PQI_MAX_OUTSTANDING_REQUESTS_KDUMP);
 }



[PATCH 24/37] smartpqi: add lockup action

2017-04-25 Thread Don Brace
From: Kevin Barnett 

add support for actions to take when controller goes offline.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |  121 +
 1 file changed, 121 insertions(+)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 2b667b5..132a419 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -60,6 +61,7 @@ MODULE_LICENSE("GPL");
 static char *hpe_branded_controller = "HPE Smart Array Controller";
 static char *microsemi_branded_controller = "Microsemi Smart Family 
Controller";
 
+static void pqi_perform_lockup_action(void);
 static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info);
 static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info);
 static void pqi_scan_start(struct Scsi_Host *shost);
@@ -81,6 +83,32 @@ static struct scsi_transport_template 
*pqi_sas_transport_template;
 
 static atomic_t pqi_controller_count = ATOMIC_INIT(0);
 
+enum pqi_lockup_action {
+   NONE,
+   REBOOT,
+   PANIC
+};
+
+static enum pqi_lockup_action pqi_lockup_action = NONE;
+
+static struct {
+   enum pqi_lockup_action  action;
+   char*name;
+} pqi_lockup_actions[] = {
+   {
+   .action = NONE,
+   .name = "none",
+   },
+   {
+   .action = REBOOT,
+   .name = "reboot",
+   },
+   {
+   .action = PANIC,
+   .name = "panic",
+   },
+};
+
 static unsigned int pqi_supported_event_types[] = {
PQI_EVENT_TYPE_HOTPLUG,
PQI_EVENT_TYPE_HARDWARE,
@@ -96,6 +124,13 @@ module_param_named(disable_device_id_wildcards,
 MODULE_PARM_DESC(disable_device_id_wildcards,
"Disable device ID wildcards.");
 
+static char *pqi_lockup_action_param;
+module_param_named(lockup_action,
+   pqi_lockup_action_param, charp, 0644);
+MODULE_PARM_DESC(lockup_action, "Action to take when controller locked up.\n"
+   "\t\tSupported: none, reboot, panic\n"
+   "\t\tDefault: none");
+
 static char *raid_levels[] = {
"RAID-0",
"RAID-4",
@@ -2735,6 +2770,8 @@ static void pqi_take_ctrl_offline(struct pqi_ctrl_info 
*ctrl_info)
ctrl_info->controller_online = false;
dev_err(_info->pci_dev->dev, "controller offline\n");
sis_shutdown_ctrl(ctrl_info);
+   pci_disable_device(ctrl_info->pci_dev);
+   pqi_perform_lockup_action();
 
for (i = 0; i < ctrl_info->num_queue_groups; i++) {
queue_group = _info->queue_groups[i];
@@ -5388,12 +5425,55 @@ static ssize_t pqi_host_rescan_store(struct device *dev,
return count;
 }
 
+static ssize_t pqi_lockup_action_show(struct device *dev,
+   struct device_attribute *attr, char *buffer)
+{
+   int count = 0;
+   unsigned int i;
+
+   for (i = 0; i < ARRAY_SIZE(pqi_lockup_actions); i++) {
+   if (pqi_lockup_actions[i].action == pqi_lockup_action)
+   count += snprintf(buffer + count, PAGE_SIZE - count,
+   "[%s] ", pqi_lockup_actions[i].name);
+   else
+   count += snprintf(buffer + count, PAGE_SIZE - count,
+   "%s ", pqi_lockup_actions[i].name);
+   }
+
+   count += snprintf(buffer + count, PAGE_SIZE - count, "\n");
+
+   return count;
+}
+
+static ssize_t pqi_lockup_action_store(struct device *dev,
+   struct device_attribute *attr, const char *buffer, size_t count)
+{
+   unsigned int i;
+   char *action_name;
+   char action_name_buffer[32];
+
+   strlcpy(action_name_buffer, buffer, sizeof(action_name_buffer));
+   action_name = strstrip(action_name_buffer);
+
+   for (i = 0; i < ARRAY_SIZE(pqi_lockup_actions); i++) {
+   if (strcmp(action_name, pqi_lockup_actions[i].name) == 0) {
+   pqi_lockup_action = pqi_lockup_actions[i].action;
+   return count;
+   }
+   }
+
+   return -EINVAL;
+}
+
 static DEVICE_ATTR(version, 0444, pqi_version_show, NULL);
 static DEVICE_ATTR(rescan, 0200, NULL, pqi_host_rescan_store);
+static DEVICE_ATTR(lockup_action, 0644,
+   pqi_lockup_action_show, pqi_lockup_action_store);
 
 static struct device_attribute *pqi_shost_attrs[] = {
_attr_version,
_attr_rescan,
+   _attr_lockup_action,
NULL
 };
 
@@ -6140,6 +6220,21 @@ static void pqi_remove_ctrl(struct pqi_ctrl_info 
*ctrl_info)
pqi_free_ctrl_resources(ctrl_info);
 }
 
+static void pqi_perform_lockup_action(void)
+{
+   switch (pqi_lockup_action) {
+   case PANIC:
+   panic("FATAL: 

[PATCH 21/37] smartpqi: change return value for LUN reset operations

2017-04-25 Thread Don Brace
From: Kevin Barnett 

change return value for controller offline to be consistent
with the rest of the driver.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index f943e58..5678b6a 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -5032,7 +5032,7 @@ static int pqi_wait_for_lun_reset_completion(struct 
pqi_ctrl_info *ctrl_info,
 
pqi_check_ctrl_health(ctrl_info);
if (pqi_ctrl_offline(ctrl_info)) {
-   rc = -ETIMEDOUT;
+   rc = -ENXIO;
break;
}
}



[PATCH 20/37] smartpqi: add ptraid support

2017-04-25 Thread Don Brace
From: Kevin Barnett 

add support for PTRAID devices

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |8 +++---
 drivers/scsi/smartpqi/smartpqi_init.c |   48 -
 2 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index d044a58c..be04bcb 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -694,7 +694,8 @@ struct pqi_config_table_heartbeat {
 #define PQI_PHYSICAL_DEVICE_BUS0
 #define PQI_RAID_VOLUME_BUS1
 #define PQI_HBA_BUS2
-#define PQI_MAX_BUSPQI_HBA_BUS
+#define PQI_EXTERNAL_RAID_VOLUME_BUS   3
+#define PQI_MAX_BUSPQI_EXTERNAL_RAID_VOLUME_BUS
 
 struct report_lun_header {
__be32  list_length;
@@ -781,6 +782,7 @@ struct pqi_scsi_dev {
__be64  wwid;
u8  volume_id[16];
u8  is_physical_device : 1;
+   u8  is_external_raid_device : 1;
u8  target_lun_valid : 1;
u8  expose_device : 1;
u8  no_uld_attach : 1;
@@ -1056,10 +1058,10 @@ enum pqi_ctrl_mode {
 #define SA_CACHE_FLUSH 0x1
 
 #define MASKED_DEVICE(lunid)   ((lunid)[3] & 0xc0)
-#define CISS_GET_BUS(lunid)((lunid)[7] & 0x3f)
+#define CISS_GET_LEVEL_2_BUS(lunid)((lunid)[7] & 0x3f)
 #define CISS_GET_LEVEL_2_TARGET(lunid) ((lunid)[6])
 #define CISS_GET_DRIVE_NUMBER(lunid)   \
-   (((CISS_GET_BUS((lunid)) - 1) << 8) +   \
+   (((CISS_GET_LEVEL_2_BUS((lunid)) - 1) << 8) + \
CISS_GET_LEVEL_2_TARGET((lunid)))
 
 #define NO_TIMEOUT ((unsigned long) -1)
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index c5b37bc..f943e58 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -147,6 +147,16 @@ static inline bool pqi_is_logical_device(struct 
pqi_scsi_dev *device)
return !device->is_physical_device;
 }
 
+static inline bool pqi_is_external_raid_device(struct pqi_scsi_dev *device)
+{
+   return device->is_external_raid_device;
+}
+
+static inline bool pqi_is_external_raid_addr(u8 *scsi3addr)
+{
+   return scsi3addr[2] != 0;
+}
+
 static inline bool pqi_ctrl_offline(struct pqi_ctrl_info *ctrl_info)
 {
return !ctrl_info->controller_online;
@@ -885,6 +895,9 @@ static void pqi_assign_bus_target_lun(struct pqi_scsi_dev 
*device)
 {
u8 *scsi3addr;
u32 lunid;
+   int bus;
+   int target;
+   int lun;
 
scsi3addr = device->scsi3addr;
lunid = get_unaligned_le32(scsi3addr);
@@ -897,8 +910,16 @@ static void pqi_assign_bus_target_lun(struct pqi_scsi_dev 
*device)
}
 
if (pqi_is_logical_device(device)) {
-   pqi_set_bus_target_lun(device, PQI_RAID_VOLUME_BUS, 0,
-   lunid & 0x3fff);
+   if (pqi_is_external_raid_device(device)) {
+   bus = PQI_EXTERNAL_RAID_VOLUME_BUS;
+   target = (lunid >> 16) & 0x3fff;
+   lun = lunid & 0xff;
+   } else {
+   bus = PQI_RAID_VOLUME_BUS;
+   target = 0;
+   lun = lunid & 0x3fff;
+   }
+   pqi_set_bus_target_lun(device, bus, target, lun);
device->target_lun_valid = true;
return;
}
@@ -1137,9 +1158,15 @@ static int pqi_get_device_info(struct pqi_ctrl_info 
*ctrl_info,
memcpy(device->model, [16], sizeof(device->model));
 
if (pqi_is_logical_device(device) && device->devtype == TYPE_DISK) {
-   pqi_get_raid_level(ctrl_info, device);
-   pqi_get_offload_status(ctrl_info, device);
-   pqi_get_volume_status(ctrl_info, device);
+   if (pqi_is_external_raid_device(device)) {
+   device->raid_level = SA_RAID_UNKNOWN;
+   device->volume_status = CISS_LV_OK;
+   device->volume_offline = false;
+   } else {
+   pqi_get_raid_level(ctrl_info, device);
+   pqi_get_offload_status(ctrl_info, device);
+   pqi_get_volume_status(ctrl_info, device);
+   }
}
 
 out:
@@ -1356,6 +1383,8 @@ static void pqi_update_all_logical_drive_queue_depths(
continue;
if (!pqi_is_logical_device(device))
continue;
+   if (pqi_is_external_raid_device(device))
+   continue;
pqi_update_logical_drive_queue_depth(ctrl_info, device);
}
 }
@@ 

[PATCH 19/37] smartpqi: update copyright

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h   |2 +-
 drivers/scsi/smartpqi/smartpqi_init.c  |2 +-
 drivers/scsi/smartpqi/smartpqi_sas_transport.c |2 +-
 drivers/scsi/smartpqi/smartpqi_sis.c   |2 +-
 drivers/scsi/smartpqi/smartpqi_sis.h   |2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 7a95868..d044a58c 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -1,6 +1,6 @@
 /*
  *driver for Microsemi PQI-based storage controllers
- *Copyright (c) 2016 Microsemi Corporation
+ *Copyright (c) 2016-2017 Microsemi Corporation
  *Copyright (c) 2016 PMC-Sierra, Inc.
  *
  *This program is free software; you can redistribute it and/or modify
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 3ffca17..c5b37bc 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -1,6 +1,6 @@
 /*
  *driver for Microsemi PQI-based storage controllers
- *Copyright (c) 2016 Microsemi Corporation
+ *Copyright (c) 2016-2017 Microsemi Corporation
  *Copyright (c) 2016 PMC-Sierra, Inc.
  *
  *This program is free software; you can redistribute it and/or modify
diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c 
b/drivers/scsi/smartpqi/smartpqi_sas_transport.c
index 52ca4f9..0d89d37 100644
--- a/drivers/scsi/smartpqi/smartpqi_sas_transport.c
+++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c
@@ -1,6 +1,6 @@
 /*
  *driver for Microsemi PQI-based storage controllers
- *Copyright (c) 2016 Microsemi Corporation
+ *Copyright (c) 2016-2017 Microsemi Corporation
  *Copyright (c) 2016 PMC-Sierra, Inc.
  *
  *This program is free software; you can redistribute it and/or modify
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c 
b/drivers/scsi/smartpqi/smartpqi_sis.c
index e5a5d50..e1cf280 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.c
+++ b/drivers/scsi/smartpqi/smartpqi_sis.c
@@ -1,6 +1,6 @@
 /*
  *driver for Microsemi PQI-based storage controllers
- *Copyright (c) 2016 Microsemi Corporation
+ *Copyright (c) 2016-2017 Microsemi Corporation
  *Copyright (c) 2016 PMC-Sierra, Inc.
  *
  *This program is free software; you can redistribute it and/or modify
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h 
b/drivers/scsi/smartpqi/smartpqi_sis.h
index 08ee0ab..983184b 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.h
+++ b/drivers/scsi/smartpqi/smartpqi_sis.h
@@ -1,6 +1,6 @@
 /*
  *driver for Microsemi PQI-based storage controllers
- *Copyright (c) 2016 Microsemi Corporation
+ *Copyright (c) 2016-2017 Microsemi Corporation
  *Copyright (c) 2016 PMC-Sierra, Inc.
  *
  *This program is free software; you can redistribute it and/or modify



[PATCH 18/37] smartpqi: cleanup messages

2017-04-25 Thread Don Brace
From: Kevin Barnett 

- improve some error messages.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   40 +++--
 drivers/scsi/smartpqi/smartpqi_sis.c  |3 ++
 2 files changed, 20 insertions(+), 23 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 10c232e..3ffca17 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -992,7 +992,10 @@ static int pqi_validate_raid_map(struct pqi_ctrl_info 
*ctrl_info,
return 0;
 
 bad_raid_map:
-   dev_warn(_info->pci_dev->dev, "%s\n", err_msg);
+   dev_warn(_info->pci_dev->dev,
+   "scsi %d:%d:%d:%d %s\n",
+   ctrl_info->scsi_host->host_no,
+   device->bus, device->target, device->lun, err_msg);
 
return -EINVAL;
 }
@@ -1251,7 +1254,7 @@ static void pqi_show_volume_status(struct pqi_ctrl_info 
*ctrl_info,
break;
case CISS_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
status =
-   "Encrypted volume inaccessible - disabled on ctrl";
+   "Volume encrypted but encryption disabled on controller";
break;
case CISS_LV_PENDING_ENCRYPTION:
status = "Volume pending migration to encrypted state";
@@ -2429,7 +2432,7 @@ static inline void pqi_aio_path_disabled(struct 
pqi_io_request *io_request)
device->offload_enabled = false;
 }
 
-static inline void pqi_take_device_offline(struct scsi_device *sdev)
+static inline void pqi_take_device_offline(struct scsi_device *sdev, char 
*path)
 {
struct pqi_ctrl_info *ctrl_info;
struct pqi_scsi_dev *device;
@@ -2439,8 +2442,8 @@ static inline void pqi_take_device_offline(struct 
scsi_device *sdev)
ctrl_info = shost_to_hba(sdev->host);
schedule_delayed_work(_info->rescan_work, 0);
device = sdev->hostdata;
-   dev_err(_info->pci_dev->dev, "offlined scsi %d:%d:%d:%d\n",
-   ctrl_info->scsi_host->host_no, device->bus,
+   dev_err(_info->pci_dev->dev, "offlined %s scsi 
%d:%d:%d:%d\n",
+   path, ctrl_info->scsi_host->host_no, device->bus,
device->target, device->lun);
}
 }
@@ -2487,7 +2490,7 @@ static void pqi_process_raid_io_error(struct 
pqi_io_request *io_request)
sshdr.sense_key == HARDWARE_ERROR &&
sshdr.asc == 0x3e &&
sshdr.ascq == 0x1) {
-   pqi_take_device_offline(scmd->device);
+   pqi_take_device_offline(scmd->device, "RAID");
host_byte = DID_NO_CONNECT;
}
 
@@ -2547,7 +2550,7 @@ static void pqi_process_aio_io_error(struct 
pqi_io_request *io_request)
case PQI_AIO_STATUS_NO_PATH_TO_DEVICE:
case PQI_AIO_STATUS_INVALID_DEVICE:
device_offline = true;
-   pqi_take_device_offline(scmd->device);
+   pqi_take_device_offline(scmd->device, "AIO");
host_byte = DID_NO_CONNECT;
scsi_status = SAM_STAT_CHECK_CONDITION;
break;
@@ -3203,11 +3206,8 @@ static int pqi_alloc_operational_queues(struct 
pqi_ctrl_info *ctrl_info)
alloc_length,
_info->queue_memory_base_dma_handle, GFP_KERNEL);
 
-   if (!ctrl_info->queue_memory_base) {
-   dev_err(_info->pci_dev->dev,
-   "unable to allocate memory for PQI admin queues\n");
+   if (!ctrl_info->queue_memory_base)
return -ENOMEM;
-   }
 
ctrl_info->queue_memory_length = alloc_length;
 
@@ -3576,7 +3576,6 @@ static int pqi_wait_for_completion_io(struct 
pqi_ctrl_info *ctrl_info,
struct completion *wait)
 {
int rc;
-   unsigned int wait_secs = 0;
 
while (1) {
if (wait_for_completion_io_timeout(wait,
@@ -3590,12 +3589,6 @@ static int pqi_wait_for_completion_io(struct 
pqi_ctrl_info *ctrl_info,
rc = -ENXIO;
break;
}
-
-   wait_secs += PQI_WAIT_FOR_COMPLETION_IO_TIMEOUT_SECS;
-
-   dev_err(_info->pci_dev->dev,
-   "waiting %u seconds for completion\n",
-   wait_secs);
}
 
return rc;
@@ -5700,7 +5693,7 @@ static int pqi_process_config_table(struct pqi_ctrl_info 
*ctrl_info)
config_table = kmalloc(table_length, GFP_KERNEL);
if (!config_table) {
dev_err(_info->pci_dev->dev,
-   "unable 

[PATCH 17/37] smartpqi: add new PCI device IDs

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |  134 +++--
 1 file changed, 109 insertions(+), 25 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 6da6db1..10c232e 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -6391,107 +6391,191 @@ static int pqi_resume(struct pci_dev *pci_dev)
 static const struct pci_device_id pqi_pci_id_table[] = {
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+  0x152d, 0x8a22)
+   },
+   {
+   PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+  0x152d, 0x8a23)
+   },
+   {
+   PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+  0x152d, 0x8a24)
+   },
+   {
+   PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+  0x152d, 0x8a36)
+   },
+   {
+   PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
+  0x152d, 0x8a37)
+   },
+   {
+   PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
   PCI_VENDOR_ID_ADAPTEC2, 0x0110)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0600)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0605)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0601)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0800)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0602)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0801)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0603)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0802)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0650)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0803)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0651)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0804)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0652)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0805)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0653)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0806)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0654)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0900)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0655)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0901)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0700)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0902)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_HP, 0x0701)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0903)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_ADAPTEC2, 0x0800)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0904)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_ADAPTEC2, 0x0801)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0905)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_ADAPTEC2, 0x0802)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0906)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_ADAPTEC2, 0x0803)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0907)
},
{
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
-  PCI_VENDOR_ID_ADAPTEC2, 0x0804)
+  PCI_VENDOR_ID_ADAPTEC2, 0x0908)
},
{
 

[PATCH 15/37] smartpqi: correct BMIC identify physical drive

2017-04-25 Thread Don Brace
From: Kevin Barnett 

correct the BMIC Identify Physical Device structure
 - missing 2 fields

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |   20 
 drivers/scsi/smartpqi/smartpqi_init.c |   16 
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 1ac09e7..e74d3ed 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -1126,9 +1126,9 @@ struct bmic_identify_physical_device {
u8  multi_lun_device_lun_count;
u8  minimum_good_fw_revision[8];
u8  unique_inquiry_bytes[20];
-   u8  current_temperature_degreesC;
-   u8  temperature_threshold_degreesC;
-   u8  max_temperature_degreesC;
+   u8  current_temperature_degrees;
+   u8  temperature_threshold_degrees;
+   u8  max_temperature_degrees;
u8  logical_blocks_per_phys_block_exp;
__le16  current_queue_depth_limit;
u8  switch_name[10];
@@ -1141,10 +1141,22 @@ struct bmic_identify_physical_device {
u8  smart_carrier_authentication;
u8  smart_carrier_app_fw_version;
u8  smart_carrier_bootloader_fw_version;
+   u8  sanitize_flags;
+   u8  encryption_key_flags;
u8  encryption_key_name[64];
__le32  misc_drive_flags;
__le16  dek_index;
-   u8  padding[112];
+   __le16  hba_drive_encryption_flags;
+   __le16  max_overwrite_time;
+   __le16  max_block_erase_time;
+   __le16  max_crypto_erase_time;
+   u8  connector_info[5];
+   u8  connector_name[8][8];
+   u8  page_83_identifier[16];
+   u8  maximum_link_rate[256];
+   u8  negotiated_physical_link_rate[256];
+   u8  box_connector_name[8];
+   u8  padding_to_multiple_of_512[9];
 };
 
 #pragma pack()
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 5a1fab1..a32ff85 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -6983,6 +6983,22 @@ static void __attribute__((unused)) 
verify_structures(void)
BUILD_BUG_ON(offsetof(struct bmic_identify_controller,
controller_mode) != 292);
 
+   BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+   phys_bay_in_box) != 115);
+   BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+   device_type) != 120);
+   BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+   redundant_path_present_map) != 1736);
+   BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+   active_path_number) != 1738);
+   BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+   alternate_paths_phys_connector) != 1739);
+   BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+   alternate_paths_phys_box_on_port) != 1755);
+   BUILD_BUG_ON(offsetof(struct bmic_identify_physical_device,
+   current_queue_depth_limit) != 1796);
+   BUILD_BUG_ON(sizeof(struct bmic_identify_physical_device) != 2560);
+
BUILD_BUG_ON(PQI_ADMIN_IQ_NUM_ELEMENTS > 255);
BUILD_BUG_ON(PQI_ADMIN_OQ_NUM_ELEMENTS > 255);
BUILD_BUG_ON(PQI_ADMIN_IQ_ELEMENT_LENGTH %



[PATCH 16/37] smartpqi: minor driver cleanup

2017-04-25 Thread Don Brace
From: Kevin Barnett 

- align with in-house driver

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |2 +-
 drivers/scsi/smartpqi/smartpqi_init.c |   38 -
 2 files changed, 15 insertions(+), 25 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index e74d3ed..7a95868 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -1053,7 +1053,7 @@ enum pqi_ctrl_mode {
 #define BMIC_WRITE_HOST_WELLNESS   0xa5
 #define BMIC_CACHE_FLUSH   0xc2
 
-#define SA_CACHE_FLUSH 0x01
+#define SA_CACHE_FLUSH 0x1
 
 #define MASKED_DEVICE(lunid)   ((lunid)[3] & 0xc0)
 #define CISS_GET_BUS(lunid)((lunid)[7] & 0x3f)
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index a32ff85..6da6db1 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -57,8 +57,6 @@ MODULE_SUPPORTED_DEVICE("Microsemi Smart Family Controllers");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
-#define PQI_ENABLE_MULTI_QUEUE_SUPPORT 0
-
 static char *hpe_branded_controller = "HPE Smart Array Controller";
 static char *microsemi_branded_controller = "Microsemi Smart Family 
Controller";
 
@@ -94,7 +92,7 @@ static unsigned int pqi_supported_event_types[] = {
 
 static int pqi_disable_device_id_wildcards;
 module_param_named(disable_device_id_wildcards,
-   pqi_disable_device_id_wildcards, int, S_IRUGO | S_IWUSR);
+   pqi_disable_device_id_wildcards, int, 0644);
 MODULE_PARM_DESC(disable_device_id_wildcards,
"Disable device ID wildcards.");
 
@@ -383,7 +381,6 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info 
*ctrl_info,
default:
dev_err(_info->pci_dev->dev, "unknown command 0x%c\n",
cmd);
-   WARN_ON(cmd);
break;
}
 
@@ -1133,10 +1130,8 @@ static int pqi_get_device_info(struct pqi_ctrl_info 
*ctrl_info,
scsi_sanitize_inquiry_string([16], 16);
 
device->devtype = buffer[0] & 0x1f;
-   memcpy(device->vendor, [8],
-   sizeof(device->vendor));
-   memcpy(device->model, [16],
-   sizeof(device->model));
+   memcpy(device->vendor, [8], sizeof(device->vendor));
+   memcpy(device->model, [16], sizeof(device->model));
 
if (pqi_is_logical_device(device) && device->devtype == TYPE_DISK) {
pqi_get_raid_level(ctrl_info, device);
@@ -1607,9 +1602,6 @@ static void pqi_update_device_list(struct pqi_ctrl_info 
*ctrl_info,
 */
device->new_device = true;
break;
-   default:
-   WARN_ON(find_result);
-   break;
}
}
 
@@ -1742,7 +1734,7 @@ static inline bool pqi_skip_device(u8 *scsi3addr,
return false;
 }
 
-static inline bool pqi_expose_device(struct pqi_scsi_dev *device)
+static inline bool pqi_ok_to_expose_device(struct pqi_scsi_dev *device)
 {
/* Expose all devices except for physical devices that are masked. */
if (device->is_physical_device && MASKED_DEVICE(device->scsi3addr))
@@ -1883,7 +1875,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info 
*ctrl_info)
 
pqi_assign_bus_target_lun(device);
 
-   device->expose_device = pqi_expose_device(device);
+   device->expose_device = pqi_ok_to_expose_device(device);
 
if (device->is_physical_device) {
device->wwid = phys_lun_ext_entry->wwid;
@@ -2682,7 +2674,6 @@ static unsigned int pqi_process_io_intr(struct 
pqi_ctrl_info *ctrl_info,
dev_err(_info->pci_dev->dev,
"unexpected IU type: 0x%x\n",
response->header.iu_type);
-   WARN_ON(response->header.iu_type);
break;
}
 
@@ -4643,7 +4634,6 @@ static int pqi_raid_submit_scsi_cmd(struct pqi_ctrl_info 
*ctrl_info,
dev_err(_info->pci_dev->dev,
"unknown data direction: %d\n",
scmd->sc_data_direction);
-   WARN_ON(scmd->sc_data_direction);
break;
}
 
@@ -4726,7 +4716,6 @@ static int pqi_aio_submit_io(struct pqi_ctrl_info 
*ctrl_info,
dev_err(_info->pci_dev->dev,
"unknown data direction: %d\n",
scmd->sc_data_direction);
-   WARN_ON(scmd->sc_data_direction);
break;
}
 
@@ -5486,8 +5475,8 @@ static ssize_t 

[PATCH 14/37] smartpqi: eliminate redundant error messages

2017-04-25 Thread Don Brace
From: Kevin Barnett 

eliminate redundant error message during initialization
if the controller has crashed.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |5 +
 drivers/scsi/smartpqi/smartpqi_sis.c  |5 -
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 0755af2..5a1fab1 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -5797,11 +5797,8 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
 * commands.
 */
rc = sis_wait_for_ctrl_ready(ctrl_info);
-   if (rc) {
-   dev_err(_info->pci_dev->dev,
-   "error initializing SIS interface\n");
+   if (rc)
return rc;
-   }
 
/*
 * Get the controller properties.  This allows us to determine
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c 
b/drivers/scsi/smartpqi/smartpqi_sis.c
index 6ca05a6..7a8c0a6 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.c
+++ b/drivers/scsi/smartpqi/smartpqi_sis.c
@@ -102,8 +102,11 @@ static int sis_wait_for_ctrl_ready_with_timeout(struct 
pqi_ctrl_info *ctrl_info,
if (status & SIS_CTRL_KERNEL_UP)
break;
}
-   if (time_after(jiffies, timeout))
+   if (time_after(jiffies, timeout)) {
+   dev_err(_info->pci_dev->dev,
+   "controller not ready\n");
return -ETIMEDOUT;
+   }
msleep(SIS_CTRL_READY_POLL_INTERVAL_MSECS);
}
 



[PATCH 13/37] smartpqi: make pdev pointer names consistent

2017-04-25 Thread Don Brace
From: Kevin Barnett 

make all variable names for pointers to struct pci_dev consistent
throughout the driver.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   41 +
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 523b730..0755af2 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -3095,17 +3095,17 @@ static int pqi_request_irqs(struct pqi_ctrl_info 
*ctrl_info)
 {
int i;
int rc;
-   struct pci_dev *pdev = ctrl_info->pci_dev;
+   struct pci_dev *pci_dev = ctrl_info->pci_dev;
 
-   ctrl_info->event_irq = pci_irq_vector(pdev, 0);
+   ctrl_info->event_irq = pci_irq_vector(pci_dev, 0);
 
for (i = 0; i < ctrl_info->num_msix_vectors_enabled; i++) {
-   rc = request_irq(pci_irq_vector(pdev, i), pqi_irq_handler, 0,
+   rc = request_irq(pci_irq_vector(pci_dev, i), pqi_irq_handler, 0,
DRIVER_NAME_SHORT, _info->queue_groups[i]);
if (rc) {
-   dev_err(>dev,
+   dev_err(_dev->dev,
"irq %u init failed with error %d\n",
-   pci_irq_vector(pdev, i), rc);
+   pci_irq_vector(pci_dev, i), rc);
return rc;
}
ctrl_info->num_msix_vectors_initialized++;
@@ -6230,7 +6230,7 @@ static void pqi_remove_ctrl(struct pqi_ctrl_info 
*ctrl_info)
pqi_free_ctrl_resources(ctrl_info);
 }
 
-static void pqi_print_ctrl_info(struct pci_dev *pdev,
+static void pqi_print_ctrl_info(struct pci_dev *pci_dev,
const struct pci_device_id *id)
 {
char *ctrl_description;
@@ -6249,41 +6249,42 @@ static void pqi_print_ctrl_info(struct pci_dev *pdev,
}
}
 
-   dev_info(>dev, "%s found\n", ctrl_description);
+   dev_info(_dev->dev, "%s found\n", ctrl_description);
 }
 
-static int pqi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int pqi_pci_probe(struct pci_dev *pci_dev,
+   const struct pci_device_id *id)
 {
int rc;
int node;
struct pqi_ctrl_info *ctrl_info;
 
-   pqi_print_ctrl_info(pdev, id);
+   pqi_print_ctrl_info(pci_dev, id);
 
if (pqi_disable_device_id_wildcards &&
id->subvendor == PCI_ANY_ID &&
id->subdevice == PCI_ANY_ID) {
-   dev_warn(>dev,
+   dev_warn(_dev->dev,
"controller not probed because device ID wildcards are 
disabled\n");
return -ENODEV;
}
 
if (id->subvendor == PCI_ANY_ID || id->subdevice == PCI_ANY_ID)
-   dev_warn(>dev,
+   dev_warn(_dev->dev,
"controller device ID matched using wildcards\n");
 
-   node = dev_to_node(>dev);
+   node = dev_to_node(_dev->dev);
if (node == NUMA_NO_NODE)
-   set_dev_node(>dev, 0);
+   set_dev_node(_dev->dev, 0);
 
ctrl_info = pqi_alloc_ctrl_info(node);
if (!ctrl_info) {
-   dev_err(>dev,
+   dev_err(_dev->dev,
"failed to allocate controller info block\n");
return -ENOMEM;
}
 
-   ctrl_info->pci_dev = pdev;
+   ctrl_info->pci_dev = pci_dev;
 
rc = pqi_pci_init(ctrl_info);
if (rc)
@@ -6301,23 +6302,23 @@ static int pqi_pci_probe(struct pci_dev *pdev, const 
struct pci_device_id *id)
return rc;
 }
 
-static void pqi_pci_remove(struct pci_dev *pdev)
+static void pqi_pci_remove(struct pci_dev *pci_dev)
 {
struct pqi_ctrl_info *ctrl_info;
 
-   ctrl_info = pci_get_drvdata(pdev);
+   ctrl_info = pci_get_drvdata(pci_dev);
if (!ctrl_info)
return;
 
pqi_remove_ctrl(ctrl_info);
 }
 
-static void pqi_shutdown(struct pci_dev *pdev)
+static void pqi_shutdown(struct pci_dev *pci_dev)
 {
int rc;
struct pqi_ctrl_info *ctrl_info;
 
-   ctrl_info = pci_get_drvdata(pdev);
+   ctrl_info = pci_get_drvdata(pci_dev);
if (!ctrl_info)
goto error;
 
@@ -6330,7 +6331,7 @@ static void pqi_shutdown(struct pci_dev *pdev)
return;
 
 error:
-   dev_warn(>dev,
+   dev_warn(_dev->dev,
"unable to flush controller cache\n");
 }
 



[PATCH 11/37] smartpqi: add pqi_wait_for_completion_io

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Add check for controller lockup during waits for synchronous
controller commands.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   33 -
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 30fc7b1..728db8f 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -3579,6 +3579,37 @@ static void pqi_start_io(struct pqi_ctrl_info *ctrl_info,
spin_unlock_irqrestore(_group->submit_lock[path], flags);
 }
 
+#define PQI_WAIT_FOR_COMPLETION_IO_TIMEOUT_SECS10
+
+static int pqi_wait_for_completion_io(struct pqi_ctrl_info *ctrl_info,
+   struct completion *wait)
+{
+   int rc;
+   unsigned int wait_secs = 0;
+
+   while (1) {
+   if (wait_for_completion_io_timeout(wait,
+   PQI_WAIT_FOR_COMPLETION_IO_TIMEOUT_SECS * HZ)) {
+   rc = 0;
+   break;
+   }
+
+   pqi_check_ctrl_health(ctrl_info);
+   if (pqi_ctrl_offline(ctrl_info)) {
+   rc = -ENXIO;
+   break;
+   }
+
+   wait_secs += PQI_WAIT_FOR_COMPLETION_IO_TIMEOUT_SECS;
+
+   dev_err(_info->pci_dev->dev,
+   "waiting %u seconds for completion\n",
+   wait_secs);
+   }
+
+   return rc;
+}
+
 static void pqi_raid_synchronous_complete(struct pqi_io_request *io_request,
void *context)
 {
@@ -3602,7 +3633,7 @@ static int 
pqi_submit_raid_request_synchronous_with_io_request(
io_request);
 
if (timeout_msecs == NO_TIMEOUT) {
-   wait_for_completion_io();
+   pqi_wait_for_completion_io(ctrl_info, );
} else {
if (!wait_for_completion_io_timeout(,
msecs_to_jiffies(timeout_msecs))) {



[PATCH 12/37] smartpqi: change functions to inline

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 728db8f..523b730 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -432,7 +432,7 @@ static struct pqi_io_request *pqi_alloc_io_request(
return io_request;
 }
 
-static void pqi_free_io_request(struct pqi_io_request *io_request)
+static inline void pqi_free_io_request(struct pqi_io_request *io_request)
 {
atomic_dec(_request->refcount);
 }



[PATCH 07/37] smartpqi: enhance resets

2017-04-25 Thread Don Brace
From: Kevin Barnett 

- Block all I/O targeted at LUN reset device.
- Wait until all I/O targeted at LUN reset device has been
  consumed by the controller.
- Issue LUN reset request.
- Wait until all outstanding I/Os and LUN reset completion
  have been received by the host.
- Return to OS results of LUN reset request.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |   13 +-
 drivers/scsi/smartpqi/smartpqi_init.c |  279 ++---
 2 files changed, 265 insertions(+), 27 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 02b3196..5b0c6fb 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -734,6 +734,8 @@ struct pqi_scsi_dev {
u8  new_device : 1;
u8  keep_device : 1;
u8  volume_offline : 1;
+   boolin_reset;
+   booldevice_offline;
u8  vendor[8];  /* bytes 8-15 of inquiry data */
u8  model[16];  /* bytes 16-31 of inquiry data */
u64 sas_address;
@@ -761,6 +763,8 @@ struct pqi_scsi_dev {
struct list_head new_device_list_entry;
struct list_head add_list_entry;
struct list_head delete_list_entry;
+
+   atomic_t scsi_cmds_outstanding;
 };
 
 /* VPD inquiry pages */
@@ -926,7 +930,9 @@ struct pqi_ctrl_info {
struct Scsi_Host *scsi_host;
 
struct mutexscan_mutex;
-   boolcontroller_online : 1;
+   struct mutexlun_reset_mutex;
+   boolcontroller_online;
+   boolblock_requests;
u8  inbound_spanning_supported : 1;
u8  outbound_spanning_supported : 1;
u8  pqi_mode_enabled : 1;
@@ -953,7 +959,9 @@ struct pqi_ctrl_info {
struct timer_list heartbeat_timer;
 
struct semaphore sync_request_sem;
-   struct semaphore lun_reset_sem;
+   atomic_tnum_busy_threads;
+   atomic_tnum_blocked_threads;
+   wait_queue_head_t block_requests_wait;
 };
 
 enum pqi_ctrl_mode {
@@ -1092,6 +1100,7 @@ int pqi_add_sas_device(struct pqi_sas_node *pqi_sas_node,
 void pqi_remove_sas_device(struct pqi_scsi_dev *device);
 struct pqi_scsi_dev *pqi_find_device_by_sas_rphy(
struct pqi_ctrl_info *ctrl_info, struct sas_rphy *rphy);
+void pqi_prep_for_scsi_done(struct scsi_cmnd *scmd);
 
 extern struct sas_function_template pqi_sas_transport_functions;
 
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 174867d..96bf318 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -126,6 +126,7 @@ static char *pqi_raid_level_to_string(u8 raid_level)
 
 static inline void pqi_scsi_done(struct scsi_cmnd *scmd)
 {
+   pqi_prep_for_scsi_done(scmd);
scmd->scsi_done(scmd);
 }
 
@@ -175,7 +176,85 @@ static inline void pqi_save_ctrl_mode(struct pqi_ctrl_info 
*ctrl_info,
sis_write_driver_scratch(ctrl_info, mode);
 }
 
-#define PQI_RESCAN_WORK_INTERVAL   (10 * HZ)
+#define PQI_RESCAN_WORK_INTERVAL   (10 * HZ)
+static inline void pqi_ctrl_block_requests(struct pqi_ctrl_info *ctrl_info)
+{
+   ctrl_info->block_requests = true;
+   scsi_block_requests(ctrl_info->scsi_host);
+}
+
+static inline void pqi_ctrl_unblock_requests(struct pqi_ctrl_info *ctrl_info)
+{
+   ctrl_info->block_requests = false;
+   wake_up_all(_info->block_requests_wait);
+   scsi_unblock_requests(ctrl_info->scsi_host);
+}
+
+static inline bool pqi_ctrl_blocked(struct pqi_ctrl_info *ctrl_info)
+{
+   return ctrl_info->block_requests;
+}
+
+static unsigned long pqi_wait_if_ctrl_blocked(struct pqi_ctrl_info *ctrl_info,
+   unsigned long timeout_msecs)
+{
+   unsigned long remaining_msecs;
+
+   if (!pqi_ctrl_blocked(ctrl_info))
+   return timeout_msecs;
+
+   atomic_inc(_info->num_blocked_threads);
+
+   if (timeout_msecs == NO_TIMEOUT) {
+   wait_event(ctrl_info->block_requests_wait,
+   !pqi_ctrl_blocked(ctrl_info));
+   remaining_msecs = timeout_msecs;
+   } else {
+   unsigned long remaining_jiffies;
+
+   remaining_jiffies =
+   wait_event_timeout(ctrl_info->block_requests_wait,
+   !pqi_ctrl_blocked(ctrl_info),
+   msecs_to_jiffies(timeout_msecs));
+   remaining_msecs = jiffies_to_msecs(remaining_jiffies);
+   }
+
+   atomic_dec(_info->num_blocked_threads);
+
+   return remaining_msecs;
+}
+
+static inline void pqi_ctrl_busy(struct pqi_ctrl_info *ctrl_info)
+{
+   atomic_inc(_info->num_busy_threads);
+}
+
+static inline void 

[PATCH 08/37] smartpqi: add suspend and resume support

2017-04-25 Thread Don Brace
From: Kevin Barnett 

add support for ACPI S3 (suspend) and S4 (hibernate) system power states.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |   12 +
 drivers/scsi/smartpqi/smartpqi_init.c |  424 +++--
 drivers/scsi/smartpqi/smartpqi_sis.c  |   75 ++
 drivers/scsi/smartpqi/smartpqi_sis.h  |3 
 4 files changed, 485 insertions(+), 29 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 5b0c6fb..06e2b71 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -61,7 +61,7 @@ struct pqi_device_registers {
 /*
  * controller registers
  *
- * These are defined by the PMC implementation.
+ * These are defined by the Microsemi implementation.
  *
  * Some registers (those named sis_*) are only used when in
  * legacy SIS mode before we transition the controller into
@@ -102,6 +102,12 @@ enum pqi_io_path {
AIO_PATH = 1
 };
 
+enum pqi_irq_mode {
+   IRQ_MODE_NONE,
+   IRQ_MODE_INTX,
+   IRQ_MODE_MSIX
+};
+
 struct pqi_sg_descriptor {
__le64  address;
__le32  length;
@@ -908,7 +914,7 @@ struct pqi_ctrl_info {
dma_addr_t  error_buffer_dma_handle;
size_t  sg_chain_buffer_length;
unsigned intnum_queue_groups;
-   unsigned intnum_active_queue_groups;
+   u16 max_hw_queue_index;
u16 num_elements_per_iq;
u16 num_elements_per_oq;
u16 max_inbound_iu_length_per_firmware;
@@ -923,6 +929,7 @@ struct pqi_ctrl_info {
struct pqi_admin_queues admin_queues;
struct pqi_queue_group queue_groups[PQI_MAX_QUEUE_GROUPS];
struct pqi_event_queue event_queue;
+   enum pqi_irq_mode irq_mode;
int max_msix_vectors;
int num_msix_vectors_enabled;
int num_msix_vectors_initialized;
@@ -937,6 +944,7 @@ struct pqi_ctrl_info {
u8  outbound_spanning_supported : 1;
u8  pqi_mode_enabled : 1;
u8  heartbeat_timer_started : 1;
+   u8  update_time_worker_scheduled : 1;
 
struct list_head scsi_device_list;
spinlock_t  scsi_device_list_lock;
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 96bf318..ca9d010 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -262,6 +262,11 @@ static inline void pqi_schedule_rescan_worker(struct 
pqi_ctrl_info *ctrl_info)
PQI_RESCAN_WORK_INTERVAL);
 }
 
+static inline void pqi_cancel_rescan_worker(struct pqi_ctrl_info *ctrl_info)
+{
+   cancel_delayed_work_sync(_info->rescan_work);
+}
+
 static int pqi_map_single(struct pci_dev *pci_dev,
struct pqi_sg_descriptor *sg_descriptor, void *buffer,
size_t buffer_length, int data_direction)
@@ -588,7 +593,7 @@ static int pqi_write_driver_version_to_host_wellness(
buffer->driver_version_tag[1] = 'V';
put_unaligned_le16(sizeof(buffer->driver_version),
>driver_version_length);
-   strncpy(buffer->driver_version, DRIVER_VERSION,
+   strncpy(buffer->driver_version, "Linux " DRIVER_VERSION,
sizeof(buffer->driver_version) - 1);
buffer->driver_version[sizeof(buffer->driver_version) - 1] = '\0';
buffer->end_tag[0] = 'Z';
@@ -686,7 +691,21 @@ static void pqi_update_time_worker(struct work_struct 
*work)
 static inline void pqi_schedule_update_time_worker(
struct pqi_ctrl_info *ctrl_info)
 {
+   if (ctrl_info->update_time_worker_scheduled)
+   return;
+
schedule_delayed_work(_info->update_time_work, 0);
+   ctrl_info->update_time_worker_scheduled = true;
+}
+
+static inline void pqi_cancel_update_time_worker(
+   struct pqi_ctrl_info *ctrl_info)
+{
+   if (!ctrl_info->update_time_worker_scheduled)
+   return;
+
+   cancel_delayed_work_sync(_info->update_time_work);
+   ctrl_info->update_time_worker_scheduled = false;
 }
 
 static int pqi_report_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd,
@@ -1967,6 +1986,18 @@ static int pqi_scan_finished(struct Scsi_Host *shost,
return !mutex_is_locked(_info->scan_mutex);
 }
 
+static void pqi_wait_until_scan_finished(struct pqi_ctrl_info *ctrl_info)
+{
+   mutex_lock(_info->scan_mutex);
+   mutex_unlock(_info->scan_mutex);
+}
+
+static void pqi_wait_until_lun_reset_finished(struct pqi_ctrl_info *ctrl_info)
+{
+   mutex_lock(_info->lun_reset_mutex);
+   mutex_unlock(_info->lun_reset_mutex);
+}
+
 static inline void pqi_set_encryption_info(
struct pqi_encryption_info *encryption_info, struct raid_map *raid_map,
u64 

[PATCH 09/37] smartpqi: add heartbeat check

2017-04-25 Thread Don Brace
From: Kevin Barnett 

check for controller lockups

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |   60 ++--
 drivers/scsi/smartpqi/smartpqi_init.c |  126 ++---
 drivers/scsi/smartpqi/smartpqi_sis.c  |4 +
 3 files changed, 143 insertions(+), 47 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 06e2b71..1ac09e7 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -490,7 +490,6 @@ struct pqi_raid_error_info {
 #define PQI_EVENT_TYPE_LOGICAL_DEVICE  0x5
 #define PQI_EVENT_TYPE_AIO_STATE_CHANGE0xfd
 #define PQI_EVENT_TYPE_AIO_CONFIG_CHANGE   0xfe
-#define PQI_EVENT_TYPE_HEARTBEAT   0xff
 
 #pragma pack()
 
@@ -635,6 +634,58 @@ struct pqi_encryption_info {
u32 encrypt_tweak_upper;
 };
 
+#pragma pack(1)
+
+#define PQI_CONFIG_TABLE_SIGNATURE "CFGTABLE"
+#define PQI_CONFIG_TABLE_MAX_LENGTH((u16)~0)
+
+/* configuration table section IDs */
+#define PQI_CONFIG_TABLE_SECTION_GENERAL_INFO  0
+#define PQI_CONFIG_TABLE_SECTION_FIRMWARE_FEATURES 1
+#define PQI_CONFIG_TABLE_SECTION_FIRMWARE_ERRATA   2
+#define PQI_CONFIG_TABLE_SECTION_DEBUG 3
+#define PQI_CONFIG_TABLE_SECTION_HEARTBEAT 4
+
+struct pqi_config_table {
+   u8  signature[8];   /* "CFGTABLE" */
+   __le32  first_section_offset;   /* offset in bytes from the base */
+   /* address of this table to the */
+   /* first section */
+};
+
+struct pqi_config_table_section_header {
+   __le16  section_id; /* as defined by the */
+   /* PQI_CONFIG_TABLE_SECTION_* */
+   /* manifest constants above */
+   __le16  next_section_offset;/* offset in bytes from base */
+   /* address of the table of the */
+   /* next section or 0 if last entry */
+};
+
+struct pqi_config_table_general_info {
+   struct pqi_config_table_section_header header;
+   __le32  section_length; /* size of this section in bytes */
+   /* including the section header */
+   __le32  max_outstanding_requests;   /* max. outstanding */
+   /* commands supported by */
+   /* the controller */
+   __le32  max_sg_size;/* max. transfer size of a single */
+   /* command */
+   __le32  max_sg_per_request; /* max. number of scatter-gather */
+   /* entries supported in a single */
+   /* command */
+};
+
+struct pqi_config_table_debug {
+   struct pqi_config_table_section_header header;
+   __le32  scratchpad;
+};
+
+struct pqi_config_table_heartbeat {
+   struct pqi_config_table_section_header header;
+   __le32  heartbeat_counter;
+};
+
 #define PQI_MAX_OUTSTANDING_REQUESTS   ((u32)~0)
 #define PQI_MAX_TRANSFER_SIZE  (4 * 1024U * 1024U)
 
@@ -645,8 +696,6 @@ struct pqi_encryption_info {
 #define PQI_HBA_BUS2
 #define PQI_MAX_BUSPQI_HBA_BUS
 
-#pragma pack(1)
-
 struct report_lun_header {
__be32  list_length;
u8  extended_response;
@@ -870,7 +919,6 @@ struct pqi_io_request {
struct list_head request_list_entry;
 };
 
-#define PQI_EVENT_HEARTBEAT0
 #define PQI_NUM_SUPPORTED_EVENTS   6
 
 struct pqi_event {
@@ -943,7 +991,6 @@ struct pqi_ctrl_info {
u8  inbound_spanning_supported : 1;
u8  outbound_spanning_supported : 1;
u8  pqi_mode_enabled : 1;
-   u8  heartbeat_timer_started : 1;
u8  update_time_worker_scheduled : 1;
 
struct list_head scsi_device_list;
@@ -963,7 +1010,8 @@ struct pqi_ctrl_info {
 
atomic_tnum_interrupts;
int previous_num_interrupts;
-   unsigned intnum_heartbeats_requested;
+   u32 previous_heartbeat_count;
+   __le32 __iomem  *heartbeat_counter;
struct timer_list heartbeat_timer;
 
struct semaphore sync_request_sem;
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index ca9d010..eda5a1a 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -267,6 +267,14 @@ static inline void pqi_cancel_rescan_worker(struct 
pqi_ctrl_info *ctrl_info)

[PATCH 10/37] smartpqi: correct bdma hw bug

2017-04-25 Thread Don Brace
From: Kevin Barnett 

add workaround for BDMA hardware bug that can cause
hw to read up to 12 SGL elements (192 bytes) beyond the
last element in the list. This fix avoids IOMMU violations

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index eda5a1a..30fc7b1 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -48,6 +48,8 @@
 #define DRIVER_NAME"Microsemi PQI Driver (v" DRIVER_VERSION ")"
 #define DRIVER_NAME_SHORT  "smartpqi"
 
+#define PQI_EXTRA_SGL_MEMORY   (12 * sizeof(struct pqi_sg_descriptor))
+
 MODULE_AUTHOR("Microsemi");
 MODULE_DESCRIPTION("Driver for Microsemi Smart Family Controller version "
DRIVER_VERSION);
@@ -3203,6 +3205,8 @@ static int pqi_alloc_operational_queues(struct 
pqi_ctrl_info *ctrl_info)
alloc_length = (size_t)aligned_pointer +
PQI_QUEUE_ELEMENT_ARRAY_ALIGNMENT;
 
+   alloc_length += PQI_EXTRA_SGL_MEMORY;
+
ctrl_info->queue_memory_base =
dma_zalloc_coherent(_info->pci_dev->dev,
alloc_length,
@@ -4320,7 +4324,8 @@ static void pqi_calculate_io_resources(struct 
pqi_ctrl_info *ctrl_info)
max_transfer_size = (max_sg_entries - 1) * PAGE_SIZE;
 
ctrl_info->sg_chain_buffer_length =
-   max_sg_entries * sizeof(struct pqi_sg_descriptor);
+   (max_sg_entries * sizeof(struct pqi_sg_descriptor)) +
+   PQI_EXTRA_SGL_MEMORY;
ctrl_info->sg_tablesize = max_sg_entries;
ctrl_info->max_sectors = max_transfer_size / 512;
 }



[PATCH 06/37] smartpqi: add supporting events

2017-04-25 Thread Don Brace
From: Kevin Barnett 

Only register for controller events that driver supports
cleanup event handling.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |   11 +--
 drivers/scsi/smartpqi/smartpqi_init.c |  110 ++---
 2 files changed, 61 insertions(+), 60 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 62045c1..02b3196 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -860,15 +860,8 @@ struct pqi_io_request {
struct list_head request_list_entry;
 };
 
-/* for indexing into the pending_events[] field of struct pqi_ctrl_info */
 #define PQI_EVENT_HEARTBEAT0
-#define PQI_EVENT_HOTPLUG  1
-#define PQI_EVENT_HARDWARE 2
-#define PQI_EVENT_PHYSICAL_DEVICE  3
-#define PQI_EVENT_LOGICAL_DEVICE   4
-#define PQI_EVENT_AIO_STATE_CHANGE 5
-#define PQI_EVENT_AIO_CONFIG_CHANGE6
-#define PQI_NUM_SUPPORTED_EVENTS   7
+#define PQI_NUM_SUPPORTED_EVENTS   6
 
 struct pqi_event {
boolpending;
@@ -951,7 +944,7 @@ struct pqi_ctrl_info {
struct pqi_io_request *io_request_pool;
u16 next_io_request_slot;
 
-   struct pqi_event pending_events[PQI_NUM_SUPPORTED_EVENTS];
+   struct pqi_event events[PQI_NUM_SUPPORTED_EVENTS];
struct work_struct event_work;
 
atomic_tnum_interrupts;
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index d28e694..174867d 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -81,6 +81,15 @@ static struct scsi_transport_template 
*pqi_sas_transport_template;
 
 static atomic_t pqi_controller_count = ATOMIC_INIT(0);
 
+static unsigned int pqi_supported_event_types[] = {
+   PQI_EVENT_TYPE_HOTPLUG,
+   PQI_EVENT_TYPE_HARDWARE,
+   PQI_EVENT_TYPE_PHYSICAL_DEVICE,
+   PQI_EVENT_TYPE_LOGICAL_DEVICE,
+   PQI_EVENT_TYPE_AIO_STATE_CHANGE,
+   PQI_EVENT_TYPE_AIO_CONFIG_CHANGE,
+};
+
 static int pqi_disable_device_id_wildcards;
 module_param_named(disable_device_id_wildcards,
pqi_disable_device_id_wildcards, int, S_IRUGO | S_IWUSR);
@@ -2665,20 +2674,20 @@ static void pqi_event_worker(struct work_struct *work)
 {
unsigned int i;
struct pqi_ctrl_info *ctrl_info;
-   struct pqi_event *pending_event;
+   struct pqi_event *event;
bool got_non_heartbeat_event = false;
 
ctrl_info = container_of(work, struct pqi_ctrl_info, event_work);
 
-   pending_event = ctrl_info->pending_events;
+   event = ctrl_info->events;
for (i = 0; i < PQI_NUM_SUPPORTED_EVENTS; i++) {
-   if (pending_event->pending) {
-   pending_event->pending = false;
-   pqi_acknowledge_event(ctrl_info, pending_event);
-   if (i != PQI_EVENT_HEARTBEAT)
+   if (event->pending) {
+   event->pending = false;
+   pqi_acknowledge_event(ctrl_info, event);
+   if (i != PQI_EVENT_TYPE_HEARTBEAT)
got_non_heartbeat_event = true;
}
-   pending_event++;
+   event++;
}
 
if (got_non_heartbeat_event)
@@ -2742,7 +2751,7 @@ static void pqi_heartbeat_timer_handler(unsigned long 
data)
pqi_take_ctrl_offline(ctrl_info);
return;
}
-   ctrl_info->pending_events[PQI_EVENT_HEARTBEAT].pending = true;
+   ctrl_info->events[PQI_EVENT_HEARTBEAT].pending = true;
schedule_work(_info->event_work);
} else {
ctrl_info->num_heartbeats_requested = 0;
@@ -2773,38 +2782,20 @@ static inline void pqi_stop_heartbeat_timer(struct 
pqi_ctrl_info *ctrl_info)
del_timer_sync(_info->heartbeat_timer);
 }
 
-static int pqi_event_type_to_event_index(unsigned int event_type)
+static inline int pqi_event_type_to_event_index(unsigned int event_type)
 {
int index;
 
-   switch (event_type) {
-   case PQI_EVENT_TYPE_HEARTBEAT:
-   index = PQI_EVENT_HEARTBEAT;
-   break;
-   case PQI_EVENT_TYPE_HOTPLUG:
-   index = PQI_EVENT_HOTPLUG;
-   break;
-   case PQI_EVENT_TYPE_HARDWARE:
-   index = PQI_EVENT_HARDWARE;
-   break;
-   case PQI_EVENT_TYPE_PHYSICAL_DEVICE:
-   index = PQI_EVENT_PHYSICAL_DEVICE;
-   break;
-   case PQI_EVENT_TYPE_LOGICAL_DEVICE:
-   index = PQI_EVENT_LOGICAL_DEVICE;
-   break;
-   case PQI_EVENT_TYPE_AIO_STATE_CHANGE:
-   index = 

[PATCH 05/37] smartpqi: ensure controller is in SIS mode at init

2017-04-25 Thread Don Brace
From: Kevin Barnett 

put in SIS mode during initialization.
support kexec/kdump

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |2 +
 drivers/scsi/smartpqi/smartpqi_init.c |   60 +++--
 drivers/scsi/smartpqi/smartpqi_sis.c  |   15 
 drivers/scsi/smartpqi/smartpqi_sis.h  |1 +
 4 files changed, 51 insertions(+), 27 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index 73754ca..62045c1 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -964,7 +964,7 @@ struct pqi_ctrl_info {
 };
 
 enum pqi_ctrl_mode {
-   UNKNOWN,
+   SIS_MODE = 0,
PQI_MODE
 };
 
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 8a9b48a..d28e694 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -5245,38 +5245,50 @@ static int pqi_get_ctrl_firmware_version(struct 
pqi_ctrl_info *ctrl_info)
return rc;
 }
 
-static int pqi_kdump_init(struct pqi_ctrl_info *ctrl_info)
+/* Switches the controller from PQI mode back into SIS mode. */
+
+static int pqi_revert_to_sis_mode(struct pqi_ctrl_info *ctrl_info)
+{
+   int rc;
+
+   sis_disable_msix(ctrl_info);
+   rc = pqi_reset(ctrl_info);
+   if (rc)
+   return rc;
+   sis_reenable_sis_mode(ctrl_info);
+   pqi_save_ctrl_mode(ctrl_info, SIS_MODE);
+
+   return 0;
+}
+
+/*
+ * If the controller isn't already in SIS mode, this function forces it into
+ * SIS mode.
+ */
+
+static int pqi_force_sis_mode(struct pqi_ctrl_info *ctrl_info)
 {
if (!sis_is_firmware_running(ctrl_info))
return -ENXIO;
 
-   if (pqi_get_ctrl_mode(ctrl_info) == PQI_MODE) {
-   sis_disable_msix(ctrl_info);
-   if (pqi_reset(ctrl_info) == 0)
-   sis_reenable_sis_mode(ctrl_info);
+   if (pqi_get_ctrl_mode(ctrl_info) == SIS_MODE)
+   return 0;
+
+   if (sis_is_kernel_up(ctrl_info)) {
+   pqi_save_ctrl_mode(ctrl_info, SIS_MODE);
+   return 0;
}
 
-   return 0;
+   return pqi_revert_to_sis_mode(ctrl_info);
 }
 
 static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
 {
int rc;
 
-   if (reset_devices) {
-   rc = pqi_kdump_init(ctrl_info);
-   if (rc)
-   return rc;
-   }
-
-   /*
-* When the controller comes out of reset, it is always running
-* in legacy SIS mode.  This is so that it can be compatible
-* with legacy drivers shipped with OSes.  So we have to talk
-* to it using SIS commands at first.  Once we are satisified
-* that the controller supports PQI, we transition it into PQI
-* mode.
-*/
+   rc = pqi_force_sis_mode(ctrl_info);
+   if (rc)
+   return rc;
 
/*
 * Wait until the controller is ready to start accepting SIS
@@ -5594,12 +5606,8 @@ static void pqi_remove_ctrl(struct pqi_ctrl_info 
*ctrl_info)
cancel_delayed_work_sync(_info->update_time_work);
pqi_remove_all_scsi_devices(ctrl_info);
pqi_unregister_scsi(ctrl_info);
-
-   if (ctrl_info->pqi_mode_enabled) {
-   sis_disable_msix(ctrl_info);
-   if (pqi_reset(ctrl_info) == 0)
-   sis_reenable_sis_mode(ctrl_info);
-   }
+   if (ctrl_info->pqi_mode_enabled)
+   pqi_revert_to_sis_mode(ctrl_info);
pqi_free_ctrl_resources(ctrl_info);
 }
 
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c 
b/drivers/scsi/smartpqi/smartpqi_sis.c
index c7d9ea1..af59998 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.c
+++ b/drivers/scsi/smartpqi/smartpqi_sis.c
@@ -127,6 +127,21 @@ bool sis_is_firmware_running(struct pqi_ctrl_info 
*ctrl_info)
return running;
 }
 
+bool sis_is_kernel_up(struct pqi_ctrl_info *ctrl_info)
+{
+   u32 status;
+   bool kernel_up;
+
+   status = readl(_info->registers->sis_firmware_status);
+
+   if (status & SIS_CTRL_KERNEL_UP)
+   kernel_up = true;
+   else
+   kernel_up = false;
+
+   return kernel_up;
+}
+
 /* used for passing command parameters/results when issuing SIS commands */
 struct sis_sync_cmd_params {
u32 mailbox[6]; /* mailboxes 0-5 */
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h 
b/drivers/scsi/smartpqi/smartpqi_sis.h
index 7f7b68c..157768d 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.h
+++ b/drivers/scsi/smartpqi/smartpqi_sis.h
@@ -21,6 +21,7 @@
 
 int sis_wait_for_ctrl_ready(struct pqi_ctrl_info *ctrl_info);
 bool sis_is_firmware_running(struct pqi_ctrl_info *ctrl_info);
+bool sis_is_kernel_up(struct pqi_ctrl_info *ctrl_info);
 int 

[PATCH 04/37] smartpqi: add in controller checkpoint for controller lockups.

2017-04-25 Thread Don Brace
From: Kevin Barnett 

tell smartpqi controller to generate a checkpoint for rare lockup
conditions.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi.h  |2 +-
 drivers/scsi/smartpqi/smartpqi_init.c |1 +
 drivers/scsi/smartpqi/smartpqi_sis.c  |7 +++
 drivers/scsi/smartpqi/smartpqi_sis.h  |1 +
 4 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index b673825..73754ca 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -933,10 +933,10 @@ struct pqi_ctrl_info {
struct Scsi_Host *scsi_host;
 
struct mutexscan_mutex;
+   boolcontroller_online : 1;
u8  inbound_spanning_supported : 1;
u8  outbound_spanning_supported : 1;
u8  pqi_mode_enabled : 1;
-   u8  controller_online : 1;
u8  heartbeat_timer_started : 1;
 
struct list_head scsi_device_list;
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 7a09fdb..8a9b48a 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -2697,6 +2697,7 @@ static void pqi_take_ctrl_offline(struct pqi_ctrl_info 
*ctrl_info)
 
ctrl_info->controller_online = false;
dev_err(_info->pci_dev->dev, "controller offline\n");
+   sis_shutdown_ctrl(ctrl_info);
 
for (i = 0; i < ctrl_info->num_queue_groups; i++) {
queue_group = _info->queue_groups[i];
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.c 
b/drivers/scsi/smartpqi/smartpqi_sis.c
index 71408f9..c7d9ea1 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.c
+++ b/drivers/scsi/smartpqi/smartpqi_sis.c
@@ -34,6 +34,7 @@
 #define SIS_REENABLE_SIS_MODE  0x1
 #define SIS_ENABLE_MSIX0x40
 #define SIS_SOFT_RESET 0x100
+#define SIS_TRIGGER_SHUTDOWN   0x80
 #define SIS_CMD_READY  0x200
 #define SIS_CMD_COMPLETE   0x1000
 #define SIS_CLEAR_CTRL_TO_HOST_DOORBELL0x1000
@@ -342,6 +343,12 @@ void sis_soft_reset(struct pqi_ctrl_info *ctrl_info)
_info->registers->sis_host_to_ctrl_doorbell);
 }
 
+void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info)
+{
+   writel(SIS_TRIGGER_SHUTDOWN,
+   _info->registers->sis_host_to_ctrl_doorbell);
+}
+
 #define SIS_MODE_READY_TIMEOUT_SECS30
 
 int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info)
diff --git a/drivers/scsi/smartpqi/smartpqi_sis.h 
b/drivers/scsi/smartpqi/smartpqi_sis.h
index bd6e7b0..7f7b68c 100644
--- a/drivers/scsi/smartpqi/smartpqi_sis.h
+++ b/drivers/scsi/smartpqi/smartpqi_sis.h
@@ -27,6 +27,7 @@ int sis_init_base_struct_addr(struct pqi_ctrl_info 
*ctrl_info);
 void sis_enable_msix(struct pqi_ctrl_info *ctrl_info);
 void sis_disable_msix(struct pqi_ctrl_info *ctrl_info);
 void sis_soft_reset(struct pqi_ctrl_info *ctrl_info);
+void sis_shutdown_ctrl(struct pqi_ctrl_info *ctrl_info);
 int sis_reenable_sis_mode(struct pqi_ctrl_info *ctrl_info);
 void sis_write_driver_scratch(struct pqi_ctrl_info *ctrl_info, u32 value);
 u32 sis_read_driver_scratch(struct pqi_ctrl_info *ctrl_info);



[PATCH 03/37] smartpqi: set pci completion timeout

2017-04-25 Thread Don Brace
From: Kevin Barnett 

add support for setting PCIe completion timeout.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   18 ++
 1 file changed, 18 insertions(+)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 39695a4..7a09fdb 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -5437,6 +5437,13 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info)
return 0;
 }
 
+static inline int pqi_set_pcie_completion_timeout(struct pci_dev *pci_dev,
+   u16 timeout)
+{
+   return pcie_capability_clear_and_set_word(pci_dev, PCI_EXP_DEVCTL2,
+   PCI_EXP_DEVCTL2_COMP_TIMEOUT, timeout);
+}
+
 static int pqi_pci_init(struct pqi_ctrl_info *ctrl_info)
 {
int rc;
@@ -5480,6 +5487,17 @@ static int pqi_pci_init(struct pqi_ctrl_info *ctrl_info)
ctrl_info->registers = ctrl_info->iomem_base;
ctrl_info->pqi_registers = _info->registers->pqi_registers;
 
+#define PCI_EXP_COMP_TIMEOUT_65_TO_210_MS  0x6
+
+   /* Increase the PCIe completion timeout. */
+   rc = pqi_set_pcie_completion_timeout(ctrl_info->pci_dev,
+   PCI_EXP_COMP_TIMEOUT_65_TO_210_MS);
+   if (rc) {
+   dev_err(_info->pci_dev->dev,
+   "failed to set PCIe completion timeout\n");
+   goto release_regions;
+   }
+
/* Enable bus mastering. */
pci_set_master(ctrl_info->pci_dev);
 



[PATCH 01/37] smartpqi: correct remove scsi devices

2017-04-25 Thread Don Brace
From: Kevin Barnett 

correct a problem caused by holding a spinlock during device deletion.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   20 +---
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index 657ad15..dd00c69 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -1823,19 +1823,25 @@ static void pqi_remove_all_scsi_devices(struct 
pqi_ctrl_info *ctrl_info)
 {
unsigned long flags;
struct pqi_scsi_dev *device;
-   struct pqi_scsi_dev *next;
 
-   spin_lock_irqsave(_info->scsi_device_list_lock, flags);
+   while (1) {
+   spin_lock_irqsave(_info->scsi_device_list_lock, flags);
+
+   device = list_first_entry_or_null(_info->scsi_device_list,
+   struct pqi_scsi_dev, scsi_device_list_entry);
+   if (device)
+   list_del(>scsi_device_list_entry);
+
+   spin_unlock_irqrestore(_info->scsi_device_list_lock,
+   flags);
+
+   if (!device)
+   break;
 
-   list_for_each_entry_safe(device, next, _info->scsi_device_list,
-   scsi_device_list_entry) {
if (device->sdev)
pqi_remove_device(ctrl_info, device);
-   list_del(>scsi_device_list_entry);
pqi_free_device(device);
}
-
-   spin_unlock_irqrestore(_info->scsi_device_list_lock, flags);
 }
 
 static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info)



[PATCH 02/37] smartpqi: cleanup interrupt management

2017-04-25 Thread Don Brace
From: Kevin Barnett 

minor cleanup of interrupt initialization and tear-down.

Reviewed-by: Scott Benesh 
Signed-off-by: Kevin Barnett 
Signed-off-by: Don Brace 
---
 drivers/scsi/smartpqi/smartpqi_init.c |   45 ++---
 1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi_init.c 
b/drivers/scsi/smartpqi/smartpqi_init.c
index dd00c69..39695a4 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -2892,9 +2892,9 @@ static irqreturn_t pqi_irq_handler(int irq, void *data)
 
 static int pqi_request_irqs(struct pqi_ctrl_info *ctrl_info)
 {
-   struct pci_dev *pdev = ctrl_info->pci_dev;
int i;
int rc;
+   struct pci_dev *pdev = ctrl_info->pci_dev;
 
ctrl_info->event_irq = pci_irq_vector(pdev, 0);
 
@@ -2913,23 +2913,44 @@ static int pqi_request_irqs(struct pqi_ctrl_info 
*ctrl_info)
return 0;
 }
 
+static void pqi_free_irqs(struct pqi_ctrl_info *ctrl_info)
+{
+   int i;
+
+   for (i = 0; i < ctrl_info->num_msix_vectors_initialized; i++)
+   free_irq(pci_irq_vector(ctrl_info->pci_dev, i),
+   _info->queue_groups[i]);
+
+   ctrl_info->num_msix_vectors_initialized = 0;
+}
+
 static int pqi_enable_msix_interrupts(struct pqi_ctrl_info *ctrl_info)
 {
-   int ret;
+   int num_vectors_enabled;
 
-   ret = pci_alloc_irq_vectors(ctrl_info->pci_dev,
+   num_vectors_enabled = pci_alloc_irq_vectors(ctrl_info->pci_dev,
PQI_MIN_MSIX_VECTORS, ctrl_info->num_queue_groups,
PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
-   if (ret < 0) {
+   if (num_vectors_enabled < 0) {
dev_err(_info->pci_dev->dev,
-   "MSI-X init failed with error %d\n", ret);
-   return ret;
+   "MSI-X init failed with error %d\n",
+   num_vectors_enabled);
+   return num_vectors_enabled;
}
 
-   ctrl_info->num_msix_vectors_enabled = ret;
+   ctrl_info->num_msix_vectors_enabled = num_vectors_enabled;
+
return 0;
 }
 
+static void pqi_disable_msix_interrupts(struct pqi_ctrl_info *ctrl_info)
+{
+   if (ctrl_info->num_msix_vectors_enabled) {
+   pci_free_irq_vectors(ctrl_info->pci_dev);
+   ctrl_info->num_msix_vectors_enabled = 0;
+   }
+}
+
 static int pqi_alloc_operational_queues(struct pqi_ctrl_info *ctrl_info)
 {
unsigned int i;
@@ -5519,14 +5540,8 @@ static inline void pqi_free_ctrl_info(struct 
pqi_ctrl_info *ctrl_info)
 
 static void pqi_free_interrupts(struct pqi_ctrl_info *ctrl_info)
 {
-   int i;
-
-   for (i = 0; i < ctrl_info->num_msix_vectors_initialized; i++) {
-   free_irq(pci_irq_vector(ctrl_info->pci_dev, i),
-   _info->queue_groups[i]);
-   }
-
-   pci_free_irq_vectors(ctrl_info->pci_dev);
+   pqi_free_irqs(ctrl_info);
+   pqi_disable_msix_interrupts(ctrl_info);
 }
 
 static void pqi_free_ctrl_resources(struct pqi_ctrl_info *ctrl_info)



[PATCH 00/37] smartpqi updates

2017-04-25 Thread Don Brace
These patches are based on Linus's tree

The changes are:

 - correct remove SCSI devices
   - Remove spin-lock
 - cleanup interrupt management
   - minor cleanup to align with in-house driver
 - set PCI completion timeout 
 - add in controller checkpoint for controller lockups.
   - helps debug rare lockup conditions
 - ensure controller is in SIS mode at driver init
   - needed for kdump/kexec
 - add supporting events
   - manage event changes from controller
 - enhance resets
   - wait for all outstanding I/Os to complete
 - add suspend and resume support
   - Support S3/S4 system power states
 - add heartbeat check
   - add check for controller lockups
 - correct bdma hw bug
   - workaround for BDMA hardware bug 
 - add pqi_wait_for_completion_io
   - add check for controller lockup
 - change functions to inline
   - align code with in-house driver
 - make pdev pointer names consistent
   - align code with in-house driver
 - eliminate redundant error messages
 - correct BMIC identify physical drive
 - minor driver cleanup
   - align code with in-house driver
 - add new PCI device IDs
 - cleanup messages
 - update copyright
 - add ptraid support
   - RBOD support
 - change return value for LUN reset operations
 - enhance kdump
 - remove qdepth calculations for logical volumes
 - add lockup action
 - correct AIO error path
   - send commands down RAID path when they fail
 on AIO path
 - update device offline
   - improve off-lined device detection.
 - update rescan worker
 - cleanup controller branding
   - make more generic
 - map more raid errors to SCSI errors
   - map RAID path errors to Linux SCSI errors
 - update timeout on admin commands
 - enhance device add and remove messages
 - make AIO references consistent
 - add raid level show sysfs entry
 - cleanup list initialization
 - add module parameters
   - heat-beat and controller management
 - remove writeq/readq function definitions
   - from Corentin Labbe 
 - bump driver version

---

Corentin Labbe (1):
  smartpqi: remove writeq/readq function definitions

Kevin Barnett (36):
  smartpqi: correct remove scsi devices
  smartpqi: cleanup interrupt management
  smartpqi: set pci completion timeout
  smartpqi: add in controller checkpoint for controller lockups.
  smartpqi: ensure controller is in SIS mode at init
  smartpqi: add supporting events
  smartpqi: enhance resets
  smartpqi: add suspend and resume support
  smartpqi: add heartbeat check
  smartpqi: correct bdma hw bug
  smartpqi: add pqi_wait_for_completion_io
  smartpqi: change functions to inline
  smartpqi: make pdev pointer names consistent
  smartpqi: eliminate redundant error messages
  smartpqi: correct BMIC identify physical drive
  smartpqi: minor driver cleanup
  smartpqi: add new PCI device IDs
  smartpqi: cleanup messages
  smartpqi: update copyright
  smartpqi: add ptraid support
  smartpqi: change return value for LUN reset operations
  smartpqi: enhance kdump
  smartpqi: remove qdepth calculations for logical volumes
  smartpqi: add lockup action
  smartpqi: correct aio error path
  smartpqi: update device offline
  smartpqi: controller offline improvements
  smartpqi: cleanup controller branding
  smartpqi: map more raid errors to SCSI errors
  smartpqi: update timeout on admin commands
  smartpqi: enhance device add and remove messages
  smartpqi: make raid bypass references consistent
  smartpqi: add raid level show
  smartpqi: cleanup list initialization
  smartpqi: add module parameters
  smartpqi: bump driver version


 drivers/scsi/smartpqi/smartpqi.h   |  192 +-
 drivers/scsi/smartpqi/smartpqi_init.c  | 2430 ++--
 drivers/scsi/smartpqi/smartpqi_sas_transport.c |2 
 drivers/scsi/smartpqi/smartpqi_sis.c   |  109 +
 drivers/scsi/smartpqi/smartpqi_sis.h   |7 
 5 files changed, 2051 insertions(+), 689 deletions(-)

--
Signature


[PATCH v2 07/21] crypto: shash, caam: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Very straightforward conversion to the new function in the caam driver
and shash library.

Signed-off-by: Logan Gunthorpe 
Cc: Herbert Xu 
Cc: "David S. Miller" 
---
 crypto/shash.c| 9 ++---
 drivers/crypto/caam/caamalg.c | 8 +++-
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/crypto/shash.c b/crypto/shash.c
index 5e31c8d..5914881 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -283,10 +283,13 @@ int shash_ahash_digest(struct ahash_request *req, struct 
shash_desc *desc)
if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) {
void *data;
 
-   data = kmap_atomic(sg_page(sg));
-   err = crypto_shash_digest(desc, data + offset, nbytes,
+   data = sg_map(sg, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(data))
+   return PTR_ERR(data);
+
+   err = crypto_shash_digest(desc, data, nbytes,
  req->result);
-   kunmap_atomic(data);
+   sg_unmap(sg, data, 0, SG_KMAP_ATOMIC);
crypto_yield(desc->flags);
} else
err = crypto_shash_init(desc) ?:
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 398807d..62d2f5d 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -89,7 +89,6 @@ static void dbg_dump_sg(const char *level, const char 
*prefix_str,
struct scatterlist *sg, size_t tlen, bool ascii)
 {
struct scatterlist *it;
-   void *it_page;
size_t len;
void *buf;
 
@@ -98,19 +97,18 @@ static void dbg_dump_sg(const char *level, const char 
*prefix_str,
 * make sure the scatterlist's page
 * has a valid virtual memory mapping
 */
-   it_page = kmap_atomic(sg_page(it));
-   if (unlikely(!it_page)) {
+   buf = sg_map(it, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(buf)) {
printk(KERN_ERR "dbg_dump_sg: kmap failed\n");
return;
}
 
-   buf = it_page + it->offset;
len = min_t(size_t, tlen, it->length);
print_hex_dump(level, prefix_str, prefix_type, rowsize,
   groupsize, buf, len, ascii);
tlen -= len;
 
-   kunmap_atomic(it_page);
+   sg_unmap(it, buf, 0, SG_KMAP_ATOMIC);
}
 }
 #endif
-- 
2.1.4



[PATCH v2 00/21] Introduce common scatterlist map function

2017-04-25 Thread Logan Gunthorpe
Changes since v1:

* Rebased onto next-20170424
* Removed the _offset version of these functions per Christoph's
  suggestion
* Added an SG_MAP_MUST_NOT_FAIL flag which will BUG_ON in future cases
  that can't gracefully fail. This removes a bunch of the noise added
  in v1 to a couple of the drivers. (Per David Laight's suggestion)
  This flag is only meant for old code
* Split the libiscsi patch into two (per Christoph's suggestion)
  the prep patch (patch 2 in this series) has already been
  sent separately
* Fixed a locking mistake in the target patch (pointed out by a bot)
* Dropped the nvmet patch and handled it with a different patch
  that has been sent separately
* Dropped the chcr patch as they have already removed the code that
  needed to be changed

I'm still hoping to only get Patch 1 in the series merged. (Any
volunteers?) I'm willing to chase down the maintainers for the remaining
patches separately after the first patch is in.

The patchset is based on next-20170424 and can be found in the sg_map_v2
branch from this git tree:

https://github.com/sbates130272/linux-p2pmem.git

--

Hi Everyone,

As part of my effort to enable P2P DMA transactions with PCI cards,
we've identified the need to be able to safely put IO memory into
scatterlists (and eventually other spots). This probably involves a
conversion from struct page to pfn_t but that migration is a ways off
and those decisions are yet to be made.

As an initial step in that direction, I've started cleaning up some of the
scatterlist code by trying to carve out a better defined layer between it
and it's users. The longer term goal would be to remove sg_page or replace
it with something that can potentially fail.

This patchset is the first step in that effort. I've introduced
a common function to map scatterlist memory and converted all the common
kmap(sg_page()) cases. This removes about 66 sg_page calls (of ~331).

Seeing this is a fairly large cleanup set that touches a wide swath of
the kernel I have limited the people I've sent this to. I'd suggest we look
toward merging the first patch and then I can send the individual subsystem
patches on to their respective maintainers and get them merged
independantly. (This is to avoid the conflicts I created with my last
cleanup set... Sorry) Though, I'm certainly open to other suggestions to get
it merged.

Logan Gunthorpe (21):
  scatterlist: Introduce sg_map helper functions
  libiscsi: Add an internal error code
  libiscsi: Make use of new the sg_map helper function
  target: Make use of the new sg_map function at 16 call sites
  drm/i915: Make use of the new sg_map helper function
  crypto: hifn_795x: Make use of the new sg_map helper function
  crypto: shash, caam: Make use of the new sg_map helper function
  dm-crypt: Make use of the new sg_map helper in 4 call sites
  staging: unisys: visorbus: Make use of the new sg_map helper function
  RDS: Make use of the new sg_map helper function
  scsi: ipr, pmcraid, isci: Make use of the new sg_map helper
  scsi: hisi_sas, mvsas, gdth: Make use of the new sg_map helper
function
  scsi: arcmsr, ips, megaraid: Make use of the new sg_map helper
function
  scsi: libfc, csiostor: Change to sg_copy_buffer in two drivers
  xen-blkfront: Make use of the new sg_map helper function
  mmc: sdhci: Make use of the new sg_map helper function
  mmc: spi: Make use of the new sg_map helper function
  mmc: tmio: Make use of the new sg_map helper function
  mmc: sdricoh_cs: Make use of the new sg_map helper function
  mmc: tifm_sd: Make use of the new sg_map helper function
  memstick: Make use of the new sg_map helper function

 crypto/shash.c  |   9 ++-
 drivers/block/xen-blkfront.c|  20 ++---
 drivers/crypto/caam/caamalg.c   |   8 +-
 drivers/crypto/hifn_795x.c  |  32 +---
 drivers/gpu/drm/i915/i915_gem.c |  27 ---
 drivers/md/dm-crypt.c   |  39 ++---
 drivers/memstick/host/jmb38x_ms.c   |  11 +--
 drivers/memstick/host/tifm_ms.c |  11 +--
 drivers/mmc/host/mmc_spi.c  |  26 --
 drivers/mmc/host/sdhci.c|  14 ++--
 drivers/mmc/host/sdricoh_cs.c   |  14 ++--
 drivers/mmc/host/tifm_sd.c  |  50 +++-
 drivers/mmc/host/tmio_mmc.h |   7 +-
 drivers/mmc/host/tmio_mmc_pio.c |  12 +++
 drivers/scsi/arcmsr/arcmsr_hba.c|  16 +++-
 drivers/scsi/csiostor/csio_scsi.c   |  54 +
 drivers/scsi/cxgbi/libcxgbi.c   |   5 ++
 drivers/scsi/gdth.c |   9 ++-
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c  |  14 ++--
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c  |  13 ++-
 drivers/scsi/ipr.c  |  27 ---
 drivers/scsi/ips.c  |   8 +-
 

[PATCH v2 14/21] scsi: libfc, csiostor: Change to sg_copy_buffer in two drivers

2017-04-25 Thread Logan Gunthorpe
These two drivers appear to duplicate the functionality of
sg_copy_buffer. So we clean them up to use the common code.

This helps us remove a couple of instances that would otherwise be
slightly tricky sg_map usages.

Signed-off-by: Logan Gunthorpe 
Cc: Johannes Thumshirn 
---
 drivers/scsi/csiostor/csio_scsi.c | 54 +++
 drivers/scsi/libfc/fc_libfc.c | 49 ---
 2 files changed, 14 insertions(+), 89 deletions(-)

diff --git a/drivers/scsi/csiostor/csio_scsi.c 
b/drivers/scsi/csiostor/csio_scsi.c
index a1ff75f..bd9d062 100644
--- a/drivers/scsi/csiostor/csio_scsi.c
+++ b/drivers/scsi/csiostor/csio_scsi.c
@@ -1489,60 +1489,14 @@ static inline uint32_t
 csio_scsi_copy_to_sgl(struct csio_hw *hw, struct csio_ioreq *req)
 {
struct scsi_cmnd *scmnd  = (struct scsi_cmnd *)csio_scsi_cmnd(req);
-   struct scatterlist *sg;
-   uint32_t bytes_left;
-   uint32_t bytes_copy;
-   uint32_t buf_off = 0;
-   uint32_t start_off = 0;
-   uint32_t sg_off = 0;
-   void *sg_addr;
-   void *buf_addr;
struct csio_dma_buf *dma_buf;
+   size_t copied;
 
-   bytes_left = scsi_bufflen(scmnd);
-   sg = scsi_sglist(scmnd);
dma_buf = (struct csio_dma_buf *)csio_list_next(>gen_list);
+   copied = sg_copy_from_buffer(scsi_sglist(scmnd), scsi_sg_count(scmnd),
+dma_buf->vaddr, scsi_bufflen(scmnd));
 
-   /* Copy data from driver buffer to SGs of SCSI CMD */
-   while (bytes_left > 0 && sg && dma_buf) {
-   if (buf_off >= dma_buf->len) {
-   buf_off = 0;
-   dma_buf = (struct csio_dma_buf *)
-   csio_list_next(dma_buf);
-   continue;
-   }
-
-   if (start_off >= sg->length) {
-   start_off -= sg->length;
-   sg = sg_next(sg);
-   continue;
-   }
-
-   buf_addr = dma_buf->vaddr + buf_off;
-   sg_off = sg->offset + start_off;
-   bytes_copy = min((dma_buf->len - buf_off),
-   sg->length - start_off);
-   bytes_copy = min((uint32_t)(PAGE_SIZE - (sg_off & ~PAGE_MASK)),
-bytes_copy);
-
-   sg_addr = kmap_atomic(sg_page(sg) + (sg_off >> PAGE_SHIFT));
-   if (!sg_addr) {
-   csio_err(hw, "failed to kmap sg:%p of ioreq:%p\n",
-   sg, req);
-   break;
-   }
-
-   csio_dbg(hw, "copy_to_sgl:sg_addr %p sg_off %d buf %p len %d\n",
-   sg_addr, sg_off, buf_addr, bytes_copy);
-   memcpy(sg_addr + (sg_off & ~PAGE_MASK), buf_addr, bytes_copy);
-   kunmap_atomic(sg_addr);
-
-   start_off +=  bytes_copy;
-   buf_off += bytes_copy;
-   bytes_left -= bytes_copy;
-   }
-
-   if (bytes_left > 0)
+   if (copied != scsi_bufflen(scmnd))
return DID_ERROR;
else
return DID_OK;
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c
index d623d08..ce0805a 100644
--- a/drivers/scsi/libfc/fc_libfc.c
+++ b/drivers/scsi/libfc/fc_libfc.c
@@ -113,45 +113,16 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
 u32 *nents, size_t *offset,
 u32 *crc)
 {
-   size_t remaining = len;
-   u32 copy_len = 0;
-
-   while (remaining > 0 && sg) {
-   size_t off, sg_bytes;
-   void *page_addr;
-
-   if (*offset >= sg->length) {
-   /*
-* Check for end and drop resources
-* from the last iteration.
-*/
-   if (!(*nents))
-   break;
-   --(*nents);
-   *offset -= sg->length;
-   sg = sg_next(sg);
-   continue;
-   }
-   sg_bytes = min(remaining, sg->length - *offset);
-
-   /*
-* The scatterlist item may be bigger than PAGE_SIZE,
-* but we are limited to mapping PAGE_SIZE at a time.
-*/
-   off = *offset + sg->offset;
-   sg_bytes = min(sg_bytes,
-  (size_t)(PAGE_SIZE - (off & ~PAGE_MASK)));
-   page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT));
-   if (crc)
-   *crc = crc32(*crc, buf, sg_bytes);
-   memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes);
-   kunmap_atomic(page_addr);
-   buf += sg_bytes;
-   *offset += sg_bytes;
- 

[PATCH v2 16/21] mmc: sdhci: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Straightforward conversion, except due to the lack of an error path we
have to use SG_MAP_MUST_NOT_FAIL which may BUG_ON in certain cases
in the future.

Signed-off-by: Logan Gunthorpe 
Cc: Adrian Hunter 
Cc: Ulf Hansson 
---
 drivers/mmc/host/sdhci.c | 14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ecd0d43..239507f 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -513,15 +513,19 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host,
return sg_count;
 }
 
+/*
+ * Note this function may return PTR_ERR and must be checked.
+ */
 static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
 {
local_irq_save(*flags);
-   return kmap_atomic(sg_page(sg)) + sg->offset;
+   return sg_map(sg, 0, SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL);
 }
 
-static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
+static void sdhci_kunmap_atomic(struct scatterlist *sg, void *buffer,
+   unsigned long *flags)
 {
-   kunmap_atomic(buffer);
+   sg_unmap(sg, buffer, 0, SG_KMAP_ATOMIC);
local_irq_restore(*flags);
 }
 
@@ -585,7 +589,7 @@ static void sdhci_adma_table_pre(struct sdhci_host *host,
if (data->flags & MMC_DATA_WRITE) {
buffer = sdhci_kmap_atomic(sg, );
memcpy(align, buffer, offset);
-   sdhci_kunmap_atomic(buffer, );
+   sdhci_kunmap_atomic(sg, buffer, );
}
 
/* tran, valid */
@@ -663,7 +667,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
 
buffer = sdhci_kmap_atomic(sg, );
memcpy(buffer, align, size);
-   sdhci_kunmap_atomic(buffer, );
+   sdhci_kunmap_atomic(sg, buffer, );
 
align += SDHCI_ADMA2_ALIGN;
}
-- 
2.1.4



[PATCH v2 18/21] mmc: tmio: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Straightforward conversion to sg_map helper. Seeing there is no
cleare error path, SG_MAP_MUST_NOT_FAIL which may BUG_ON in certain
cases in the future.

Signed-off-by: Logan Gunthorpe 
Cc: Wolfram Sang 
Cc: Ulf Hansson 
---
 drivers/mmc/host/tmio_mmc.h |  7 +--
 drivers/mmc/host/tmio_mmc_pio.c | 12 
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index d0edb57..bc43eb0 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -202,17 +202,20 @@ void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, 
u32 i);
 void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
 irqreturn_t tmio_mmc_irq(int irq, void *devid);
 
+/* Note: this function may return PTR_ERR and must be checked! */
 static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
 unsigned long *flags)
 {
+   void *ret;
+
local_irq_save(*flags);
-   return kmap_atomic(sg_page(sg)) + sg->offset;
+   return sg_map(sg, 0, SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL);
 }
 
 static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
  unsigned long *flags, void *virt)
 {
-   kunmap_atomic(virt - sg->offset);
+   sg_unmap(sg, virt, 0, SG_KMAP_ATOMIC);
local_irq_restore(*flags);
 }
 
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index a2d92f1..bbb4f19 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -506,6 +506,18 @@ static void tmio_mmc_check_bounce_buffer(struct 
tmio_mmc_host *host)
if (host->sg_ptr == >bounce_sg) {
unsigned long flags;
void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, );
+   if (IS_ERR(sg_vaddr)) {
+   /*
+* This should really never happen unless
+* the code is changed to use memory that is
+* not mappable in the sg. Seeing there doesn't
+* seem to be any error path out of here,
+* we can only WARN.
+*/
+   WARN(1, "Non-mappable memory used in sg!");
+   return;
+   }
+
memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length);
tmio_mmc_kunmap_atomic(host->sg_orig, , sg_vaddr);
}
-- 
2.1.4



[PATCH v2 03/21] libiscsi: Make use of new the sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Convert the kmap and kmap_atomic uses to the sg_map function. We now
store the flags for the kmap instead of a boolean to indicate
atomicitiy. We use ISCSI_TCP_INTERNAL_ERR error type that was prepared
earlier for this.

Signed-off-by: Logan Gunthorpe 
Cc: Lee Duncan 
Cc: Chris Leech 
---
 drivers/scsi/libiscsi_tcp.c | 32 
 include/scsi/libiscsi_tcp.h |  2 +-
 2 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 63a1d69..a34e25c 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -133,25 +133,23 @@ static void iscsi_tcp_segment_map(struct iscsi_segment 
*segment, int recv)
if (page_count(sg_page(sg)) >= 1 && !recv)
return;
 
-   if (recv) {
-   segment->atomic_mapped = true;
-   segment->sg_mapped = kmap_atomic(sg_page(sg));
-   } else {
-   segment->atomic_mapped = false;
-   /* the xmit path can sleep with the page mapped so use kmap */
-   segment->sg_mapped = kmap(sg_page(sg));
+   /* the xmit path can sleep with the page mapped so don't use atomic */
+   segment->sg_map_flags = recv ? SG_KMAP_ATOMIC : SG_KMAP;
+   segment->sg_mapped = sg_map(sg, 0, segment->sg_map_flags);
+
+   if (IS_ERR(segment->sg_mapped)) {
+   segment->sg_mapped = NULL;
+   return;
}
 
-   segment->data = segment->sg_mapped + sg->offset + segment->sg_offset;
+   segment->data = segment->sg_mapped + segment->sg_offset;
 }
 
 void iscsi_tcp_segment_unmap(struct iscsi_segment *segment)
 {
if (segment->sg_mapped) {
-   if (segment->atomic_mapped)
-   kunmap_atomic(segment->sg_mapped);
-   else
-   kunmap(sg_page(segment->sg));
+   sg_unmap(segment->sg, segment->sg_mapped, 0,
+segment->sg_map_flags);
segment->sg_mapped = NULL;
segment->data = NULL;
}
@@ -304,6 +302,9 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn,
break;
}
 
+   if (segment->data)
+   return -EFAULT;
+
copy = min(len - copied, segment->size - segment->copied);
ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copying %d\n", copy);
memcpy(segment->data + segment->copied, ptr + copied, copy);
@@ -927,6 +928,13 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct 
sk_buff *skb,
  avail);
rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail);
BUG_ON(rc == 0);
+   if (rc < 0) {
+   ISCSI_DBG_TCP(conn, "memory fault. Consumed %d\n",
+ consumed);
+   *status = ISCSI_TCP_INTERNAL_ERR;
+   goto skb_done;
+   }
+
consumed += rc;
 
if (segment->total_copied >= segment->total_size) {
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h
index 90691ad..58c79af 100644
--- a/include/scsi/libiscsi_tcp.h
+++ b/include/scsi/libiscsi_tcp.h
@@ -47,7 +47,7 @@ struct iscsi_segment {
struct scatterlist  *sg;
void*sg_mapped;
unsigned intsg_offset;
-   boolatomic_mapped;
+   int sg_map_flags;
 
iscsi_segment_done_fn_t *done;
 };
-- 
2.1.4



[PATCH v2 09/21] staging: unisys: visorbus: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Straightforward conversion to the new function.

Signed-off-by: Logan Gunthorpe 
Acked-by: David Kershner 
---
 drivers/staging/unisys/visorhba/visorhba_main.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c 
b/drivers/staging/unisys/visorhba/visorhba_main.c
index d372115..c77426c 100644
--- a/drivers/staging/unisys/visorhba/visorhba_main.c
+++ b/drivers/staging/unisys/visorhba/visorhba_main.c
@@ -843,7 +843,6 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct 
scsi_cmnd *scsicmd)
struct scatterlist *sg;
unsigned int i;
char *this_page;
-   char *this_page_orig;
int bufind = 0;
struct visordisk_info *vdisk;
struct visorhba_devdata *devdata;
@@ -870,11 +869,14 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct 
scsi_cmnd *scsicmd)
 
sg = scsi_sglist(scsicmd);
for (i = 0; i < scsi_sg_count(scsicmd); i++) {
-   this_page_orig = kmap_atomic(sg_page(sg + i));
-   this_page = (void *)((unsigned long)this_page_orig |
-sg[i].offset);
+   this_page = sg_map(sg + i, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(this_page)) {
+   scsicmd->result = DID_ERROR << 16;
+   return;
+   }
+
memcpy(this_page, buf + bufind, sg[i].length);
-   kunmap_atomic(this_page_orig);
+   sg_unmap(sg + i, this_page, 0, SG_KMAP_ATOMIC);
}
} else {
devdata = (struct visorhba_devdata *)scsidev->host->hostdata;
-- 
2.1.4



[PATCH v2 21/21] memstick: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Straightforward conversion, but we have to make use of
SG_MAP_MUST_NOT_FAIL which may BUG_ON in certain cases
in the future.

Signed-off-by: Logan Gunthorpe 
Cc: Alex Dubov 
---
 drivers/memstick/host/jmb38x_ms.c | 11 ++-
 drivers/memstick/host/tifm_ms.c   | 11 ++-
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/memstick/host/jmb38x_ms.c 
b/drivers/memstick/host/jmb38x_ms.c
index 48db922..9019e37 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -303,7 +303,6 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host 
*host)
unsigned int off;
unsigned int t_size, p_cnt;
unsigned char *buf;
-   struct page *pg;
unsigned long flags = 0;
 
if (host->req->long_data) {
@@ -318,14 +317,14 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host 
*host)
unsigned int uninitialized_var(p_off);
 
if (host->req->long_data) {
-   pg = nth_page(sg_page(>req->sg),
- off >> PAGE_SHIFT);
p_off = offset_in_page(off);
p_cnt = PAGE_SIZE - p_off;
p_cnt = min(p_cnt, length);
 
local_irq_save(flags);
-   buf = kmap_atomic(pg) + p_off;
+   buf = sg_map(>req->sg,
+off - host->req->sg.offset,
+SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL);
} else {
buf = host->req->data + host->block_pos;
p_cnt = host->req->data_len - host->block_pos;
@@ -341,7 +340,9 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host 
*host)
 : jmb38x_ms_read_reg_data(host, buf, p_cnt);
 
if (host->req->long_data) {
-   kunmap_atomic(buf - p_off);
+   sg_unmap(>req->sg, buf,
+off - host->req->sg.offset,
+SG_KMAP_ATOMIC);
local_irq_restore(flags);
}
 
diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c
index 7bafa72..304985d 100644
--- a/drivers/memstick/host/tifm_ms.c
+++ b/drivers/memstick/host/tifm_ms.c
@@ -186,7 +186,6 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms 
*host)
unsigned int off;
unsigned int t_size, p_cnt;
unsigned char *buf;
-   struct page *pg;
unsigned long flags = 0;
 
if (host->req->long_data) {
@@ -203,14 +202,14 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms 
*host)
unsigned int uninitialized_var(p_off);
 
if (host->req->long_data) {
-   pg = nth_page(sg_page(>req->sg),
- off >> PAGE_SHIFT);
p_off = offset_in_page(off);
p_cnt = PAGE_SIZE - p_off;
p_cnt = min(p_cnt, length);
 
local_irq_save(flags);
-   buf = kmap_atomic(pg) + p_off;
+   buf = sg_map(>req->sg,
+off - host->req->sg.offset,
+SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL);
} else {
buf = host->req->data + host->block_pos;
p_cnt = host->req->data_len - host->block_pos;
@@ -221,7 +220,9 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms 
*host)
 : tifm_ms_read_data(host, buf, p_cnt);
 
if (host->req->long_data) {
-   kunmap_atomic(buf - p_off);
+   sg_unmap(>req->sg, buf,
+off - host->req->sg.offset,
+SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL);
local_irq_restore(flags);
}
 
-- 
2.1.4



[PATCH v2 17/21] mmc: spi: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
We use the sg_map helper but it's slightly more complicated
as we only check for the error when the mapping actually gets used.
Such that if the mapping failed but wasn't needed then no
error occurs.

Signed-off-by: Logan Gunthorpe 
Cc: Ulf Hansson 
---
 drivers/mmc/host/mmc_spi.c | 26 +++---
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 476e53d..d614f36 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -676,9 +676,15 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct 
spi_transfer *t,
struct scratch  *scratch = host->data;
u32 pattern;
 
-   if (host->mmc->use_spi_crc)
+   if (host->mmc->use_spi_crc) {
+   if (IS_ERR(t->tx_buf))
+   return PTR_ERR(t->tx_buf);
+
scratch->crc_val = cpu_to_be16(
crc_itu_t(0, t->tx_buf, t->len));
+   t->tx_buf += t->len;
+   }
+
if (host->dma_dev)
dma_sync_single_for_device(host->dma_dev,
host->data_dma, sizeof(*scratch),
@@ -743,7 +749,6 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct 
spi_transfer *t,
return status;
}
 
-   t->tx_buf += t->len;
if (host->dma_dev)
t->tx_dma += t->len;
 
@@ -809,6 +814,11 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct 
spi_transfer *t,
}
leftover = status << 1;
 
+   if (bitshift || host->mmc->use_spi_crc) {
+   if (IS_ERR(t->rx_buf))
+   return PTR_ERR(t->rx_buf);
+   }
+
if (host->dma_dev) {
dma_sync_single_for_device(host->dma_dev,
host->data_dma, sizeof(*scratch),
@@ -860,9 +870,10 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct 
spi_transfer *t,
scratch->crc_val, crc, t->len);
return -EILSEQ;
}
+
+   t->rx_buf += t->len;
}
 
-   t->rx_buf += t->len;
if (host->dma_dev)
t->rx_dma += t->len;
 
@@ -933,11 +944,11 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct 
mmc_command *cmd,
}
 
/* allow pio too; we don't allow highmem */
-   kmap_addr = kmap(sg_page(sg));
+   kmap_addr = sg_map(sg, 0, SG_KMAP);
if (direction == DMA_TO_DEVICE)
-   t->tx_buf = kmap_addr + sg->offset;
+   t->tx_buf = kmap_addr;
else
-   t->rx_buf = kmap_addr + sg->offset;
+   t->rx_buf = kmap_addr;
 
/* transfer each block, and update request status */
while (length) {
@@ -967,7 +978,8 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct 
mmc_command *cmd,
/* discard mappings */
if (direction == DMA_FROM_DEVICE)
flush_kernel_dcache_page(sg_page(sg));
-   kunmap(sg_page(sg));
+   if (!IS_ERR(kmap_addr))
+   sg_unmap(sg, kmap_addr, 0, SG_KMAP);
if (dma_dev)
dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir);
 
-- 
2.1.4



[PATCH v2 11/21] scsi: ipr, pmcraid, isci: Make use of the new sg_map helper

2017-04-25 Thread Logan Gunthorpe
Very straightforward conversion of three scsi drivers.

Signed-off-by: Logan Gunthorpe 
Cc: Brian King 
Cc: Artur Paszkiewicz 
---
 drivers/scsi/ipr.c  | 27 ++-
 drivers/scsi/isci/request.c | 42 +-
 drivers/scsi/pmcraid.c  | 19 ---
 3 files changed, 51 insertions(+), 37 deletions(-)

diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index b0c68d2..b2324e1 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3895,7 +3895,7 @@ static void ipr_free_ucode_buffer(struct ipr_sglist 
*sglist)
 static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
 u8 *buffer, u32 len)
 {
-   int bsize_elem, i, result = 0;
+   int bsize_elem, i;
struct scatterlist *scatterlist;
void *kaddr;
 
@@ -3905,32 +3905,33 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist 
*sglist,
scatterlist = sglist->scatterlist;
 
for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {
-   struct page *page = sg_page([i]);
+   kaddr = sg_map([i], 0, SG_KMAP);
+   if (IS_ERR(kaddr)) {
+   ipr_trace;
+   return PTR_ERR(kaddr);
+   }
 
-   kaddr = kmap(page);
memcpy(kaddr, buffer, bsize_elem);
-   kunmap(page);
+   sg_unmap([i], kaddr, 0, SG_KMAP);
 
scatterlist[i].length = bsize_elem;
-
-   if (result != 0) {
-   ipr_trace;
-   return result;
-   }
}
 
if (len % bsize_elem) {
-   struct page *page = sg_page([i]);
+   kaddr = sg_map([i], 0, SG_KMAP);
+   if (IS_ERR(kaddr)) {
+   ipr_trace;
+   return PTR_ERR(kaddr);
+   }
 
-   kaddr = kmap(page);
memcpy(kaddr, buffer, len % bsize_elem);
-   kunmap(page);
+   sg_unmap([i], kaddr, 0, SG_KMAP);
 
scatterlist[i].length = len % bsize_elem;
}
 
sglist->buffer_len = len;
-   return result;
+   return 0;
 }
 
 /**
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 47f66e9..6f5521b 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -1424,12 +1424,14 @@ sci_stp_request_pio_data_in_copy_data_buffer(struct 
isci_stp_request *stp_req,
sg = task->scatter;
 
while (total_len > 0) {
-   struct page *page = sg_page(sg);
-
copy_len = min_t(int, total_len, sg_dma_len(sg));
-   kaddr = kmap_atomic(page);
-   memcpy(kaddr + sg->offset, src_addr, copy_len);
-   kunmap_atomic(kaddr);
+   kaddr = sg_map(sg, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(kaddr))
+   return SCI_FAILURE;
+
+   memcpy(kaddr, src_addr, copy_len);
+   sg_unmap(sg, kaddr, 0, SG_KMAP_ATOMIC);
+
total_len -= copy_len;
src_addr += copy_len;
sg = sg_next(sg);
@@ -1771,14 +1773,16 @@ sci_io_request_frame_handler(struct isci_request *ireq,
case SCI_REQ_SMP_WAIT_RESP: {
struct sas_task *task = isci_request_access_task(ireq);
struct scatterlist *sg = >smp_task.smp_resp;
-   void *frame_header, *kaddr;
+   void *frame_header;
u8 *rsp;
 
sci_unsolicited_frame_control_get_header(>uf_control,
 frame_index,
 _header);
-   kaddr = kmap_atomic(sg_page(sg));
-   rsp = kaddr + sg->offset;
+   rsp = sg_map(sg, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(rsp))
+   return SCI_FAILURE;
+
sci_swab32_cpy(rsp, frame_header, 1);
 
if (rsp[0] == SMP_RESPONSE) {
@@ -1814,7 +1818,7 @@ sci_io_request_frame_handler(struct isci_request *ireq,
ireq->sci_status = 
SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
sci_change_state(>sm, SCI_REQ_COMPLETED);
}
-   kunmap_atomic(kaddr);
+   sg_unmap(sg, rsp, 0, SG_KMAP_ATOMIC);
 
sci_controller_release_frame(ihost, frame_index);
 
@@ -2919,15 +2923,18 @@ static void isci_request_io_request_complete(struct 
isci_host *ihost,
case SAS_PROTOCOL_SMP: {
struct scatterlist *sg = >smp_task.smp_req;
struct smp_req *smp_req;
-   void *kaddr;
 
dma_unmap_sg(>pdev->dev, sg, 1, 

[PATCH v2 06/21] crypto: hifn_795x: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Conversion of a couple kmap_atomic instances to the sg_map helper
function.

However, it looks like there was a bug in the original code: the source
scatter lists offset (t->offset) was passed to ablkcipher_get which
added it to the destination address. This doesn't make a lot of
sense, but t->offset is likely always zero anyway. So, this patch cleans
that brokeness up.

Also, a change to the error path: if ablkcipher_get failed, everything
seemed to proceed as if it hadn't. Setting 'error' should hopefully
clear that up.

Signed-off-by: Logan Gunthorpe 
Cc: Herbert Xu 
Cc: "David S. Miller" 
---
 drivers/crypto/hifn_795x.c | 32 +---
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index e09d405..34b1870 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -1619,7 +1619,7 @@ static int hifn_start_device(struct hifn_device *dev)
return 0;
 }
 
-static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int 
offset,
+static int ablkcipher_get(void *saddr, unsigned int *srestp,
struct scatterlist *dst, unsigned int size, unsigned int 
*nbytesp)
 {
unsigned int srest = *srestp, nbytes = *nbytesp, copy;
@@ -1632,15 +1632,17 @@ static int ablkcipher_get(void *saddr, unsigned int 
*srestp, unsigned int offset
while (size) {
copy = min3(srest, dst->length, size);
 
-   daddr = kmap_atomic(sg_page(dst));
-   memcpy(daddr + dst->offset + offset, saddr, copy);
-   kunmap_atomic(daddr);
+   daddr = sg_map(dst, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(daddr))
+   return PTR_ERR(daddr);
+
+   memcpy(daddr, saddr, copy);
+   sg_unmap(dst, daddr, 0, SG_KMAP_ATOMIC);
 
nbytes -= copy;
size -= copy;
srest -= copy;
saddr += copy;
-   offset = 0;
 
pr_debug("%s: copy: %u, size: %u, srest: %u, nbytes: %u.\n",
 __func__, copy, size, srest, nbytes);
@@ -1671,11 +1673,12 @@ static inline void hifn_complete_sa(struct hifn_device 
*dev, int i)
 
 static void hifn_process_ready(struct ablkcipher_request *req, int error)
 {
+   int err;
struct hifn_request_context *rctx = ablkcipher_request_ctx(req);
 
if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
unsigned int nbytes = req->nbytes;
-   int idx = 0, err;
+   int idx = 0;
struct scatterlist *dst, *t;
void *saddr;
 
@@ -1695,17 +1698,24 @@ static void hifn_process_ready(struct 
ablkcipher_request *req, int error)
continue;
}
 
-   saddr = kmap_atomic(sg_page(t));
+   saddr = sg_map(t, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(saddr)) {
+   if (!error)
+   error = PTR_ERR(saddr);
+   break;
+   }
+
+   err = ablkcipher_get(saddr, >length,
+dst, nbytes, );
+   sg_unmap(t, saddr, 0, SG_KMAP_ATOMIC);
 
-   err = ablkcipher_get(saddr, >length, t->offset,
-   dst, nbytes, );
if (err < 0) {
-   kunmap_atomic(saddr);
+   if (!error)
+   error = err;
break;
}
 
idx += err;
-   kunmap_atomic(saddr);
}
 
hifn_cipher_walk_exit(>walk);
-- 
2.1.4



[PATCH v2 15/21] xen-blkfront: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Straightforward conversion to the new helper, except due to the lack
of error path, we have to use SG_MAP_MUST_NOT_FAIL which may BUG_ON in
certain cases in the future.

Signed-off-by: Logan Gunthorpe 
Cc: Boris Ostrovsky 
Cc: Juergen Gross 
Cc: Konrad Rzeszutek Wilk 
Cc: "Roger Pau Monné" 
---
 drivers/block/xen-blkfront.c | 20 +++-
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 3945963..ed62175 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -816,8 +816,9 @@ static int blkif_queue_rw_req(struct request *req, struct 
blkfront_ring_info *ri
BUG_ON(sg->offset + sg->length > PAGE_SIZE);
 
if (setup.need_copy) {
-   setup.bvec_off = sg->offset;
-   setup.bvec_data = kmap_atomic(sg_page(sg));
+   setup.bvec_off = 0;
+   setup.bvec_data = sg_map(sg, 0, SG_KMAP_ATOMIC |
+SG_MAP_MUST_NOT_FAIL);
}
 
gnttab_foreach_grant_in_range(sg_page(sg),
@@ -827,7 +828,7 @@ static int blkif_queue_rw_req(struct request *req, struct 
blkfront_ring_info *ri
  );
 
if (setup.need_copy)
-   kunmap_atomic(setup.bvec_data);
+   sg_unmap(sg, setup.bvec_data, 0, SG_KMAP_ATOMIC);
}
if (setup.segments)
kunmap_atomic(setup.segments);
@@ -1053,7 +1054,7 @@ static int xen_translate_vdev(int vdevice, int *minor, 
unsigned int *offset)
case XEN_SCSI_DISK5_MAJOR:
case XEN_SCSI_DISK6_MAJOR:
case XEN_SCSI_DISK7_MAJOR:
-   *offset = (*minor / PARTS_PER_DISK) + 
+   *offset = (*minor / PARTS_PER_DISK) +
((major - XEN_SCSI_DISK1_MAJOR + 1) * 16) +
EMULATED_SD_DISK_NAME_OFFSET;
*minor = *minor +
@@ -1068,7 +1069,7 @@ static int xen_translate_vdev(int vdevice, int *minor, 
unsigned int *offset)
case XEN_SCSI_DISK13_MAJOR:
case XEN_SCSI_DISK14_MAJOR:
case XEN_SCSI_DISK15_MAJOR:
-   *offset = (*minor / PARTS_PER_DISK) + 
+   *offset = (*minor / PARTS_PER_DISK) +
((major - XEN_SCSI_DISK8_MAJOR + 8) * 16) +
EMULATED_SD_DISK_NAME_OFFSET;
*minor = *minor +
@@ -1119,7 +1120,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
if (!VDEV_IS_EXTENDED(info->vdevice)) {
err = xen_translate_vdev(info->vdevice, , );
if (err)
-   return err; 
+   return err;
nr_parts = PARTS_PER_DISK;
} else {
minor = BLKIF_MINOR_EXT(info->vdevice);
@@ -1483,8 +1484,9 @@ static bool blkif_completion(unsigned long *id,
for_each_sg(s->sg, sg, num_sg, i) {
BUG_ON(sg->offset + sg->length > PAGE_SIZE);
 
-   data.bvec_offset = sg->offset;
-   data.bvec_data = kmap_atomic(sg_page(sg));
+   data.bvec_offset = 0;
+   data.bvec_data = sg_map(sg, 0, SG_KMAP_ATOMIC |
+   SG_MAP_MUST_NOT_FAIL);
 
gnttab_foreach_grant_in_range(sg_page(sg),
  sg->offset,
@@ -1492,7 +1494,7 @@ static bool blkif_completion(unsigned long *id,
  blkif_copy_from_grant,
  );
 
-   kunmap_atomic(data.bvec_data);
+   sg_unmap(sg, data.bvec_data, 0, SG_KMAP_ATOMIC);
}
}
/* Add the persistent grant into the list of free grants */
-- 
2.1.4



[PATCH v2 12/21] scsi: hisi_sas, mvsas, gdth: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Very straightforward conversion of three scsi drivers.

Signed-off-by: Logan Gunthorpe 
Cc: Achim Leubner 
Cc: John Garry 
---
 drivers/scsi/gdth.c|  9 +++--
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 14 +-
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 13 +
 drivers/scsi/mvsas/mv_sas.c| 10 +-
 4 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index d020a13..c70248a2 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -2301,10 +2301,15 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, 
Scsi_Cmnd *scp,
 return;
 }
 local_irq_save(flags);
-address = kmap_atomic(sg_page(sl)) + sl->offset;
+address = sg_map(sl, 0, SG_KMAP_ATOMIC);
+if (IS_ERR(address)) {
+scp->result = DID_ERROR << 16;
+return;
+   }
+
 memcpy(address, buffer, cpnow);
 flush_dcache_page(sg_page(sl));
-kunmap_atomic(address);
+sg_unmap(sl, address, 0, SG_KMAP_ATOMIC);
 local_irq_restore(flags);
 if (cpsum == cpcount)
 break;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
index fc1c1b2..b3953e3 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -1381,18 +1381,22 @@ static int slot_complete_v1_hw(struct hisi_hba 
*hisi_hba,
void *to;
struct scatterlist *sg_resp = >smp_task.smp_resp;
 
-   ts->stat = SAM_STAT_GOOD;
-   to = kmap_atomic(sg_page(sg_resp));
+   to = sg_map(sg_resp, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(to)) {
+   dev_err(dev, "slot complete: error mapping memory");
+   ts->stat = SAS_SG_ERR;
+   break;
+   }
 
+   ts->stat = SAM_STAT_GOOD;
dma_unmap_sg(dev, >smp_task.smp_resp, 1,
 DMA_FROM_DEVICE);
dma_unmap_sg(dev, >smp_task.smp_req, 1,
 DMA_TO_DEVICE);
-   memcpy(to + sg_resp->offset,
-  slot->status_buffer +
+   memcpy(to, slot->status_buffer +
   sizeof(struct hisi_sas_err_record),
   sg_dma_len(sg_resp));
-   kunmap_atomic(to);
+   sg_unmap(sg_resp, to, 0, SG_KMAP_ATOMIC);
break;
}
case SAS_PROTOCOL_SATA:
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index e241921..3e674a4 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -2307,18 +2307,23 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct 
hisi_sas_slot *slot)
struct scatterlist *sg_resp = >smp_task.smp_resp;
void *to;
 
+   to = sg_map(sg_resp, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(to)) {
+   dev_err(dev, "slot complete: error mapping memory");
+   ts->stat = SAS_SG_ERR;
+   break;
+   }
+
ts->stat = SAM_STAT_GOOD;
-   to = kmap_atomic(sg_page(sg_resp));
 
dma_unmap_sg(dev, >smp_task.smp_resp, 1,
 DMA_FROM_DEVICE);
dma_unmap_sg(dev, >smp_task.smp_req, 1,
 DMA_TO_DEVICE);
-   memcpy(to + sg_resp->offset,
-  slot->status_buffer +
+   memcpy(to, slot->status_buffer +
   sizeof(struct hisi_sas_err_record),
   sg_dma_len(sg_resp));
-   kunmap_atomic(to);
+   sg_unmap(sg_resp, to, 0, SG_KMAP_ATOMIC);
break;
}
case SAS_PROTOCOL_SATA:
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index c7cc803..a72e0ce 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -1798,11 +1798,11 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 
rx_desc, u32 flags)
case SAS_PROTOCOL_SMP: {
struct scatterlist *sg_resp = >smp_task.smp_resp;
tstat->stat = SAM_STAT_GOOD;
-   to = kmap_atomic(sg_page(sg_resp));
-   memcpy(to + sg_resp->offset,
-   slot->response + sizeof(struct mvs_err_info),
-   sg_dma_len(sg_resp));
-   kunmap_atomic(to);
+   to = sg_map(sg_resp, 0, SG_KMAP_ATOMIC);
+   memcpy(to,
+  slot->response + sizeof(struct mvs_err_info),
+  

[PATCH v2 13/21] scsi: arcmsr, ips, megaraid: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Very straightforward conversion of three scsi drivers

Signed-off-by: Logan Gunthorpe 
Cc: Adaptec OEM Raid Solutions 
Cc: Kashyap Desai 
Cc: Sumit Saxena 
Cc: Shivasharan S 
---
 drivers/scsi/arcmsr/arcmsr_hba.c | 16 
 drivers/scsi/ips.c   |  8 
 drivers/scsi/megaraid.c  |  9 +++--
 3 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index af032c4..8c2de17 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -2306,7 +2306,10 @@ static int arcmsr_iop_message_xfer(struct 
AdapterControlBlock *acb,
 
use_sg = scsi_sg_count(cmd);
sg = scsi_sglist(cmd);
-   buffer = kmap_atomic(sg_page(sg)) + sg->offset;
+   buffer = sg_map(sg, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(buffer))
+   return ARCMSR_MESSAGE_FAIL;
+
if (use_sg > 1) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
@@ -2539,7 +2542,7 @@ static int arcmsr_iop_message_xfer(struct 
AdapterControlBlock *acb,
 message_out:
if (use_sg) {
struct scatterlist *sg = scsi_sglist(cmd);
-   kunmap_atomic(buffer - sg->offset);
+   sg_unmap(sg, buffer, 0, SG_KMAP_ATOMIC);
}
return retvalue;
 }
@@ -2590,11 +2593,16 @@ static void arcmsr_handle_virtual_command(struct 
AdapterControlBlock *acb,
strncpy([32], "R001", 4); /* Product Revision */
 
sg = scsi_sglist(cmd);
-   buffer = kmap_atomic(sg_page(sg)) + sg->offset;
+   buffer = sg_map(sg, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(buffer)) {
+   cmd->result = (DID_ERROR << 16);
+   cmd->scsi_done(cmd);
+   return;
+   }
 
memcpy(buffer, inqdata, sizeof(inqdata));
sg = scsi_sglist(cmd);
-   kunmap_atomic(buffer - sg->offset);
+   sg_unmap(sg, buffer, 0, SG_KMAP_ATOMIC);
 
cmd->scsi_done(cmd);
}
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 3419e1b..6e91729 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -1506,14 +1506,14 @@ static int ips_is_passthru(struct scsi_cmnd *SC)
 /* kmap_atomic() ensures addressability of the user buffer.*/
 /* local_irq_save() protects the KM_IRQ0 address slot. */
 local_irq_save(flags);
-buffer = kmap_atomic(sg_page(sg)) + sg->offset;
-if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
+buffer = sg_map(sg, 0, SG_KMAP_ATOMIC);
+if (!IS_ERR(buffer) && buffer[0] == 'C' && buffer[1] == 'O' &&
 buffer[2] == 'P' && buffer[3] == 'P') {
-kunmap_atomic(buffer - sg->offset);
+sg_unmap(sg, buffer, 0, SG_KMAP_ATOMIC);
 local_irq_restore(flags);
 return 1;
 }
-kunmap_atomic(buffer - sg->offset);
+sg_unmap(sg, buffer, 0, SG_KMAP_ATOMIC);
 local_irq_restore(flags);
}
return 0;
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 3c63c29..f8aee59 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -663,10 +663,15 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int 
*busy)
struct scatterlist *sg;
 
sg = scsi_sglist(cmd);
-   buf = kmap_atomic(sg_page(sg)) + sg->offset;
+   buf = sg_map(sg, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(buf)) {
+cmd->result = (DID_ERROR << 16);
+   cmd->scsi_done(cmd);
+   return NULL;
+   }
 
memset(buf, 0, cmd->cmnd[4]);
-   kunmap_atomic(buf - sg->offset);
+   sg_unmap(sg, buf, 0, SG_KMAP_ATOMIC);
 
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
-- 
2.1.4



[PATCH v2 19/21] mmc: sdricoh_cs: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
This is a straightforward conversion to the new function.

Signed-off-by: Logan Gunthorpe 
Cc: Sascha Sommer 
Cc: Ulf Hansson 
---
 drivers/mmc/host/sdricoh_cs.c | 14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index 5ff26ab..03225c3 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -319,16 +319,20 @@ static void sdricoh_request(struct mmc_host *mmc, struct 
mmc_request *mrq)
for (i = 0; i < data->blocks; i++) {
size_t len = data->blksz;
u8 *buf;
-   struct page *page;
int result;
-   page = sg_page(data->sg);
 
-   buf = kmap(page) + data->sg->offset + (len * i);
+   buf = sg_map(data->sg, (len * i), SG_KMAP);
+   if (IS_ERR(buf)) {
+   cmd->error = PTR_ERR(buf);
+   break;
+   }
+
result =
sdricoh_blockio(host,
data->flags & MMC_DATA_READ, buf, len);
-   kunmap(page);
-   flush_dcache_page(page);
+   sg_unmap(data->sg, buf, (len * i), SG_KMAP);
+
+   flush_dcache_page(sg_page(data->sg));
if (result) {
dev_err(dev, "sdricoh_request: cmd %i "
"block transfer failed\n", cmd->opcode);
-- 
2.1.4



[PATCH v2 20/21] mmc: tifm_sd: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
This conversion is a bit complicated. We modiy the read_fifo,
write_fifo and copy_page functions to take a scatterlist instead of a
page. Thus we can use sg_map instead of kmap_atomic. There's a bit of
accounting that needed to be done for the offset for this to work.
(Seeing sg_map takes care of the offset but it's already added and
used earlier in the code.)

There's also no error path, so we use SG_MAP_MUST_NOT_FAIL which may
BUG_ON in certain cases in the future.

Signed-off-by: Logan Gunthorpe 
Cc: Alex Dubov 
Cc: Ulf Hansson 
---
 drivers/mmc/host/tifm_sd.c | 50 +++---
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 93c4b40..e64345a 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -111,14 +111,16 @@ struct tifm_sd {
 };
 
 /* for some reason, host won't respond correctly to readw/writew */
-static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
+static void tifm_sd_read_fifo(struct tifm_sd *host, struct scatterlist *sg,
  unsigned int off, unsigned int cnt)
 {
struct tifm_dev *sock = host->dev;
unsigned char *buf;
unsigned int pos = 0, val;
 
-   buf = kmap_atomic(pg) + off;
+   buf = sg_map(sg, off - sg->offset,
+SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL);
+
if (host->cmd_flags & DATA_CARRY) {
buf[pos++] = host->bounce_buf_data[0];
host->cmd_flags &= ~DATA_CARRY;
@@ -134,17 +136,19 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, 
struct page *pg,
}
buf[pos++] = (val >> 8) & 0xff;
}
-   kunmap_atomic(buf - off);
+   sg_unmap(sg, buf, off - sg->offset, SG_KMAP_ATOMIC);
 }
 
-static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
+static void tifm_sd_write_fifo(struct tifm_sd *host, struct scatterlist *sg,
   unsigned int off, unsigned int cnt)
 {
struct tifm_dev *sock = host->dev;
unsigned char *buf;
unsigned int pos = 0, val;
 
-   buf = kmap_atomic(pg) + off;
+   buf = sg_map(sg, off - sg->offset,
+SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL);
+
if (host->cmd_flags & DATA_CARRY) {
val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
writel(val, sock->addr + SOCK_MMCSD_DATA);
@@ -161,7 +165,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct 
page *pg,
val |= (buf[pos++] << 8) & 0xff00;
writel(val, sock->addr + SOCK_MMCSD_DATA);
}
-   kunmap_atomic(buf - off);
+   sg_unmap(sg, buf, off - sg->offset, SG_KMAP_ATOMIC);
 }
 
 static void tifm_sd_transfer_data(struct tifm_sd *host)
@@ -170,7 +174,6 @@ static void tifm_sd_transfer_data(struct tifm_sd *host)
struct scatterlist *sg = r_data->sg;
unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2;
unsigned int p_off, p_cnt;
-   struct page *pg;
 
if (host->sg_pos == host->sg_len)
return;
@@ -192,33 +195,39 @@ static void tifm_sd_transfer_data(struct tifm_sd *host)
}
off = sg[host->sg_pos].offset + host->block_pos;
 
-   pg = nth_page(sg_page([host->sg_pos]), off >> PAGE_SHIFT);
p_off = offset_in_page(off);
p_cnt = PAGE_SIZE - p_off;
p_cnt = min(p_cnt, cnt);
p_cnt = min(p_cnt, t_size);
 
if (r_data->flags & MMC_DATA_READ)
-   tifm_sd_read_fifo(host, pg, p_off, p_cnt);
+   tifm_sd_read_fifo(host, [host->sg_pos], p_off,
+ p_cnt);
else if (r_data->flags & MMC_DATA_WRITE)
-   tifm_sd_write_fifo(host, pg, p_off, p_cnt);
+   tifm_sd_write_fifo(host, [host->sg_pos], p_off,
+  p_cnt);
 
t_size -= p_cnt;
host->block_pos += p_cnt;
}
 }
 
-static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
- struct page *src, unsigned int src_off,
+static void tifm_sd_copy_page(struct scatterlist *dst, unsigned int dst_off,
+ struct scatterlist *src, unsigned int src_off,
  unsigned int count)
 {
-   unsigned char *src_buf = kmap_atomic(src) + src_off;
-   unsigned char *dst_buf = kmap_atomic(dst) + dst_off;
+   unsigned char *src_buf, *dst_buf;
+
+   src_off -= src->offset;
+   dst_off -= dst->offset;
+
+   src_buf = sg_map(src, src_off, SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL);
+   dst_buf = sg_map(dst, dst_off, SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL);
 
memcpy(dst_buf, src_buf, 

[PATCH v2 10/21] RDS: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
Straightforward conversion except there's no error path, so we
make use of SG_MAP_MUST_NOT_FAIL which may BUG_ON in certain cases
in the future.

Signed-off-by: Logan Gunthorpe 
Cc: Santosh Shilimkar 
Cc: "David S. Miller" 
---
 net/rds/ib_recv.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c
index e10624a..c665689 100644
--- a/net/rds/ib_recv.c
+++ b/net/rds/ib_recv.c
@@ -800,10 +800,10 @@ static void rds_ib_cong_recv(struct rds_connection *conn,
 
to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off);
BUG_ON(to_copy & 7); /* Must be 64bit aligned. */
+   addr = sg_map(>f_sg, 0,
+ SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL);
 
-   addr = kmap_atomic(sg_page(>f_sg));
-
-   src = addr + frag->f_sg.offset + frag_off;
+   src = addr + frag_off;
dst = (void *)map->m_page_addrs[map_page] + map_off;
for (k = 0; k < to_copy; k += 8) {
/* Record ports that became uncongested, ie
@@ -811,7 +811,7 @@ static void rds_ib_cong_recv(struct rds_connection *conn,
uncongested |= ~(*src) & *dst;
*dst++ = *src++;
}
-   kunmap_atomic(addr);
+   sg_unmap(>f_sg, addr, 0, SG_KMAP_ATOMIC);
 
copied += to_copy;
 
-- 
2.1.4



[PATCH v2 01/21] scatterlist: Introduce sg_map helper functions

2017-04-25 Thread Logan Gunthorpe
This patch introduces functions which kmap the pages inside an sgl.
These functions replace a common pattern of kmap(sg_page(sg)) that is
used in more than 50 places within the kernel.

The motivation for this work is to eventually safely support sgls that
contain io memory. In order for that to work, any access to the contents
of an iomem SGL will need to be done with iomemcpy or hit some warning.
(The exact details of how this will work have yet to be worked out.)
Having all the kmaps in one place is just a first step in that
direction. Additionally, seeing this helps cut down the users of sg_page,
it should make any effort to go to struct-page-less DMAs a little
easier (should that idea ever swing back into favour again).

A flags option is added to select between a regular or atomic mapping so
these functions can replace kmap(sg_page or kmap_atomic(sg_page.
Future work may expand this to have flags for using page_address or
vmap. We include a flag to require the function not to fail to
support legacy code that has no easy error path. Much further in the
future, there may be a flag to allocate memory and copy the data
from/to iomem.

We also add the semantic that sg_map can fail to create a mapping,
despite the fact that the current code this is replacing is assumed to
never fail and the current version of these functions cannot fail. This
is to support iomem which may either have to fail to create the mapping or
allocate memory as a bounce buffer which itself can fail.

Also, in terms of cleanup, a few of the existing kmap(sg_page) users
play things a bit loose in terms of whether they apply sg->offset
so using these helper functions should help avoid such issues.

Signed-off-by: Logan Gunthorpe 
---
 include/linux/scatterlist.h | 85 +
 1 file changed, 85 insertions(+)

diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index cb3c8fe..fad170b 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -5,6 +5,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 struct scatterlist {
@@ -126,6 +127,90 @@ static inline struct page *sg_page(struct scatterlist *sg)
return (struct page *)((sg)->page_link & ~0x3);
 }
 
+#define SG_KMAP (1 << 0)   /* create a mapping with kmap */
+#define SG_KMAP_ATOMIC  (1 << 1)   /* create a mapping with kmap_atomic */
+#define SG_MAP_MUST_NOT_FAIL (1 << 2)  /* indicate sg_map should not fail */
+
+/**
+ * sg_map - kmap a page inside an sgl
+ * @sg:SG entry
+ * @offset:Offset into entry
+ * @flags: Flags for creating the mapping
+ *
+ * Description:
+ *   Use this function to map a page in the scatterlist at the specified
+ *   offset. sg->offset is already added for you. Note: the semantics of
+ *   this function are that it may fail. Thus, its output should be checked
+ *   with IS_ERR and PTR_ERR. Otherwise, a pointer to the specified offset
+ *   in the mapped page is returned.
+ *
+ *   Flags can be any of:
+ * * SG_KMAP   - Use kmap to create the mapping
+ * * SG_KMAP_ATOMIC- Use kmap_atomic to map the page atommically.
+ *   Thus, the rules of that function apply: the
+ *   cpu may not sleep until it is unmaped.
+ * * SG_MAP_MUST_NOT_FAIL  - Indicate that sg_map must not fail.
+ *   If it does, it will issue a BUG_ON instead.
+ *   This is intended for legacy code only, it
+ *   is not to be used in new code.
+ *
+ *   Also, consider carefully whether this function is appropriate. It is
+ *   largely not recommended for new code and if the sgl came from another
+ *   subsystem and you don't know what kind of memory might be in the list
+ *   then you definitely should not call it. Non-mappable memory may be in
+ *   the sgl and thus this function may fail unexpectedly. Consider using
+ *   sg_copy_to_buffer instead.
+ **/
+static inline void *sg_map(struct scatterlist *sg, size_t offset, int flags)
+{
+   struct page *pg;
+   unsigned int pg_off;
+   void *ret;
+
+   offset += sg->offset;
+   pg = nth_page(sg_page(sg), offset >> PAGE_SHIFT);
+   pg_off = offset_in_page(offset);
+
+   if (flags & SG_KMAP_ATOMIC)
+   ret = kmap_atomic(pg) + pg_off;
+   else if (flags & SG_KMAP)
+   ret = kmap(pg) + pg_off;
+   else
+   ret = ERR_PTR(-EINVAL);
+
+   /*
+* In theory, this can't happen yet. Once we start adding
+* unmapable memory, it also shouldn't happen unless developers
+* start putting unmappable struct pages in sgls and passing
+* it to code that doesn't support it.
+*/
+   BUG_ON(flags & SG_MAP_MUST_NOT_FAIL && IS_ERR(ret));
+
+   return ret;
+}
+
+/**
+ * sg_unmap - unmap a page that was mapped with 

[PATCH v2 08/21] dm-crypt: Make use of the new sg_map helper in 4 call sites

2017-04-25 Thread Logan Gunthorpe
Very straightforward conversion to the new function in all four spots.

Signed-off-by: Logan Gunthorpe 
Cc: Alasdair Kergon 
Cc: Mike Snitzer 
---
 drivers/md/dm-crypt.c | 39 ++-
 1 file changed, 26 insertions(+), 13 deletions(-)

diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 8dbecf1..841f1fc 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -635,9 +635,12 @@ static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 
*iv,
 
if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) {
sg = crypt_get_sg_data(cc, dmreq->sg_in);
-   src = kmap_atomic(sg_page(sg));
-   r = crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
-   kunmap_atomic(src);
+   src = sg_map(sg, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(src))
+   return PTR_ERR(src);
+
+   r = crypt_iv_lmk_one(cc, iv, dmreq, src);
+   sg_unmap(sg, src, 0, SG_KMAP_ATOMIC);
} else
memset(iv, 0, cc->iv_size);
 
@@ -655,14 +658,18 @@ static int crypt_iv_lmk_post(struct crypt_config *cc, u8 
*iv,
return 0;
 
sg = crypt_get_sg_data(cc, dmreq->sg_out);
-   dst = kmap_atomic(sg_page(sg));
-   r = crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
+   dst = sg_map(sg, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(dst))
+   return PTR_ERR(dst);
+
+   r = crypt_iv_lmk_one(cc, iv, dmreq, dst);
 
/* Tweak the first block of plaintext sector */
if (!r)
-   crypto_xor(dst + sg->offset, iv, cc->iv_size);
+   crypto_xor(dst, iv, cc->iv_size);
+
+   sg_unmap(sg, dst, 0, SG_KMAP_ATOMIC);
 
-   kunmap_atomic(dst);
return r;
 }
 
@@ -786,9 +793,12 @@ static int crypt_iv_tcw_gen(struct crypt_config *cc, u8 
*iv,
/* Remove whitening from ciphertext */
if (bio_data_dir(dmreq->ctx->bio_in) != WRITE) {
sg = crypt_get_sg_data(cc, dmreq->sg_in);
-   src = kmap_atomic(sg_page(sg));
-   r = crypt_iv_tcw_whitening(cc, dmreq, src + sg->offset);
-   kunmap_atomic(src);
+   src = sg_map(sg, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(src))
+   return PTR_ERR(src);
+
+   r = crypt_iv_tcw_whitening(cc, dmreq, src);
+   sg_unmap(sg, src, 0, SG_KMAP_ATOMIC);
}
 
/* Calculate IV */
@@ -812,9 +822,12 @@ static int crypt_iv_tcw_post(struct crypt_config *cc, u8 
*iv,
 
/* Apply whitening on ciphertext */
sg = crypt_get_sg_data(cc, dmreq->sg_out);
-   dst = kmap_atomic(sg_page(sg));
-   r = crypt_iv_tcw_whitening(cc, dmreq, dst + sg->offset);
-   kunmap_atomic(dst);
+   dst = sg_map(sg, 0, SG_KMAP_ATOMIC);
+   if (IS_ERR(dst))
+   return PTR_ERR(dst);
+
+   r = crypt_iv_tcw_whitening(cc, dmreq, dst);
+   sg_unmap(sg, dst, 0, SG_KMAP_ATOMIC);
 
return r;
 }
-- 
2.1.4



[PATCH v2 05/21] drm/i915: Make use of the new sg_map helper function

2017-04-25 Thread Logan Gunthorpe
This is a single straightforward conversion from kmap to sg_map.

We also create the i915_gem_object_unmap function to common up the
unmap code.

Signed-off-by: Logan Gunthorpe 
Acked-by: Daniel Vetter 
---
 drivers/gpu/drm/i915/i915_gem.c | 27 ---
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 07e9b27..2c33000 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2202,6 +2202,15 @@ static void __i915_gem_object_reset_page_iter(struct 
drm_i915_gem_object *obj)
radix_tree_delete(>mm.get_page.radix, iter.index);
 }
 
+static void i915_gem_object_unmap(const struct drm_i915_gem_object *obj,
+ void *ptr)
+{
+   if (is_vmalloc_addr(ptr))
+   vunmap(ptr);
+   else
+   sg_unmap(obj->mm.pages->sgl, ptr, 0, SG_KMAP);
+}
+
 void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj,
 enum i915_mm_subclass subclass)
 {
@@ -2229,10 +2238,7 @@ void __i915_gem_object_put_pages(struct 
drm_i915_gem_object *obj,
void *ptr;
 
ptr = ptr_mask_bits(obj->mm.mapping);
-   if (is_vmalloc_addr(ptr))
-   vunmap(ptr);
-   else
-   kunmap(kmap_to_page(ptr));
+   i915_gem_object_unmap(obj, ptr);
 
obj->mm.mapping = NULL;
}
@@ -2499,8 +2505,11 @@ static void *i915_gem_object_map(const struct 
drm_i915_gem_object *obj,
void *addr;
 
/* A single page can always be kmapped */
-   if (n_pages == 1 && type == I915_MAP_WB)
-   return kmap(sg_page(sgt->sgl));
+   if (n_pages == 1 && type == I915_MAP_WB) {
+   addr = sg_map(sgt->sgl, 0, SG_KMAP);
+   if (IS_ERR(addr))
+   return NULL;
+   }
 
if (n_pages > ARRAY_SIZE(stack_pages)) {
/* Too big for stack -- allocate temporary array instead */
@@ -2567,11 +2576,7 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object 
*obj,
goto err_unpin;
}
 
-   if (is_vmalloc_addr(ptr))
-   vunmap(ptr);
-   else
-   kunmap(kmap_to_page(ptr));
-
+   i915_gem_object_unmap(obj, ptr);
ptr = obj->mm.mapping = NULL;
}
 
-- 
2.1.4



[PATCH v2 02/21] libiscsi: Add an internal error code

2017-04-25 Thread Logan Gunthorpe
This is a prep patch to add a new error code to libiscsi. We want to
rework some kmap calls to be able to fail. When we do, we'd like to
use this error code.

This patch simply introduces ISCSI_TCP_INTERNAL_ERR and prints
"Internal Error." when it gets hit.

Signed-off-by: Logan Gunthorpe 
---
 drivers/scsi/cxgbi/libcxgbi.c | 5 +
 include/scsi/libiscsi_tcp.h   | 1 +
 2 files changed, 6 insertions(+)

diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index bd7d39e..e38d0c1 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -1556,6 +1556,11 @@ static inline int read_pdu_skb(struct iscsi_conn *conn,
 */
iscsi_conn_printk(KERN_ERR, conn, "Invalid pdu or skb.");
return -EFAULT;
+   case ISCSI_TCP_INTERNAL_ERR:
+   pr_info("skb 0x%p, off %u, %d, TCP_INTERNAL_ERR.\n",
+   skb, offset, offloaded);
+   iscsi_conn_printk(KERN_ERR, conn, "Internal error.");
+   return -EFAULT;
case ISCSI_TCP_SEGMENT_DONE:
log_debug(1 << CXGBI_DBG_PDU_RX,
"skb 0x%p, off %u, %d, TCP_SEG_DONE, rc %d.\n",
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h
index 30520d5..90691ad 100644
--- a/include/scsi/libiscsi_tcp.h
+++ b/include/scsi/libiscsi_tcp.h
@@ -92,6 +92,7 @@ enum {
ISCSI_TCP_SKB_DONE, /* skb is out of data */
ISCSI_TCP_CONN_ERR, /* iscsi layer has fired a conn err */
ISCSI_TCP_SUSPENDED,/* conn is suspended */
+   ISCSI_TCP_INTERNAL_ERR, /* an internal error occurred */
 };
 
 extern void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn);
-- 
2.1.4



Re: [PATCH] lpfc: Fix memory corruption of the lpfc_ncmd->list pointers

2017-04-25 Thread Christoph Hellwig
On Tue, Apr 25, 2017 at 10:58:44AM -0700, Christoph Hellwig wrote:
> On Fri, Apr 21, 2017 at 05:49:08PM -0700, jsmart2...@gmail.com wrote:
> > This is a nvme-specific bug. The patch was cut against the
> > linux-block tree, for-4.12/block tree. It should be pulled in through
> > that tree.
> 
> It conflicts with your nvme changes that are in the nvme-4.12.
> Can you respin it?

Sorry for the noise.  It applies fine and I've applied it.


Re: [PATCH] lpfc: Fix memory corruption of the lpfc_ncmd->list pointers

2017-04-25 Thread Christoph Hellwig
On Fri, Apr 21, 2017 at 05:49:08PM -0700, jsmart2...@gmail.com wrote:
> This is a nvme-specific bug. The patch was cut against the
> linux-block tree, for-4.12/block tree. It should be pulled in through
> that tree.

It conflicts with your nvme changes that are in the nvme-4.12.
Can you respin it?


Re: [PATCH] nvme/scsi: Consider LBA format in IO splitting calculation

2017-04-25 Thread Christoph Hellwig
Applied to nvme-4.12.


Re: [RFC] scsi: reduce protection of scan_mutex in scsi_remove_device

2017-04-25 Thread Bart Van Assche
On Tue, 2017-04-25 at 17:42 +, Song Liu wrote:
> I have been studying the code recently. I am wondering whether the following 
> would work:
> 
> 1. Introduce a new mutex for scsi_device to protect most operations in the 
>list you gathered above;
> 
> 2. For operations like host->slave_destroy(), ensure they access scsi_host 
>data with host_lock (or another spin lock). 
> 
>I looked into all instances of slave_destroy, only 2 of them: 
>dc395x_slave_destroy() and visorhba_slave_destroy() access scsi_host data 
>without protection of spin lock. 
> 
> 3. Once 1 and 2 is ready, __scsi_remove_device() only need to hold the mutex
>for the scsi_device. scan_mutex is no longer required. 
> 
> Is this a valid path?

Sorry but I don't think so. Unlocking and reacquiring scan_mutex would create
the potential that LUN scanning occurs in the meantime and hence that it fails
because LUN removal is incomplete.

Bart.

  1   2   >