June 14, 2017

2017-06-14 Thread Johnson King
Attn,

My name is Johnson King, the principal attorney of my law firm., Johnson King & 
Co. A deceased client Mr. Henry died in 2010 and left a sum little above US$ 28 
million in his account here in Unity Bank Plc. Normally banking procedures 
requires that the bank declares the account forfeitable and transfer the 
proceeds to the Registry of Unclaimed Property for government use after 8 years 
from the time of the death of the deceased client.

The present situation made me to contact you given that you and my deceased 
client share the same last name and nationality which made it favorably 
disposed towards this proposals to present you as the Cestui Que trust and 
administrator of the account. It may also interest you to know that the 
transaction will be executed within the ambit of law and nothing shall be done 
outside of it.If you are not familiar with estate and probate measures, I shall 
send further information to you concerning these once i get a positive 
response. Whereas We will discuss the ratios succinctly and promote them in 
written signed agreement before commencement.

I wish to submit that I would expect nothing less but honesty and transparency. 
I will uncover to you further information on the matter in our following 
communications. If this business interests you kindly revert with your direct 
phone number for further exhaustive phone talk.

I look forward to having a good business relationship with you.

Yours sincerely,
Johnson King & Co


Re: [ANNOUNCE]: Broadcom (Emulex) FC Target driver - efct

2017-06-14 Thread Sebastian Herbszt
Hannes Reinecke wrote:
> On 06/13/2017 01:08 AM, James Smart wrote:

[snip]

> > Questions:
> > a) How best to deal with overlapping pci id's ?  E.g. if we do (1)
> > and we have an initiator and target driver, there is a lot of
> > adapters that are fully functional for target operation, but were
> > sold as primarily an initiator adapter. How could we manage target
> > mode enablement without code mod or hard pci id partitioning ?   I
> > know individual pci unbind/bind could work, but its been frowned
> > upon as a long term option. Same thing goes for module parameters
> > to select which ports do what role. 
> That indeed is a problem.
> 
> Ideally we should be able to set the required mode on a per-port base;
> having it per PCI device might be too coarse. Unless you represent
> each port as a PCI function; not sure if that's the case, though.

It seems to be the case.
At least a dual port FC HBA (SLI-3) has two PCI functions.

> If we were to allow to set the mode on a per-port base we could easily
> implement kernel parameters like fctarget=WWPN and/or
> fcinitiator=WWPN; NVMe could be treated similarly.
> And have a config option specifying if the default FC mode should be
> initiator or target.

The old lpfc+lpfc_scst combination and also qla2xxx+tcm_qla2xxx allow
simultaneous initiator and target mode on the same port. I guess this
won't be possible with a split driver.

Sebastian


RE: [PATCH v2] storvsc: use default I/O timeout handler for FC devices

2017-06-14 Thread Long Li


> -Original Message-
> From: Johannes Thumshirn [mailto:jthumsh...@suse.de]
> Sent: Wednesday, June 14, 2017 1:25 AM
> To: Long Li ; James E.J. Bottomley
> ; Martin K. Petersen ;
> linux-scsi@vger.kernel.org; linux-ker...@vger.kernel.org; KY Srinivasan
> ; Bart Van Assche ;
> Christoph Hellwig ; Stephen Hemminger
> 
> Cc: Long Li 
> Subject: Re: [PATCH v2] storvsc: use default I/O timeout handler for FC 
> devices
> 
> On 06/13/2017 11:34 PM, Long Li wrote:
> > From: Long Li 
> >
> > FC disks issue I/O directly to the host storage port driver, this is
> > diffirent to VHD disks where I/O is virtualized and timeout is handled
> > by the host VSP (Virtualization Service Provider).
> >
> > FC disks are usually setup in a multipath system, and they don't want
> > to reset timer on I/O timeout. Timeout is detected by multipath as a
> > good time to failover and recover.
> >
> > Patch v2 includes suggestions from Bart Van Assche
> > 
> >
> > Signed-off-by: Long Li 
> > ---
> >  drivers/scsi/storvsc_drv.c | 4 
> >  1 file changed, 4 insertions(+)
> >
> > diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
> > index 8d955db..3cc8d67 100644
> > --- a/drivers/scsi/storvsc_drv.c
> > +++ b/drivers/scsi/storvsc_drv.c
> > @@ -1495,6 +1495,10 @@ static int storvsc_host_reset_handler(struct
> scsi_cmnd *scmnd)
> >   */
> >  static enum blk_eh_timer_return storvsc_eh_timed_out(struct scsi_cmnd
> > *scmnd)  {
> > +#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
> > +   if (scmnd->device->host->transportt == fc_transport_template)
> > +   return fc_eh_timed_out(scmnd);
> > +#endif
> 
> Can you please change the #if IS_ENABLED() to
> if(IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
>   && scmnd->device->host->transportt == fc_transport_template)
> 
> That way we have better compiler coverage.

Thank you for pointing this out.

The coding style is kept consistent with the rest of the FC related code in 
storvsc. E.g. the definition of fc_transport_template (and many other places):

#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
static struct scsi_transport_template *fc_transport_template;
#endif

I suggest we make another patch to fix this in all the places. This patch is 
mainly for fixing FC timeout.

Long

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


Re: [PATCH 0/7] Enable iSCSI offload drivers to use information from iface.

2017-06-14 Thread Robert LeBlanc
On Wed, Jun 14, 2017 at 3:20 AM, Rangankar, Manish
 wrote:
>
> On 13/06/17 10:19 PM, "Robert LeBlanc"  wrote:
>
>>On Wed, Jun 7, 2017 at 12:30 PM, Robert LeBlanc 
>>wrote:
>>> On Wed, Jun 7, 2017 at 10:28 AM, Chris Leech  wrote:
 On Tue, Jun 06, 2017 at 12:07:10PM -0600, Robert LeBlanc wrote:
> This patchset enables iSCSI offload drivers to have access to the
>iface
> information provided by iscsid. This allows users to have more control
> of how the driver connects to the iSCSI target. iSER is updated to use
> iface.ipaddress to set the source IP address if configured. This
>allows
> iSER to use multiple ports on the same network or in more complicated
> routed configurations.
>
> Since there is already a change to the function parameters, dst_addr
> is upgraded to sockaddr_storage so that it is more future proof and
>makes
> the size of the struct static and not dependent on checking the
>SA_FAMILY.
>
> This is dependent on updates to Open-iSCSI.

 Hi Robert,

 I don't think that passing the iface_rec structure directly from the
 iscsid internals into a netlink message is a good way to go about this.
 It's really big, there's an embedded list_head with user address
 pointers that needs to be left out, and there are 32/64-bit layout
 differences.

 Let me take a look at how you're proposing using this info for iSER, if
 it makes sense I think we should come up with a better designed
 structure for passing the information.

 Thanks,
 Chris

>>>
>>> Chris,
>>>
>>> Thank you for your feedback. I agree that the entire iface is probably
>>> overkill, it was more of a proof of concept. We are only using the
>>> ipaddress in the iface for iSER (in my patch), but I could see other
>>> drivers benefiting from some of the other data in the iface (mac,
>>> interface_name, vlan, etc) so I didn't want to be too restrictive so
>>> that it wouldn't have to be extended later. I've not worked on
>>> userspace/kernel interaction before so I need some guidance to make
>>> the transition between userspace and kernel versions smoother.
>>>
>>> This patchset works for what we need and it is very important for us
>>> (and I'm sure others once the feature is available) and I'm happy to
>>> put in the time to get it accepted upstream, I'm just new to kernel
>>> development and need some guidance.
>>
>>Are there other comments/ideas/suggestions specifically from the
>>iSCSI/iSER guys? I'd like to keep this patch moving.
>
> Considering partial iSCSI offload solution (like bnx2i and qedi) point of
> view, we liked the idea from Hannes to create TAP interface to associate
> with each iSCSI offload interface, which will allow us to use userspace
> tools for configuration. I haven't dig into its details yet, but at higher
> level it looks like this will help us to move away from our dependency
> over iscsiuio.

I'm having a hard time wrapping my head around this idea. How can
configuring a TAP (separate Ethernet device) affect the offload NIC. I
don't see how you can bind to the right interface with the IP address
or how that is passed to rdma_connect() using a TAP. Is TAP used
instead of netlink for communicating between userspace and the kernel?
Obviously by my questions, at the moment I'm not sure how to approach
this at all and would be the wrong person to make this happen.

If someone can explain how this would work and point to some code that
does something like this (examples are good for me), I can try to
create a patch with TAPs. As I mentioned before, this is important for
us and I'm willing to put in the time to learn and code, but I'm
really lost at this point.

Thank you,


Robert LeBlanc
PGP Fingerprint 79A2 9CA4 6CC4 45DD A904  C70E E654 3BB2 FA62 B9F1


[PATCH v6 14/22] scsi: hisi_sas: add v3 cq interrupt handler

2017-06-14 Thread John Garry
From: Xiang Chen 

Add v3 cq interrupt handler slot_complete_v3_hw().

Note: The slot error handling needs to be further
  refined in the future to examine all fields
  in the error record, and handle appropriately,
  instead of current solution - just report
  SAS_OPEN_REJECT.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 340 +
 1 file changed, 340 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 3065252..4869b73 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -157,6 +157,32 @@
 #define SL_RX_BCAST_CHK_MSK(PORT_BASE + 0x2c0)
 #define PHYCTRL_OOB_RESTART_MSK(PORT_BASE + 0x2c4)
 
+/* Completion header */
+/* dw0 */
+#define CMPLT_HDR_CMPLT_OFF0
+#define CMPLT_HDR_CMPLT_MSK(0x3 << CMPLT_HDR_CMPLT_OFF)
+#define CMPLT_HDR_ERROR_PHASE_OFF   2
+#define CMPLT_HDR_ERROR_PHASE_MSK   (0xff << CMPLT_HDR_ERROR_PHASE_OFF)
+#define CMPLT_HDR_RSPNS_XFRD_OFF   10
+#define CMPLT_HDR_RSPNS_XFRD_MSK   (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
+#define CMPLT_HDR_ERX_OFF  12
+#define CMPLT_HDR_ERX_MSK  (0x1 << CMPLT_HDR_ERX_OFF)
+#define CMPLT_HDR_ABORT_STAT_OFF   13
+#define CMPLT_HDR_ABORT_STAT_MSK   (0x7 << CMPLT_HDR_ABORT_STAT_OFF)
+/* abort_stat */
+#define STAT_IO_NOT_VALID  0x1
+#define STAT_IO_NO_DEVICE  0x2
+#define STAT_IO_COMPLETE   0x3
+#define STAT_IO_ABORTED0x4
+/* dw1 */
+#define CMPLT_HDR_IPTT_OFF 0
+#define CMPLT_HDR_IPTT_MSK (0x << CMPLT_HDR_IPTT_OFF)
+#define CMPLT_HDR_DEV_ID_OFF   16
+#define CMPLT_HDR_DEV_ID_MSK   (0x << CMPLT_HDR_DEV_ID_OFF)
+/* dw3 */
+#define CMPLT_HDR_IO_IN_TARGET_OFF 17
+#define CMPLT_HDR_IO_IN_TARGET_MSK (0x1 << CMPLT_HDR_IO_IN_TARGET_OFF)
+
 struct hisi_sas_complete_v3_hdr {
__le32 dw0;
__le32 dw1;
@@ -164,6 +190,24 @@ struct hisi_sas_complete_v3_hdr {
__le32 dw3;
 };
 
+struct hisi_sas_err_record_v3 {
+   /* dw0 */
+   __le32 trans_tx_fail_type;
+
+   /* dw1 */
+   __le32 trans_rx_fail_type;
+
+   /* dw2 */
+   __le16 dma_tx_err_type;
+   __le16 sipc_rx_err_type;
+
+   /* dw3 */
+   __le32 dma_rx_err_type;
+};
+
+#define RX_DATA_LEN_UNDERFLOW_OFF  6
+#define RX_DATA_LEN_UNDERFLOW_MSK  (1 << RX_DATA_LEN_UNDERFLOW_OFF)
+
 #define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096
 #define HISI_SAS_MSI_COUNT_V3_HW 32
 
@@ -625,11 +669,275 @@ static irqreturn_t int_chnl_int_v3_hw(int irq_no, void 
*p)
return IRQ_HANDLED;
 }
 
+static void
+slot_err_v3_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
+  struct hisi_sas_slot *slot)
+{
+   struct task_status_struct *ts = >task_status;
+   struct hisi_sas_complete_v3_hdr *complete_queue =
+   hisi_hba->complete_hdr[slot->cmplt_queue];
+   struct hisi_sas_complete_v3_hdr *complete_hdr =
+   _queue[slot->cmplt_queue_slot];
+   struct hisi_sas_err_record_v3 *record = slot->status_buffer;
+   u32 dma_rx_err_type = record->dma_rx_err_type;
+   u32 trans_tx_fail_type = record->trans_tx_fail_type;
+
+   switch (task->task_proto) {
+   case SAS_PROTOCOL_SSP:
+   if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) {
+   ts->residual = trans_tx_fail_type;
+   ts->stat = SAS_DATA_UNDERRUN;
+   } else if (complete_hdr->dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) {
+   ts->stat = SAS_QUEUE_FULL;
+   slot->abort = 1;
+   } else {
+   ts->stat = SAS_OPEN_REJECT;
+   ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+   }
+   break;
+   case SAS_PROTOCOL_SATA:
+   case SAS_PROTOCOL_STP:
+   case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+   if (dma_rx_err_type & RX_DATA_LEN_UNDERFLOW_MSK) {
+   ts->residual = trans_tx_fail_type;
+   ts->stat = SAS_DATA_UNDERRUN;
+   } else if (complete_hdr->dw3 & CMPLT_HDR_IO_IN_TARGET_MSK) {
+   ts->stat = SAS_PHY_DOWN;
+   slot->abort = 1;
+   } else {
+   ts->stat = SAS_OPEN_REJECT;
+   ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
+   }
+   hisi_sas_sata_done(task, slot);
+   break;
+   case SAS_PROTOCOL_SMP:
+   ts->stat = SAM_STAT_CHECK_CONDITION;
+   break;
+   default:
+   break;
+   }
+}
+
+static int
+slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot)
+{
+ 

[PATCH v6 09/22] scsi: hisi_sas: add skeleton v3 hw driver

2017-06-14 Thread John Garry
Add skeleton driver for v3 hw in hisi_sas_v3_hw.c

File hisi_sas_v3_hw.c will serve 2 purposes:
- probing and initialisation of the controller based on pci device
- hw layer for v3-based controllers

The controller design is quite similar to v2 hw in hip07.

However key differences include:
-All v2 hw bugs are fixed (hopefully), so workarounds are not
required
-support for device deregistration
-some interrupt modifications
-configurable max device support

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/Kconfig  | 10 +++-
 drivers/scsi/hisi_sas/Makefile |  1 +
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 47 ++
 3 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig
index 374a329..d42f29a 100644
--- a/drivers/scsi/hisi_sas/Kconfig
+++ b/drivers/scsi/hisi_sas/Kconfig
@@ -6,4 +6,12 @@ config SCSI_HISI_SAS
select BLK_DEV_INTEGRITY
depends on ATA
help
-   This driver supports HiSilicon's SAS HBA
+   This driver supports HiSilicon's SAS HBA, including support 
based
+   on platform device
+
+config SCSI_HISI_SAS_PCI
+   tristate "HiSilicon SAS on PCI bus"
+   depends on SCSI_HISI_SAS
+   depends on PCI
+   help
+   This driver supports HiSilicon's SAS HBA based on PCI device
diff --git a/drivers/scsi/hisi_sas/Makefile b/drivers/scsi/hisi_sas/Makefile
index c6d3a1b..24623f2 100644
--- a/drivers/scsi/hisi_sas/Makefile
+++ b/drivers/scsi/hisi_sas/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SCSI_HISI_SAS)+= hisi_sas_main.o
 obj-$(CONFIG_SCSI_HISI_SAS)+= hisi_sas_v1_hw.o hisi_sas_v2_hw.o
+obj-$(CONFIG_SCSI_HISI_SAS_PCI)+= hisi_sas_v3_hw.o
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
new file mode 100644
index 000..cf72577
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "hisi_sas.h"
+#define DRV_NAME "hisi_sas_v3_hw"
+
+static int
+hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+   return 0;
+}
+
+static void hisi_sas_v3_remove(struct pci_dev *pdev)
+{
+}
+
+enum {
+   /* instances of the controller */
+   hip08,
+};
+
+static const struct pci_device_id sas_v3_pci_table[] = {
+   { PCI_VDEVICE(HUAWEI, 0xa230), hip08 },
+   {}
+};
+
+static struct pci_driver sas_v3_pci_driver = {
+   .name   = DRV_NAME,
+   .id_table   = sas_v3_pci_table,
+   .probe  = hisi_sas_v3_probe,
+   .remove = hisi_sas_v3_remove,
+};
+
+module_pci_driver(sas_v3_pci_driver);
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry ");
+MODULE_DESCRIPTION("HISILICON SAS controller v3 hw driver based on pci 
device");
+MODULE_ALIAS("platform:" DRV_NAME);
-- 
1.9.1



[PATCH v6 20/22] scsi: hisi_sas: add get_wideport_bitmap_v3_hw()

2017-06-14 Thread John Garry
From: Xiang Chen 

Add code for interface get_wideport_bitmap.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index ef5c158..3cd4b9a 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -629,6 +629,18 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int 
phy_no)
hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
 }
 
+static int get_wideport_bitmap_v3_hw(struct hisi_hba *hisi_hba, int port_id)
+{
+   int i, bitmap = 0;
+   u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+
+   for (i = 0; i < hisi_hba->n_phy; i++)
+   if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id)
+   bitmap |= 1 << i;
+
+   return bitmap;
+}
+
 /**
  * The callpath to this function and upto writing the write
  * queue pointer should be safe from interruption.
@@ -1550,6 +1562,7 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
.hw_init = hisi_sas_v3_init,
.setup_itct = setup_itct_v3_hw,
.max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW,
+   .get_wideport_bitmap = get_wideport_bitmap_v3_hw,
.complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
.free_device = free_device_v3_hw,
.sl_notify = sl_notify_v3_hw,
-- 
1.9.1



[PATCH v6 01/22] scsi: hisi_sas: fix timeout check in hisi_sas_internal_task_abort()

2017-06-14 Thread John Garry
From: Xiang Chen 

We need to check for timeout before task status, or the task will be
mistook as completed internal abort command.
Also add protection for sas_task.task_state_flags in
hisi_sas_tmf_timedout().

Signed-off-by: Xiang Chen 
Signed-off-by: John Garry 
---
 drivers/scsi/hisi_sas/hisi_sas_main.c | 25 +
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index f720d3c..3605d28 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -691,8 +691,13 @@ static void hisi_sas_task_done(struct sas_task *task)
 static void hisi_sas_tmf_timedout(unsigned long data)
 {
struct sas_task *task = (struct sas_task *)data;
+   unsigned long flags;
+
+   spin_lock_irqsave(>task_state_lock, flags);
+   if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+   task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+   spin_unlock_irqrestore(>task_state_lock, flags);
 
-   task->task_state_flags |= SAS_TASK_STATE_ABORTED;
complete(>slow_task->completion);
 }
 
@@ -1247,6 +1252,17 @@ static int hisi_sas_query_task(struct sas_task *task)
wait_for_completion(>slow_task->completion);
res = TMF_RESP_FUNC_FAILED;
 
+   /* Internal abort timed out */
+   if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+   if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+   struct hisi_sas_slot *slot = task->lldd_task;
+
+   if (slot)
+   slot->task = NULL;
+   dev_err(dev, "internal task abort: timeout.\n");
+   }
+   }
+
if (task->task_status.resp == SAS_TASK_COMPLETE &&
task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
res = TMF_RESP_FUNC_COMPLETE;
@@ -1259,13 +1275,6 @@ static int hisi_sas_query_task(struct sas_task *task)
goto exit;
}
 
-   /* Internal abort timed out */
-   if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-   if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-   dev_err(dev, "internal task abort: timeout.\n");
-   }
-   }
-
 exit:
dev_dbg(dev, "internal task abort: task to dev %016llx task=%p "
"resp: 0x%x sts 0x%x\n",
-- 
1.9.1



[PATCH v6 13/22] scsi: hisi_sas: add phy up/down/bcast and channel ISR

2017-06-14 Thread John Garry
From: Xiang Chen 

Add code to initialise interrupts and add some interrupt handlers.

Also add function hisi_sas_v3_destroy_irqs() to clean-up
irqs upon module unloading.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 283 +
 1 file changed, 283 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 5580250..3065252 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -173,6 +173,13 @@ enum {
HISI_SAS_PHY_INT_NR
 };
 
+static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
+{
+   void __iomem *regs = hisi_hba->regs + off;
+
+   return readl(regs);
+}
+
 static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
 {
void __iomem *regs = hisi_hba->regs + off;
@@ -397,6 +404,269 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, 
int phy_no)
hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
 }
 
+static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
+{
+   int i, res = 0;
+   u32 context, port_id, link_rate, hard_phy_linkrate;
+   struct hisi_sas_phy *phy = _hba->phy[phy_no];
+   struct asd_sas_phy *sas_phy = >sas_phy;
+   struct device *dev = hisi_hba->dev;
+
+   hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
+
+   port_id = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+   port_id = (port_id >> (4 * phy_no)) & 0xf;
+   link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+   link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+
+   if (port_id == 0xf) {
+   dev_err(dev, "phyup: phy%d invalid portid\n", phy_no);
+   res = IRQ_NONE;
+   goto end;
+   }
+   sas_phy->linkrate = link_rate;
+   hard_phy_linkrate = hisi_sas_phy_read32(hisi_hba, phy_no,
+   HARD_PHY_LINKRATE);
+   phy->maximum_linkrate = hard_phy_linkrate & 0xf;
+   phy->minimum_linkrate = (hard_phy_linkrate >> 4) & 0xf;
+   phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+
+   /* Check for SATA dev */
+   context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
+   if (context & (1 << phy_no)) {
+   struct hisi_sas_initial_fis *initial_fis;
+   struct dev_to_host_fis *fis;
+   u8 attached_sas_addr[SAS_ADDR_SIZE] = {0};
+
+   dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
+   initial_fis = _hba->initial_fis[phy_no];
+   fis = _fis->fis;
+   sas_phy->oob_mode = SATA_OOB_MODE;
+   attached_sas_addr[0] = 0x50;
+   attached_sas_addr[7] = phy_no;
+   memcpy(sas_phy->attached_sas_addr,
+  attached_sas_addr,
+  SAS_ADDR_SIZE);
+   memcpy(sas_phy->frame_rcvd, fis,
+  sizeof(struct dev_to_host_fis));
+   phy->phy_type |= PORT_TYPE_SATA;
+   phy->identify.device_type = SAS_SATA_DEV;
+   phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
+   phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
+   } else {
+   u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
+   struct sas_identify_frame *id =
+   (struct sas_identify_frame *)frame_rcvd;
+
+   dev_info(dev, "phyup: phy%d link_rate=%d\n", phy_no, link_rate);
+   for (i = 0; i < 6; i++) {
+   u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no,
+  RX_IDAF_DWORD0 + (i * 4));
+   frame_rcvd[i] = __swab32(idaf);
+   }
+   sas_phy->oob_mode = SAS_OOB_MODE;
+   memcpy(sas_phy->attached_sas_addr,
+  >sas_addr,
+  SAS_ADDR_SIZE);
+   phy->phy_type |= PORT_TYPE_SAS;
+   phy->identify.device_type = id->dev_type;
+   phy->frame_rcvd_size = sizeof(struct sas_identify_frame);
+   if (phy->identify.device_type == SAS_END_DEVICE)
+   phy->identify.target_port_protocols =
+   SAS_PROTOCOL_SSP;
+   else if (phy->identify.device_type != SAS_PHY_UNUSED)
+   phy->identify.target_port_protocols =
+   SAS_PROTOCOL_SMP;
+   }
+
+   phy->port_id = port_id;
+   phy->phy_attached = 1;
+   queue_work(hisi_hba->wq, >phyup_ws);
+
+end:
+   hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0,
+CHL_INT0_SL_PHY_ENABLE_MSK);
+   hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0);
+
+   return res;
+}
+
+static int phy_down_v3_hw(int 

[PATCH v6 06/22] scsi: hisi_sas: relocate get_ncq_tag_v2_hw()

2017-06-14 Thread John Garry
From: Xiang Chen 

Relocate get_ncq_tag_v2_hw() to a common location, as
future hw versions will require it.
Also rename with "hisi_sas_" prefix for consistency.

Signed-off-by: Xiang Chen 
Signed-off-by: John Garry 
---
 drivers/scsi/hisi_sas/hisi_sas.h   |  1 +
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 15 +++
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 16 +---
 3 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 1dcdf66..19c6ffd 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -366,6 +366,7 @@ struct hisi_sas_command_table_ssp {
 extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port);
 extern void hisi_sas_sata_done(struct sas_task *task,
struct hisi_sas_slot *slot);
+extern int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag);
 extern int hisi_sas_probe(struct platform_device *pdev,
  const struct hisi_sas_hw *ops);
 extern int hisi_sas_remove(struct platform_device *pdev);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index ab133d4..f53a93b 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -97,6 +97,21 @@ void hisi_sas_sata_done(struct sas_task *task,
 }
 EXPORT_SYMBOL_GPL(hisi_sas_sata_done);
 
+int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag)
+{
+   struct ata_queued_cmd *qc = task->uldd_task;
+
+   if (qc) {
+   if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+   qc->tf.command == ATA_CMD_FPDMA_READ) {
+   *tag = qc->tag;
+   return 1;
+   }
+   }
+   return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_get_ncq_tag);
+
 static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
 {
return device->port->ha->lldd_ha;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index fdd7019..9cc5435 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -2332,20 +2332,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
return sts;
 }
 
-static int get_ncq_tag_v2_hw(struct sas_task *task, u32 *tag)
-{
-   struct ata_queued_cmd *qc = task->uldd_task;
-
-   if (qc) {
-   if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
-   qc->tf.command == ATA_CMD_FPDMA_READ) {
-   *tag = qc->tag;
-   return 1;
-   }
-   }
-   return 0;
-}
-
 static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
  struct hisi_sas_slot *slot)
 {
@@ -2393,7 +2379,7 @@ static int prep_ata_v2_hw(struct hisi_hba *hisi_hba,
hdr->dw1 = cpu_to_le32(dw1);
 
/* dw2 */
-   if (task->ata_task.use_ncq && get_ncq_tag_v2_hw(task, _tag)) {
+   if (task->ata_task.use_ncq && hisi_sas_get_ncq_tag(task, _tag)) {
task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF;
}
-- 
1.9.1



[PATCH v6 07/22] scsi: hisi_sas: add pci_dev in hisi_hba struct

2017-06-14 Thread John Garry
Since hip08 SAS controller is based on pci device, add hisi_hba.pci_dev
for hip08 (will be v3), and also rename hisi_hba.pdev to .platform_dev
for clarity.

In addition, for common code which wants to reference the controller
device struct, add hisi_hba.dev, and change the common code to use
it.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas.h   |  6 -
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 36 ++--
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 28 +++---
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 44 +-
 4 files changed, 59 insertions(+), 55 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 19c6ffd..84cac98 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -196,7 +197,10 @@ struct hisi_hba {
/* This must be the first element, used by SHOST_TO_SAS_HA */
struct sas_ha_struct *p;
 
-   struct platform_device *pdev;
+   struct platform_device *platform_dev;
+   struct pci_dev *pci_dev;
+   struct device *dev;
+
void __iomem *regs;
struct regmap *ctrl;
u32 ctrl_reset_reg;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index f53a93b..139df45 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -168,7 +168,7 @@ void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, 
struct sas_task *task,
 {
 
if (task) {
-   struct device *dev = _hba->pdev->dev;
+   struct device *dev = hisi_hba->dev;
struct domain_device *device = task->dev;
struct hisi_sas_device *sas_dev = device->lldd_dev;
 
@@ -245,7 +245,7 @@ static void hisi_sas_slot_abort(struct work_struct *work)
struct scsi_cmnd *cmnd = task->uldd_task;
struct hisi_sas_tmf_task tmf_task;
struct scsi_lun lun;
-   struct device *dev = _hba->pdev->dev;
+   struct device *dev = hisi_hba->dev;
int tag = abort_slot->idx;
unsigned long flags;
 
@@ -279,7 +279,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct 
hisi_sas_dq
struct hisi_sas_slot *slot;
struct hisi_sas_cmd_hdr *cmd_hdr_base;
struct asd_sas_port *sas_port = device->port;
-   struct device *dev = _hba->pdev->dev;
+   struct device *dev = hisi_hba->dev;
int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
unsigned long flags;
 
@@ -451,7 +451,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t 
gfp_flags,
u32 pass = 0;
unsigned long flags;
struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
-   struct device *dev = _hba->pdev->dev;
+   struct device *dev = hisi_hba->dev;
struct domain_device *device = task->dev;
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_sas_dq *dq = sas_dev->dq;
@@ -546,7 +546,7 @@ static int hisi_sas_dev_found(struct domain_device *device)
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
struct domain_device *parent_dev = device->parent;
struct hisi_sas_device *sas_dev;
-   struct device *dev = _hba->pdev->dev;
+   struct device *dev = hisi_hba->dev;
 
if (hisi_hba->hw->alloc_dev)
sas_dev = hisi_hba->hw->alloc_dev(device);
@@ -731,7 +731,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)
 {
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
-   struct device *dev = _hba->pdev->dev;
+   struct device *dev = hisi_hba->dev;
int dev_id = sas_dev->device_id;
 
dev_info(dev, "found dev[%d:%x] is gone\n",
@@ -814,7 +814,7 @@ static int hisi_sas_exec_internal_tmf_task(struct 
domain_device *device,
 {
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
-   struct device *dev = _hba->pdev->dev;
+   struct device *dev = hisi_hba->dev;
struct sas_task *task;
int res, retry;
 
@@ -931,7 +931,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device 
*device)
struct ata_link *link;
int rc = TMF_RESP_FUNC_FAILED;
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
-   struct device *dev = _hba->pdev->dev;
+   struct device *dev = hisi_hba->dev;
int s = sizeof(struct host_to_dev_fis);
unsigned long flags;
 
@@ -989,7 +989,7 @@ static int hisi_sas_controller_reset(struct hisi_hba 
*hisi_hba)
return -1;
 
if (!test_and_set_bit(HISI_SAS_RESET_BIT, _hba->flags)) {
-   struct device *dev = _hba->pdev->dev;
+

[PATCH v6 21/22] scsi: hisi_sas: add v3 code to fill some more hw function pointers

2017-06-14 Thread John Garry
From: Xiang Chen 

Add code to fill the interface of phy_hard_reset, phy_get_max_linkrate,
and phy enable/disable.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 39 ++
 1 file changed, 39 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 3cd4b9a..cf1eb47 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -129,6 +129,8 @@
 #define TXID_AUTO  (PORT_BASE + 0xb8)
 #define CT3_OFF1
 #define CT3_MSK(0x1 << CT3_OFF)
+#define TX_HARDRST_OFF  2
+#define TX_HARDRST_MSK  (0x1 << TX_HARDRST_OFF)
 #define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
 #define RXOP_CHECK_CFG_H   (PORT_BASE + 0xfc)
 #define SAS_SSP_CON_TIMER_CFG  (PORT_BASE + 0x134)
@@ -596,6 +598,14 @@ static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, 
int phy_no)
hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
 }
 
+static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+   u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+   cfg &= ~PHY_CFG_ENA_MSK;
+   hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
 static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
 {
config_id_frame_v3_hw(hisi_hba, phy_no);
@@ -603,6 +613,11 @@ static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int 
phy_no)
enable_phy_v3_hw(hisi_hba, phy_no);
 }
 
+static void stop_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+   disable_phy_v3_hw(hisi_hba, phy_no);
+}
+
 static void start_phys_v3_hw(struct hisi_hba *hisi_hba)
 {
int i;
@@ -611,6 +626,26 @@ static void start_phys_v3_hw(struct hisi_hba *hisi_hba)
start_phy_v3_hw(hisi_hba, i);
 }
 
+static void phy_hard_reset_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+   struct hisi_sas_phy *phy = _hba->phy[phy_no];
+   u32 txid_auto;
+
+   stop_phy_v3_hw(hisi_hba, phy_no);
+   if (phy->identify.device_type == SAS_END_DEVICE) {
+   txid_auto = hisi_sas_phy_read32(hisi_hba, phy_no, TXID_AUTO);
+   hisi_sas_phy_write32(hisi_hba, phy_no, TXID_AUTO,
+   txid_auto | TX_HARDRST_MSK);
+   }
+   msleep(100);
+   start_phy_v3_hw(hisi_hba, phy_no);
+}
+
+enum sas_linkrate phy_get_max_linkrate_v3_hw(void)
+{
+   return SAS_LINK_RATE_12_0_GBPS;
+}
+
 static void phys_init_v3_hw(struct hisi_hba *hisi_hba)
 {
start_phys_v3_hw(hisi_hba);
@@ -1574,6 +1609,10 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
.start_delivery = start_delivery_v3_hw,
.slot_complete = slot_complete_v3_hw,
.phys_init = phys_init_v3_hw,
+   .phy_enable = enable_phy_v3_hw,
+   .phy_disable = disable_phy_v3_hw,
+   .phy_hard_reset = phy_hard_reset_v3_hw,
+   .phy_get_max_linkrate = phy_get_max_linkrate_v3_hw,
 };
 
 static struct Scsi_Host *
-- 
1.9.1



[PATCH v6 05/22] scsi: hisi_sas: relocate sata_done_v2_hw()

2017-06-14 Thread John Garry
From: Xiang Chen 

Relocate get_ata_protocol() to a common location, as future hw
versions will require it.
Also rename with "hisi_sas_" prefix for consistency.

Signed-off-by: Xiang Chen 
Signed-off-by: John Garry 
---
 drivers/scsi/hisi_sas/hisi_sas.h   |  2 ++
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 15 +++
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 18 ++
 3 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index a50c699..1dcdf66 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -364,6 +364,8 @@ struct hisi_sas_command_table_ssp {
 
 extern u8 hisi_sas_get_ata_protocol(u8 cmd, int direction);
 extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port);
+extern void hisi_sas_sata_done(struct sas_task *task,
+   struct hisi_sas_slot *slot);
 extern int hisi_sas_probe(struct platform_device *pdev,
  const struct hisi_sas_hw *ops);
 extern int hisi_sas_remove(struct platform_device *pdev);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 5b51d9a..ab133d4 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -82,6 +82,21 @@ u8 hisi_sas_get_ata_protocol(u8 cmd, int direction)
 }
 EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol);
 
+void hisi_sas_sata_done(struct sas_task *task,
+   struct hisi_sas_slot *slot)
+{
+   struct task_status_struct *ts = >task_status;
+   struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf;
+   struct dev_to_host_fis *d2h = slot->status_buffer +
+ sizeof(struct hisi_sas_err_record);
+
+   resp->frame_len = sizeof(struct dev_to_host_fis);
+   memcpy(>ending_fis[0], d2h, sizeof(struct dev_to_host_fis));
+
+   ts->buf_valid_size = sizeof(*resp);
+}
+EXPORT_SYMBOL_GPL(hisi_sas_sata_done);
+
 static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
 {
return device->port->ha->lldd_ha;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index d9314c4..fdd7019 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -1683,20 +1683,6 @@ static int prep_ssp_v2_hw(struct hisi_hba *hisi_hba,
return 0;
 }
 
-static void sata_done_v2_hw(struct hisi_hba *hisi_hba, struct sas_task *task,
-   struct hisi_sas_slot *slot)
-{
-   struct task_status_struct *ts = >task_status;
-   struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf;
-   struct dev_to_host_fis *d2h = slot->status_buffer +
- sizeof(struct hisi_sas_err_record);
-
-   resp->frame_len = sizeof(struct dev_to_host_fis);
-   memcpy(>ending_fis[0], d2h, sizeof(struct dev_to_host_fis));
-
-   ts->buf_valid_size = sizeof(*resp);
-}
-
 #define TRANS_TX_ERR   0
 #define TRANS_RX_ERR   1
 #define DMA_TX_ERR 2
@@ -2189,7 +2175,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
break;
}
}
-   sata_done_v2_hw(hisi_hba, task, slot);
+   hisi_sas_sata_done(task, slot);
}
break;
default:
@@ -2317,7 +2303,7 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
{
ts->stat = SAM_STAT_GOOD;
-   sata_done_v2_hw(hisi_hba, task, slot);
+   hisi_sas_sata_done(task, slot);
break;
}
default:
-- 
1.9.1



[PATCH v6 00/22] hisi_sas: hip08 support

2017-06-14 Thread John Garry
This patchset adds support for the HiSilicon SAS controller
in the hip08 chipset.

The key difference compared to earlier chipsets is that the
controller is an integrated PCI endpoint in hip08.
As such, the controller is a pci device (not a platform device,
like v2 hw in hip07).

The driver is refactored so it can support both platform and 
pci device-based controllers.

New hw layer file hisi_sas_v3_hw.c is added for v3 hw
support, which also includes pci device proving and
initialisation. 

Common functionality is still in hisi_sas_main.c, along with
platform device probing and initialization.

As for the patches, (ignoring #1-3) the first few
reorganise some functions from v2 hw.c into main.c, as they
are required for v3 hw. Then support is added for pci
device-based controller in subsequent patches.
And then hip08 support is added in the final patches.

Differences to v5 series:
- Fixed erroneous spinlock flag reuse
- Omit support ECC and AXI bus fatal error support

Difference to v4 series:
-report SAS_DATA_UNDERRUN to libsas for underflow

Differences to v3 series:
- Addressed Christoph's comments, including:
 - remove msi disable in probe, and improve irq
registration and deregistration
 - remove hisi_sas_is_rw_cmd() to check underflow,
and use scsi_cmnd underflow field instead

Differences to v2 series:
- Add patch to change hisi_sas_device.device_id size
- Add device dq pointer
- Remove hisi_sas_v3_hw prototype in v3 driver
- Add explicit comment in hisi_sas_get_fw_info()

Differences to v1 series:
- Addressed Arnd's comments, including:
 - read sas address from device node DSD under PCI host
bridge
 - add comment in fatal axi error patch commit log regarding
controller reset
 - eliminate hisi_sas_pci_init.c, and move functionality into
hisi_sas_v3_hw.c, eliminating one layer of indirection

John Garry (5):
  scsi: hisi_sas: define hisi_sas_device.device_id as int
  scsi: hisi_sas: add pci_dev in hisi_hba struct
  scsi: hisi_sas: create hisi_sas_get_fw_info()
  scsi: hisi_sas: add skeleton v3 hw driver
  scsi: hisi_sas: add initialisation for v3 pci-based controller

Xiang Chen (17):
  scsi: hisi_sas: fix timeout check in hisi_sas_internal_task_abort()
  scsi: hisi_sas: optimise the usage of hisi_hba.lock
  scsi: hisi_sas: relocate get_ata_protocol()
  scsi: hisi_sas: relocate sata_done_v2_hw()
  scsi: hisi_sas: relocate get_ncq_tag_v2_hw()
  scsi: hisi_sas: add v3 hw init
  scsi: hisi_sas: add v3 hw PHY init
  scsi: hisi_sas: add phy up/down/bcast and channel ISR
  scsi: hisi_sas: add v3 cq interrupt handler
  scsi: hisi_sas: add v3 code to send SSP frame
  scsi: hisi_sas: add v3 code to send SMP frame
  scsi: hisi_sas: add v3 code to send ATA frame
  scsi: hisi_sas: add v3 code for itct setup and free
  scsi: hisi_sas: add v3 code to send internal abort command
  scsi: hisi_sas: add get_wideport_bitmap_v3_hw()
  scsi: hisi_sas: add v3 code to fill some more hw function pointers
  scsi: hisi_sas: modify internal abort dev flow for v3 hw

 drivers/scsi/hisi_sas/Kconfig  |   10 +-
 drivers/scsi/hisi_sas/Makefile |1 +
 drivers/scsi/hisi_sas/hisi_sas.h   |   42 +-
 drivers/scsi/hisi_sas/hisi_sas_main.c  |  363 +--
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c |   51 +-
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c |  179 +---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 1846 
 7 files changed, 2225 insertions(+), 267 deletions(-)
 create mode 100644 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

-- 
1.9.1



[PATCH v6 03/22] scsi: hisi_sas: optimise the usage of hisi_hba.lock

2017-06-14 Thread John Garry
From: Xiang Chen 

Currently hisi_hba.lock is locked to deliver and receive a
command to/from any hw queue. This causes much
contention at high data-rates.

To boost performance, lock on a per queue basis for
sending and receiving commands to/from hw.

Certain critical regions still need to be locked in the delivery
and completion stages with hisi_hba.lock.

New element hisi_sas_device.dq is added to store the delivery
queue for a device, so it does not need to be needlessly
re-calculated for every task.

Signed-off-by: Xiang Chen 
Signed-off-by: John Garry 
---
 drivers/scsi/hisi_sas/hisi_sas.h   |  9 +++--
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 69 +++---
 drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 23 
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 34 -
 4 files changed, 77 insertions(+), 58 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index b4e96fa9..68ba7bd 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -102,6 +102,8 @@ struct hisi_sas_cq {
 
 struct hisi_sas_dq {
struct hisi_hba *hisi_hba;
+   struct hisi_sas_slot*slot_prep;
+   spinlock_t lock;
int wr_point;
int id;
 };
@@ -109,6 +111,7 @@ struct hisi_sas_dq {
 struct hisi_sas_device {
struct hisi_hba *hisi_hba;
struct domain_device*sas_device;
+   struct hisi_sas_dq  *dq;
struct list_headlist;
u64 attached_phy;
atomic64_t running_req;
@@ -154,9 +157,8 @@ struct hisi_sas_hw {
struct domain_device *device);
struct hisi_sas_device *(*alloc_dev)(struct domain_device *device);
void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no);
-   int (*get_free_slot)(struct hisi_hba *hisi_hba, u32 dev_id,
-   int *q, int *s);
-   void (*start_delivery)(struct hisi_hba *hisi_hba);
+   int (*get_free_slot)(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq);
+   void (*start_delivery)(struct hisi_sas_dq *dq);
int (*prep_ssp)(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot, int is_tmf,
struct hisi_sas_tmf_task *tmf);
@@ -217,7 +219,6 @@ struct hisi_hba {
struct hisi_sas_port port[HISI_SAS_MAX_PHYS];
 
int queue_count;
-   struct hisi_sas_slot*slot_prep;
 
struct dma_pool *sge_page_pool;
struct hisi_sas_device  devices[HISI_SAS_MAX_DEVICES];
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 54e0cf2..4e78cbc 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -179,10 +179,11 @@ static void hisi_sas_slot_abort(struct work_struct *work)
task->task_done(task);
 }
 
-static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
- int is_tmf, struct hisi_sas_tmf_task *tmf,
- int *pass)
+static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq
+   *dq, int is_tmf, struct hisi_sas_tmf_task *tmf,
+   int *pass)
 {
+   struct hisi_hba *hisi_hba = dq->hisi_hba;
struct domain_device *device = task->dev;
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_sas_port *port;
@@ -240,18 +241,24 @@ static int hisi_sas_task_prep(struct sas_task *task, 
struct hisi_hba *hisi_hba,
} else
n_elem = task->num_scatter;
 
+   spin_lock_irqsave(_hba->lock, flags);
if (hisi_hba->hw->slot_index_alloc)
rc = hisi_hba->hw->slot_index_alloc(hisi_hba, _idx,
device);
else
rc = hisi_sas_slot_index_alloc(hisi_hba, _idx);
-   if (rc)
+   if (rc) {
+   spin_unlock_irqrestore(_hba->lock, flags);
goto err_out;
-   rc = hisi_hba->hw->get_free_slot(hisi_hba, sas_dev->device_id,
-   _queue, _queue_slot);
+   }
+   spin_unlock_irqrestore(_hba->lock, flags);
+
+   rc = hisi_hba->hw->get_free_slot(hisi_hba, dq);
if (rc)
goto err_out_tag;
 
+   dlvry_queue = dq->id;
+   dlvry_queue_slot = dq->wr_point;
slot = _hba->slot_info[slot_idx];
memset(slot, 0, sizeof(struct hisi_sas_slot));
 
@@ -316,7 +323,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct 
hisi_hba *hisi_hba,
task->task_state_flags |= SAS_TASK_AT_INITIATOR;
spin_unlock_irqrestore(>task_state_lock, flags);
 
-   hisi_hba->slot_prep = slot;
+   dq->slot_prep = slot;
 
atomic64_inc(_dev->running_req);
++(*pass);
@@ -335,7 +342,9 @@ static int hisi_sas_task_prep(struct 

[PATCH v6 18/22] scsi: hisi_sas: add v3 code for itct setup and free

2017-06-14 Thread John Garry
From: Xiang Chen 

Add code to itct setup and free for v3 hw.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 114 +
 1 file changed, 114 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 30c103b..b9ab24d 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -24,6 +24,11 @@
 #define PHY_PORT_NUM_MA0x28
 #define PHY_CONN_RATE  0x30
 #define AXI_AHB_CLK_CFG0x3c
+#define ITCT_CLR   0x44
+#define ITCT_CLR_EN_OFF16
+#define ITCT_CLR_EN_MSK(0x1 << ITCT_CLR_EN_OFF)
+#define ITCT_DEV_OFF   0
+#define ITCT_DEV_MSK   (0x7ff << ITCT_DEV_OFF)
 #define AXI_USER1  0x48
 #define AXI_USER2  0x4c
 #define IO_SATA_BROKEN_MSG_ADDR_LO 0x58
@@ -226,6 +231,26 @@
 #define CMPLT_HDR_IO_IN_TARGET_OFF 17
 #define CMPLT_HDR_IO_IN_TARGET_MSK (0x1 << CMPLT_HDR_IO_IN_TARGET_OFF)
 
+/* ITCT header */
+/* qw0 */
+#define ITCT_HDR_DEV_TYPE_OFF  0
+#define ITCT_HDR_DEV_TYPE_MSK  (0x3 << ITCT_HDR_DEV_TYPE_OFF)
+#define ITCT_HDR_VALID_OFF 2
+#define ITCT_HDR_VALID_MSK (0x1 << ITCT_HDR_VALID_OFF)
+#define ITCT_HDR_MCR_OFF   5
+#define ITCT_HDR_MCR_MSK   (0xf << ITCT_HDR_MCR_OFF)
+#define ITCT_HDR_VLN_OFF   9
+#define ITCT_HDR_VLN_MSK   (0xf << ITCT_HDR_VLN_OFF)
+#define ITCT_HDR_SMP_TIMEOUT_OFF   16
+#define ITCT_HDR_AWT_CONTINUE_OFF  25
+#define ITCT_HDR_PORT_ID_OFF   28
+#define ITCT_HDR_PORT_ID_MSK   (0xf << ITCT_HDR_PORT_ID_OFF)
+/* qw2 */
+#define ITCT_HDR_INLT_OFF  0
+#define ITCT_HDR_INLT_MSK  (0xULL << ITCT_HDR_INLT_OFF)
+#define ITCT_HDR_RTOLT_OFF 48
+#define ITCT_HDR_RTOLT_MSK (0xULL << ITCT_HDR_RTOLT_OFF)
+
 struct hisi_sas_complete_v3_hdr {
__le32 dw0;
__le32 dw1;
@@ -460,6 +485,93 @@ static void config_id_frame_v3_hw(struct hisi_hba 
*hisi_hba, int phy_no)
__swab32(identify_buffer[5]));
 }
 
+static void setup_itct_v3_hw(struct hisi_hba *hisi_hba,
+struct hisi_sas_device *sas_dev)
+{
+   struct domain_device *device = sas_dev->sas_device;
+   struct device *dev = hisi_hba->dev;
+   u64 qw0, device_id = sas_dev->device_id;
+   struct hisi_sas_itct *itct = _hba->itct[device_id];
+   struct domain_device *parent_dev = device->parent;
+   struct asd_sas_port *sas_port = device->port;
+   struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
+
+   memset(itct, 0, sizeof(*itct));
+
+   /* qw0 */
+   qw0 = 0;
+   switch (sas_dev->dev_type) {
+   case SAS_END_DEVICE:
+   case SAS_EDGE_EXPANDER_DEVICE:
+   case SAS_FANOUT_EXPANDER_DEVICE:
+   qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF;
+   break;
+   case SAS_SATA_DEV:
+   case SAS_SATA_PENDING:
+   if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+   qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF;
+   else
+   qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF;
+   break;
+   default:
+   dev_warn(dev, "setup itct: unsupported dev type (%d)\n",
+sas_dev->dev_type);
+   }
+
+   qw0 |= ((1 << ITCT_HDR_VALID_OFF) |
+   (device->linkrate << ITCT_HDR_MCR_OFF) |
+   (1 << ITCT_HDR_VLN_OFF) |
+   (0xfa << ITCT_HDR_SMP_TIMEOUT_OFF) |
+   (1 << ITCT_HDR_AWT_CONTINUE_OFF) |
+   (port->id << ITCT_HDR_PORT_ID_OFF));
+   itct->qw0 = cpu_to_le64(qw0);
+
+   /* qw1 */
+   memcpy(>sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+   itct->sas_addr = __swab64(itct->sas_addr);
+
+   /* qw2 */
+   if (!dev_is_sata(device))
+   itct->qw2 = cpu_to_le64((5000ULL << ITCT_HDR_INLT_OFF) |
+   (0x1ULL << ITCT_HDR_RTOLT_OFF));
+}
+
+static void free_device_v3_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+   u64 dev_id = sas_dev->device_id;
+   struct device *dev = hisi_hba->dev;
+   struct hisi_sas_itct *itct = _hba->itct[dev_id];
+   u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
+
+   /* clear the itct interrupt state */
+   if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
+   hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
+ENT_INT_SRC3_ITC_INT_MSK);
+
+   /* clear the itct table*/
+   reg_val = hisi_sas_read32(hisi_hba, 

[PATCH v6 17/22] scsi: hisi_sas: add v3 code to send ATA frame

2017-06-14 Thread John Garry
From: Xiang Chen 

Add code to prepare ATA frame for v3 hw

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 106 +
 1 file changed, 106 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 515f50c..30c103b 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -171,8 +171,11 @@
 #define CMD_HDR_CMD_OFF29
 #define CMD_HDR_CMD_MSK(0x7 << CMD_HDR_CMD_OFF)
 /* dw1 */
+#define CMD_HDR_UNCON_CMD_OFF  3
 #define CMD_HDR_DIR_OFF5
 #define CMD_HDR_DIR_MSK(0x3 << CMD_HDR_DIR_OFF)
+#define CMD_HDR_RESET_OFF  7
+#define CMD_HDR_RESET_MSK  (0x1 << CMD_HDR_RESET_OFF)
 #define CMD_HDR_VDTL_OFF   10
 #define CMD_HDR_VDTL_MSK   (0x1 << CMD_HDR_VDTL_OFF)
 #define CMD_HDR_FRAME_TYPE_OFF 11
@@ -182,6 +185,8 @@
 /* dw2 */
 #define CMD_HDR_CFL_OFF0
 #define CMD_HDR_CFL_MSK(0x1ff << CMD_HDR_CFL_OFF)
+#define CMD_HDR_NCQ_TAG_OFF10
+#define CMD_HDR_NCQ_TAG_MSK(0x1f << CMD_HDR_NCQ_TAG_OFF)
 #define CMD_HDR_MRFL_OFF   15
 #define CMD_HDR_MRFL_MSK   (0x1ff << CMD_HDR_MRFL_OFF)
 #define CMD_HDR_SG_MOD_OFF 24
@@ -260,6 +265,11 @@ enum {
 #define DIR_TO_DEVICE 2
 #define DIR_RESERVED 3
 
+#define CMD_IS_UNCONSTRAINT(cmd) \
+   ((cmd == ATA_CMD_READ_LOG_EXT) || \
+   (cmd == ATA_CMD_READ_LOG_DMA_EXT) || \
+   (cmd == ATA_CMD_DEV_RESET))
+
 static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
 {
void __iomem *regs = hisi_hba->regs + off;
@@ -725,6 +735,101 @@ static int prep_smp_v3_hw(struct hisi_hba *hisi_hba,
return rc;
 }
 
+static int get_ncq_tag_v3_hw(struct sas_task *task, u32 *tag)
+{
+   struct ata_queued_cmd *qc = task->uldd_task;
+
+   if (qc) {
+   if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+   qc->tf.command == ATA_CMD_FPDMA_READ) {
+   *tag = qc->tag;
+   return 1;
+   }
+   }
+   return 0;
+}
+
+static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+   struct sas_task *task = slot->task;
+   struct domain_device *device = task->dev;
+   struct domain_device *parent_dev = device->parent;
+   struct hisi_sas_device *sas_dev = device->lldd_dev;
+   struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+   struct asd_sas_port *sas_port = device->port;
+   struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
+   u8 *buf_cmd;
+   int has_data = 0, rc = 0, hdr_tag = 0;
+   u32 dw1 = 0, dw2 = 0;
+
+   hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
+   if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type))
+   hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF);
+   else
+   hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF);
+
+   switch (task->data_dir) {
+   case DMA_TO_DEVICE:
+   has_data = 1;
+   dw1 |= DIR_TO_DEVICE << CMD_HDR_DIR_OFF;
+   break;
+   case DMA_FROM_DEVICE:
+   has_data = 1;
+   dw1 |= DIR_TO_INI << CMD_HDR_DIR_OFF;
+   break;
+   default:
+   dw1 &= ~CMD_HDR_DIR_MSK;
+   }
+
+   if ((task->ata_task.fis.command == ATA_CMD_DEV_RESET) &&
+   (task->ata_task.fis.control & ATA_SRST))
+   dw1 |= 1 << CMD_HDR_RESET_OFF;
+
+   dw1 |= (hisi_sas_get_ata_protocol(
+   task->ata_task.fis.command, task->data_dir))
+   << CMD_HDR_FRAME_TYPE_OFF;
+   dw1 |= sas_dev->device_id << CMD_HDR_DEV_ID_OFF;
+
+   if (CMD_IS_UNCONSTRAINT(task->ata_task.fis.command))
+   dw1 |= 1 << CMD_HDR_UNCON_CMD_OFF;
+
+   hdr->dw1 = cpu_to_le32(dw1);
+
+   /* dw2 */
+   if (task->ata_task.use_ncq && get_ncq_tag_v3_hw(task, _tag)) {
+   task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
+   dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF;
+   }
+
+   dw2 |= (HISI_SAS_MAX_STP_RESP_SZ / 4) << CMD_HDR_CFL_OFF |
+   2 << CMD_HDR_SG_MOD_OFF;
+   hdr->dw2 = cpu_to_le32(dw2);
+
+   /* dw3 */
+   hdr->transfer_tags = cpu_to_le32(slot->idx);
+
+   if (has_data) {
+   rc = prep_prd_sge_v3_hw(hisi_hba, slot, hdr, task->scatter,
+   slot->n_elem);
+   if (rc)
+   return rc;
+   }
+
+   hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+   hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+   

[PATCH v6 11/22] scsi: hisi_sas: add v3 hw init

2017-06-14 Thread John Garry
From: Xiang Chen 

Add code to initialise v3 hardware.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 277 +
 1 file changed, 277 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index e9a9fb0..1a5eae6 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -11,7 +11,283 @@
 #include "hisi_sas.h"
 #define DRV_NAME "hisi_sas_v3_hw"
 
+/* global registers need init*/
+#define DLVRY_QUEUE_ENABLE 0x0
+#define IOST_BASE_ADDR_LO  0x8
+#define IOST_BASE_ADDR_HI  0xc
+#define ITCT_BASE_ADDR_LO  0x10
+#define ITCT_BASE_ADDR_HI  0x14
+#define IO_BROKEN_MSG_ADDR_LO  0x18
+#define IO_BROKEN_MSG_ADDR_HI  0x1c
+#define AXI_AHB_CLK_CFG0x3c
+#define AXI_USER1  0x48
+#define AXI_USER2  0x4c
+#define IO_SATA_BROKEN_MSG_ADDR_LO 0x58
+#define IO_SATA_BROKEN_MSG_ADDR_HI 0x5c
+#define SATA_INITI_D2H_STORE_ADDR_LO   0x60
+#define SATA_INITI_D2H_STORE_ADDR_HI   0x64
+#define CFG_MAX_TAG0x68
+#define HGC_SAS_TX_OPEN_FAIL_RETRY_CTRL0x84
+#define HGC_SAS_TXFAIL_RETRY_CTRL  0x88
+#define HGC_GET_ITV_TIME   0x90
+#define DEVICE_MSG_WORK_MODE   0x94
+#define OPENA_WT_CONTI_TIME0x9c
+#define I_T_NEXUS_LOSS_TIME0xa0
+#define MAX_CON_TIME_LIMIT_TIME0xa4
+#define BUS_INACTIVE_LIMIT_TIME0xa8
+#define REJECT_TO_OPEN_LIMIT_TIME  0xac
+#define CFG_AGING_TIME 0xbc
+#define HGC_DFX_CFG2   0xc0
+#define CFG_ABT_SET_QUERY_IPTT 0xd4
+#define CFG_SET_ABORTED_IPTT_OFF   0
+#define CFG_SET_ABORTED_IPTT_MSK   (0xfff << CFG_SET_ABORTED_IPTT_OFF)
+#define CFG_1US_TIMER_TRSH 0xcc
+#define INT_COAL_EN0x19c
+#define OQ_INT_COAL_TIME   0x1a0
+#define OQ_INT_COAL_CNT0x1a4
+#define ENT_INT_COAL_TIME  0x1a8
+#define ENT_INT_COAL_CNT   0x1ac
+#define OQ_INT_SRC 0x1b0
+#define OQ_INT_SRC_MSK 0x1b4
+#define ENT_INT_SRC1   0x1b8
+#define ENT_INT_SRC1_D2H_FIS_CH0_OFF   0
+#define ENT_INT_SRC1_D2H_FIS_CH0_MSK   (0x1 << ENT_INT_SRC1_D2H_FIS_CH0_OFF)
+#define ENT_INT_SRC1_D2H_FIS_CH1_OFF   8
+#define ENT_INT_SRC1_D2H_FIS_CH1_MSK   (0x1 << ENT_INT_SRC1_D2H_FIS_CH1_OFF)
+#define ENT_INT_SRC2   0x1bc
+#define ENT_INT_SRC3   0x1c0
+#define ENT_INT_SRC3_WP_DEPTH_OFF  8
+#define ENT_INT_SRC3_IPTT_SLOT_NOMATCH_OFF 9
+#define ENT_INT_SRC3_RP_DEPTH_OFF  10
+#define ENT_INT_SRC3_AXI_OFF   11
+#define ENT_INT_SRC3_FIFO_OFF  12
+#define ENT_INT_SRC3_LM_OFF14
+#define ENT_INT_SRC3_ITC_INT_OFF   15
+#define ENT_INT_SRC3_ITC_INT_MSK   (0x1 << ENT_INT_SRC3_ITC_INT_OFF)
+#define ENT_INT_SRC3_ABT_OFF   16
+#define ENT_INT_SRC_MSK1   0x1c4
+#define ENT_INT_SRC_MSK2   0x1c8
+#define ENT_INT_SRC_MSK3   0x1cc
+#define CHNL_PHYUPDOWN_INT_MSK 0x1d0
+#define CHNL_ENT_INT_MSK   0x1d4
+#define HGC_COM_INT_MSK0x1d8
+#define SAS_ECC_INTR   0x1e8
+#define SAS_ECC_INTR_MSK   0x1ec
+#define HGC_ERR_STAT_EN0x238
+#define DLVRY_Q_0_BASE_ADDR_LO 0x260
+#define DLVRY_Q_0_BASE_ADDR_HI 0x264
+#define DLVRY_Q_0_DEPTH0x268
+#define DLVRY_Q_0_WR_PTR   0x26c
+#define DLVRY_Q_0_RD_PTR   0x270
+#define HYPER_STREAM_ID_EN_CFG 0xc80
+#define OQ0_INT_SRC_MSK0xc90
+#define COMPL_Q_0_BASE_ADDR_LO 0x4e0
+#define COMPL_Q_0_BASE_ADDR_HI 0x4e4
+#define COMPL_Q_0_DEPTH0x4e8
+#define COMPL_Q_0_WR_PTR   0x4ec
+#define COMPL_Q_0_RD_PTR   0x4f0
+#define AWQOS_AWCACHE_CFG  0xc84
+#define ARQOS_ARCACHE_CFG  0xc88
+
+/* phy registers requiring init */
+#define PORT_BASE  (0x2000)
+#define PROG_PHY_LINK_RATE (PORT_BASE + 0x8)
+#define PHY_CTRL   (PORT_BASE + 0x14)
+#define PHY_CTRL_RESET_OFF 0
+#define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
+#define SL_CFG (PORT_BASE + 0x84)
+#define RXOP_CHECK_CFG_H   (PORT_BASE + 0xfc)
+#define SAS_SSP_CON_TIMER_CFG  (PORT_BASE + 0x134)
+#define SAS_SMP_CON_TIMER_CFG  (PORT_BASE + 0x138)
+#define SAS_STP_CON_TIMER_CFG  (PORT_BASE + 0x13c)
+#define CHL_INT0   (PORT_BASE + 0x1b4)
+#define 

[PATCH v6 08/22] scsi: hisi_sas: create hisi_sas_get_fw_info()

2017-06-14 Thread John Garry
Move the functionality to retrieve the fw info into
a dedicated device type-agnostic function,
hisi_sas_get_fw_info().

The reasoning is that this function will be required
for future pci-based platforms.

Also add some debug logs for failure.

Signed-off-by: John Garry 
---
 drivers/scsi/hisi_sas/hisi_sas.h  |   1 +
 drivers/scsi/hisi_sas/hisi_sas_main.c | 107 ++
 2 files changed, 71 insertions(+), 37 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 84cac98..c1f6669 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -371,6 +371,7 @@ struct hisi_sas_command_table_ssp {
 extern void hisi_sas_sata_done(struct sas_task *task,
struct hisi_sas_slot *slot);
 extern int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag);
+extern int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba);
 extern int hisi_sas_probe(struct platform_device *pdev,
  const struct hisi_sas_hw *ops);
 extern int hisi_sas_remove(struct platform_device *pdev);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 139df45..81c053c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1729,66 +1729,99 @@ static void hisi_sas_rst_work_handler(struct 
work_struct *work)
hisi_sas_controller_reset(hisi_hba);
 }
 
-static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
- const struct hisi_sas_hw *hw)
+int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba)
 {
-   struct resource *res;
-   struct Scsi_Host *shost;
-   struct hisi_hba *hisi_hba;
-   struct device *dev = >dev;
-   struct device_node *np = pdev->dev.of_node;
+   struct device *dev = hisi_hba->dev;
+   struct platform_device *pdev = hisi_hba->platform_dev;
+   struct device_node *np = pdev ? pdev->dev.of_node : NULL;
struct clk *refclk;
 
-   shost = scsi_host_alloc(_sas_sht, sizeof(*hisi_hba));
-   if (!shost) {
-   dev_err(dev, "scsi host alloc failed\n");
-   return NULL;
-   }
-   hisi_hba = shost_priv(shost);
-
-   INIT_WORK(_hba->rst_work, hisi_sas_rst_work_handler);
-   hisi_hba->hw = hw;
-   hisi_hba->platform_dev = pdev;
-   hisi_hba->dev = dev;
-   hisi_hba->shost = shost;
-   SHOST_TO_SAS_HA(shost) = _hba->sha;
-
-   init_timer(_hba->timer);
-
if (device_property_read_u8_array(dev, "sas-addr", hisi_hba->sas_addr,
- SAS_ADDR_SIZE))
-   goto err_out;
+ SAS_ADDR_SIZE)) {
+   dev_err(dev, "could not get property sas-addr\n");
+   return -ENOENT;
+   }
 
if (np) {
+   /*
+* These properties are only required for platform device-based
+* controller with DT firmware.
+*/
hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(np,
"hisilicon,sas-syscon");
-   if (IS_ERR(hisi_hba->ctrl))
-   goto err_out;
+   if (IS_ERR(hisi_hba->ctrl)) {
+   dev_err(dev, "could not get syscon\n");
+   return -ENOENT;
+   }
 
if (device_property_read_u32(dev, "ctrl-reset-reg",
-_hba->ctrl_reset_reg))
-   goto err_out;
+_hba->ctrl_reset_reg)) {
+   dev_err(dev,
+   "could not get property ctrl-reset-reg\n");
+   return -ENOENT;
+   }
 
if (device_property_read_u32(dev, "ctrl-reset-sts-reg",
-_hba->ctrl_reset_sts_reg))
-   goto err_out;
+_hba->ctrl_reset_sts_reg)) {
+   dev_err(dev,
+   "could not get property ctrl-reset-sts-reg\n");
+   return -ENOENT;
+   }
 
if (device_property_read_u32(dev, "ctrl-clock-ena-reg",
-_hba->ctrl_clock_ena_reg))
-   goto err_out;
+_hba->ctrl_clock_ena_reg)) {
+   dev_err(dev,
+   "could not get property ctrl-clock-ena-reg\n");
+   return -ENOENT;
+   }
}
 
-   refclk = devm_clk_get(>dev, NULL);
+   refclk = devm_clk_get(dev, NULL);
if (IS_ERR(refclk))
dev_dbg(dev, "no ref clk property\n");
else

[PATCH v6 04/22] scsi: hisi_sas: relocate get_ata_protocol()

2017-06-14 Thread John Garry
From: Xiang Chen 

Relocate get_ata_protocol() to a common location, as future
hw versions will require it.
Also rename with "hisi_sas_" prefix for consistency.

Signed-off-by: Xiang Chen 
Signed-off-by: John Garry 
---
 drivers/scsi/hisi_sas/hisi_sas.h   |  7 
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 59 ++
 drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 67 +-
 3 files changed, 68 insertions(+), 65 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 68ba7bd..a50c699 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -46,6 +46,12 @@
((type == SAS_EDGE_EXPANDER_DEVICE) || \
(type == SAS_FANOUT_EXPANDER_DEVICE))
 
+#define HISI_SAS_SATA_PROTOCOL_NONDATA 0x1
+#define HISI_SAS_SATA_PROTOCOL_PIO 0x2
+#define HISI_SAS_SATA_PROTOCOL_DMA 0x4
+#define HISI_SAS_SATA_PROTOCOL_FPDMA   0x8
+#define HISI_SAS_SATA_PROTOCOL_ATAPI   0x10
+
 struct hisi_hba;
 
 enum {
@@ -356,6 +362,7 @@ struct hisi_sas_command_table_ssp {
struct hisi_sas_command_table_stp stp;
 };
 
+extern u8 hisi_sas_get_ata_protocol(u8 cmd, int direction);
 extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port);
 extern int hisi_sas_probe(struct platform_device *pdev,
  const struct hisi_sas_hw *ops);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 4e78cbc..5b51d9a 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -23,6 +23,65 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device 
*device,
 int abort_flag, int tag);
 static int hisi_sas_softreset_ata_disk(struct domain_device *device);
 
+u8 hisi_sas_get_ata_protocol(u8 cmd, int direction)
+{
+   switch (cmd) {
+   case ATA_CMD_FPDMA_WRITE:
+   case ATA_CMD_FPDMA_READ:
+   case ATA_CMD_FPDMA_RECV:
+   case ATA_CMD_FPDMA_SEND:
+   case ATA_CMD_NCQ_NON_DATA:
+   return HISI_SAS_SATA_PROTOCOL_FPDMA;
+
+   case ATA_CMD_DOWNLOAD_MICRO:
+   case ATA_CMD_ID_ATA:
+   case ATA_CMD_PMP_READ:
+   case ATA_CMD_READ_LOG_EXT:
+   case ATA_CMD_PIO_READ:
+   case ATA_CMD_PIO_READ_EXT:
+   case ATA_CMD_PMP_WRITE:
+   case ATA_CMD_WRITE_LOG_EXT:
+   case ATA_CMD_PIO_WRITE:
+   case ATA_CMD_PIO_WRITE_EXT:
+   return HISI_SAS_SATA_PROTOCOL_PIO;
+
+   case ATA_CMD_DSM:
+   case ATA_CMD_DOWNLOAD_MICRO_DMA:
+   case ATA_CMD_PMP_READ_DMA:
+   case ATA_CMD_PMP_WRITE_DMA:
+   case ATA_CMD_READ:
+   case ATA_CMD_READ_EXT:
+   case ATA_CMD_READ_LOG_DMA_EXT:
+   case ATA_CMD_READ_STREAM_DMA_EXT:
+   case ATA_CMD_TRUSTED_RCV_DMA:
+   case ATA_CMD_TRUSTED_SND_DMA:
+   case ATA_CMD_WRITE:
+   case ATA_CMD_WRITE_EXT:
+   case ATA_CMD_WRITE_FUA_EXT:
+   case ATA_CMD_WRITE_QUEUED:
+   case ATA_CMD_WRITE_LOG_DMA_EXT:
+   case ATA_CMD_WRITE_STREAM_DMA_EXT:
+   return HISI_SAS_SATA_PROTOCOL_DMA;
+
+   case ATA_CMD_CHK_POWER:
+   case ATA_CMD_DEV_RESET:
+   case ATA_CMD_EDD:
+   case ATA_CMD_FLUSH:
+   case ATA_CMD_FLUSH_EXT:
+   case ATA_CMD_VERIFY:
+   case ATA_CMD_VERIFY_EXT:
+   case ATA_CMD_SET_FEATURES:
+   case ATA_CMD_STANDBY:
+   case ATA_CMD_STANDBYNOW1:
+   return HISI_SAS_SATA_PROTOCOL_NONDATA;
+   default:
+   if (direction == DMA_NONE)
+   return HISI_SAS_SATA_PROTOCOL_NONDATA;
+   return HISI_SAS_SATA_PROTOCOL_PIO;
+   }
+}
+EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol);
+
 static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
 {
return device->port->ha->lldd_ha;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
index 2607aac..d9314c4 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c
@@ -554,12 +554,6 @@ enum {
 #define DIR_TO_DEVICE 2
 #define DIR_RESERVED 3
 
-#define SATA_PROTOCOL_NONDATA  0x1
-#define SATA_PROTOCOL_PIO  0x2
-#define SATA_PROTOCOL_DMA  0x4
-#define SATA_PROTOCOL_FPDMA0x8
-#define SATA_PROTOCOL_ATAPI0x10
-
 #define ERR_ON_TX_PHASE(err_phase) (err_phase == 0x2 || \
err_phase == 0x4 || err_phase == 0x8 ||\
err_phase == 0x6 || err_phase == 0xa)
@@ -2352,64 +2346,6 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba,
return sts;
 }
 
-static u8 get_ata_protocol(u8 cmd, int direction)
-{
-   switch (cmd) {
-   case ATA_CMD_FPDMA_WRITE:
-   case ATA_CMD_FPDMA_READ:
-   case ATA_CMD_FPDMA_RECV:
-   case ATA_CMD_FPDMA_SEND:
-   case ATA_CMD_NCQ_NON_DATA:
-   

[PATCH v6 22/22] scsi: hisi_sas: modify internal abort dev flow for v3 hw

2017-06-14 Thread John Garry
From: Xiang Chen 

There is a change for abort dev for v3 hw: add registers to configure
unaborted iptt for a device, and then inform this to logic.

Signed-off-by: Xiang Chen 
Signed-off-by: John Garry 
---
 drivers/scsi/hisi_sas/hisi_sas.h   |  2 ++
 drivers/scsi/hisi_sas/hisi_sas_main.c  | 15 +++
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 28 
 3 files changed, 45 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index e89f6ae..4fc2308 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -188,6 +188,8 @@ struct hisi_sas_hw {
void (*free_device)(struct hisi_hba *hisi_hba,
struct hisi_sas_device *dev);
int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id);
+   void (*dereg_device)(struct hisi_hba *hisi_hba,
+   struct domain_device *device);
int (*soft_reset)(struct hisi_hba *hisi_hba);
int max_command_entries;
int complete_hdr_size;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 0a32211..0e2db9a 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -727,6 +727,13 @@ static void hisi_sas_release_tasks(struct hisi_hba 
*hisi_hba)
}
 }
 
+static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba,
+   struct domain_device *device)
+{
+   if (hisi_hba->hw->dereg_device)
+   hisi_hba->hw->dereg_device(hisi_hba, device);
+}
+
 static void hisi_sas_dev_gone(struct domain_device *device)
 {
struct hisi_sas_device *sas_dev = device->lldd_dev;
@@ -740,6 +747,8 @@ static void hisi_sas_dev_gone(struct domain_device *device)
hisi_sas_internal_task_abort(hisi_hba, device,
 HISI_SAS_INT_ABT_DEV, 0);
 
+   hisi_sas_dereg_device(hisi_hba, device);
+
hisi_hba->hw->free_device(hisi_hba, sas_dev);
device->lldd_dev = NULL;
memset(sas_dev, 0, sizeof(*sas_dev));
@@ -1071,6 +1080,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
if (task->dev->dev_type == SAS_SATA_DEV) {
hisi_sas_internal_task_abort(hisi_hba, device,
 HISI_SAS_INT_ABT_DEV, 0);
+   hisi_sas_dereg_device(hisi_hba, device);
rc = hisi_sas_softreset_ata_disk(device);
}
} else if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SMP) {
@@ -1137,6 +1147,10 @@ static int hisi_sas_I_T_nexus_reset(struct domain_device 
*device)
return TMF_RESP_FUNC_FAILED;
sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
 
+   hisi_sas_internal_task_abort(hisi_hba, device,
+   HISI_SAS_INT_ABT_DEV, 0);
+   hisi_sas_dereg_device(hisi_hba, device);
+
rc = hisi_sas_debug_I_T_nexus_reset(device);
 
if (rc == TMF_RESP_FUNC_COMPLETE) {
@@ -1164,6 +1178,7 @@ static int hisi_sas_lu_reset(struct domain_device 
*device, u8 *lun)
  HISI_SAS_INT_ABT_DEV, 0);
if (rc == TMF_RESP_FUNC_FAILED)
goto out;
+   hisi_sas_dereg_device(hisi_hba, device);
 
phy = sas_get_local_phy(device);
 
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index cf1eb47..c998b81 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -50,6 +50,10 @@
 #define CFG_ABT_SET_QUERY_IPTT 0xd4
 #define CFG_SET_ABORTED_IPTT_OFF   0
 #define CFG_SET_ABORTED_IPTT_MSK   (0xfff << CFG_SET_ABORTED_IPTT_OFF)
+#define CFG_SET_ABORTED_EN_OFF 12
+#define CFG_ABT_SET_IPTT_DONE  0xd8
+#define CFG_ABT_SET_IPTT_DONE_OFF  0
+#define HGC_IOMB_PROC1_STATUS  0x104
 #define CFG_1US_TIMER_TRSH 0xcc
 #define CHNL_INT_STATUS0x148
 #define INT_COAL_EN0x19c
@@ -583,6 +587,29 @@ static void free_device_v3_hw(struct hisi_hba *hisi_hba,
}
 }
 
+static void dereg_device_v3_hw(struct hisi_hba *hisi_hba,
+   struct domain_device *device)
+{
+   struct hisi_sas_slot *slot, *slot2;
+   struct hisi_sas_device *sas_dev = device->lldd_dev;
+   u32 cfg_abt_set_query_iptt;
+
+   cfg_abt_set_query_iptt = hisi_sas_read32(hisi_hba,
+   CFG_ABT_SET_QUERY_IPTT);
+   list_for_each_entry_safe(slot, slot2, _dev->list, entry) {
+   cfg_abt_set_query_iptt &= ~CFG_SET_ABORTED_IPTT_MSK;
+   cfg_abt_set_query_iptt |= (1 << CFG_SET_ABORTED_EN_OFF) |
+   (slot->idx << CFG_SET_ABORTED_IPTT_OFF);
+   

[PATCH v6 10/22] scsi: hisi_sas: add initialisation for v3 pci-based controller

2017-06-14 Thread John Garry
Add the code to initialise the controller which is based on pci
device in hisi_sas_v3_hw.c

The core controller routines are still in hisi_sas_main.c; some
common initialisation functions are also exported from
hisi_sas_main.c

For pci-based controller, the device properties, like
phy count and sas address are read from the firmware,
same as platform device-based controller.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas.h   |   6 ++
 drivers/scsi/hisi_sas/hisi_sas_main.c  |  18 ++--
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 154 +
 3 files changed, 172 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index c1f6669..e89f6ae 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -366,6 +366,12 @@ struct hisi_sas_command_table_ssp {
struct hisi_sas_command_table_stp stp;
 };
 
+extern struct scsi_transport_template *hisi_sas_stt;
+extern struct scsi_host_template *hisi_sas_sht;
+
+extern void hisi_sas_init_add(struct hisi_hba *hisi_hba);
+extern int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost);
+extern void hisi_sas_free(struct hisi_hba *hisi_hba);
 extern u8 hisi_sas_get_ata_protocol(u8 cmd, int direction);
 extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port);
 extern void hisi_sas_sata_done(struct sas_task *task,
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 81c053c..0a32211 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -1476,9 +1476,10 @@ void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, 
u32 old_state,
 }
 EXPORT_SYMBOL_GPL(hisi_sas_rescan_topology);
 
-static struct scsi_transport_template *hisi_sas_stt;
+struct scsi_transport_template *hisi_sas_stt;
+EXPORT_SYMBOL_GPL(hisi_sas_stt);
 
-static struct scsi_host_template hisi_sas_sht = {
+static struct scsi_host_template _hisi_sas_sht = {
.module = THIS_MODULE,
.name   = DRV_NAME,
.queuecommand   = sas_queuecommand,
@@ -1498,6 +1499,8 @@ void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, 
u32 old_state,
.target_destroy = sas_target_destroy,
.ioctl  = sas_ioctl,
 };
+struct scsi_host_template *hisi_sas_sht = &_hisi_sas_sht;
+EXPORT_SYMBOL_GPL(hisi_sas_sht);
 
 static struct sas_domain_function_template hisi_sas_transport_ops = {
.lldd_dev_found = hisi_sas_dev_found,
@@ -1545,7 +1548,7 @@ void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
 }
 EXPORT_SYMBOL_GPL(hisi_sas_init_mem);
 
-static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
 {
struct device *dev = hisi_hba->dev;
int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
@@ -1664,8 +1667,9 @@ static int hisi_sas_alloc(struct hisi_hba *hisi_hba, 
struct Scsi_Host *shost)
 err_out:
return -ENOMEM;
 }
+EXPORT_SYMBOL_GPL(hisi_sas_alloc);
 
-static void hisi_sas_free(struct hisi_hba *hisi_hba)
+void hisi_sas_free(struct hisi_hba *hisi_hba)
 {
struct device *dev = hisi_hba->dev;
int i, s, max_command_entries = hisi_hba->hw->max_command_entries;
@@ -1720,6 +1724,7 @@ static void hisi_sas_free(struct hisi_hba *hisi_hba)
if (hisi_hba->wq)
destroy_workqueue(hisi_hba->wq);
 }
+EXPORT_SYMBOL_GPL(hisi_sas_free);
 
 static void hisi_sas_rst_work_handler(struct work_struct *work)
 {
@@ -1805,7 +1810,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct 
platform_device *pdev,
struct hisi_hba *hisi_hba;
struct device *dev = >dev;
 
-   shost = scsi_host_alloc(_sas_sht, sizeof(*hisi_hba));
+   shost = scsi_host_alloc(hisi_sas_sht, sizeof(*hisi_hba));
if (!shost) {
dev_err(dev, "scsi host alloc failed\n");
return NULL;
@@ -1847,7 +1852,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct 
platform_device *pdev,
return NULL;
 }
 
-static void hisi_sas_init_add(struct hisi_hba *hisi_hba)
+void hisi_sas_init_add(struct hisi_hba *hisi_hba)
 {
int i;
 
@@ -1856,6 +1861,7 @@ static void hisi_sas_init_add(struct hisi_hba *hisi_hba)
   hisi_hba->sas_addr,
   SAS_ADDR_SIZE);
 }
+EXPORT_SYMBOL_GPL(hisi_sas_init_add);
 
 int hisi_sas_probe(struct platform_device *pdev,
 const struct hisi_sas_hw *hw)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index cf72577..e9a9fb0 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -11,14 +11,168 @@
 #include "hisi_sas.h"
 #define DRV_NAME "hisi_sas_v3_hw"
 
+static const 

[PATCH v6 02/22] scsi: hisi_sas: define hisi_sas_device.device_id as int

2017-06-14 Thread John Garry
Currently hisi_sas_device.device_id is a u64. This can create a
problem in selecting the queue for a device, in that this code
does a 64b division on device id. For some 32b systems, 64b division
is slow and the lib reference must be explicitly included.

The device id does not need to be 64b in size, so, as a solution,
just make as an int.

Also, struct hisi_sas_device elements are re-ordered to improve
packing efficiency.

Signed-off-by: John Garry 
---
 drivers/scsi/hisi_sas/hisi_sas.h  |  8 
 drivers/scsi/hisi_sas/hisi_sas_main.c | 10 +-
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 4e28f32..b4e96fa9 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -107,15 +107,15 @@ struct hisi_sas_dq {
 };
 
 struct hisi_sas_device {
-   enum sas_device_typedev_type;
struct hisi_hba *hisi_hba;
struct domain_device*sas_device;
+   struct list_headlist;
u64 attached_phy;
-   u64 device_id;
atomic64_t running_req;
-   struct list_headlist;
-   u8 dev_status;
+   enum sas_device_typedev_type;
+   int device_id;
int sata_idx;
+   u8 dev_status;
 };
 
 struct hisi_sas_slot {
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 3605d28..54e0cf2 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -209,7 +209,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct 
hisi_hba *hisi_hba,
 
if (DEV_IS_GONE(sas_dev)) {
if (sas_dev)
-   dev_info(dev, "task prep: device %llu not ready\n",
+   dev_info(dev, "task prep: device %d not ready\n",
 sas_dev->device_id);
else
dev_info(dev, "task prep: device %016llx not ready\n",
@@ -627,9 +627,9 @@ static void hisi_sas_dev_gone(struct domain_device *device)
struct hisi_sas_device *sas_dev = device->lldd_dev;
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
struct device *dev = _hba->pdev->dev;
-   u64 dev_id = sas_dev->device_id;
+   int dev_id = sas_dev->device_id;
 
-   dev_info(dev, "found dev[%lld:%x] is gone\n",
+   dev_info(dev, "found dev[%d:%x] is gone\n",
 sas_dev->device_id, sas_dev->dev_type);
 
hisi_sas_internal_task_abort(hisi_hba, device,
@@ -1082,7 +1082,7 @@ static int hisi_sas_lu_reset(struct domain_device 
*device, u8 *lun)
}
 out:
if (rc != TMF_RESP_FUNC_COMPLETE)
-   dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n",
+   dev_err(dev, "lu_reset: for device[%d]:rc= %d\n",
 sas_dev->device_id, rc);
return rc;
 }
@@ -1129,7 +1129,7 @@ static int hisi_sas_query_task(struct sas_task *task)
 }
 
 static int
-hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id,
+hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
  struct sas_task *task, int abort_flag,
  int task_tag)
 {
-- 
1.9.1



[PATCH v6 12/22] scsi: hisi_sas: add v3 hw PHY init

2017-06-14 Thread John Garry
From: Xiang Chen 

Add code to configure PHYs for v3 hw.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 127 -
 1 file changed, 126 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 1a5eae6..5580250 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -19,6 +19,10 @@
 #define ITCT_BASE_ADDR_HI  0x14
 #define IO_BROKEN_MSG_ADDR_LO  0x18
 #define IO_BROKEN_MSG_ADDR_HI  0x1c
+#define PHY_CONTEXT0x20
+#define PHY_STATE  0x24
+#define PHY_PORT_NUM_MA0x28
+#define PHY_CONN_RATE  0x30
 #define AXI_AHB_CLK_CFG0x3c
 #define AXI_USER1  0x48
 #define AXI_USER2  0x4c
@@ -42,6 +46,7 @@
 #define CFG_SET_ABORTED_IPTT_OFF   0
 #define CFG_SET_ABORTED_IPTT_MSK   (0xfff << CFG_SET_ABORTED_IPTT_OFF)
 #define CFG_1US_TIMER_TRSH 0xcc
+#define CHNL_INT_STATUS0x148
 #define INT_COAL_EN0x19c
 #define OQ_INT_COAL_TIME   0x1a0
 #define OQ_INT_COAL_CNT0x1a4
@@ -68,9 +73,11 @@
 #define ENT_INT_SRC_MSK1   0x1c4
 #define ENT_INT_SRC_MSK2   0x1c8
 #define ENT_INT_SRC_MSK3   0x1cc
+#define ENT_INT_SRC_MSK3_ENT95_MSK_OFF 31
 #define CHNL_PHYUPDOWN_INT_MSK 0x1d0
 #define CHNL_ENT_INT_MSK   0x1d4
 #define HGC_COM_INT_MSK0x1d8
+#define ENT_INT_SRC_MSK3_ENT95_MSK_MSK (0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF)
 #define SAS_ECC_INTR   0x1e8
 #define SAS_ECC_INTR_MSK   0x1ec
 #define HGC_ERR_STAT_EN0x238
@@ -91,11 +98,33 @@
 
 /* phy registers requiring init */
 #define PORT_BASE  (0x2000)
+#define PHY_CFG(PORT_BASE + 0x0)
+#define HARD_PHY_LINKRATE  (PORT_BASE + 0x4)
+#define PHY_CFG_ENA_OFF0
+#define PHY_CFG_ENA_MSK(0x1 << PHY_CFG_ENA_OFF)
+#define PHY_CFG_DC_OPT_OFF 2
+#define PHY_CFG_DC_OPT_MSK (0x1 << PHY_CFG_DC_OPT_OFF)
 #define PROG_PHY_LINK_RATE (PORT_BASE + 0x8)
 #define PHY_CTRL   (PORT_BASE + 0x14)
 #define PHY_CTRL_RESET_OFF 0
 #define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
 #define SL_CFG (PORT_BASE + 0x84)
+#define SL_CONTROL (PORT_BASE + 0x94)
+#define SL_CONTROL_NOTIFY_EN_OFF   0
+#define SL_CONTROL_NOTIFY_EN_MSK   (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
+#define SL_CTA_OFF 17
+#define SL_CTA_MSK (0x1 << SL_CTA_OFF)
+#define TX_ID_DWORD0   (PORT_BASE + 0x9c)
+#define TX_ID_DWORD1   (PORT_BASE + 0xa0)
+#define TX_ID_DWORD2   (PORT_BASE + 0xa4)
+#define TX_ID_DWORD3   (PORT_BASE + 0xa8)
+#define TX_ID_DWORD4   (PORT_BASE + 0xaC)
+#define TX_ID_DWORD5   (PORT_BASE + 0xb0)
+#define TX_ID_DWORD6   (PORT_BASE + 0xb4)
+#define TXID_AUTO  (PORT_BASE + 0xb8)
+#define CT3_OFF1
+#define CT3_MSK(0x1 << CT3_OFF)
+#define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
 #define RXOP_CHECK_CFG_H   (PORT_BASE + 0xfc)
 #define SAS_SSP_CON_TIMER_CFG  (PORT_BASE + 0x134)
 #define SAS_SMP_CON_TIMER_CFG  (PORT_BASE + 0x138)
@@ -136,6 +165,13 @@ struct hisi_sas_complete_v3_hdr {
 };
 
 #define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096
+#define HISI_SAS_MSI_COUNT_V3_HW 32
+
+enum {
+   HISI_SAS_PHY_PHY_UPDOWN,
+   HISI_SAS_PHY_CHNL_INT,
+   HISI_SAS_PHY_INT_NR
+};
 
 static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
 {
@@ -152,6 +188,14 @@ static void hisi_sas_phy_write32(struct hisi_hba 
*hisi_hba, int phy_no,
writel(val, regs);
 }
 
+static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
+ int phy_no, u32 off)
+{
+   void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+   return readl(regs);
+}
+
 static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
 {
int i;
@@ -266,6 +310,45 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
 upper_32_bits(hisi_hba->initial_fis_dma));
 }
 
+static void config_phy_opt_mode_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+   u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+   cfg &= ~PHY_CFG_DC_OPT_MSK;
+   cfg |= 1 << PHY_CFG_DC_OPT_OFF;
+   hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+

[PATCH v6 16/22] scsi: hisi_sas: add v3 code to send SMP frame

2017-06-14 Thread John Garry
From: Xiang Chen 

Add code to prepare SMP frame.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 74 ++
 1 file changed, 74 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index c869aca..515f50c 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -186,6 +186,9 @@
 #define CMD_HDR_MRFL_MSK   (0x1ff << CMD_HDR_MRFL_OFF)
 #define CMD_HDR_SG_MOD_OFF 24
 #define CMD_HDR_SG_MOD_MSK (0x3 << CMD_HDR_SG_MOD_OFF)
+/* dw3 */
+#define CMD_HDR_IPTT_OFF   0
+#define CMD_HDR_IPTT_MSK   (0x << CMD_HDR_IPTT_OFF)
 /* dw6 */
 #define CMD_HDR_DIF_SGL_LEN_OFF0
 #define CMD_HDR_DIF_SGL_LEN_MSK(0x << 
CMD_HDR_DIF_SGL_LEN_OFF)
@@ -652,6 +655,76 @@ static int prep_ssp_v3_hw(struct hisi_hba *hisi_hba,
return 0;
 }
 
+static int prep_smp_v3_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+   struct sas_task *task = slot->task;
+   struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+   struct domain_device *device = task->dev;
+   struct device *dev = hisi_hba->dev;
+   struct hisi_sas_port *port = slot->port;
+   struct scatterlist *sg_req, *sg_resp;
+   struct hisi_sas_device *sas_dev = device->lldd_dev;
+   dma_addr_t req_dma_addr;
+   unsigned int req_len, resp_len;
+   int elem, rc;
+
+   /*
+* DMA-map SMP request, response buffers
+*/
+   /* req */
+   sg_req = >smp_task.smp_req;
+   elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
+   if (!elem)
+   return -ENOMEM;
+   req_len = sg_dma_len(sg_req);
+   req_dma_addr = sg_dma_address(sg_req);
+
+   /* resp */
+   sg_resp = >smp_task.smp_resp;
+   elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
+   if (!elem) {
+   rc = -ENOMEM;
+   goto err_out_req;
+   }
+   resp_len = sg_dma_len(sg_resp);
+   if ((req_len & 0x3) || (resp_len & 0x3)) {
+   rc = -EINVAL;
+   goto err_out_resp;
+   }
+
+   /* create header */
+   /* dw0 */
+   hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
+  (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */
+  (2 << CMD_HDR_CMD_OFF)); /* smp */
+
+   /* map itct entry */
+   hdr->dw1 = cpu_to_le32((sas_dev->device_id << CMD_HDR_DEV_ID_OFF) |
+  (1 << CMD_HDR_FRAME_TYPE_OFF) |
+  (DIR_NO_DATA << CMD_HDR_DIR_OFF));
+
+   /* dw2 */
+   hdr->dw2 = cpu_to_le32req_len - 4) / 4) << CMD_HDR_CFL_OFF) |
+  (HISI_SAS_MAX_SMP_RESP_SZ / 4 <<
+  CMD_HDR_MRFL_OFF));
+
+   hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+   hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
+   hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+   return 0;
+
+err_out_resp:
+   dma_unmap_sg(dev, >task->smp_task.smp_resp, 1,
+DMA_FROM_DEVICE);
+err_out_req:
+   dma_unmap_sg(dev, >task->smp_task.smp_req, 1,
+DMA_TO_DEVICE);
+   return rc;
+}
+
 static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
int i, res = 0;
@@ -1225,6 +1298,7 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
.complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
.sl_notify = sl_notify_v3_hw,
.prep_ssp = prep_ssp_v3_hw,
+   .prep_smp = prep_smp_v3_hw,
.get_free_slot = get_free_slot_v3_hw,
.start_delivery = start_delivery_v3_hw,
.slot_complete = slot_complete_v3_hw,
-- 
1.9.1



[PATCH v6 19/22] scsi: hisi_sas: add v3 code to send internal abort command

2017-06-14 Thread John Garry
From: Xiang Chen 

Add code to prepare internal abort command.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 38 ++
 1 file changed, 38 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index b9ab24d..ef5c158 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -165,6 +165,10 @@
 /* HW dma structures */
 /* Delivery queue header */
 /* dw0 */
+#define CMD_HDR_ABORT_FLAG_OFF 0
+#define CMD_HDR_ABORT_FLAG_MSK (0x3 << CMD_HDR_ABORT_FLAG_OFF)
+#define CMD_HDR_ABORT_DEVICE_TYPE_OFF  2
+#define CMD_HDR_ABORT_DEVICE_TYPE_MSK  (0x1 << CMD_HDR_ABORT_DEVICE_TYPE_OFF)
 #define CMD_HDR_RESP_REPORT_OFF5
 #define CMD_HDR_RESP_REPORT_MSK(0x1 << CMD_HDR_RESP_REPORT_OFF)
 #define CMD_HDR_TLR_CTRL_OFF   6
@@ -204,6 +208,11 @@
 #define CMD_HDR_DIF_SGL_LEN_MSK(0x << 
CMD_HDR_DIF_SGL_LEN_OFF)
 #define CMD_HDR_DATA_SGL_LEN_OFF   16
 #define CMD_HDR_DATA_SGL_LEN_MSK   (0x << CMD_HDR_DATA_SGL_LEN_OFF)
+/* dw7 */
+#define CMD_HDR_ADDR_MODE_SEL_OFF  15
+#define CMD_HDR_ADDR_MODE_SEL_MSK  (1 << CMD_HDR_ADDR_MODE_SEL_OFF)
+#define CMD_HDR_ABORT_IPTT_OFF 16
+#define CMD_HDR_ABORT_IPTT_MSK (0x << CMD_HDR_ABORT_IPTT_OFF)
 
 /* Completion header */
 /* dw0 */
@@ -942,6 +951,34 @@ static int prep_ata_v3_hw(struct hisi_hba *hisi_hba,
return 0;
 }
 
+static int prep_abort_v3_hw(struct hisi_hba *hisi_hba,
+   struct hisi_sas_slot *slot,
+   int device_id, int abort_flag, int tag_to_abort)
+{
+   struct sas_task *task = slot->task;
+   struct domain_device *dev = task->dev;
+   struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+   struct hisi_sas_port *port = slot->port;
+
+   /* dw0 */
+   hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/
+  (port->id << CMD_HDR_PORT_OFF) |
+  ((dev_is_sata(dev) ? 1:0)
+   << CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
+   (abort_flag
+<< CMD_HDR_ABORT_FLAG_OFF));
+
+   /* dw1 */
+   hdr->dw1 = cpu_to_le32(device_id
+   << CMD_HDR_DEV_ID_OFF);
+
+   /* dw7 */
+   hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF);
+   hdr->transfer_tags = cpu_to_le32(slot->idx);
+
+   return 0;
+}
+
 static int phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
 {
int i, res = 0;
@@ -1519,6 +1556,7 @@ static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
.prep_ssp = prep_ssp_v3_hw,
.prep_smp = prep_smp_v3_hw,
.prep_stp = prep_ata_v3_hw,
+   .prep_abort = prep_abort_v3_hw,
.get_free_slot = get_free_slot_v3_hw,
.start_delivery = start_delivery_v3_hw,
.slot_complete = slot_complete_v3_hw,
-- 
1.9.1



[PATCH v6 15/22] scsi: hisi_sas: add v3 code to send SSP frame

2017-06-14 Thread John Garry
From: Xiang Chen 

Add code to prepare SSP frame and deliver it to hardware.

Signed-off-by: John Garry 
Signed-off-by: Xiang Chen 
---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 208 +
 1 file changed, 208 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c 
b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 4869b73..c869aca 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -157,6 +157,41 @@
 #define SL_RX_BCAST_CHK_MSK(PORT_BASE + 0x2c0)
 #define PHYCTRL_OOB_RESTART_MSK(PORT_BASE + 0x2c4)
 
+/* HW dma structures */
+/* Delivery queue header */
+/* dw0 */
+#define CMD_HDR_RESP_REPORT_OFF5
+#define CMD_HDR_RESP_REPORT_MSK(0x1 << CMD_HDR_RESP_REPORT_OFF)
+#define CMD_HDR_TLR_CTRL_OFF   6
+#define CMD_HDR_TLR_CTRL_MSK   (0x3 << CMD_HDR_TLR_CTRL_OFF)
+#define CMD_HDR_PORT_OFF   18
+#define CMD_HDR_PORT_MSK   (0xf << CMD_HDR_PORT_OFF)
+#define CMD_HDR_PRIORITY_OFF   27
+#define CMD_HDR_PRIORITY_MSK   (0x1 << CMD_HDR_PRIORITY_OFF)
+#define CMD_HDR_CMD_OFF29
+#define CMD_HDR_CMD_MSK(0x7 << CMD_HDR_CMD_OFF)
+/* dw1 */
+#define CMD_HDR_DIR_OFF5
+#define CMD_HDR_DIR_MSK(0x3 << CMD_HDR_DIR_OFF)
+#define CMD_HDR_VDTL_OFF   10
+#define CMD_HDR_VDTL_MSK   (0x1 << CMD_HDR_VDTL_OFF)
+#define CMD_HDR_FRAME_TYPE_OFF 11
+#define CMD_HDR_FRAME_TYPE_MSK (0x1f << CMD_HDR_FRAME_TYPE_OFF)
+#define CMD_HDR_DEV_ID_OFF 16
+#define CMD_HDR_DEV_ID_MSK (0x << CMD_HDR_DEV_ID_OFF)
+/* dw2 */
+#define CMD_HDR_CFL_OFF0
+#define CMD_HDR_CFL_MSK(0x1ff << CMD_HDR_CFL_OFF)
+#define CMD_HDR_MRFL_OFF   15
+#define CMD_HDR_MRFL_MSK   (0x1ff << CMD_HDR_MRFL_OFF)
+#define CMD_HDR_SG_MOD_OFF 24
+#define CMD_HDR_SG_MOD_MSK (0x3 << CMD_HDR_SG_MOD_OFF)
+/* dw6 */
+#define CMD_HDR_DIF_SGL_LEN_OFF0
+#define CMD_HDR_DIF_SGL_LEN_MSK(0x << 
CMD_HDR_DIF_SGL_LEN_OFF)
+#define CMD_HDR_DATA_SGL_LEN_OFF   16
+#define CMD_HDR_DATA_SGL_LEN_MSK   (0x << CMD_HDR_DATA_SGL_LEN_OFF)
+
 /* Completion header */
 /* dw0 */
 #define CMPLT_HDR_CMPLT_OFF0
@@ -217,6 +252,11 @@ enum {
HISI_SAS_PHY_INT_NR
 };
 
+#define DIR_NO_DATA 0
+#define DIR_TO_INI 1
+#define DIR_TO_DEVICE 2
+#define DIR_RESERVED 3
+
 static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
 {
void __iomem *regs = hisi_hba->regs + off;
@@ -224,6 +264,13 @@ static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 
off)
return readl(regs);
 }
 
+static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
+{
+   void __iomem *regs = hisi_hba->regs + off;
+
+   return readl_relaxed(regs);
+}
+
 static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
 {
void __iomem *regs = hisi_hba->regs + off;
@@ -448,6 +495,163 @@ static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, 
int phy_no)
hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
 }
 
+/**
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+ */
+static int
+get_free_slot_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq)
+{
+   struct device *dev = hisi_hba->dev;
+   int queue = dq->id;
+   u32 r, w;
+
+   w = dq->wr_point;
+   r = hisi_sas_read32_relaxed(hisi_hba,
+   DLVRY_Q_0_RD_PTR + (queue * 0x14));
+   if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
+   dev_warn(dev, "full queue=%d r=%d w=%d\n\n",
+   queue, r, w);
+   return -EAGAIN;
+   }
+
+   return 0;
+}
+
+static void start_delivery_v3_hw(struct hisi_sas_dq *dq)
+{
+   struct hisi_hba *hisi_hba = dq->hisi_hba;
+   int dlvry_queue = dq->slot_prep->dlvry_queue;
+   int dlvry_queue_slot = dq->slot_prep->dlvry_queue_slot;
+
+   dq->wr_point = ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS;
+   hisi_sas_write32(hisi_hba, DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+dq->wr_point);
+}
+
+static int prep_prd_sge_v3_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ struct hisi_sas_cmd_hdr *hdr,
+ struct scatterlist *scatter,
+ int n_elem)
+{
+   struct device *dev = hisi_hba->dev;
+   struct scatterlist *sg;
+   int i;
+
+   if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
+   dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
+   n_elem);
+   

Re: mpt3sas: driver got task abort request just after it's .shutdown() function is invoked

2017-06-14 Thread Bart Van Assche
On Wed, 2017-06-14 at 12:20 +0530, Sreekanth Reddy wrote:
> I am using 4.9 kernel and I am observing NULL pointer deference type
> kernel panic in the below scenario,
> 
> * Hotplug (i.e. hot add) the HBA (with a set of drives attached to it)
> to the system just few seconds before issuing "poweroff" command.
> 
> * Observed that during drives discovery process; for some of the
> drives "MODE SENSE" command got timed out.
> 
> * And as "poweroff" command issued, so kernel as called driver's
> shutdown() callback function and driver has cleaned up all the HBA
> resources (such as IRQ's, memory pools etc).
> 
> * But as the "MODE SENSE" command got timed out, so SCSI EH thread has
> invoked driver's .eh_abort_handler() callback function, but by this
> time driver has already cleaned up the resources and so it leads to
> kernel panic when it trying to access one of these resources.
> 
> I was assuming that kernel should not call driver's shutdown()
> callback function until all the outstanding IOs count reaches to zero
> (i.e. kernel should call the driver's shutdown() functions only after
> clearing up all the outstanding IOs). Please correct me if I am wrong,
> and please suggest better way to handle these types of issues.

Hello Sreekanth,

The SCSI core is not aware of PCIe (hot-)removal and hence cannot help
in this case. I think SCSI LLDs are responsible when .shutdown() is
called for 1) waiting until any ongoing scsi_scan_target() call has
finished and 2) calling scsi_remove_host() from inside pci_driver.shutdown().

Bart.

Re: [PATCH v2 1/2] libsas: Don't process sas events in static works

2017-06-14 Thread John Garry

On 14/06/2017 10:04, wangyijing wrote:

 static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
>>  {
>> +  struct sas_ha_event *ev;
>> +
>>BUG_ON(event >= HA_NUM_EVENTS);
>>
>> -  sas_queue_event(event, _ha->pending,
>> -  _ha->ha_events[event].work, sas_ha);
>> +  ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
>> +  if (!ev)
>> +  return;

> GFP_ATOMIC allocations can fail and then no events will be queued *and* we
> don't report the error back to the caller.
>

Yes, it's really a problem, but I don't find a better solution, do you have 
some suggestion ?



Dan raised an issue with this approach, regarding a malfunctioning PHY 
which spews out events. I still don't think we're handling it safely. 
Here's the suggestion:

- each asd_sas_phy owns a finite-sized pool of events
- when the event pool becomes exhausted, libsas stops queuing events 
(obviously) and disables the PHY in the LLDD
- upon attempting to re-enable the PHY from sysfs, libsas first checks 
that the pool is still not exhausted


If you cannot find a good solution, then let us know and we can help.

John



Re: [PATCH] scsi: sas: scsi_queue_work can fail, so make callers aware

2017-06-14 Thread Johannes Thumshirn
On 06/14/2017 02:57 PM, John Garry wrote:
> On 14/06/2017 12:52, Johannes Thumshirn wrote:
>> libsas uses scsi_queue_work() to queue it's internal event
>> notifications. scsi_queue_work() can return -EINVAL if the work queue
>> doesn't exist and it does call queue_work() which can return false if
>> the work is already queued.
>>
> 
> Hi Johannes,
> 
> When the queuing fails and we an report error, what is the caller, i.e.
> the LLDD, supposed to do with this information?
> 
> I mean, the LLDD is just reporting an event, like a broadcast event, and
> libsas could not handle it for some reason. The LLDD probably does not
> know how to handle this, apart from printing an error or maybe even
> disabling the originating PHY.

This depends on the event and the LLDD I guess. If it's -EINVAL (a.k.a
SCSI work queue not present) there's not much an LLDD can do about. If
it's a plain false, we could for instance report that we re-queue an
event or something similar.

>> Make the SAS event code capable of returning errors up to the caller,
>> which is handy when changing to dynamically allocated work in libsas
>> as well, as discussed here: https://lkml.org/lkml/2017/6/14/121.
> 
> I will comment on this patchset separately.

It's merrily a preparation patch for this libsas patchset and IFF we
want to merge it that way.

Should've made it clear in the log, sorry.

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


Re: [PATCH] scsi: sas: scsi_queue_work can fail, so make callers aware

2017-06-14 Thread John Garry

On 14/06/2017 12:52, Johannes Thumshirn wrote:

libsas uses scsi_queue_work() to queue it's internal event
notifications. scsi_queue_work() can return -EINVAL if the work queue
doesn't exist and it does call queue_work() which can return false if
the work is already queued.



Hi Johannes,

When the queuing fails and we an report error, what is the caller, i.e. 
the LLDD, supposed to do with this information?


I mean, the LLDD is just reporting an event, like a broadcast event, and 
libsas could not handle it for some reason. The LLDD probably does not 
know how to handle this, apart from printing an error or maybe even 
disabling the originating PHY.



Make the SAS event code capable of returning errors up to the caller,
which is handy when changing to dynamically allocated work in libsas
as well, as discussed here: https://lkml.org/lkml/2017/6/14/121.


I will comment on this patchset separately.

Much appreciated,
John



Signed-off-by: Johannes Thumshirn 
---
 drivers/scsi/libsas/sas_event.c| 36 ++--
 drivers/scsi/libsas/sas_internal.h |  4 ++--
 include/scsi/libsas.h  |  6 +++---
 3 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index aadbd5314c5c..c0d0d979b76d 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -27,30 +27,38 @@
 #include "sas_internal.h"
 #include "sas_dump.h"

-void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
+int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
 {
+   int rc = 0;
+
if (!test_bit(SAS_HA_REGISTERED, >state))
-   return;
+   return 0;

if (test_bit(SAS_HA_DRAINING, >state)) {
/* add it to the defer list, if not already pending */
if (list_empty(>drain_node))
list_add(>drain_node, >defer_q);
} else
-   scsi_queue_work(ha->core.shost, >work);
+   rc = scsi_queue_work(ha->core.shost, >work);
+
+   return rc;
 }

-static void sas_queue_event(int event, unsigned long *pending,
+static int sas_queue_event(int event, unsigned long *pending,
struct sas_work *work,
struct sas_ha_struct *ha)
 {
+   int rc = 0;
+
if (!test_and_set_bit(event, pending)) {
unsigned long flags;

spin_lock_irqsave(>lock, flags);
-   sas_queue_work(ha, work);
+   rc = sas_queue_work(ha, work);
spin_unlock_irqrestore(>lock, flags);
}
+
+   return rc;
 }


@@ -116,32 +124,32 @@ void sas_enable_revalidation(struct sas_ha_struct *ha)
mutex_unlock(>disco_mutex);
 }

-static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
+static int notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
 {
BUG_ON(event >= HA_NUM_EVENTS);

-   sas_queue_event(event, _ha->pending,
-   _ha->ha_events[event].work, sas_ha);
+   return sas_queue_event(event, _ha->pending,
+  _ha->ha_events[event].work, sas_ha);
 }

-static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
+static int notify_port_event(struct asd_sas_phy *phy, enum port_event event)
 {
struct sas_ha_struct *ha = phy->ha;

BUG_ON(event >= PORT_NUM_EVENTS);

-   sas_queue_event(event, >port_events_pending,
-   >port_events[event].work, ha);
+   return sas_queue_event(event, >port_events_pending,
+  >port_events[event].work, ha);
 }

-void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
+int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
 {
struct sas_ha_struct *ha = phy->ha;

BUG_ON(event >= PHY_NUM_EVENTS);

-   sas_queue_event(event, >phy_events_pending,
-   >phy_events[event].work, ha);
+   return sas_queue_event(event, >phy_events_pending,
+  >phy_events[event].work, ha);
 }

 int sas_init_events(struct sas_ha_struct *sas_ha)
diff --git a/drivers/scsi/libsas/sas_internal.h 
b/drivers/scsi/libsas/sas_internal.h
index b306b7843d99..a216c957b639 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -76,7 +76,7 @@ void sas_porte_broadcast_rcvd(struct work_struct *work);
 void sas_porte_link_reset_err(struct work_struct *work);
 void sas_porte_timer_event(struct work_struct *work);
 void sas_porte_hard_reset(struct work_struct *work);
-void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw);
+int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw);

 int sas_notify_lldd_dev_found(struct domain_device *);
 void sas_notify_lldd_dev_gone(struct domain_device *);
@@ -85,7 +85,7 @@ int 

[PATCH] scsi: sas: scsi_queue_work can fail, so make callers aware

2017-06-14 Thread Johannes Thumshirn
libsas uses scsi_queue_work() to queue it's internal event
notifications. scsi_queue_work() can return -EINVAL if the work queue
doesn't exist and it does call queue_work() which can return false if
the work is already queued.

Make the SAS event code capable of returning errors up to the caller,
which is handy when changing to dynamically allocated work in libsas
as well, as discussed here: https://lkml.org/lkml/2017/6/14/121.

Signed-off-by: Johannes Thumshirn 
---
 drivers/scsi/libsas/sas_event.c| 36 ++--
 drivers/scsi/libsas/sas_internal.h |  4 ++--
 include/scsi/libsas.h  |  6 +++---
 3 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index aadbd5314c5c..c0d0d979b76d 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -27,30 +27,38 @@
 #include "sas_internal.h"
 #include "sas_dump.h"
 
-void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
+int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
 {
+   int rc = 0;
+
if (!test_bit(SAS_HA_REGISTERED, >state))
-   return;
+   return 0;
 
if (test_bit(SAS_HA_DRAINING, >state)) {
/* add it to the defer list, if not already pending */
if (list_empty(>drain_node))
list_add(>drain_node, >defer_q);
} else
-   scsi_queue_work(ha->core.shost, >work);
+   rc = scsi_queue_work(ha->core.shost, >work);
+
+   return rc;
 }
 
-static void sas_queue_event(int event, unsigned long *pending,
+static int sas_queue_event(int event, unsigned long *pending,
struct sas_work *work,
struct sas_ha_struct *ha)
 {
+   int rc = 0;
+
if (!test_and_set_bit(event, pending)) {
unsigned long flags;
 
spin_lock_irqsave(>lock, flags);
-   sas_queue_work(ha, work);
+   rc = sas_queue_work(ha, work);
spin_unlock_irqrestore(>lock, flags);
}
+
+   return rc;
 }
 
 
@@ -116,32 +124,32 @@ void sas_enable_revalidation(struct sas_ha_struct *ha)
mutex_unlock(>disco_mutex);
 }
 
-static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
+static int notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
 {
BUG_ON(event >= HA_NUM_EVENTS);
 
-   sas_queue_event(event, _ha->pending,
-   _ha->ha_events[event].work, sas_ha);
+   return sas_queue_event(event, _ha->pending,
+  _ha->ha_events[event].work, sas_ha);
 }
 
-static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
+static int notify_port_event(struct asd_sas_phy *phy, enum port_event event)
 {
struct sas_ha_struct *ha = phy->ha;
 
BUG_ON(event >= PORT_NUM_EVENTS);
 
-   sas_queue_event(event, >port_events_pending,
-   >port_events[event].work, ha);
+   return sas_queue_event(event, >port_events_pending,
+  >port_events[event].work, ha);
 }
 
-void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
+int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
 {
struct sas_ha_struct *ha = phy->ha;
 
BUG_ON(event >= PHY_NUM_EVENTS);
 
-   sas_queue_event(event, >phy_events_pending,
-   >phy_events[event].work, ha);
+   return sas_queue_event(event, >phy_events_pending,
+  >phy_events[event].work, ha);
 }
 
 int sas_init_events(struct sas_ha_struct *sas_ha)
diff --git a/drivers/scsi/libsas/sas_internal.h 
b/drivers/scsi/libsas/sas_internal.h
index b306b7843d99..a216c957b639 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -76,7 +76,7 @@ void sas_porte_broadcast_rcvd(struct work_struct *work);
 void sas_porte_link_reset_err(struct work_struct *work);
 void sas_porte_timer_event(struct work_struct *work);
 void sas_porte_hard_reset(struct work_struct *work);
-void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw);
+int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw);
 
 int sas_notify_lldd_dev_found(struct domain_device *);
 void sas_notify_lldd_dev_gone(struct domain_device *);
@@ -85,7 +85,7 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id,
enum phy_func phy_func, struct sas_phy_linkrates *);
 int sas_smp_get_phy_events(struct sas_phy *phy);
 
-void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event);
+int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event);
 void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
 struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
 struct domain_device 

Re: [ANNOUNCE]: Broadcom (Emulex) FC Target driver - efct

2017-06-14 Thread Hannes Reinecke
On 06/13/2017 01:08 AM, James Smart wrote:
> On 5/16/2017 12:59 PM, Roland Dreier wrote:
>> On Sun, Mar 5, 2017 at 8:35 AM, Sebastian Herbszt  wrote:
>>> Just like Hannes I do favour integration. I guess it could be
>>> comparable to qla2xxx + tcm_qla2xxx, lpfc + lpfc_scst and
>>> lpfc + tcm_lpfc. That approach might even help Bart with his
>>> target driver unification if he didn't give up on that topic.
>> Resurrecting this old topic - sorry for not seeing this go by initially.
>>
>> For context, I have a lot of experience debugging the qla2xxx target
>> code - we did a lot of work to get error/exception paths correct.
>> Basic FC target support is pretty straightforward but handling SAN log
>> in / log out events and other strange things that initiators do took a
>> lot of effort.
>>
>> Anyway, my feeling is that the integration of tcm_qla2xxx and qla2xxx
>> was overall a net negative.  Having the target driver grafted onto the
>> side of an already-complex driver that has a bunch of code not
>> relevant to the target (SCSI error handling, logging into and timing
>> out remote target ports, etc) made the code harder to debug and harder
>> to get right.
>>
>> Of course I'm in favor of making common code really common.  So
>> certainly we should have a common library of SLI-4 code that both the
>> initiator and target driver share.  And if there is more commonality,
>> that's great.  But any code similar to "if (initiator) ... else ..."
>> is really suspect to me - grepping for "qla_ini_mode_enabled" shows
>> great examples like
>>
>> ...
>>
>> Handling "dual mode" (both initiator and target on the same port at
>> the same time) is a design challenge, but I don't think the current
>> qla2xxx driver is an example of a maintainable way to do that.
>>
>> (I'm agnostic about what to do about SLI-3 - perhaps the cleanest
>> thing to do is split the driver between SLI-4 and SLI-3, and handle
>> the initiator and target drivers for those two cases as appropriate)
>>
>> I'd love to discuss this further and come up with a design that meets
>> the concerns about integration but also learns the lessons from
>> tcm_qla2xxx.
>>
>>   - R.
> 
> 
> Thanks for the feedback.  I believe you echo many of our concerns as we
> look at "merging them into one".  I agree with your statements on the
> number of if-else roles and know that we made this even more complicated
> by the driver doing fc-nvme initiator and fc-nvme target as well.  Your
> small list of "mode_enabled" hits pales in comparison to a hit list in
> the current driver if looking for SCSI initiator support
> (LPFC_ENABLE_FCP), NVME initiator support (LPFC_ENABLE_NVME), or NVME
> target support (phba->nvmet_support). And that's before adding SCSI
> target support.   We're also concerned about the discovery engines as
> not only are there lots of different paths for the different roles as
> well as support for fcoe, but there are a lot of carefully managed
> accommodations for various oem and switch environments. It's very
> difficult to replicate and retest all these different configurations and
> scenarios.
> 
> Here's what I'd like to propose for a direction:
> 1) Create an initiator driver and a target driver.  For now, initiator
> would support both SCSI and NVME initiator. Target would support SCSI
> and NVME target.
Well, _actually_ you only would need to move the NVMe target
functionality into a new driver...

> 2) SLI3 support would be contained only within the initiator driver and
> limited to SCSI (as it is today in lpfc).
> 3) SLI4 support would be library-ized,so that the code can be shared
> between the two drivers.  Library-izing SLI-4 means SLI-3 will also be
> library-ized.
> 4) Discovery support would be librarized so it can be shared. As part of
> this effort we will minimally move generic functions from the library to
> drivers/scsi/libfc (example: setting RPA payloads, etc).  At this time,
> the drivers will not attempt to use libfc for discovery. There is too
> much sensitive code tied to interlocks with adapter api design that are
> visible in the discovery state machine. Use of libfc can be a future,
> but for the short term, the goal is a single library for the broadcom
> initiator/target drivers.
> 5) lpfc will be refactored, addressing concerns that have been desired
> for a while.
> 
That all sound reasonable.

> 
> To start this effort, I'd like a bcmlpfc directory to be made within the
> drivers staging tree. The directory would be populated with the efct
> driver and a copy of the existing lpfc driver.   Work can then commence
> on refactoring lpfc and creating the libraries and integrating the
> libraries into both drivers.  As lpfc is updated in the main tree,
> patches would be posted to the staging version of lpfc to keep them on par.
> 
Ok.

> 
> Questions:
> a) How best to deal with overlapping pci id's ?  E.g. if we do (1) and
> we have an initiator and target driver, there is a lot of adapters that
> are 

Re: [PATCH v2] storvsc: use default I/O timeout handler for FC devices

2017-06-14 Thread Johannes Thumshirn
On 06/13/2017 11:34 PM, Long Li wrote:
> From: Long Li 
> 
> FC disks issue I/O directly to the host storage port driver, this is
> diffirent to VHD disks where I/O is virtualized and timeout is handled
> by the host VSP (Virtualization Service Provider).
> 
> FC disks are usually setup in a multipath system, and they don't want to
> reset timer on I/O timeout. Timeout is detected by multipath as a good 
> time to failover and recover.
> 
> Patch v2 includes suggestions from Bart Van Assche
> 
> 
> Signed-off-by: Long Li 
> ---
>  drivers/scsi/storvsc_drv.c | 4 
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
> index 8d955db..3cc8d67 100644
> --- a/drivers/scsi/storvsc_drv.c
> +++ b/drivers/scsi/storvsc_drv.c
> @@ -1495,6 +1495,10 @@ static int storvsc_host_reset_handler(struct scsi_cmnd 
> *scmnd)
>   */
>  static enum blk_eh_timer_return storvsc_eh_timed_out(struct scsi_cmnd *scmnd)
>  {
> +#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
> + if (scmnd->device->host->transportt == fc_transport_template)
> + return fc_eh_timed_out(scmnd);
> +#endif

Can you please change the #if IS_ENABLED() to
if(IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
&& scmnd->device->host->transportt == fc_transport_template)

That way we have better compiler coverage.

Thanks,
Johannes

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


Re: [PATCH v2 1/2] libsas: Don't process sas events in static works

2017-06-14 Thread wangyijing


在 2017/6/14 17:18, Johannes Thumshirn 写道:
> On 06/14/2017 11:04 AM, wangyijing wrote:
  static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event 
 event)
  {
 +  struct sas_ha_event *ev;
 +
BUG_ON(event >= HA_NUM_EVENTS);
  
 -  sas_queue_event(event, _ha->pending,
 -  _ha->ha_events[event].work, sas_ha);
 +  ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
 +  if (!ev)
 +  return;
>>> GFP_ATOMIC allocations can fail and then no events will be queued *and* we
>>> don't report the error back to the caller.
>>>
>>
>> Yes, it's really a problem, but I don't find a better solution, do you have 
>> some suggestion ?
> 
> Something like this?
> 
> diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c
> b/drivers/scsi/hisi_sas/hisi_sas_main.c
> index d622db502ec9..27cd7307d308 100644
> --- a/drivers/scsi/hisi_sas/hisi_sas_main.c
> +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
> @@ -894,7 +894,11 @@ static int hisi_sas_controller_reset(struct
> hisi_hba *hisi_hba)
> hisi_sas_release_tasks(hisi_hba);
> spin_unlock_irqrestore(_hba->lock, flags);
> 
> -   sas_ha->notify_ha_event(sas_ha, HAE_RESET);
> +   rc = sas_ha->notify_ha_event(sas_ha, HAE_RESET);
> +   if (rc) {
> +   dev_warn(dev, "failed to queue HA event (%d)\n",
> rc);
> +   goto out;
> +   }
> dev_dbg(dev, "controller reset successful!\n");
> } else
> return -1;
> diff --git a/drivers/scsi/libsas/sas_event.c
> b/drivers/scsi/libsas/sas_event.c
> index aadbd5314c5c..6c91fb31f891 100644
> --- a/drivers/scsi/libsas/sas_event.c
> +++ b/drivers/scsi/libsas/sas_event.c
> @@ -116,7 +116,7 @@ void sas_enable_revalidation(struct sas_ha_struct *ha)
> mutex_unlock(>disco_mutex);
>  }
> 
> -static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event
> event)
> +static int notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event
> event)
>  {
> BUG_ON(event >= HA_NUM_EVENTS);
> 
> diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
> index dd0f72c95abe..5d9cd6d20855 100644
> --- a/include/scsi/libsas.h
> +++ b/include/scsi/libsas.h
> @@ -415,7 +415,7 @@ struct sas_ha_struct {
> * their siblings when forming wide ports */
> 
> /* LLDD calls these to notify the class of an event. */
> -   void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
> +   int (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
> void (*notify_port_event)(struct asd_sas_phy *, enum port_event);
> void (*notify_phy_event)(struct asd_sas_phy *, enum phy_event);

This make sense, return a fail status and report it to the callers.


> 
> 



Re: [PATCH v2 1/2] libsas: Don't process sas events in static works

2017-06-14 Thread Johannes Thumshirn
On 06/14/2017 11:04 AM, wangyijing wrote:
>>>  static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event 
>>> event)
>>>  {
>>> +   struct sas_ha_event *ev;
>>> +
>>> BUG_ON(event >= HA_NUM_EVENTS);
>>>  
>>> -   sas_queue_event(event, _ha->pending,
>>> -   _ha->ha_events[event].work, sas_ha);
>>> +   ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
>>> +   if (!ev)
>>> +   return;
>> GFP_ATOMIC allocations can fail and then no events will be queued *and* we
>> don't report the error back to the caller.
>>
> 
> Yes, it's really a problem, but I don't find a better solution, do you have 
> some suggestion ?

Something like this?

diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index d622db502ec9..27cd7307d308 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -894,7 +894,11 @@ static int hisi_sas_controller_reset(struct
hisi_hba *hisi_hba)
hisi_sas_release_tasks(hisi_hba);
spin_unlock_irqrestore(_hba->lock, flags);

-   sas_ha->notify_ha_event(sas_ha, HAE_RESET);
+   rc = sas_ha->notify_ha_event(sas_ha, HAE_RESET);
+   if (rc) {
+   dev_warn(dev, "failed to queue HA event (%d)\n",
rc);
+   goto out;
+   }
dev_dbg(dev, "controller reset successful!\n");
} else
return -1;
diff --git a/drivers/scsi/libsas/sas_event.c
b/drivers/scsi/libsas/sas_event.c
index aadbd5314c5c..6c91fb31f891 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -116,7 +116,7 @@ void sas_enable_revalidation(struct sas_ha_struct *ha)
mutex_unlock(>disco_mutex);
 }

-static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event
event)
+static int notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event
event)
 {
BUG_ON(event >= HA_NUM_EVENTS);

diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index dd0f72c95abe..5d9cd6d20855 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -415,7 +415,7 @@ struct sas_ha_struct {
* their siblings when forming wide ports */

/* LLDD calls these to notify the class of an event. */
-   void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
+   int (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
void (*notify_port_event)(struct asd_sas_phy *, enum port_event);
void (*notify_phy_event)(struct asd_sas_phy *, enum phy_event);


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


Re: [PATCH 0/7] Enable iSCSI offload drivers to use information from iface.

2017-06-14 Thread Rangankar, Manish

On 13/06/17 10:19 PM, "Robert LeBlanc"  wrote:

>On Wed, Jun 7, 2017 at 12:30 PM, Robert LeBlanc 
>wrote:
>> On Wed, Jun 7, 2017 at 10:28 AM, Chris Leech  wrote:
>>> On Tue, Jun 06, 2017 at 12:07:10PM -0600, Robert LeBlanc wrote:
 This patchset enables iSCSI offload drivers to have access to the
iface
 information provided by iscsid. This allows users to have more control
 of how the driver connects to the iSCSI target. iSER is updated to use
 iface.ipaddress to set the source IP address if configured. This
allows
 iSER to use multiple ports on the same network or in more complicated
 routed configurations.

 Since there is already a change to the function parameters, dst_addr
 is upgraded to sockaddr_storage so that it is more future proof and
makes
 the size of the struct static and not dependent on checking the
SA_FAMILY.

 This is dependent on updates to Open-iSCSI.
>>>
>>> Hi Robert,
>>>
>>> I don't think that passing the iface_rec structure directly from the
>>> iscsid internals into a netlink message is a good way to go about this.
>>> It's really big, there's an embedded list_head with user address
>>> pointers that needs to be left out, and there are 32/64-bit layout
>>> differences.
>>>
>>> Let me take a look at how you're proposing using this info for iSER, if
>>> it makes sense I think we should come up with a better designed
>>> structure for passing the information.
>>>
>>> Thanks,
>>> Chris
>>>
>>
>> Chris,
>>
>> Thank you for your feedback. I agree that the entire iface is probably
>> overkill, it was more of a proof of concept. We are only using the
>> ipaddress in the iface for iSER (in my patch), but I could see other
>> drivers benefiting from some of the other data in the iface (mac,
>> interface_name, vlan, etc) so I didn't want to be too restrictive so
>> that it wouldn't have to be extended later. I've not worked on
>> userspace/kernel interaction before so I need some guidance to make
>> the transition between userspace and kernel versions smoother.
>>
>> This patchset works for what we need and it is very important for us
>> (and I'm sure others once the feature is available) and I'm happy to
>> put in the time to get it accepted upstream, I'm just new to kernel
>> development and need some guidance.
>
>Are there other comments/ideas/suggestions specifically from the
>iSCSI/iSER guys? I'd like to keep this patch moving.

Considering partial iSCSI offload solution (like bnx2i and qedi) point of
view, we liked the idea from Hannes to create TAP interface to associate
with each iSCSI offload interface, which will allow us to use userspace
tools for configuration. I haven't dig into its details yet, but at higher
level it looks like this will help us to move away from our dependency
over iscsiuio. 


Thanks,
Manish R.



Re: [PATCH v2 2/2] libsas: Enhance libsas hotplug

2017-06-14 Thread wangyijing
>> In this patch, we try to solve these issues in following steps:
>> 1. create a new workqueue used to run sas event work, instead of scsi host 
>> workqueue,
>>because we may block sas event work, we cannot block the normal scsi 
>> works.
>>When libsas receive a phy down event, sas_deform_port would be called, 
>> and now we
>>block sas_deform_port and wait for destruction work finish, in 
>> sas_destruct_devices,
>>we may wait ata error handler, it would take a long time, so if do all 
>> stuff in scsi
>>host workq, libsas may block other scsi works too long.
>> 2. create a new workqueue used to run sas discovery events work, instead of 
>> scsi host
>>workqueue, because in some cases, eg. in revalidate domain event, we may 
>> unregister
>>a sas device and discover new one, we must sync the execution, wait the 
>> remove process
>>finish, then start a new discovery. So we must put the probe and destruct 
>> discovery
>>events in a new workqueue to avoid deadlock.
>> 3. introudce a asd_sas_port level wait-complete and a sas_discovery level 
>> wait-complete
>>we use former wait-complete to achieve a sas event atomic process and use 
>> latter to
>>make a sas discovery sync.
>> 4. remove disco_mutex in sas_revalidate_domain, since now 
>> sas_revalidate_domain sync
>>the destruct discovery event execution, it's no need to lock disco mutex 
>> there.
> 
> The way you've written the changelog suggests this patch should be split
> into 4 patches, each one taking care of one of your change items.

I will split it in next version.

Thanks!
Yijing.


> 



Re: [PATCH v2 1/2] libsas: Don't process sas events in static works

2017-06-14 Thread wangyijing
>>  static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event 
>> event)
>>  {
>> +struct sas_ha_event *ev;
>> +
>>  BUG_ON(event >= HA_NUM_EVENTS);
>>  
>> -sas_queue_event(event, _ha->pending,
>> -_ha->ha_events[event].work, sas_ha);
>> +ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
>> +if (!ev)
>> +return;
> GFP_ATOMIC allocations can fail and then no events will be queued *and* we
> don't report the error back to the caller.
> 

Yes, it's really a problem, but I don't find a better solution, do you have 
some suggestion ?

> 
> 
>> index 64e9cdd..c227a8b 100644
>> --- a/drivers/scsi/libsas/sas_init.c
>> +++ b/drivers/scsi/libsas/sas_init.c
>> @@ -111,10 +111,6 @@ void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
>>  
>>  void sas_hae_reset(struct work_struct *work)
>>  {
>> -struct sas_ha_event *ev = to_sas_ha_event(work);
>> -struct sas_ha_struct *ha = ev->ha;
>> -
>> -clear_bit(HAE_RESET, >pending);
>>  }
> 
> I don't really get why you need a stubbed out sas_hae_reset(). Can't we
> just kill it if it doesn't have anything left to do?

I have no idea about this function history, I agree clean it out.

> 
> 



Re: [PATCH v2 2/2] libsas: Enhance libsas hotplug

2017-06-14 Thread Johannes Thumshirn
On 06/14/2017 09:33 AM, Yijing Wang wrote:
> Libsas complete a hotplug event notified by LLDD in several works,
> for example, if libsas receive a PHYE_LOSS_OF_SIGNAL, we process it
> in following steps:
> 
> notify_phy_event  [interrupt context]
>   sas_queue_event [queue work on shost->work_q]
>   sas_phye_loss_of_signal [running in shost->work_q]
>   sas_deform_port [remove sas port]
>   sas_unregister_dev
>   sas_discover_event  [queue destruct 
> work on shost->work_q tail]
> 
> In above case, complete whole hotplug in two works, remove sas port first, 
> then
> put the destruction of device in another work and queue it on in the tail of
> workqueue, since sas port is the parent of the children rphy device, so if 
> remove
> sas port first, the children rphy device would also be deleted, when the 
> destruction
> work coming, it would find the target has been removed already, and report a
> sysfs warning calltrace.
> 
> queue tail queue head
> DISCE_DESTRUCT> PORTE_BYTES_DMAED event ->PHYE_LOSS_OF_SIGNAL[running]
> 
> There are other hotplug issues in current framework, in above case, if there 
> is
> hotadd sas event queued between hotremove works, the hotplug order would be 
> broken
> and unexpected issues would happen.
> 
> In this patch, we try to solve these issues in following steps:
> 1. create a new workqueue used to run sas event work, instead of scsi host 
> workqueue,
>because we may block sas event work, we cannot block the normal scsi works.
>When libsas receive a phy down event, sas_deform_port would be called, and 
> now we
>block sas_deform_port and wait for destruction work finish, in 
> sas_destruct_devices,
>we may wait ata error handler, it would take a long time, so if do all 
> stuff in scsi
>host workq, libsas may block other scsi works too long.
> 2. create a new workqueue used to run sas discovery events work, instead of 
> scsi host
>workqueue, because in some cases, eg. in revalidate domain event, we may 
> unregister
>a sas device and discover new one, we must sync the execution, wait the 
> remove process
>finish, then start a new discovery. So we must put the probe and destruct 
> discovery
>events in a new workqueue to avoid deadlock.
> 3. introudce a asd_sas_port level wait-complete and a sas_discovery level 
> wait-complete
>we use former wait-complete to achieve a sas event atomic process and use 
> latter to
>make a sas discovery sync.
> 4. remove disco_mutex in sas_revalidate_domain, since now 
> sas_revalidate_domain sync
>the destruct discovery event execution, it's no need to lock disco mutex 
> there.

The way you've written the changelog suggests this patch should be split
into 4 patches, each one taking care of one of your change items.

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


Re: [PATCH v2 1/2] libsas: Don't process sas events in static works

2017-06-14 Thread Johannes Thumshirn
On 06/14/2017 09:33 AM, Yijing Wang wrote:
> Now libsas hotplug work is static, LLDD driver queue
> the hotplug work into shost->work_q. If LLDD driver
> burst post lots hotplug events to libsas, the hotplug
> events may pending in the workqueue like
> 
> shost->work_q
> new work[PORTE_BYTES_DMAED] --> |[PHYE_LOSS_OF_SIGNAL][PORTE_BYTES_DMAED] -> 
> processing
> |<---wait worker to process>|
> In this case, a new PORTE_BYTES_DMAED event coming, libsas try to queue it
> to shost->work_q, but this work is already pending, so it would be lost.
> Finally, libsas delete the related sas port and sas devices, but LLDD driver
> expect libsas add the sas port and devices(last sas event).
> 
> This patch remove the static defined hotplug work, and use dynamic work to
> avoid missing hotplug events.
> 
> Signed-off-by: Yijing Wang 
> Signed-off-by: Yousong He 
> Signed-off-by: Qilin Chen 
> ---

[...]

>  static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event 
> event)
>  {
> + struct sas_ha_event *ev;
> +
>   BUG_ON(event >= HA_NUM_EVENTS);
>  
> - sas_queue_event(event, _ha->pending,
> - _ha->ha_events[event].work, sas_ha);
> + ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
> + if (!ev)
> + return;
GFP_ATOMIC allocations can fail and then no events will be queued *and* we
don't report the error back to the caller.



> index 64e9cdd..c227a8b 100644
> --- a/drivers/scsi/libsas/sas_init.c
> +++ b/drivers/scsi/libsas/sas_init.c
> @@ -111,10 +111,6 @@ void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
>  
>  void sas_hae_reset(struct work_struct *work)
>  {
> - struct sas_ha_event *ev = to_sas_ha_event(work);
> - struct sas_ha_struct *ha = ev->ha;
> -
> - clear_bit(HAE_RESET, >pending);
>  }

I don't really get why you need a stubbed out sas_hae_reset(). Can't we
just kill it if it doesn't have anything left to do?


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


[Resend][PATCH v2 2/2] libsas: Enhance libsas hotplug

2017-06-14 Thread Yijing Wang
Libsas complete a hotplug event notified by LLDD in several works,
for example, if libsas receive a PHYE_LOSS_OF_SIGNAL, we process it
in following steps:

notify_phy_event[interrupt context]
sas_queue_event [queue work on shost->work_q]
sas_phye_loss_of_signal [running in shost->work_q]
sas_deform_port [remove sas port]
sas_unregister_dev
sas_discover_event  [queue destruct 
work on shost->work_q tail]

In above case, complete whole hotplug in two works, remove sas port first, then
put the destruction of device in another work and queue it on in the tail of
workqueue, since sas port is the parent of the children rphy device, so if 
remove
sas port first, the children rphy device would also be deleted, when the 
destruction
work coming, it would find the target has been removed already, and report a
sysfs warning calltrace.

queue tail queue head
DISCE_DESTRUCT> PORTE_BYTES_DMAED event ->PHYE_LOSS_OF_SIGNAL[running]

There are other hotplug issues in current framework, in above case, if there is
hotadd sas event queued between hotremove works, the hotplug order would be 
broken
and unexpected issues would happen.

In this patch, we try to solve these issues in following steps:
1. create a new workqueue used to run sas event work, instead of scsi host 
workqueue,
   because we may block sas event work, we cannot block the normal scsi works.
   When libsas receive a phy down event, sas_deform_port would be called, and 
now we
   block sas_deform_port and wait for destruction work finish, in 
sas_destruct_devices,
   we may wait ata error handler, it would take a long time, so if do all stuff 
in scsi
   host workq, libsas may block other scsi works too long.
2. create a new workqueue used to run sas discovery events work, instead of 
scsi host
   workqueue, because in some cases, eg. in revalidate domain event, we may 
unregister
   a sas device and discover new one, we must sync the execution, wait the 
remove process
   finish, then start a new discovery. So we must put the probe and destruct 
discovery
   events in a new workqueue to avoid deadlock.
3. introudce a asd_sas_port level wait-complete and a sas_discovery level 
wait-complete
   we use former wait-complete to achieve a sas event atomic process and use 
latter to
   make a sas discovery sync.
4. remove disco_mutex in sas_revalidate_domain, since now sas_revalidate_domain 
sync
   the destruct discovery event execution, it's no need to lock disco mutex 
there.

Signed-off-by: Yijing Wang 
---
 drivers/scsi/libsas/sas_discover.c | 58 ++--
 drivers/scsi/libsas/sas_event.c|  2 +-
 drivers/scsi/libsas/sas_expander.c |  9 +-
 drivers/scsi/libsas/sas_init.c | 23 +-
 drivers/scsi/libsas/sas_internal.h | 61 ++
 drivers/scsi/libsas/sas_port.c |  4 +++
 include/scsi/libsas.h  |  9 ++
 7 files changed, 148 insertions(+), 18 deletions(-)

diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 60de662..43e8a1e 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -503,11 +503,10 @@ static void sas_revalidate_domain(struct work_struct 
*work)
struct domain_device *ddev = port->port_dev;
 
/* prevent revalidation from finding sata links in recovery */
-   mutex_lock(>disco_mutex);
if (test_bit(SAS_HA_ATA_EH_ACTIVE, >state)) {
SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n",
port->id, task_pid_nr(current));
-   goto out;
+   return;
}
 
clear_bit(DISCE_REVALIDATE_DOMAIN, >disc.pending);
@@ -521,20 +520,57 @@ static void sas_revalidate_domain(struct work_struct 
*work)
 
SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
port->id, task_pid_nr(current), res);
- out:
-   mutex_unlock(>disco_mutex);
+}
+
+static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
+   [DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
+   [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
+   [DISCE_PROBE] = sas_probe_devices,
+   [DISCE_SUSPEND] = sas_suspend_devices,
+   [DISCE_RESUME] = sas_resume_devices,
+   [DISCE_DESTRUCT] = sas_destruct_devices,
+};
+
+/* a simple wrapper for sas discover event funtions */
+static void sas_discover_common_fn(struct work_struct *work)
+{
+   struct sas_discovery_event *ev = to_sas_discovery_event(work);
+   struct asd_sas_port *port = ev->port;
+
+   sas_event_fns[ev->type](work);
+   sas_unbusy_port(port);
 }
 
 /* -- Events -- */
 
 static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw)
 {

[Resend][PATCH v2 1/2] libsas: Don't process sas events in static works

2017-06-14 Thread Yijing Wang
Now libsas hotplug work is static, LLDD driver queue
the hotplug work into shost->work_q. If LLDD driver
burst post lots hotplug events to libsas, the hotplug
events may pending in the workqueue like

shost->work_q
new work[PORTE_BYTES_DMAED] --> |[PHYE_LOSS_OF_SIGNAL][PORTE_BYTES_DMAED] -> 
processing
|<---wait worker to process>|
In this case, a new PORTE_BYTES_DMAED event coming, libsas try to queue it
to shost->work_q, but this work is already pending, so it would be lost.
Finally, libsas delete the related sas port and sas devices, but LLDD driver
expect libsas add the sas port and devices(last sas event).

This patch remove the static defined hotplug work, and use dynamic work to
avoid missing hotplug events.

Signed-off-by: Yijing Wang 
Signed-off-by: Yousong He 
Signed-off-by: Qilin Chen 
---
 drivers/scsi/libsas/sas_event.c| 88 +++---
 drivers/scsi/libsas/sas_init.c |  6 ---
 drivers/scsi/libsas/sas_internal.h |  3 ++
 drivers/scsi/libsas/sas_phy.c  | 45 ---
 drivers/scsi/libsas/sas_port.c | 18 
 include/scsi/libsas.h  | 10 +
 6 files changed, 84 insertions(+), 86 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index aadbd53..06c5c4b 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -27,6 +27,10 @@
 #include "sas_internal.h"
 #include "sas_dump.h"
 
+static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = {
+   [HAE_RESET] = sas_hae_reset,
+};
+
 void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
 {
if (!test_bit(SAS_HA_REGISTERED, >state))
@@ -40,17 +44,14 @@ void sas_queue_work(struct sas_ha_struct *ha, struct 
sas_work *sw)
scsi_queue_work(ha->core.shost, >work);
 }
 
-static void sas_queue_event(int event, unsigned long *pending,
-   struct sas_work *work,
+static void sas_queue_event(int event, struct sas_work *work,
struct sas_ha_struct *ha)
 {
-   if (!test_and_set_bit(event, pending)) {
-   unsigned long flags;
+   unsigned long flags;
 
-   spin_lock_irqsave(>lock, flags);
-   sas_queue_work(ha, work);
-   spin_unlock_irqrestore(>lock, flags);
-   }
+   spin_lock_irqsave(>lock, flags);
+   sas_queue_work(ha, work);
+   spin_unlock_irqrestore(>lock, flags);
 }
 
 
@@ -111,52 +112,87 @@ void sas_enable_revalidation(struct sas_ha_struct *ha)
if (!test_and_clear_bit(ev, >pending))
continue;
 
-   sas_queue_event(ev, >pending, >disc_work[ev].work, ha);
+   sas_queue_event(ev, >disc_work[ev].work, ha);
}
mutex_unlock(>disco_mutex);
 }
 
+static void sas_ha_event_worker(struct work_struct *work)
+{
+   struct sas_ha_event *ev = to_sas_ha_event(work);
+
+   sas_ha_event_fns[ev->type](work);
+   kfree(ev);
+}
+
+static void sas_port_event_worker(struct work_struct *work)
+{
+   struct asd_sas_event *ev = to_asd_sas_event(work);
+
+   sas_port_event_fns[ev->type](work);
+   kfree(ev);
+}
+
+static void sas_phy_event_worker(struct work_struct *work)
+{
+   struct asd_sas_event *ev = to_asd_sas_event(work);
+
+   sas_phy_event_fns[ev->type](work);
+   kfree(ev);
+}
+
 static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
 {
+   struct sas_ha_event *ev;
+
BUG_ON(event >= HA_NUM_EVENTS);
 
-   sas_queue_event(event, _ha->pending,
-   _ha->ha_events[event].work, sas_ha);
+   ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, sas_ha_event_worker);
+   ev->ha = sas_ha;
+   ev->type = event;
+   sas_queue_event(event, >work, sas_ha);
 }
 
 static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
 {
+   struct asd_sas_event *ev;
struct sas_ha_struct *ha = phy->ha;
 
BUG_ON(event >= PORT_NUM_EVENTS);
 
-   sas_queue_event(event, >port_events_pending,
-   >port_events[event].work, ha);
+   ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, sas_port_event_worker);
+   ev->phy = phy;
+   ev->type = event;
+   sas_queue_event(event, >work, ha);
 }
 
 void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
 {
+   struct asd_sas_event *ev;
struct sas_ha_struct *ha = phy->ha;
 
BUG_ON(event >= PHY_NUM_EVENTS);
 
-   sas_queue_event(event, >phy_events_pending,
-   >phy_events[event].work, ha);
+   ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, 

[Resend][PATCH v2 0/2] Enhance libsas hotplug feature

2017-06-14 Thread Yijing Wang
Now the libsas hotplug has some issues, Dan Williams report
a similar bug here before
https://www.mail-archive.com/linux-scsi@vger.kernel.org/msg39187.html

The issues we have found
1. if LLDD burst reports lots of phy-up/phy-down sas events, some events
   may lost because a same sas events is pending now, finally libsas topo
   may different the hardware.
2. receive a phy down sas event, libsas call sas_deform_port to remove
   devices, it would first delete the sas port, then put a destruction
   discovery event in a new work, and queue it at the tail of workqueue,
   once the sas port be deleted, its children device will be deleted too,
   when the destruction work start, it will found the target device has
   been removed, and report a sysfs warnning.
3. since a hotplug process will be devided into several works, if a phy up
   sas event insert into phydown works, like
   destruction work  ---> PORTE_BYTES_DMAED (sas_form_port) 
>PHYE_LOSS_OF_SIGNAL
   the hot remove flow would broken by PORTE_BYTES_DMAED event, it's not
   we expected, and issues would occur.

The first patch fix the sas events lost, and the second one introudce 
wait-complete
to fix the hotplug order issues.

v1->v2: some code improvements suggested by John Garry

Yijing Wang (2):
  libsas: Don't process sas events in static works
  libsas: Enhance libsas hotplug

 drivers/scsi/libsas/sas_discover.c | 58 +---
 drivers/scsi/libsas/sas_event.c| 90 ++
 drivers/scsi/libsas/sas_expander.c |  9 +++-
 drivers/scsi/libsas/sas_init.c | 29 +---
 drivers/scsi/libsas/sas_internal.h | 64 +++
 drivers/scsi/libsas/sas_phy.c  | 45 ---
 drivers/scsi/libsas/sas_port.c | 22 +-
 include/scsi/libsas.h  | 19 
 8 files changed, 232 insertions(+), 104 deletions(-)

-- 
2.5.0



[PATCH v2 2/2] libsas: Enhance libsas hotplug

2017-06-14 Thread Yijing Wang
Libsas complete a hotplug event notified by LLDD in several works,
for example, if libsas receive a PHYE_LOSS_OF_SIGNAL, we process it
in following steps:

notify_phy_event[interrupt context]
sas_queue_event [queue work on shost->work_q]
sas_phye_loss_of_signal [running in shost->work_q]
sas_deform_port [remove sas port]
sas_unregister_dev
sas_discover_event  [queue destruct 
work on shost->work_q tail]

In above case, complete whole hotplug in two works, remove sas port first, then
put the destruction of device in another work and queue it on in the tail of
workqueue, since sas port is the parent of the children rphy device, so if 
remove
sas port first, the children rphy device would also be deleted, when the 
destruction
work coming, it would find the target has been removed already, and report a
sysfs warning calltrace.

queue tail queue head
DISCE_DESTRUCT> PORTE_BYTES_DMAED event ->PHYE_LOSS_OF_SIGNAL[running]

There are other hotplug issues in current framework, in above case, if there is
hotadd sas event queued between hotremove works, the hotplug order would be 
broken
and unexpected issues would happen.

In this patch, we try to solve these issues in following steps:
1. create a new workqueue used to run sas event work, instead of scsi host 
workqueue,
   because we may block sas event work, we cannot block the normal scsi works.
   When libsas receive a phy down event, sas_deform_port would be called, and 
now we
   block sas_deform_port and wait for destruction work finish, in 
sas_destruct_devices,
   we may wait ata error handler, it would take a long time, so if do all stuff 
in scsi
   host workq, libsas may block other scsi works too long.
2. create a new workqueue used to run sas discovery events work, instead of 
scsi host
   workqueue, because in some cases, eg. in revalidate domain event, we may 
unregister
   a sas device and discover new one, we must sync the execution, wait the 
remove process
   finish, then start a new discovery. So we must put the probe and destruct 
discovery
   events in a new workqueue to avoid deadlock.
3. introudce a asd_sas_port level wait-complete and a sas_discovery level 
wait-complete
   we use former wait-complete to achieve a sas event atomic process and use 
latter to
   make a sas discovery sync.
4. remove disco_mutex in sas_revalidate_domain, since now sas_revalidate_domain 
sync
   the destruct discovery event execution, it's no need to lock disco mutex 
there.

Signed-off-by: Yijing Wang 
---
 drivers/scsi/libsas/sas_discover.c | 58 ++--
 drivers/scsi/libsas/sas_event.c|  2 +-
 drivers/scsi/libsas/sas_expander.c |  9 +-
 drivers/scsi/libsas/sas_init.c | 23 +-
 drivers/scsi/libsas/sas_internal.h | 61 ++
 drivers/scsi/libsas/sas_port.c |  4 +++
 include/scsi/libsas.h  |  9 ++
 7 files changed, 148 insertions(+), 18 deletions(-)

diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 60de662..43e8a1e 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -503,11 +503,10 @@ static void sas_revalidate_domain(struct work_struct 
*work)
struct domain_device *ddev = port->port_dev;
 
/* prevent revalidation from finding sata links in recovery */
-   mutex_lock(>disco_mutex);
if (test_bit(SAS_HA_ATA_EH_ACTIVE, >state)) {
SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n",
port->id, task_pid_nr(current));
-   goto out;
+   return;
}
 
clear_bit(DISCE_REVALIDATE_DOMAIN, >disc.pending);
@@ -521,20 +520,57 @@ static void sas_revalidate_domain(struct work_struct 
*work)
 
SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
port->id, task_pid_nr(current), res);
- out:
-   mutex_unlock(>disco_mutex);
+}
+
+static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
+   [DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
+   [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
+   [DISCE_PROBE] = sas_probe_devices,
+   [DISCE_SUSPEND] = sas_suspend_devices,
+   [DISCE_RESUME] = sas_resume_devices,
+   [DISCE_DESTRUCT] = sas_destruct_devices,
+};
+
+/* a simple wrapper for sas discover event funtions */
+static void sas_discover_common_fn(struct work_struct *work)
+{
+   struct sas_discovery_event *ev = to_sas_discovery_event(work);
+   struct asd_sas_port *port = ev->port;
+
+   sas_event_fns[ev->type](work);
+   sas_unbusy_port(port);
 }
 
 /* -- Events -- */
 
 static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw)
 {

[PATCH v2 0/2] Enhance libsas hotplug feature

2017-06-14 Thread Yijing Wang
Now the libsas hotplug has some issues, Dan Williams report
a similar bug here before
https://www.mail-archive.com/linux-scsi@vger.kernel.org/msg39187.html

The issues we have found
1. if LLDD burst reports lots of phy-up/phy-down sas events, some events
   may lost because a same sas events is pending now, finally libsas topo
   may different the hardware.
2. receive a phy down sas event, libsas call sas_deform_port to remove
   devices, it would first delete the sas port, then put a destruction
   discovery event in a new work, and queue it at the tail of workqueue,
   once the sas port be deleted, its children device will be deleted too,
   when the destruction work start, it will found the target device has
   been removed, and report a sysfs warnning.
3. since a hotplug process will be devided into several works, if a phy up
   sas event insert into phydown works, like
   destruction work  ---> PORTE_BYTES_DMAED (sas_form_port) 
>PHYE_LOSS_OF_SIGNAL
   the hot remove flow would broken by PORTE_BYTES_DMAED event, it's not
   we expected, and issues would occur.

The first patch fix the sas events lost, and the second one introudce 
wait-complete
to fix the hotplug order issues.

v1->v2: some code improvements suggested by John Garry

Yijing Wang (2):
  libsas: Don't process sas events in static works
  libsas: Enhance libsas hotplug

 drivers/scsi/libsas/sas_discover.c | 58 +---
 drivers/scsi/libsas/sas_event.c| 90 ++
 drivers/scsi/libsas/sas_expander.c |  9 +++-
 drivers/scsi/libsas/sas_init.c | 29 +---
 drivers/scsi/libsas/sas_internal.h | 64 +++
 drivers/scsi/libsas/sas_phy.c  | 45 ---
 drivers/scsi/libsas/sas_port.c | 22 +-
 include/scsi/libsas.h  | 19 
 8 files changed, 232 insertions(+), 104 deletions(-)

-- 
2.5.0



[PATCH v2 1/2] libsas: Don't process sas events in static works

2017-06-14 Thread Yijing Wang
Now libsas hotplug work is static, LLDD driver queue
the hotplug work into shost->work_q. If LLDD driver
burst post lots hotplug events to libsas, the hotplug
events may pending in the workqueue like

shost->work_q
new work[PORTE_BYTES_DMAED] --> |[PHYE_LOSS_OF_SIGNAL][PORTE_BYTES_DMAED] -> 
processing
|<---wait worker to process>|
In this case, a new PORTE_BYTES_DMAED event coming, libsas try to queue it
to shost->work_q, but this work is already pending, so it would be lost.
Finally, libsas delete the related sas port and sas devices, but LLDD driver
expect libsas add the sas port and devices(last sas event).

This patch remove the static defined hotplug work, and use dynamic work to
avoid missing hotplug events.

Signed-off-by: Yijing Wang 
Signed-off-by: Yousong He 
Signed-off-by: Qilin Chen 
---
 drivers/scsi/libsas/sas_event.c| 88 +++---
 drivers/scsi/libsas/sas_init.c |  6 ---
 drivers/scsi/libsas/sas_internal.h |  3 ++
 drivers/scsi/libsas/sas_phy.c  | 45 ---
 drivers/scsi/libsas/sas_port.c | 18 
 include/scsi/libsas.h  | 10 +
 6 files changed, 84 insertions(+), 86 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index aadbd53..06c5c4b 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -27,6 +27,10 @@
 #include "sas_internal.h"
 #include "sas_dump.h"
 
+static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = {
+   [HAE_RESET] = sas_hae_reset,
+};
+
 void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
 {
if (!test_bit(SAS_HA_REGISTERED, >state))
@@ -40,17 +44,14 @@ void sas_queue_work(struct sas_ha_struct *ha, struct 
sas_work *sw)
scsi_queue_work(ha->core.shost, >work);
 }
 
-static void sas_queue_event(int event, unsigned long *pending,
-   struct sas_work *work,
+static void sas_queue_event(int event, struct sas_work *work,
struct sas_ha_struct *ha)
 {
-   if (!test_and_set_bit(event, pending)) {
-   unsigned long flags;
+   unsigned long flags;
 
-   spin_lock_irqsave(>lock, flags);
-   sas_queue_work(ha, work);
-   spin_unlock_irqrestore(>lock, flags);
-   }
+   spin_lock_irqsave(>lock, flags);
+   sas_queue_work(ha, work);
+   spin_unlock_irqrestore(>lock, flags);
 }
 
 
@@ -111,52 +112,87 @@ void sas_enable_revalidation(struct sas_ha_struct *ha)
if (!test_and_clear_bit(ev, >pending))
continue;
 
-   sas_queue_event(ev, >pending, >disc_work[ev].work, ha);
+   sas_queue_event(ev, >disc_work[ev].work, ha);
}
mutex_unlock(>disco_mutex);
 }
 
+static void sas_ha_event_worker(struct work_struct *work)
+{
+   struct sas_ha_event *ev = to_sas_ha_event(work);
+
+   sas_ha_event_fns[ev->type](work);
+   kfree(ev);
+}
+
+static void sas_port_event_worker(struct work_struct *work)
+{
+   struct asd_sas_event *ev = to_asd_sas_event(work);
+
+   sas_port_event_fns[ev->type](work);
+   kfree(ev);
+}
+
+static void sas_phy_event_worker(struct work_struct *work)
+{
+   struct asd_sas_event *ev = to_asd_sas_event(work);
+
+   sas_phy_event_fns[ev->type](work);
+   kfree(ev);
+}
+
 static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
 {
+   struct sas_ha_event *ev;
+
BUG_ON(event >= HA_NUM_EVENTS);
 
-   sas_queue_event(event, _ha->pending,
-   _ha->ha_events[event].work, sas_ha);
+   ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, sas_ha_event_worker);
+   ev->ha = sas_ha;
+   ev->type = event;
+   sas_queue_event(event, >work, sas_ha);
 }
 
 static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
 {
+   struct asd_sas_event *ev;
struct sas_ha_struct *ha = phy->ha;
 
BUG_ON(event >= PORT_NUM_EVENTS);
 
-   sas_queue_event(event, >port_events_pending,
-   >port_events[event].work, ha);
+   ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, sas_port_event_worker);
+   ev->phy = phy;
+   ev->type = event;
+   sas_queue_event(event, >work, ha);
 }
 
 void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
 {
+   struct asd_sas_event *ev;
struct sas_ha_struct *ha = phy->ha;
 
BUG_ON(event >= PHY_NUM_EVENTS);
 
-   sas_queue_event(event, >phy_events_pending,
-   >phy_events[event].work, ha);
+   ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, 

mpt3sas: driver got task abort request just after it's .shutdown() function is invoked

2017-06-14 Thread Sreekanth Reddy
Hi All,

I am using 4.9 kernel and I am observing NULL pointer deference type
kernel panic in the below scenario,

* Hotplug (i.e. hot add) the HBA (with a set of drives attached to it)
to the system just few seconds before issuing "poweroff" command.

* Observed that during drives discovery process; for some of the
drives "MODE SENSE" command got timed out.

* And as "poweroff" command issued, so kernel as called driver's
shutdown() callback function and driver has cleaned up all the HBA
resources (such as IRQ's, memory pools etc).

* But as the "MODE SENSE" command got timed out, so SCSI EH thread has
invoked driver's .eh_abort_handler() callback function, but by this
time driver has already cleaned up the resources and so it leads to
kernel panic when it trying to access one of these resources.

I was assuming that kernel should not call driver's shutdown()
callback function until all the outstanding IOs count reaches to zero
(i.e. kernel should call the driver's shutdown() functions only after
clearing up all the outstanding IOs). Please correct me if I am wrong,
and please suggest better way to handle these types of issues.

Thanks,
Sreekanth


Here I am copying the required driver logs,

[  429.995550] mpt3sas :b6:00.0: enabling device (0100 -> 0102)
[  429.995629] mpt3sas_cm3: 64 BIT PCI BUS DMA ADDRESSING SUPPORTED,
total mem (131164804 kB)
[  429.995636] mpt3sas_cm3: _base_get_ioc_facts
[  429.995636] mpt3sas_cm3: _base_wait_for_iocstate
[  430.109107] offset:data
[  430.109107] [0x00]:03110206
[  430.109108] [0x04]:2e00
[  430.109108] [0x08]:
[  430.109108] [0x0c]:
[  430.109109] [0x10]:
[  430.109109] [0x14]:60010080
[  430.109110] [0x18]:22281700
[  430.109110] [0x1c]:0007a85c
[  430.109110] [0x20]:0e00
[  430.109111] [0x24]:00100040
[  430.109111] [0x28]:0180001b
[  430.109111] [0x2c]:00b100b0
[  430.109112] [0x30]:006c0003
[  430.109112] [0x34]:0020ffe0
[  430.109112] [0x38]:00800263
[  430.109113] [0x3c]:0019
[  430.109113] mpt3sas_cm3: IOC Number : 0
[  430.109114] mpt3sas_cm3: hba queue depth(5888), max chains per io(128)
[  430.109114] mpt3sas_cm3: request frame size(256), reply frame size(128)
[  430.109130] mpt3sas_cm3: msix is supported, vector_count(96)
[  430.109131] mpt3sas_cm3: MSI-X vectors supported: 96, no of cores:
16, max_msix_vectors: -1
[  430.109497] mpt3sas3-msix0: PCI-MSI-X enabled: IRQ 76
[  430.109497] mpt3sas3-msix1: PCI-MSI-X enabled: IRQ 77
[  430.109498] mpt3sas3-msix2: PCI-MSI-X enabled: IRQ 78
[  430.109498] mpt3sas3-msix3: PCI-MSI-X enabled: IRQ 79
[  430.109499] mpt3sas3-msix4: PCI-MSI-X enabled: IRQ 80
[  430.109499] mpt3sas3-msix5: PCI-MSI-X enabled: IRQ 81
[  430.109499] mpt3sas3-msix6: PCI-MSI-X enabled: IRQ 82
[  430.109500] mpt3sas3-msix7: PCI-MSI-X enabled: IRQ 83
[  430.109500] mpt3sas3-msix8: PCI-MSI-X enabled: IRQ 84
[  430.109500] mpt3sas3-msix9: PCI-MSI-X enabled: IRQ 85
[  430.109501] mpt3sas3-msix10: PCI-MSI-X enabled: IRQ 86
[  430.109501] mpt3sas3-msix11: PCI-MSI-X enabled: IRQ 87
[  430.109502] mpt3sas3-msix12: PCI-MSI-X enabled: IRQ 88
[  430.109502] mpt3sas3-msix13: PCI-MSI-X enabled: IRQ 89
[  430.109502] mpt3sas3-msix14: PCI-MSI-X enabled: IRQ 90
[  430.109503] mpt3sas3-msix15: PCI-MSI-X enabled: IRQ 91
[  430.109504] mpt3sas_cm3: iomem(0xfb80),
mapped(0xc9000e89), size(65536)
[  430.109504] mpt3sas_cm3: ioport(0xc000), size(256)
[  430.109531] mpt3sas_cm3: _base_get_ioc_facts
[  430.109531] mpt3sas_cm3: _base_wait_for_iocstate
[  430.222840] offset:data
[  430.222840] [0x00]:03110206
[  430.222841] [0x04]:2e00
[  430.222841] [0x08]:
[  430.222842] [0x0c]:
[  430.222842] [0x10]:
[  430.222842] [0x14]:60010080
[  430.222843] [0x18]:22281700
[  430.222843] [0x1c]:0007a85c
[  430.222844] [0x20]:0e00
[  430.222844] [0x24]:00100040
[  430.222844] [0x28]:0180001b
[  430.222845] [0x2c]:00b100b0
[  430.222845] [0x30]:006c0003
[  430.222846] [0x34]:0020ffe0
[  430.222846] [0x38]:00800263
[  430.222846] [0x3c]:0019
[  430.222847] mpt3sas_cm3: IOC Number : 0
[  430.222847] mpt3sas_cm3: hba queue depth(5888), max chains per io(128)
[  430.222848] mpt3sas_cm3: request frame size(256), reply frame size(128)
[  430.222848] mpt3sas_cm3: _base_make_ioc_ready
[  430.222850] mpt3sas_cm3: _base_get_port_facts
[  430.276713] offset:data
[  430.276714] [0x00]:0507
[  430.276714] [0x04]:
[  430.276714] [0x08]:
[  430.276715] [0x0c]:
[  430.276715] [0x10]:
[  430.276716] [0x14]:3000
[  430.276716] [0x18]:00d8
[  430.276716] mpt3sas_cm3: _base_allocate_memory_pools
[  430.276717] mpt3sas_cm3: scatter gather: sge_in_main_msg(8),
sge_per_chain(15), sge_per_io(128), chains_per_io(9)
[  430.276718] mpt3sas_cm3: scsi host: can_queue depth (5772)
[