[PATCH v3 3/7] libsas: Use new workqueue to run sas event

2017-07-10 Thread Yijing Wang
Now all libsas works are queued to scsi host workqueue,
include sas event work post by LLDD and sas discovery
work, and a sas hotplug flow may be divided into several
works, e.g libsas receive a PORTE_BYTES_DMAED event,
now we process it as following steps:
sas_form_port  --- run in work in shot workq
sas_discover_domain  --- run in another work in shost workq
...
sas_probe_devices  --- run in new work in shost workq
We found during hot-add a device, libsas may need run several
works in same workqueue to add device in system, the process is
not atomic, it may interrupt by other sas event works, like
PHYE_LOSS_OF_SIGNAL. Finally, we would found lots unexpected
errors. This patch is preparation of execute libsas sas event
in sync.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
CC: John Garry <john.ga...@huawei.com>
CC: Johannes Thumshirn <jthumsh...@suse.de>
CC: Ewan Milne <emi...@redhat.com>
CC: Christoph Hellwig <h...@lst.de>
CC: Tomas Henzl <the...@redhat.com>
CC: Dan Williams <dan.j.willi...@intel.com>
---
 drivers/scsi/libsas/sas_event.c | 4 ++--
 drivers/scsi/libsas/sas_init.c  | 7 +++
 include/scsi/libsas.h   | 1 +
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index a1370bd..a72a089 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -46,7 +46,7 @@ int sas_queue_work(struct sas_ha_struct *ha, struct sas_work 
*sw)
if (list_empty(>drain_node))
list_add(>drain_node, >defer_q);
} else
-   rc = scsi_queue_work(ha->core.shost, >work);
+   rc = queue_work(ha->event_q, >work);
 
return rc;
 }
@@ -69,7 +69,7 @@ void __sas_drain_work(struct sas_ha_struct *ha)
 {
int ret;
unsigned long flags;
-   struct workqueue_struct *wq = ha->core.shost->work_q;
+   struct workqueue_struct *wq = ha->event_q;
struct sas_work *sw, *_sw;
 
set_bit(SAS_HA_DRAINING, >state);
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index c227a8b..2f3b736 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -115,6 +115,7 @@ void sas_hae_reset(struct work_struct *work)
 
 int sas_register_ha(struct sas_ha_struct *sas_ha)
 {
+   char name[64];
int error = 0;
 
mutex_init(_ha->disco_mutex);
@@ -146,6 +147,11 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
goto Undo_ports;
}
 
+   snprintf(name, 64, "%s_event_q", dev_name(sas_ha->dev));
+   sas_ha->event_q = create_singlethread_workqueue(name);
+   if (!sas_ha->event_q)
+   goto Undo_ports;
+
INIT_LIST_HEAD(_ha->eh_done_q);
INIT_LIST_HEAD(_ha->eh_ata_q);
 
@@ -180,6 +186,7 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
mutex_lock(_ha->drain_mutex);
__sas_drain_work(sas_ha);
mutex_unlock(_ha->drain_mutex);
+   destroy_workqueue(sas_ha->event_q);
 
return 0;
 }
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 628f48b..a01ca42 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -402,6 +402,7 @@ struct sas_ha_struct {
char *sas_ha_name;
struct device *dev;   /* should be set */
struct module *lldd_module; /* should be set */
+   struct workqueue_struct *event_q;
 
u8 *sas_addr; /* must be set */
u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
-- 
2.5.0



[PATCH v3 3/7] libsas: Use new workqueue to run sas event

2017-07-10 Thread Yijing Wang
Now all libsas works are queued to scsi host workqueue,
include sas event work post by LLDD and sas discovery
work, and a sas hotplug flow may be divided into several
works, e.g libsas receive a PORTE_BYTES_DMAED event,
now we process it as following steps:
sas_form_port  --- run in work in shot workq
sas_discover_domain  --- run in another work in shost workq
...
sas_probe_devices  --- run in new work in shost workq
We found during hot-add a device, libsas may need run several
works in same workqueue to add device in system, the process is
not atomic, it may interrupt by other sas event works, like
PHYE_LOSS_OF_SIGNAL. Finally, we would found lots unexpected
errors. This patch is preparation of execute libsas sas event
in sync.

Signed-off-by: Yijing Wang 
CC: John Garry 
CC: Johannes Thumshirn 
CC: Ewan Milne 
CC: Christoph Hellwig 
CC: Tomas Henzl 
CC: Dan Williams 
---
 drivers/scsi/libsas/sas_event.c | 4 ++--
 drivers/scsi/libsas/sas_init.c  | 7 +++
 include/scsi/libsas.h   | 1 +
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index a1370bd..a72a089 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -46,7 +46,7 @@ int sas_queue_work(struct sas_ha_struct *ha, struct sas_work 
*sw)
if (list_empty(>drain_node))
list_add(>drain_node, >defer_q);
} else
-   rc = scsi_queue_work(ha->core.shost, >work);
+   rc = queue_work(ha->event_q, >work);
 
return rc;
 }
@@ -69,7 +69,7 @@ void __sas_drain_work(struct sas_ha_struct *ha)
 {
int ret;
unsigned long flags;
-   struct workqueue_struct *wq = ha->core.shost->work_q;
+   struct workqueue_struct *wq = ha->event_q;
struct sas_work *sw, *_sw;
 
set_bit(SAS_HA_DRAINING, >state);
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index c227a8b..2f3b736 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -115,6 +115,7 @@ void sas_hae_reset(struct work_struct *work)
 
 int sas_register_ha(struct sas_ha_struct *sas_ha)
 {
+   char name[64];
int error = 0;
 
mutex_init(_ha->disco_mutex);
@@ -146,6 +147,11 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
goto Undo_ports;
}
 
+   snprintf(name, 64, "%s_event_q", dev_name(sas_ha->dev));
+   sas_ha->event_q = create_singlethread_workqueue(name);
+   if (!sas_ha->event_q)
+   goto Undo_ports;
+
INIT_LIST_HEAD(_ha->eh_done_q);
INIT_LIST_HEAD(_ha->eh_ata_q);
 
@@ -180,6 +186,7 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
mutex_lock(_ha->drain_mutex);
__sas_drain_work(sas_ha);
mutex_unlock(_ha->drain_mutex);
+   destroy_workqueue(sas_ha->event_q);
 
return 0;
 }
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 628f48b..a01ca42 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -402,6 +402,7 @@ struct sas_ha_struct {
char *sas_ha_name;
struct device *dev;   /* should be set */
struct module *lldd_module; /* should be set */
+   struct workqueue_struct *event_q;
 
u8 *sas_addr; /* must be set */
u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
-- 
2.5.0



[PATCH v3 7/7] libsas: release disco mutex during waiting in sas_ex_discover_end_dev

2017-07-10 Thread Yijing Wang
Disco mutex was introudced to prevent domain rediscovery competing
with ata error handling(87c8331). If we have already hold the lock
in sas_revalidate_domain and sync executing probe, deadlock caused,
because, sas_probe_sata() also need hold disco_mutex. Since disco mutex
use to prevent revalidata domain happen during ata error handler,
it should be safe to release disco mutex when sync probe, because
no new revalidate domain event would be process until the sync return,
and the current sas revalidate domain finish.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
CC: John Garry <john.ga...@huawei.com>
CC: Johannes Thumshirn <jthumsh...@suse.de>
CC: Ewan Milne <emi...@redhat.com>
CC: Christoph Hellwig <h...@lst.de>
CC: Tomas Henzl <the...@redhat.com>
CC: Dan Williams <dan.j.willi...@intel.com>
---
 drivers/scsi/libsas/sas_expander.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/scsi/libsas/sas_expander.c 
b/drivers/scsi/libsas/sas_expander.c
index 9d26c28..077024e 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -776,6 +776,7 @@ static struct domain_device *sas_ex_discover_end_dev(
struct ex_phy *phy = _ex->ex_phy[phy_id];
struct domain_device *child = NULL;
struct sas_rphy *rphy;
+   bool prev_lock;
int res;
 
if (phy->attached_sata_host || phy->attached_sata_ps)
@@ -803,6 +804,7 @@ static struct domain_device *sas_ex_discover_end_dev(
sas_ex_get_linkrate(parent, child, phy);
sas_device_set_phy(child, phy->port);
 
+   prev_lock = mutex_is_locked(>port->ha->disco_mutex);
 #ifdef CONFIG_SCSI_SAS_ATA
if ((phy->attached_tproto & SAS_PROTOCOL_STP) || 
phy->attached_sata_dev) {
res = sas_get_ata_info(child, phy);
@@ -832,7 +834,11 @@ static struct domain_device *sas_ex_discover_end_dev(
SAS_ADDR(parent->sas_addr), phy_id, res);
goto out_list_del;
}
+   if (prev_lock)
+   mutex_unlock(>port->ha->disco_mutex);
sas_disc_wait_completion(child->port, DISCE_PROBE);
+   if (prev_lock)
+   mutex_lock(>port->ha->disco_mutex);
 
} else
 #endif
@@ -861,7 +867,11 @@ static struct domain_device *sas_ex_discover_end_dev(
SAS_ADDR(parent->sas_addr), phy_id, res);
goto out_list_del;
}
+   if (prev_lock)
+   mutex_unlock(>port->ha->disco_mutex);
sas_disc_wait_completion(child->port, DISCE_PROBE);
+   if (prev_lock)
+   mutex_lock(>port->ha->disco_mutex);
} else {
SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
phy->attached_tproto, SAS_ADDR(parent->sas_addr),
-- 
2.5.0



[PATCH v3 5/7] libsas: add a new workqueue to run probe/destruct discovery event

2017-07-10 Thread Yijing Wang
Sometimes, we want sync libsas probe or destruct in sas discovery work,
like when libsas revalidate domain. We need to split probe and destruct
work from the scsi host workqueue.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
CC: John Garry <john.ga...@huawei.com>
CC: Johannes Thumshirn <jthumsh...@suse.de>
CC: Ewan Milne <emi...@redhat.com>
CC: Christoph Hellwig <h...@lst.de>
CC: Tomas Henzl <the...@redhat.com>
CC: Dan Williams <dan.j.willi...@intel.com>
---
 drivers/scsi/libsas/sas_discover.c | 13 -
 drivers/scsi/libsas/sas_init.c |  8 
 include/scsi/libsas.h  |  1 +
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 5d4a3a8..a25d648 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -559,7 +559,18 @@ static void sas_chain_work(struct sas_ha_struct *ha, 
struct sas_work *sw)
 * not racing against draining
 */
sas_port_get(port);
-   ret = scsi_queue_work(ha->core.shost, >work);
+   /*
+* discovery event probe and destruct would be called in other
+* discovery event like discover domain and revalidate domain
+* events, in some cases, we need to sync execute probe and destruct
+* events, so run probe and destruct discover events except in a new
+* workqueue.
+*/
+   if (ev->type == DISCE_PROBE || ev->type == DISCE_DESTRUCT)
+   ret = queue_work(ha->disc_q, >work);
+   else
+   ret = scsi_queue_work(ha->core.shost, >work);
+
if (ret != 1)
sas_port_put(port);
 }
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 2f3b736..df1d78b 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -152,6 +152,13 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
if (!sas_ha->event_q)
goto Undo_ports;
 
+   snprintf(name, 64, "%s_disc_q", dev_name(sas_ha->dev));
+   sas_ha->disc_q = create_singlethread_workqueue(name);
+   if(!sas_ha->disc_q) {
+   destroy_workqueue(sas_ha->event_q);
+   goto Undo_ports;
+   }
+
INIT_LIST_HEAD(_ha->eh_done_q);
INIT_LIST_HEAD(_ha->eh_ata_q);
 
@@ -187,6 +194,7 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
__sas_drain_work(sas_ha);
mutex_unlock(_ha->drain_mutex);
destroy_workqueue(sas_ha->event_q);
+   destroy_workqueue(sas_ha->disc_q);
 
return 0;
 }
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index c2ef05e..4bcb9fe 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -406,6 +406,7 @@ struct sas_ha_struct {
struct device *dev;   /* should be set */
struct module *lldd_module; /* should be set */
struct workqueue_struct *event_q;
+   struct workqueue_struct *disc_q;
 
u8 *sas_addr; /* must be set */
u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
-- 
2.5.0



[PATCH v3 2/7] libsas: remove unused port_gone_completion

2017-07-10 Thread Yijing Wang
No one uses the port_gone_completion in struct asd_sas_port,
clean it out.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 include/scsi/libsas.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index c41328d..628f48b 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -263,8 +263,6 @@ struct sas_discovery {
 /* The port struct is Class:RW, driver:RO */
 struct asd_sas_port {
 /* private: */
-   struct completion port_gone_completion;
-
struct sas_discovery disc;
struct domain_device *port_dev;
spinlock_t dev_list_lock;
-- 
2.5.0



[PATCH v3 7/7] libsas: release disco mutex during waiting in sas_ex_discover_end_dev

2017-07-10 Thread Yijing Wang
Disco mutex was introudced to prevent domain rediscovery competing
with ata error handling(87c8331). If we have already hold the lock
in sas_revalidate_domain and sync executing probe, deadlock caused,
because, sas_probe_sata() also need hold disco_mutex. Since disco mutex
use to prevent revalidata domain happen during ata error handler,
it should be safe to release disco mutex when sync probe, because
no new revalidate domain event would be process until the sync return,
and the current sas revalidate domain finish.

Signed-off-by: Yijing Wang 
CC: John Garry 
CC: Johannes Thumshirn 
CC: Ewan Milne 
CC: Christoph Hellwig 
CC: Tomas Henzl 
CC: Dan Williams 
---
 drivers/scsi/libsas/sas_expander.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/scsi/libsas/sas_expander.c 
b/drivers/scsi/libsas/sas_expander.c
index 9d26c28..077024e 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -776,6 +776,7 @@ static struct domain_device *sas_ex_discover_end_dev(
struct ex_phy *phy = _ex->ex_phy[phy_id];
struct domain_device *child = NULL;
struct sas_rphy *rphy;
+   bool prev_lock;
int res;
 
if (phy->attached_sata_host || phy->attached_sata_ps)
@@ -803,6 +804,7 @@ static struct domain_device *sas_ex_discover_end_dev(
sas_ex_get_linkrate(parent, child, phy);
sas_device_set_phy(child, phy->port);
 
+   prev_lock = mutex_is_locked(>port->ha->disco_mutex);
 #ifdef CONFIG_SCSI_SAS_ATA
if ((phy->attached_tproto & SAS_PROTOCOL_STP) || 
phy->attached_sata_dev) {
res = sas_get_ata_info(child, phy);
@@ -832,7 +834,11 @@ static struct domain_device *sas_ex_discover_end_dev(
SAS_ADDR(parent->sas_addr), phy_id, res);
goto out_list_del;
}
+   if (prev_lock)
+   mutex_unlock(>port->ha->disco_mutex);
sas_disc_wait_completion(child->port, DISCE_PROBE);
+   if (prev_lock)
+   mutex_lock(>port->ha->disco_mutex);
 
} else
 #endif
@@ -861,7 +867,11 @@ static struct domain_device *sas_ex_discover_end_dev(
SAS_ADDR(parent->sas_addr), phy_id, res);
goto out_list_del;
}
+   if (prev_lock)
+   mutex_unlock(>port->ha->disco_mutex);
sas_disc_wait_completion(child->port, DISCE_PROBE);
+   if (prev_lock)
+   mutex_lock(>port->ha->disco_mutex);
} else {
SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
phy->attached_tproto, SAS_ADDR(parent->sas_addr),
-- 
2.5.0



[PATCH v3 5/7] libsas: add a new workqueue to run probe/destruct discovery event

2017-07-10 Thread Yijing Wang
Sometimes, we want sync libsas probe or destruct in sas discovery work,
like when libsas revalidate domain. We need to split probe and destruct
work from the scsi host workqueue.

Signed-off-by: Yijing Wang 
CC: John Garry 
CC: Johannes Thumshirn 
CC: Ewan Milne 
CC: Christoph Hellwig 
CC: Tomas Henzl 
CC: Dan Williams 
---
 drivers/scsi/libsas/sas_discover.c | 13 -
 drivers/scsi/libsas/sas_init.c |  8 
 include/scsi/libsas.h  |  1 +
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 5d4a3a8..a25d648 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -559,7 +559,18 @@ static void sas_chain_work(struct sas_ha_struct *ha, 
struct sas_work *sw)
 * not racing against draining
 */
sas_port_get(port);
-   ret = scsi_queue_work(ha->core.shost, >work);
+   /*
+* discovery event probe and destruct would be called in other
+* discovery event like discover domain and revalidate domain
+* events, in some cases, we need to sync execute probe and destruct
+* events, so run probe and destruct discover events except in a new
+* workqueue.
+*/
+   if (ev->type == DISCE_PROBE || ev->type == DISCE_DESTRUCT)
+   ret = queue_work(ha->disc_q, >work);
+   else
+   ret = scsi_queue_work(ha->core.shost, >work);
+
if (ret != 1)
sas_port_put(port);
 }
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 2f3b736..df1d78b 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -152,6 +152,13 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
if (!sas_ha->event_q)
goto Undo_ports;
 
+   snprintf(name, 64, "%s_disc_q", dev_name(sas_ha->dev));
+   sas_ha->disc_q = create_singlethread_workqueue(name);
+   if(!sas_ha->disc_q) {
+   destroy_workqueue(sas_ha->event_q);
+   goto Undo_ports;
+   }
+
INIT_LIST_HEAD(_ha->eh_done_q);
INIT_LIST_HEAD(_ha->eh_ata_q);
 
@@ -187,6 +194,7 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
__sas_drain_work(sas_ha);
mutex_unlock(_ha->drain_mutex);
destroy_workqueue(sas_ha->event_q);
+   destroy_workqueue(sas_ha->disc_q);
 
return 0;
 }
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index c2ef05e..4bcb9fe 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -406,6 +406,7 @@ struct sas_ha_struct {
struct device *dev;   /* should be set */
struct module *lldd_module; /* should be set */
struct workqueue_struct *event_q;
+   struct workqueue_struct *disc_q;
 
u8 *sas_addr; /* must be set */
u8 hashed_sas_addr[HASHED_SAS_ADDR_SIZE];
-- 
2.5.0



[PATCH v3 2/7] libsas: remove unused port_gone_completion

2017-07-10 Thread Yijing Wang
No one uses the port_gone_completion in struct asd_sas_port,
clean it out.

Signed-off-by: Yijing Wang 
---
 include/scsi/libsas.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index c41328d..628f48b 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -263,8 +263,6 @@ struct sas_discovery {
 /* The port struct is Class:RW, driver:RO */
 struct asd_sas_port {
 /* private: */
-   struct completion port_gone_completion;
-
struct sas_discovery disc;
struct domain_device *port_dev;
spinlock_t dev_list_lock;
-- 
2.5.0



[PATCH v3 6/7] libsas: add wait-complete support to sync discovery event

2017-07-10 Thread Yijing Wang
Introduce a sync flag to tag discovery event whether need to
sync execute, per-event wait-complete ensure sync.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
CC: John Garry <john.ga...@huawei.com>
CC: Johannes Thumshirn <jthumsh...@suse.de>
CC: Ewan Milne <emi...@redhat.com>
CC: Christoph Hellwig <h...@lst.de>
CC: Tomas Henzl <the...@redhat.com>
CC: Dan Williams <dan.j.willi...@intel.com>
---
 drivers/scsi/libsas/sas_discover.c |  8 ++--
 drivers/scsi/libsas/sas_expander.c | 12 +++-
 drivers/scsi/libsas/sas_internal.h | 27 +++
 include/scsi/libsas.h  |  2 ++
 4 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index a25d648..d68f8dd 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -378,6 +378,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct 
domain_device *dev)
list_del_init(>disco_list_node);
sas_rphy_free(dev->rphy);
sas_unregister_common_dev(port, dev);
+   sas_disc_cancel_sync(>disc.disc_work[DISCE_DESTRUCT]);
return;
}
 
@@ -541,6 +542,7 @@ static void sas_discover_common_fn(struct work_struct *work)
struct asd_sas_port *port = ev->port;
 
sas_event_fns[ev->type](work);
+   sas_disc_wakeup(ev);
sas_port_put(port);
 }
 
@@ -571,8 +573,10 @@ static void sas_chain_work(struct sas_ha_struct *ha, 
struct sas_work *sw)
else
ret = scsi_queue_work(ha->core.shost, >work);
 
-   if (ret != 1)
+   if (ret != 1) {
sas_port_put(port);
+   sas_disc_cancel_sync(ev);
+   }
 }
 
 static void sas_chain_event(int event, unsigned long *pending,
@@ -592,9 +596,9 @@ int sas_discover_event(struct asd_sas_port *port, enum 
discover_event ev)
 {
struct sas_discovery *disc;
 
+   disc = >disc;
if (!port)
return 0;
-   disc = >disc;
 
BUG_ON(ev >= DISC_NUM_EVENTS);
 
diff --git a/drivers/scsi/libsas/sas_expander.c 
b/drivers/scsi/libsas/sas_expander.c
index 570b2cb..9d26c28 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -822,14 +822,18 @@ static struct domain_device *sas_ex_discover_end_dev(
 
list_add_tail(>disco_list_node, 
>port->disco_list);
 
+   sas_disc_wait_init(child->port, DISCE_PROBE);
res = sas_discover_sata(child);
if (res) {
+   
sas_disc_cancel_sync(>port->disc.disc_work[DISCE_PROBE]);
SAS_DPRINTK("sas_discover_sata() for device %16llx at "
"%016llx:0x%x returned 0x%x\n",
SAS_ADDR(child->sas_addr),
SAS_ADDR(parent->sas_addr), phy_id, res);
goto out_list_del;
}
+   sas_disc_wait_completion(child->port, DISCE_PROBE);
+
} else
 #endif
  if (phy->attached_tproto & SAS_PROTOCOL_SSP) {
@@ -847,14 +851,17 @@ static struct domain_device *sas_ex_discover_end_dev(
 
list_add_tail(>disco_list_node, 
>port->disco_list);
 
+   sas_disc_wait_init(child->port, DISCE_PROBE);
res = sas_discover_end_dev(child);
if (res) {
+   
sas_disc_cancel_sync(>port->disc.disc_work[DISCE_PROBE]);
SAS_DPRINTK("sas_discover_end_dev() for device %16llx "
"at %016llx:0x%x returned 0x%x\n",
SAS_ADDR(child->sas_addr),
SAS_ADDR(parent->sas_addr), phy_id, res);
goto out_list_del;
}
+   sas_disc_wait_completion(child->port, DISCE_PROBE);
} else {
SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
phy->attached_tproto, SAS_ADDR(parent->sas_addr),
@@ -1890,8 +1897,11 @@ static void sas_unregister_devs_sas_addr(struct 
domain_device *parent,
if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE 
||
child->dev_type == 
SAS_FANOUT_EXPANDER_DEVICE)
sas_unregister_ex_tree(parent->port, 
child);
-   else
+   else {
+   sas_disc_wait_init(parent->port, 
DISCE_DESTRUCT);
sas_unregister_dev(parent->port, child);
+   sas_disc_wait_completion

[PATCH v3 0/7] Enhance libsas hotplug feature

2017-07-10 Thread Yijing Wang
This patchset is based Johannes's patch
"scsi: sas: scsi_queue_work can fail, so make callers aware"

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.

v2->v3: some code improvements suggested by Johannes and John,
split v2 patch 2 into several small pathes.
v1->v2: some code improvements suggested by John Garry

Yijing Wang (7):
  libsas: Use static sas event pool to appease sas event lost
  libsas: remove unused port_gone_completion
  libsas: Use new workqueue to run sas event
  libsas: add sas event wait-complete support
  libsas: add a new workqueue to run probe/destruct discovery event
  libsas: add wait-complete support to sync discovery event
  libsas: release disco mutex during waiting in sas_ex_discover_end_dev

 drivers/scsi/libsas/sas_discover.c |  58 +++---
 drivers/scsi/libsas/sas_event.c| 212 -
 drivers/scsi/libsas/sas_expander.c |  22 +++-
 drivers/scsi/libsas/sas_init.c |  21 ++--
 drivers/scsi/libsas/sas_internal.h |  64 +++
 drivers/scsi/libsas/sas_phy.c  |  48 +++--
 drivers/scsi/libsas/sas_port.c |  22 ++--
 include/scsi/libsas.h  |  27 +++--
 8 files changed, 373 insertions(+), 101 deletions(-)

-- 
2.5.0



[PATCH v3 6/7] libsas: add wait-complete support to sync discovery event

2017-07-10 Thread Yijing Wang
Introduce a sync flag to tag discovery event whether need to
sync execute, per-event wait-complete ensure sync.

Signed-off-by: Yijing Wang 
CC: John Garry 
CC: Johannes Thumshirn 
CC: Ewan Milne 
CC: Christoph Hellwig 
CC: Tomas Henzl 
CC: Dan Williams 
---
 drivers/scsi/libsas/sas_discover.c |  8 ++--
 drivers/scsi/libsas/sas_expander.c | 12 +++-
 drivers/scsi/libsas/sas_internal.h | 27 +++
 include/scsi/libsas.h  |  2 ++
 4 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index a25d648..d68f8dd 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -378,6 +378,7 @@ void sas_unregister_dev(struct asd_sas_port *port, struct 
domain_device *dev)
list_del_init(>disco_list_node);
sas_rphy_free(dev->rphy);
sas_unregister_common_dev(port, dev);
+   sas_disc_cancel_sync(>disc.disc_work[DISCE_DESTRUCT]);
return;
}
 
@@ -541,6 +542,7 @@ static void sas_discover_common_fn(struct work_struct *work)
struct asd_sas_port *port = ev->port;
 
sas_event_fns[ev->type](work);
+   sas_disc_wakeup(ev);
sas_port_put(port);
 }
 
@@ -571,8 +573,10 @@ static void sas_chain_work(struct sas_ha_struct *ha, 
struct sas_work *sw)
else
ret = scsi_queue_work(ha->core.shost, >work);
 
-   if (ret != 1)
+   if (ret != 1) {
sas_port_put(port);
+   sas_disc_cancel_sync(ev);
+   }
 }
 
 static void sas_chain_event(int event, unsigned long *pending,
@@ -592,9 +596,9 @@ int sas_discover_event(struct asd_sas_port *port, enum 
discover_event ev)
 {
struct sas_discovery *disc;
 
+   disc = >disc;
if (!port)
return 0;
-   disc = >disc;
 
BUG_ON(ev >= DISC_NUM_EVENTS);
 
diff --git a/drivers/scsi/libsas/sas_expander.c 
b/drivers/scsi/libsas/sas_expander.c
index 570b2cb..9d26c28 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -822,14 +822,18 @@ static struct domain_device *sas_ex_discover_end_dev(
 
list_add_tail(>disco_list_node, 
>port->disco_list);
 
+   sas_disc_wait_init(child->port, DISCE_PROBE);
res = sas_discover_sata(child);
if (res) {
+   
sas_disc_cancel_sync(>port->disc.disc_work[DISCE_PROBE]);
SAS_DPRINTK("sas_discover_sata() for device %16llx at "
"%016llx:0x%x returned 0x%x\n",
SAS_ADDR(child->sas_addr),
SAS_ADDR(parent->sas_addr), phy_id, res);
goto out_list_del;
}
+   sas_disc_wait_completion(child->port, DISCE_PROBE);
+
} else
 #endif
  if (phy->attached_tproto & SAS_PROTOCOL_SSP) {
@@ -847,14 +851,17 @@ static struct domain_device *sas_ex_discover_end_dev(
 
list_add_tail(>disco_list_node, 
>port->disco_list);
 
+   sas_disc_wait_init(child->port, DISCE_PROBE);
res = sas_discover_end_dev(child);
if (res) {
+   
sas_disc_cancel_sync(>port->disc.disc_work[DISCE_PROBE]);
SAS_DPRINTK("sas_discover_end_dev() for device %16llx "
"at %016llx:0x%x returned 0x%x\n",
SAS_ADDR(child->sas_addr),
SAS_ADDR(parent->sas_addr), phy_id, res);
goto out_list_del;
}
+   sas_disc_wait_completion(child->port, DISCE_PROBE);
} else {
SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
phy->attached_tproto, SAS_ADDR(parent->sas_addr),
@@ -1890,8 +1897,11 @@ static void sas_unregister_devs_sas_addr(struct 
domain_device *parent,
if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE 
||
child->dev_type == 
SAS_FANOUT_EXPANDER_DEVICE)
sas_unregister_ex_tree(parent->port, 
child);
-   else
+   else {
+   sas_disc_wait_init(parent->port, 
DISCE_DESTRUCT);
sas_unregister_dev(parent->port, child);
+   sas_disc_wait_completion(parent->port, 
DISCE_DESTRUCT);
+   }
found = child;
break;
}
diff -

[PATCH v3 0/7] Enhance libsas hotplug feature

2017-07-10 Thread Yijing Wang
This patchset is based Johannes's patch
"scsi: sas: scsi_queue_work can fail, so make callers aware"

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.

v2->v3: some code improvements suggested by Johannes and John,
split v2 patch 2 into several small pathes.
v1->v2: some code improvements suggested by John Garry

Yijing Wang (7):
  libsas: Use static sas event pool to appease sas event lost
  libsas: remove unused port_gone_completion
  libsas: Use new workqueue to run sas event
  libsas: add sas event wait-complete support
  libsas: add a new workqueue to run probe/destruct discovery event
  libsas: add wait-complete support to sync discovery event
  libsas: release disco mutex during waiting in sas_ex_discover_end_dev

 drivers/scsi/libsas/sas_discover.c |  58 +++---
 drivers/scsi/libsas/sas_event.c| 212 -
 drivers/scsi/libsas/sas_expander.c |  22 +++-
 drivers/scsi/libsas/sas_init.c |  21 ++--
 drivers/scsi/libsas/sas_internal.h |  64 +++
 drivers/scsi/libsas/sas_phy.c  |  48 +++--
 drivers/scsi/libsas/sas_port.c |  22 ++--
 include/scsi/libsas.h  |  27 +++--
 8 files changed, 373 insertions(+), 101 deletions(-)

-- 
2.5.0



[PATCH v3 1/7] libsas: Use static sas event pool to appease sas event lost

2017-07-10 Thread Yijing Wang
Now libsas hotplug work is static, every sas event type has its own
static work, 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 and use static sas event work pool to appease this issue, since
it's static work pool, it won't make memory exhaust.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
CC: John Garry <john.ga...@huawei.com>
CC: Johannes Thumshirn <jthumsh...@suse.de>
CC: Ewan Milne <emi...@redhat.com>
CC: Christoph Hellwig <h...@lst.de>
CC: Tomas Henzl <the...@redhat.com>
CC: Dan Williams <dan.j.willi...@intel.com>
---
 drivers/scsi/libsas/sas_event.c| 208 -
 drivers/scsi/libsas/sas_init.c |   6 --
 drivers/scsi/libsas/sas_internal.h |   3 +
 drivers/scsi/libsas/sas_phy.c  |  48 +++--
 drivers/scsi/libsas/sas_port.c |  18 ++--
 include/scsi/libsas.h  |  16 +--
 6 files changed, 216 insertions(+), 83 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index c0d0d97..a1370bd 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -27,13 +27,20 @@
 #include "sas_internal.h"
 #include "sas_dump.h"
 
+static DEFINE_SPINLOCK(sas_event_lock);
+
+static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = {
+  [HAE_RESET] = sas_hae_reset,
+};
+
 int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
 {
int rc = 0;
 
if (!test_bit(SAS_HA_REGISTERED, >state))
-   return 0;
+   return rc;
 
+   rc = 1;
if (test_bit(SAS_HA_DRAINING, >state)) {
/* add it to the defer list, if not already pending */
if (list_empty(>drain_node))
@@ -44,19 +51,15 @@ int sas_queue_work(struct sas_ha_struct *ha, struct 
sas_work *sw)
return rc;
 }
 
-static int sas_queue_event(int event, unsigned long *pending,
-   struct sas_work *work,
+static int sas_queue_event(int event, struct sas_work *work,
struct sas_ha_struct *ha)
 {
int rc = 0;
+   unsigned long flags;
 
-   if (!test_and_set_bit(event, pending)) {
-   unsigned long flags;
-
-   spin_lock_irqsave(>lock, flags);
-   rc = sas_queue_work(ha, work);
-   spin_unlock_irqrestore(>lock, flags);
-   }
+   spin_lock_irqsave(>lock, flags);
+   rc = sas_queue_work(ha, work);
+   spin_unlock_irqrestore(>lock, flags);
 
return rc;
 }
@@ -64,6 +67,8 @@ static int sas_queue_event(int event, unsigned long *pending,
 
 void __sas_drain_work(struct sas_ha_struct *ha)
 {
+   int ret;
+   unsigned long flags;
struct workqueue_struct *wq = ha->core.shost->work_q;
struct sas_work *sw, *_sw;
 
@@ -78,7 +83,12 @@ void __sas_drain_work(struct sas_ha_struct *ha)
clear_bit(SAS_HA_DRAINING, >state);
list_for_each_entry_safe(sw, _sw, >defer_q, drain_node) {
list_del_init(>drain_node);
-   sas_queue_work(ha, sw);
+   ret = sas_queue_work(ha, sw);
+   if (ret != 1) {
+   spin_lock_irqsave(_event_lock, flags);
+   sw->used = false;
+   spin_unlock_irqrestore(_event_lock, flags);
+   }
}
spin_unlock_irq(>lock);
 }
@@ -119,51 +129,197 @@ 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_free_ha_event(struct sas_ha_event *event)
+{
+   unsigned long flags;
+   spin_lock_irqsave(_event_lock, flags);
+   event->work.used = false;
+   spin_unlock_irqrestore(_event_lock, flags);
+}
+
+static void sas_free_port_event(struct asd_sas_event *event)
+{
+   unsigned long flags;
+   spin_lock_irqsave(_event_lock, flags);
+   event->work.used = false;
+   spin_unlock_irqrestore(_event_lock, flags);
+}
+
+static void sas_free_phy_event(struct asd_sas_event *event)
+{
+   unsigned long flags;
+   

[PATCH v3 1/7] libsas: Use static sas event pool to appease sas event lost

2017-07-10 Thread Yijing Wang
Now libsas hotplug work is static, every sas event type has its own
static work, 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 and use static sas event work pool to appease this issue, since
it's static work pool, it won't make memory exhaust.

Signed-off-by: Yijing Wang 
CC: John Garry 
CC: Johannes Thumshirn 
CC: Ewan Milne 
CC: Christoph Hellwig 
CC: Tomas Henzl 
CC: Dan Williams 
---
 drivers/scsi/libsas/sas_event.c| 208 -
 drivers/scsi/libsas/sas_init.c |   6 --
 drivers/scsi/libsas/sas_internal.h |   3 +
 drivers/scsi/libsas/sas_phy.c  |  48 +++--
 drivers/scsi/libsas/sas_port.c |  18 ++--
 include/scsi/libsas.h  |  16 +--
 6 files changed, 216 insertions(+), 83 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index c0d0d97..a1370bd 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -27,13 +27,20 @@
 #include "sas_internal.h"
 #include "sas_dump.h"
 
+static DEFINE_SPINLOCK(sas_event_lock);
+
+static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = {
+  [HAE_RESET] = sas_hae_reset,
+};
+
 int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
 {
int rc = 0;
 
if (!test_bit(SAS_HA_REGISTERED, >state))
-   return 0;
+   return rc;
 
+   rc = 1;
if (test_bit(SAS_HA_DRAINING, >state)) {
/* add it to the defer list, if not already pending */
if (list_empty(>drain_node))
@@ -44,19 +51,15 @@ int sas_queue_work(struct sas_ha_struct *ha, struct 
sas_work *sw)
return rc;
 }
 
-static int sas_queue_event(int event, unsigned long *pending,
-   struct sas_work *work,
+static int sas_queue_event(int event, struct sas_work *work,
struct sas_ha_struct *ha)
 {
int rc = 0;
+   unsigned long flags;
 
-   if (!test_and_set_bit(event, pending)) {
-   unsigned long flags;
-
-   spin_lock_irqsave(>lock, flags);
-   rc = sas_queue_work(ha, work);
-   spin_unlock_irqrestore(>lock, flags);
-   }
+   spin_lock_irqsave(>lock, flags);
+   rc = sas_queue_work(ha, work);
+   spin_unlock_irqrestore(>lock, flags);
 
return rc;
 }
@@ -64,6 +67,8 @@ static int sas_queue_event(int event, unsigned long *pending,
 
 void __sas_drain_work(struct sas_ha_struct *ha)
 {
+   int ret;
+   unsigned long flags;
struct workqueue_struct *wq = ha->core.shost->work_q;
struct sas_work *sw, *_sw;
 
@@ -78,7 +83,12 @@ void __sas_drain_work(struct sas_ha_struct *ha)
clear_bit(SAS_HA_DRAINING, >state);
list_for_each_entry_safe(sw, _sw, >defer_q, drain_node) {
list_del_init(>drain_node);
-   sas_queue_work(ha, sw);
+   ret = sas_queue_work(ha, sw);
+   if (ret != 1) {
+   spin_lock_irqsave(_event_lock, flags);
+   sw->used = false;
+   spin_unlock_irqrestore(_event_lock, flags);
+   }
}
spin_unlock_irq(>lock);
 }
@@ -119,51 +129,197 @@ 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_free_ha_event(struct sas_ha_event *event)
+{
+   unsigned long flags;
+   spin_lock_irqsave(_event_lock, flags);
+   event->work.used = false;
+   spin_unlock_irqrestore(_event_lock, flags);
+}
+
+static void sas_free_port_event(struct asd_sas_event *event)
+{
+   unsigned long flags;
+   spin_lock_irqsave(_event_lock, flags);
+   event->work.used = false;
+   spin_unlock_irqrestore(_event_lock, flags);
+}
+
+static void sas_free_phy_event(struct asd_sas_event *event)
+{
+   unsigned long flags;
+   spin_lock_irqsave(_event_lock, flags);
+   event->work.used = false;
+   spin_unlock_irqrestore(_event_lock, flags);
+}
+
+static void sas_ha_event_worker(struct work_struct *

[PATCH v3 4/7] libsas: add sas event wait-complete support

2017-07-10 Thread Yijing Wang
Introduce wait-complete for libsas sas event processing,
execute sas port create/destruct in sync.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
CC: John Garry <john.ga...@huawei.com>
CC: Johannes Thumshirn <jthumsh...@suse.de>
CC: Ewan Milne <emi...@redhat.com>
CC: Christoph Hellwig <h...@lst.de>
CC: Tomas Henzl <the...@redhat.com>
CC: Dan Williams <dan.j.willi...@intel.com>
---
 drivers/scsi/libsas/sas_discover.c | 41 --
 drivers/scsi/libsas/sas_internal.h | 34 +++
 drivers/scsi/libsas/sas_port.c |  4 
 include/scsi/libsas.h  |  5 -
 4 files changed, 72 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 60de662..5d4a3a8 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -525,16 +525,43 @@ static void sas_revalidate_domain(struct work_struct 
*work)
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_port_put(port);
+}
+
+
 /* -- Events -- */
 
 static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw)
 {
+   int ret;
+   struct sas_discovery_event *ev = to_sas_discovery_event(>work);
+   struct asd_sas_port *port = ev->port;
+
/* chained work is not subject to SA_HA_DRAINING or
 * SAS_HA_REGISTERED, because it is either submitted in the
 * workqueue, or known to be submitted from a context that is
 * not racing against draining
 */
-   scsi_queue_work(ha->core.shost, >work);
+   sas_port_get(port);
+   ret = scsi_queue_work(ha->core.shost, >work);
+   if (ret != 1)
+   sas_port_put(port);
 }
 
 static void sas_chain_event(int event, unsigned long *pending,
@@ -575,18 +602,10 @@ void sas_init_disc(struct sas_discovery *disc, struct 
asd_sas_port *port)
 {
int i;
 
-   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,
-   };
-
disc->pending = 0;
for (i = 0; i < DISC_NUM_EVENTS; i++) {
-   INIT_SAS_WORK(>disc_work[i].work, sas_event_fns[i]);
+   INIT_SAS_WORK(>disc_work[i].work, sas_discover_common_fn);
disc->disc_work[i].port = port;
+   disc->disc_work[i].type = i;
}
 }
diff --git a/drivers/scsi/libsas/sas_internal.h 
b/drivers/scsi/libsas/sas_internal.h
index f03ce64..890b5d26 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -100,6 +100,40 @@ void sas_free_device(struct kref *kref);
 extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS];
 extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS];
 
+static void sas_complete_event(struct kref *kref)
+{
+   struct asd_sas_port *port = container_of(kref, struct asd_sas_port, 
ref);
+
+   complete_all(>completion);
+}
+
+static inline void sas_port_put(struct asd_sas_port *port)
+{
+   if (port->is_sync)
+   kref_put(>ref, sas_complete_event);
+}
+
+static inline void sas_port_wait_init(struct asd_sas_port *port)
+{
+   init_completion(>completion);
+   kref_init(>ref);
+   port->is_sync = true;
+}
+
+static inline void sas_port_wait_completion(
+   struct asd_sas_port *port)
+{
+   sas_port_put(port);
+   wait_for_completion(>completion);
+   port->is_sync = false;
+}
+
+static inline void sas_port_get(struct asd_sas_port *port)
+{
+   if (port && port->is_sync)
+   kref_get(>ref);
+}
+
 #ifdef CONFIG_SCSI_SAS_HOST_SMP
 extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
struct request *rsp);
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 9326628..d589adb 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/l

[PATCH v3 4/7] libsas: add sas event wait-complete support

2017-07-10 Thread Yijing Wang
Introduce wait-complete for libsas sas event processing,
execute sas port create/destruct in sync.

Signed-off-by: Yijing Wang 
CC: John Garry 
CC: Johannes Thumshirn 
CC: Ewan Milne 
CC: Christoph Hellwig 
CC: Tomas Henzl 
CC: Dan Williams 
---
 drivers/scsi/libsas/sas_discover.c | 41 --
 drivers/scsi/libsas/sas_internal.h | 34 +++
 drivers/scsi/libsas/sas_port.c |  4 
 include/scsi/libsas.h  |  5 -
 4 files changed, 72 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 60de662..5d4a3a8 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -525,16 +525,43 @@ static void sas_revalidate_domain(struct work_struct 
*work)
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_port_put(port);
+}
+
+
 /* -- Events -- */
 
 static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw)
 {
+   int ret;
+   struct sas_discovery_event *ev = to_sas_discovery_event(>work);
+   struct asd_sas_port *port = ev->port;
+
/* chained work is not subject to SA_HA_DRAINING or
 * SAS_HA_REGISTERED, because it is either submitted in the
 * workqueue, or known to be submitted from a context that is
 * not racing against draining
 */
-   scsi_queue_work(ha->core.shost, >work);
+   sas_port_get(port);
+   ret = scsi_queue_work(ha->core.shost, >work);
+   if (ret != 1)
+   sas_port_put(port);
 }
 
 static void sas_chain_event(int event, unsigned long *pending,
@@ -575,18 +602,10 @@ void sas_init_disc(struct sas_discovery *disc, struct 
asd_sas_port *port)
 {
int i;
 
-   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,
-   };
-
disc->pending = 0;
for (i = 0; i < DISC_NUM_EVENTS; i++) {
-   INIT_SAS_WORK(>disc_work[i].work, sas_event_fns[i]);
+   INIT_SAS_WORK(>disc_work[i].work, sas_discover_common_fn);
disc->disc_work[i].port = port;
+   disc->disc_work[i].type = i;
}
 }
diff --git a/drivers/scsi/libsas/sas_internal.h 
b/drivers/scsi/libsas/sas_internal.h
index f03ce64..890b5d26 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -100,6 +100,40 @@ void sas_free_device(struct kref *kref);
 extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS];
 extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS];
 
+static void sas_complete_event(struct kref *kref)
+{
+   struct asd_sas_port *port = container_of(kref, struct asd_sas_port, 
ref);
+
+   complete_all(>completion);
+}
+
+static inline void sas_port_put(struct asd_sas_port *port)
+{
+   if (port->is_sync)
+   kref_put(>ref, sas_complete_event);
+}
+
+static inline void sas_port_wait_init(struct asd_sas_port *port)
+{
+   init_completion(>completion);
+   kref_init(>ref);
+   port->is_sync = true;
+}
+
+static inline void sas_port_wait_completion(
+   struct asd_sas_port *port)
+{
+   sas_port_put(port);
+   wait_for_completion(>completion);
+   port->is_sync = false;
+}
+
+static inline void sas_port_get(struct asd_sas_port *port)
+{
+   if (port && port->is_sync)
+   kref_get(>ref);
+}
+
 #ifdef CONFIG_SCSI_SAS_HOST_SMP
 extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
struct request *rsp);
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 9326628..d589adb 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -191,7 +191,9 @@ static void sas_form_port(struct asd_sas_phy *phy)
if (si->dft->lldd_port_formed)
si->dft->lldd_port_formed(phy);

[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 <wangyij...@huawei.com>
---
 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 -- */
 
 stat

[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(str

[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



[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



[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 <wangyij...@huawei.com>
Signed-off-by: Yousong He <heyous...@huawei.com>
Signed-off-by: Qilin Chen <chenqil...@huawei.com>
---
 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,
-

[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);

[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 <wangyij...@huawei.com>
---
 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 -- */
 
 stat

[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(str

[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 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 <wangyij...@huawei.com>
Signed-off-by: Yousong He <heyous...@huawei.com>
Signed-off-by: Qilin Chen <chenqil...@huawei.com>
---
 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,
-

[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);

[PATCH 2/2] libsas: Enhance libsas hotplug

2017-05-20 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.
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 <wangyij...@huawei.com>
---
 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 | 31 +++-
 drivers/scsi/libsas/sas_internal.h | 50 
 drivers/scsi/libsas/sas_port.c |  4 +++
 include/scsi/libsas.h  | 11 +++-
 7 files changed, 146 insertions(+), 19 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)
 {
+   int ret;
+   struct sas_discovery_event *ev = to_sas_discovery_event(>work);
+   struct asd_sas_port *port = ev->port;
+
/* chained work is not subject to SA_HA_DRAINING or
 * SAS_HA_REGISTERED, because it is e

[PATCH 2/2] libsas: Enhance libsas hotplug

2017-05-20 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.
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 | 31 +++-
 drivers/scsi/libsas/sas_internal.h | 50 
 drivers/scsi/libsas/sas_port.c |  4 +++
 include/scsi/libsas.h  | 11 +++-
 7 files changed, 146 insertions(+), 19 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)
 {
+   int ret;
+   struct sas_discovery_event *ev = to_sas_discovery_event(>work);
+   struct asd_sas_port *port = ev->port;
+
/* chained work is not subject to SA_HA_DRAINING or
 * SAS_HA_REGISTERED, because it is either submitted 

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

2017-05-20 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 <wangyij...@huawei.com>
Signed-off-by: Yousong He <heyous...@huawei.com>
Signed-off-by: Qilin Chen <chenqil...@huawei.com>
---
 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,
-

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

2017-05-20 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);

[PATCH 0/2] Enhance libsas hotplug feature

2017-05-20 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.

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 | 37 +---
 drivers/scsi/libsas/sas_internal.h | 53 ++
 drivers/scsi/libsas/sas_phy.c  | 45 ---
 drivers/scsi/libsas/sas_port.c | 22 +-
 include/scsi/libsas.h  | 21 +
 8 files changed, 230 insertions(+), 105 deletions(-)

-- 
2.5.0



[PATCH 0/2] Enhance libsas hotplug feature

2017-05-20 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.

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 | 37 +---
 drivers/scsi/libsas/sas_internal.h | 53 ++
 drivers/scsi/libsas/sas_phy.c  | 45 ---
 drivers/scsi/libsas/sas_port.c | 22 +-
 include/scsi/libsas.h  | 21 +
 8 files changed, 230 insertions(+), 105 deletions(-)

-- 
2.5.0



[PATCH v2] block: Don't register a registered bdi device

2017-01-17 Thread Yijing Wang
 ip6_tables intel_rapl sb_edac 
edac_core x86_pkg_temp_pclmul joydev ghash_clmulni_intel iTCO_wdt ipmi_ssif 
mei_me pcspkr mei iTCO_vendor_support ipmi_si i2c_i801 lpc_ich mfd_corema 
acpi_pad wmi acpi_power_meter nfsd auth_rpcgss nfs_acl lockd grace binfmt_misc 
sunrpc xfs libcrc32c ast i2c_algo_bit drm_kore raid_class nvme_core 
scsi_transport_sas dca
[  +0.080566] CPU: 17 PID: 281 Comm: kworker/u49:5 Tainted: GW   
4.9.0-rc2 #1
[  +0.009472] Hardware name: Supermicro SYS-2028U-TNRT+/X10DRU-i+, BIOS 1.1 
07/22/2015
[  +0.009169] Workqueue: events_unbound async_run_entry_fn
[  +0.007340] RIP: 0010:[]  [] 
sysfs_do_create_link_sd.isra.2+0x34/0xb0
[  +0.010294] Call Trace:
[  +0.005269]  [] sysfs_create_link+0x25/0x40
[  +0.008568]  [] device_add_disk+0x1fc/0x480
[  +0.008551]  [] sd_probe_async+0x110/0x1c0
[  +0.008456]  [] async_run_entry_fn+0x39/0x140
[  +0.010021]  [] process_one_work+0x15f/0x430
[  +0.009623]  [] worker_thread+0x4e/0x490
[  +0.007422]  [] ? process_one_work+0x430/0x430
[  +0.008728]  [] kthread+0xd9/0xf0
[  +0.007578]  [] ? kthread_park+0x60/0x60
[  +0.006816]  [] ret_from_fork+0x25/0x30
[  +0.006814] Code: 75 48 85 ff 74 70 55 48 89 e5 41 57 41 56 41 55 41 54 49 89 
fe 53 48 c7 c7 90 74 01 82 48 89 f3 41 89 cc  c5 ff ff c6 05 15 48 d5
[  +0.022853] RIP  [] sysfs_do_create_link_sd.isra.2+0x34/0xb0
[  +0.008679]  RSP 
[  +0.006129] BUG: unable to handle kernel

While create the first raid disk, we hide first raid disk's PD devices
(remove sdx device), but leave the bdi device in kernel, we won't call
bdi_unregister() in del_gendisk. So if we cancal the raid, and create
second raid disk, kernel try to register the bdi device again, then
the warning calltrace dump, bcause the bdi device already exist in kernel.
This patch check the bdi device state before register a new bdi device,
avoid register a registered bdi device again.

-v2: remove the spin lock protect, because the sd_probe caller should
 guarantee the scsi_device valid, and the bdi device is unregister
 when scsi_device/block queue removed.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 block/genhd.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/block/genhd.c b/block/genhd.c
index fcd6d4f..fbb2a96 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -614,7 +614,8 @@ void device_add_disk(struct device *parent, struct gendisk 
*disk)
 
/* Register BDI before referencing it from bdev */
bdi = >queue->backing_dev_info;
-   bdi_register_owner(bdi, disk_to_dev(disk));
+   if (!test_bit(WB_registered, >wb.state))
+   bdi_register_owner(bdi, disk_to_dev(disk));
 
blk_register_region(disk_devt(disk), disk->minors, NULL,
exact_match, exact_lock, disk);
-- 
2.5.0



[PATCH v2] block: Don't register a registered bdi device

2017-01-17 Thread Yijing Wang
 ip6_tables intel_rapl sb_edac 
edac_core x86_pkg_temp_pclmul joydev ghash_clmulni_intel iTCO_wdt ipmi_ssif 
mei_me pcspkr mei iTCO_vendor_support ipmi_si i2c_i801 lpc_ich mfd_corema 
acpi_pad wmi acpi_power_meter nfsd auth_rpcgss nfs_acl lockd grace binfmt_misc 
sunrpc xfs libcrc32c ast i2c_algo_bit drm_kore raid_class nvme_core 
scsi_transport_sas dca
[  +0.080566] CPU: 17 PID: 281 Comm: kworker/u49:5 Tainted: GW   
4.9.0-rc2 #1
[  +0.009472] Hardware name: Supermicro SYS-2028U-TNRT+/X10DRU-i+, BIOS 1.1 
07/22/2015
[  +0.009169] Workqueue: events_unbound async_run_entry_fn
[  +0.007340] RIP: 0010:[]  [] 
sysfs_do_create_link_sd.isra.2+0x34/0xb0
[  +0.010294] Call Trace:
[  +0.005269]  [] sysfs_create_link+0x25/0x40
[  +0.008568]  [] device_add_disk+0x1fc/0x480
[  +0.008551]  [] sd_probe_async+0x110/0x1c0
[  +0.008456]  [] async_run_entry_fn+0x39/0x140
[  +0.010021]  [] process_one_work+0x15f/0x430
[  +0.009623]  [] worker_thread+0x4e/0x490
[  +0.007422]  [] ? process_one_work+0x430/0x430
[  +0.008728]  [] kthread+0xd9/0xf0
[  +0.007578]  [] ? kthread_park+0x60/0x60
[  +0.006816]  [] ret_from_fork+0x25/0x30
[  +0.006814] Code: 75 48 85 ff 74 70 55 48 89 e5 41 57 41 56 41 55 41 54 49 89 
fe 53 48 c7 c7 90 74 01 82 48 89 f3 41 89 cc  c5 ff ff c6 05 15 48 d5
[  +0.022853] RIP  [] sysfs_do_create_link_sd.isra.2+0x34/0xb0
[  +0.008679]  RSP 
[  +0.006129] BUG: unable to handle kernel

While create the first raid disk, we hide first raid disk's PD devices
(remove sdx device), but leave the bdi device in kernel, we won't call
bdi_unregister() in del_gendisk. So if we cancal the raid, and create
second raid disk, kernel try to register the bdi device again, then
the warning calltrace dump, bcause the bdi device already exist in kernel.
This patch check the bdi device state before register a new bdi device,
avoid register a registered bdi device again.

-v2: remove the spin lock protect, because the sd_probe caller should
 guarantee the scsi_device valid, and the bdi device is unregister
 when scsi_device/block queue removed.

Signed-off-by: Yijing Wang 
---
 block/genhd.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/block/genhd.c b/block/genhd.c
index fcd6d4f..fbb2a96 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -614,7 +614,8 @@ void device_add_disk(struct device *parent, struct gendisk 
*disk)
 
/* Register BDI before referencing it from bdev */
bdi = >queue->backing_dev_info;
-   bdi_register_owner(bdi, disk_to_dev(disk));
+   if (!test_bit(WB_registered, >wb.state))
+   bdi_register_owner(bdi, disk_to_dev(disk));
 
blk_register_region(disk_devt(disk), disk->minors, NULL,
exact_match, exact_lock, disk);
-- 
2.5.0



[PATCH] block: Don't register a registered bdi device

2017-01-10 Thread Yijing Wang
 intel_rapl sb_edac 
edac_core x86_pkg_temp_pclmul joydev ghash_clmulni_intel iTCO_wdt ipmi_ssif 
mei_me pcspkr mei iTCO_vendor_support ipmi_si i2c_i801 lpc_ich mfd_corema 
acpi_pad wmi acpi_power_meter nfsd auth_rpcgss nfs_acl lockd grace binfmt_misc 
sunrpc xfs libcrc32c ast i2c_algo_bit drm_kore raid_class nvme_core 
scsi_transport_sas dca
[  +0.080566] CPU: 17 PID: 281 Comm: kworker/u49:5 Tainted: GW   
4.9.0-rc2 #1
[  +0.009472] Hardware name: Supermicro SYS-2028U-TNRT+/X10DRU-i+, BIOS 1.1 
07/22/2015
[  +0.009169] Workqueue: events_unbound async_run_entry_fn
[  +0.007340] RIP: 0010:[]  [] 
sysfs_do_create_link_sd.isra.2+0x34/0xb0
[  +0.010294] Call Trace:
[  +0.005269]  [] sysfs_create_link+0x25/0x40
[  +0.008568]  [] device_add_disk+0x1fc/0x480
[  +0.008551]  [] sd_probe_async+0x110/0x1c0
[  +0.008456]  [] async_run_entry_fn+0x39/0x140
[  +0.010021]  [] process_one_work+0x15f/0x430
[  +0.009623]  [] worker_thread+0x4e/0x490
[  +0.007422]  [] ? process_one_work+0x430/0x430
[  +0.008728]  [] kthread+0xd9/0xf0
[  +0.007578]  [] ? kthread_park+0x60/0x60
[  +0.006816]  [] ret_from_fork+0x25/0x30
[  +0.006814] Code: 75 48 85 ff 74 70 55 48 89 e5 41 57 41 56 41 55 41 54 49 89 
fe 53 48 c7 c7 90 74 01 82 48 89 f3 41 89 cc  c5 ff ff c6 05 15 48 d5
[  +0.022853] RIP  [] sysfs_do_create_link_sd.isra.2+0x34/0xb0
[  +0.008679]  RSP 
[  +0.006129] BUG: unable to handle kernel

While create the first raid disk, we hide first raid disk's PD devices
(remove sdx device), but leave the bdi device in kernel, we won't call
bdi_unregister() in del_gendisk, we will do it when we cleanup request
queue. Then we cancal the raid, and create second raid disk based same
disks, then kernel try to probe the sdx device and register the bdi device
again in device_add_disk(), then the warning calltrace dump, bcause the
bdi device already exist in kernel.

This patch check the bdi device state before register a new bdi device to
avoid register a registered bdi device again.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 block/genhd.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/block/genhd.c b/block/genhd.c
index fcd6d4f..2c2f95e 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -614,7 +614,10 @@ void device_add_disk(struct device *parent, struct gendisk 
*disk)
 
/* Register BDI before referencing it from bdev */
bdi = >queue->backing_dev_info;
-   bdi_register_owner(bdi, disk_to_dev(disk));
+   spin_lock_bh(>wb.work_lock);
+   if (!test_bit(WB_registered, >wb.state))
+   bdi_register_owner(bdi, disk_to_dev(disk));
+   spin_unlock_bh(>wb.work_lock);
 
blk_register_region(disk_devt(disk), disk->minors, NULL,
exact_match, exact_lock, disk);
-- 
2.5.0



[PATCH] block: Don't register a registered bdi device

2017-01-10 Thread Yijing Wang
 intel_rapl sb_edac 
edac_core x86_pkg_temp_pclmul joydev ghash_clmulni_intel iTCO_wdt ipmi_ssif 
mei_me pcspkr mei iTCO_vendor_support ipmi_si i2c_i801 lpc_ich mfd_corema 
acpi_pad wmi acpi_power_meter nfsd auth_rpcgss nfs_acl lockd grace binfmt_misc 
sunrpc xfs libcrc32c ast i2c_algo_bit drm_kore raid_class nvme_core 
scsi_transport_sas dca
[  +0.080566] CPU: 17 PID: 281 Comm: kworker/u49:5 Tainted: GW   
4.9.0-rc2 #1
[  +0.009472] Hardware name: Supermicro SYS-2028U-TNRT+/X10DRU-i+, BIOS 1.1 
07/22/2015
[  +0.009169] Workqueue: events_unbound async_run_entry_fn
[  +0.007340] RIP: 0010:[]  [] 
sysfs_do_create_link_sd.isra.2+0x34/0xb0
[  +0.010294] Call Trace:
[  +0.005269]  [] sysfs_create_link+0x25/0x40
[  +0.008568]  [] device_add_disk+0x1fc/0x480
[  +0.008551]  [] sd_probe_async+0x110/0x1c0
[  +0.008456]  [] async_run_entry_fn+0x39/0x140
[  +0.010021]  [] process_one_work+0x15f/0x430
[  +0.009623]  [] worker_thread+0x4e/0x490
[  +0.007422]  [] ? process_one_work+0x430/0x430
[  +0.008728]  [] kthread+0xd9/0xf0
[  +0.007578]  [] ? kthread_park+0x60/0x60
[  +0.006816]  [] ret_from_fork+0x25/0x30
[  +0.006814] Code: 75 48 85 ff 74 70 55 48 89 e5 41 57 41 56 41 55 41 54 49 89 
fe 53 48 c7 c7 90 74 01 82 48 89 f3 41 89 cc  c5 ff ff c6 05 15 48 d5
[  +0.022853] RIP  [] sysfs_do_create_link_sd.isra.2+0x34/0xb0
[  +0.008679]  RSP 
[  +0.006129] BUG: unable to handle kernel

While create the first raid disk, we hide first raid disk's PD devices
(remove sdx device), but leave the bdi device in kernel, we won't call
bdi_unregister() in del_gendisk, we will do it when we cleanup request
queue. Then we cancal the raid, and create second raid disk based same
disks, then kernel try to probe the sdx device and register the bdi device
again in device_add_disk(), then the warning calltrace dump, bcause the
bdi device already exist in kernel.

This patch check the bdi device state before register a new bdi device to
avoid register a registered bdi device again.

Signed-off-by: Yijing Wang 
---
 block/genhd.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/block/genhd.c b/block/genhd.c
index fcd6d4f..2c2f95e 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -614,7 +614,10 @@ void device_add_disk(struct device *parent, struct gendisk 
*disk)
 
/* Register BDI before referencing it from bdev */
bdi = >queue->backing_dev_info;
-   bdi_register_owner(bdi, disk_to_dev(disk));
+   spin_lock_bh(>wb.work_lock);
+   if (!test_bit(WB_registered, >wb.state))
+   bdi_register_owner(bdi, disk_to_dev(disk));
+   spin_unlock_bh(>wb.work_lock);
 
blk_register_region(disk_devt(disk), disk->minors, NULL,
exact_match, exact_lock, disk);
-- 
2.5.0



[PATCH 2/2] bcache: remove unused parameter

2016-11-24 Thread Yijing Wang
Parameter bio is no longer used, clean it.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 drivers/md/bcache/request.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 40ffe5e..bf6e432 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -26,12 +26,12 @@ struct kmem_cache *bch_search_cache;
 
 static void bch_data_insert_start(struct closure *);
 
-static unsigned cache_mode(struct cached_dev *dc, struct bio *bio)
+static unsigned cache_mode(struct cached_dev *dc)
 {
return BDEV_CACHE_MODE(>sb);
 }
 
-static bool verify(struct cached_dev *dc, struct bio *bio)
+static bool verify(struct cached_dev *dc)
 {
return dc->verify;
 }
@@ -371,7 +371,7 @@ static struct hlist_head *iohash(struct cached_dev *dc, 
uint64_t k)
 static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
 {
struct cache_set *c = dc->disk.c;
-   unsigned mode = cache_mode(dc, bio);
+   unsigned mode = cache_mode(dc);
unsigned sectors, congested = bch_get_congested(c);
struct task_struct *task = current;
struct io *i;
@@ -746,7 +746,7 @@ static void cached_dev_read_done(struct closure *cl)
s->cache_miss = NULL;
}
 
-   if (verify(dc, >bio.bio) && s->recoverable && !s->read_dirty_data)
+   if (verify(dc) && s->recoverable && !s->read_dirty_data)
bch_data_verify(dc, s->orig_bio);
 
bio_complete(s);
@@ -771,7 +771,7 @@ static void cached_dev_read_done_bh(struct closure *cl)
 
if (s->iop.error)
continue_at_nobarrier(cl, cached_dev_read_error, bcache_wq);
-   else if (s->iop.bio || verify(dc, >bio.bio))
+   else if (s->iop.bio || verify(dc))
continue_at_nobarrier(cl, cached_dev_read_done, bcache_wq);
else
continue_at_nobarrier(cl, cached_dev_bio_complete, NULL);
@@ -898,7 +898,7 @@ static void cached_dev_write(struct cached_dev *dc, struct 
search *s)
s->iop.bypass = true;
 
if (should_writeback(dc, s->orig_bio,
-cache_mode(dc, bio),
+cache_mode(dc),
 s->iop.bypass)) {
s->iop.bypass = false;
s->iop.writeback = true;
-- 
2.5.0



[PATCH 1/2] bcache: Remove redundant set_capacity

2016-11-24 Thread Yijing Wang
set_capacity() has been called in bcache_device_init(),
remove the redundant one.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 drivers/md/bcache/super.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 849ad44..b638a16 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1126,9 +1126,6 @@ static int cached_dev_init(struct cached_dev *dc, 
unsigned block_size)
if (ret)
return ret;
 
-   set_capacity(dc->disk.disk,
-dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
-
dc->disk.disk->queue->backing_dev_info.ra_pages =
max(dc->disk.disk->queue->backing_dev_info.ra_pages,
q->backing_dev_info.ra_pages);
-- 
2.5.0



[PATCH 1/2] bcache: Remove redundant set_capacity

2016-11-24 Thread Yijing Wang
set_capacity() has been called in bcache_device_init(),
remove the redundant one.

Signed-off-by: Yijing Wang 
---
 drivers/md/bcache/super.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 849ad44..b638a16 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1126,9 +1126,6 @@ static int cached_dev_init(struct cached_dev *dc, 
unsigned block_size)
if (ret)
return ret;
 
-   set_capacity(dc->disk.disk,
-dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
-
dc->disk.disk->queue->backing_dev_info.ra_pages =
max(dc->disk.disk->queue->backing_dev_info.ra_pages,
q->backing_dev_info.ra_pages);
-- 
2.5.0



[PATCH 2/2] bcache: remove unused parameter

2016-11-24 Thread Yijing Wang
Parameter bio is no longer used, clean it.

Signed-off-by: Yijing Wang 
---
 drivers/md/bcache/request.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 40ffe5e..bf6e432 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -26,12 +26,12 @@ struct kmem_cache *bch_search_cache;
 
 static void bch_data_insert_start(struct closure *);
 
-static unsigned cache_mode(struct cached_dev *dc, struct bio *bio)
+static unsigned cache_mode(struct cached_dev *dc)
 {
return BDEV_CACHE_MODE(>sb);
 }
 
-static bool verify(struct cached_dev *dc, struct bio *bio)
+static bool verify(struct cached_dev *dc)
 {
return dc->verify;
 }
@@ -371,7 +371,7 @@ static struct hlist_head *iohash(struct cached_dev *dc, 
uint64_t k)
 static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
 {
struct cache_set *c = dc->disk.c;
-   unsigned mode = cache_mode(dc, bio);
+   unsigned mode = cache_mode(dc);
unsigned sectors, congested = bch_get_congested(c);
struct task_struct *task = current;
struct io *i;
@@ -746,7 +746,7 @@ static void cached_dev_read_done(struct closure *cl)
s->cache_miss = NULL;
}
 
-   if (verify(dc, >bio.bio) && s->recoverable && !s->read_dirty_data)
+   if (verify(dc) && s->recoverable && !s->read_dirty_data)
bch_data_verify(dc, s->orig_bio);
 
bio_complete(s);
@@ -771,7 +771,7 @@ static void cached_dev_read_done_bh(struct closure *cl)
 
if (s->iop.error)
continue_at_nobarrier(cl, cached_dev_read_error, bcache_wq);
-   else if (s->iop.bio || verify(dc, >bio.bio))
+   else if (s->iop.bio || verify(dc))
continue_at_nobarrier(cl, cached_dev_read_done, bcache_wq);
else
continue_at_nobarrier(cl, cached_dev_bio_complete, NULL);
@@ -898,7 +898,7 @@ static void cached_dev_write(struct cached_dev *dc, struct 
search *s)
s->iop.bypass = true;
 
if (should_writeback(dc, s->orig_bio,
-cache_mode(dc, bio),
+cache_mode(dc),
 s->iop.bypass)) {
s->iop.bypass = false;
s->iop.writeback = true;
-- 
2.5.0



[RFC][PATCH v2 0/2] Improve libsas hotplug

2016-09-26 Thread Yijing Wang
v1-v2: Fix memory allocation issue in interrupt context.

Yijing Wang (2):
  libsas: Alloc dynamic work to avoid missing sas events
  libsas: Fix hotplug issue in libsas

 drivers/scsi/libsas/sas_ata.c   |  34 ++---
 drivers/scsi/libsas/sas_discover.c  | 245 ++--
 drivers/scsi/libsas/sas_event.c |  61 +
 drivers/scsi/libsas/sas_expander.c  |  54 ++--
 drivers/scsi/libsas/sas_init.c  |  31 -
 drivers/scsi/libsas/sas_internal.h  |  45 ++-
 drivers/scsi/libsas/sas_phy.c   |  50 +++-
 drivers/scsi/libsas/sas_port.c  |  35 --
 drivers/scsi/libsas/sas_scsi_host.c |  23 
 include/scsi/libsas.h   |  13 +-
 include/scsi/sas_ata.h  |   4 +-
 11 files changed, 404 insertions(+), 191 deletions(-)

-- 
2.5.0



[RFC][PATCH v2 0/2] Improve libsas hotplug

2016-09-26 Thread Yijing Wang
v1-v2: Fix memory allocation issue in interrupt context.

Yijing Wang (2):
  libsas: Alloc dynamic work to avoid missing sas events
  libsas: Fix hotplug issue in libsas

 drivers/scsi/libsas/sas_ata.c   |  34 ++---
 drivers/scsi/libsas/sas_discover.c  | 245 ++--
 drivers/scsi/libsas/sas_event.c |  61 +
 drivers/scsi/libsas/sas_expander.c  |  54 ++--
 drivers/scsi/libsas/sas_init.c  |  31 -
 drivers/scsi/libsas/sas_internal.h  |  45 ++-
 drivers/scsi/libsas/sas_phy.c   |  50 +++-
 drivers/scsi/libsas/sas_port.c  |  35 --
 drivers/scsi/libsas/sas_scsi_host.c |  23 
 include/scsi/libsas.h   |  13 +-
 include/scsi/sas_ata.h  |   4 +-
 11 files changed, 404 insertions(+), 191 deletions(-)

-- 
2.5.0



[RFC][PATCH v2 1/2] libsas: Alloc dynamic work to avoid missing sas events

2016-09-26 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 event to libsas, the hotplug
events may pending in the workqueue like

shost->workq
tail | PHYE_LOSS_OF_SIGNAL  | PORTE_BYTES_DMAED | head

In this case, if a new PORTE_BYTES_DMAED event coming,
it would be lost, because we can not queue a work which
is already pending in the workqueue, also libsas has a
pending bit to avoid queue the same event.

The lost hotplug event make something confusing, e.g.
we have sas disks connected hardware, but we can not
found them in kernel.

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

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
Signed-off-by: Yousong He <heyous...@huawei.com>
Signed-off-by: Qilin Chen <chenqil...@huawei.com>
---
 drivers/scsi/libsas/sas_event.c| 61 ++
 drivers/scsi/libsas/sas_init.c |  5 +---
 drivers/scsi/libsas/sas_internal.h |  3 ++
 drivers/scsi/libsas/sas_phy.c  | 50 +--
 drivers/scsi/libsas/sas_port.c | 23 +++---
 include/scsi/libsas.h  |  8 -
 6 files changed, 66 insertions(+), 84 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index aadbd53..091f5c4 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,60 @@ 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 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_fns[event]);
+   ev->ha = sas_ha;
+   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_fns[event]);
+   ev->phy = phy;
+   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, sas_phy_event_fns[event]);
+   ev->phy = phy;
+   sas_queue_event(event, >work, ha);
 }
 
 int sas_init_events(struct sas_ha_struct *sas_ha)
 {
-   static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = {
-   [HAE_RESET] = sas_hae_reset,
-   };
-
-   int i;
-
-   for (i = 0; i < HA_NUM_EVENTS; i++) {
-   INIT_SAS_WORK(_ha->ha_events[i].work, sas_ha_event_fns[i]);
-   sas_ha->ha_events[i].ha = sas_ha;
-   }
-
sas_ha->notify_ha_event

[RFC][PATCH v2 1/2] libsas: Alloc dynamic work to avoid missing sas events

2016-09-26 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 event to libsas, the hotplug
events may pending in the workqueue like

shost->workq
tail | PHYE_LOSS_OF_SIGNAL  | PORTE_BYTES_DMAED | head

In this case, if a new PORTE_BYTES_DMAED event coming,
it would be lost, because we can not queue a work which
is already pending in the workqueue, also libsas has a
pending bit to avoid queue the same event.

The lost hotplug event make something confusing, e.g.
we have sas disks connected hardware, but we can not
found them in kernel.

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| 61 ++
 drivers/scsi/libsas/sas_init.c |  5 +---
 drivers/scsi/libsas/sas_internal.h |  3 ++
 drivers/scsi/libsas/sas_phy.c  | 50 +--
 drivers/scsi/libsas/sas_port.c | 23 +++---
 include/scsi/libsas.h  |  8 -
 6 files changed, 66 insertions(+), 84 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index aadbd53..091f5c4 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,60 @@ 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 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_fns[event]);
+   ev->ha = sas_ha;
+   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_fns[event]);
+   ev->phy = phy;
+   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, sas_phy_event_fns[event]);
+   ev->phy = phy;
+   sas_queue_event(event, >work, ha);
 }
 
 int sas_init_events(struct sas_ha_struct *sas_ha)
 {
-   static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = {
-   [HAE_RESET] = sas_hae_reset,
-   };
-
-   int i;
-
-   for (i = 0; i < HA_NUM_EVENTS; i++) {
-   INIT_SAS_WORK(_ha->ha_events[i].work, sas_ha_event_fns[i]);
-   sas_ha->ha_events[i].ha = sas_ha;
-   }
-
sas_ha->notify_ha_event = notify_ha_event;
sas_ha->notify_port_event = notify_port_event;
sa

[RFC][PATCH v2 2/2] libsas: Fix hotplug issue in libsas

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

The root cause of the issues is we use one workqueue(shost->work_q) to
process libsas event, and we divide a hot-on or hot-remove flow to several
events to process. E.g. we start a new work and queue it into the same
workqueue in sas_deform_port() to remove the children devices after
the sas port. So if there is one hot-on event between remove sas port
and destruct the children devices, some unexpected errors would
be caused.

This patch modify hotplug event process mechanism to solve the
hotplug problems in libsas. We move device add/del operation to
a new workqueue(named sas_dev_wq).

And we use sas_port_alloc_num to replace sas_port_alloc function
because when discovery is concurrently executing with the device
adding or destroying, the old sas port resource may have not
completely deleted, the new sas port resource of the same name
will be created, and this will cause calltrace about sysfs
device node.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
Signed-off-by: Yousong He <heyous...@huawei.com>
Signed-off-by: Qilin Chen <chenqil...@huawei.com>
---
 drivers/scsi/libsas/sas_ata.c   |  34 ++---
 drivers/scsi/libsas/sas_discover.c  | 245 ++--
 drivers/scsi/libsas/sas_expander.c  |  54 ++--
 drivers/scsi/libsas/sas_init.c  |  26 +++-
 drivers/scsi/libsas/sas_internal.h  |  46 ++-
 drivers/scsi/libsas/sas_port.c  |  12 +-
 drivers/scsi/libsas/sas_scsi_host.c |  23 
 include/scsi/libsas.h   |   5 +-
 include/scsi/sas_ata.h  |   4 +-
 9 files changed, 340 insertions(+), 109 deletions(-)

diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 763f012..877efa8 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -619,32 +619,22 @@ static int sas_get_ata_command_set(struct domain_device 
*dev)
return ata_dev_classify();
 }
 
-void sas_probe_sata(struct asd_sas_port *port)
+void sas_probe_sata_device(struct domain_device *dev)
 {
-   struct domain_device *dev, *n;
-
-   mutex_lock(>ha->disco_mutex);
-   list_for_each_entry(dev, >disco_list, disco_list_node) {
-   if (!dev_is_sata(dev))
-   continue;
-
-   ata_sas_async_probe(dev->sata_dev.ap);
-   }
-   mutex_unlock(>ha->disco_mutex);
+   struct asd_sas_port *port = dev->port;
 
-   list_for_each_entry_safe(dev, n, >disco_list, disco_list_node) {
-   if (!dev_is_sata(dev))
-   continue;
+   if (!port || !port->ha || !dev_is_sata(dev))
+   return;
 
-   sas_ata_wait_eh(dev);
+   ata_sas_async_probe(dev->sata_dev.ap);
 
-   /* if libata could not bring the link up, don't surface
-* the device
-*/
-   if (ata_dev_disabled(sas_to_ata_dev(dev)))
-   sas_fail_probe(dev, __func__, -ENODEV);
-   }
+   sas_ata_wait_eh(dev);
 
+   /* if libata could not bring the link up, don't surface
+* the device
+*/
+   if (ata_dev_disabled(sas_to_ata_dev(dev)))
+   sas_fail_probe(dev, __func__, -ENODEV);
 }
 
 static void sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
@@ -729,7 +719,7 @@ int sas_discover_sata(struct domain_device *dev)
if (res)
return res;
 
-   sas_discover_event(dev->port, DISCE_PROBE);
+   sas_notify_device_event(dev, SAS_DEVICE_ADD);
return 0;
 }
 
diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 60de662..ea57c66 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -34,6 +34,12 @@
 #include 
 #include "../scsi_sas_internal.h"
 
+
+static void sas_unregister_common_dev(struct asd_sas_port *port,
+   struct domain_device *dev);
+static void sas_unregister_fail_dev(struct asd_sas_port *port,
+   struct domain_device *dev);
+
 /* -- Basic task processing for discovery purposes -- */
 
 void sas_init_dev(struct domain_device *dev)
@@ -158,11 +164,8 @@ static int sas_get_port_device(struct asd_sas_port *port)
 
if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEVICE)
list_add_tail(>disco_list_node, >disco_list);
-   else {
-   spin_lock_irq(>dev_list_lock);
-   list_add_tail(>dev_list_node, >dev_list);
-   spin_unlock_irq(>dev_list_lock);
-   }
+   else
+   list_add_tail(>dev_list_node, >expander_list);
 
spin_lock_irq(>phy_list_lock);
list_for_each_entry(phy, >phy_list, port_phy_el)
@@ -212,34 +215,83 @@ void sas_not

[RFC][PATCH v2 2/2] libsas: Fix hotplug issue in libsas

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

The root cause of the issues is we use one workqueue(shost->work_q) to
process libsas event, and we divide a hot-on or hot-remove flow to several
events to process. E.g. we start a new work and queue it into the same
workqueue in sas_deform_port() to remove the children devices after
the sas port. So if there is one hot-on event between remove sas port
and destruct the children devices, some unexpected errors would
be caused.

This patch modify hotplug event process mechanism to solve the
hotplug problems in libsas. We move device add/del operation to
a new workqueue(named sas_dev_wq).

And we use sas_port_alloc_num to replace sas_port_alloc function
because when discovery is concurrently executing with the device
adding or destroying, the old sas port resource may have not
completely deleted, the new sas port resource of the same name
will be created, and this will cause calltrace about sysfs
device node.

Signed-off-by: Yijing Wang 
Signed-off-by: Yousong He 
Signed-off-by: Qilin Chen 
---
 drivers/scsi/libsas/sas_ata.c   |  34 ++---
 drivers/scsi/libsas/sas_discover.c  | 245 ++--
 drivers/scsi/libsas/sas_expander.c  |  54 ++--
 drivers/scsi/libsas/sas_init.c  |  26 +++-
 drivers/scsi/libsas/sas_internal.h  |  46 ++-
 drivers/scsi/libsas/sas_port.c  |  12 +-
 drivers/scsi/libsas/sas_scsi_host.c |  23 
 include/scsi/libsas.h   |   5 +-
 include/scsi/sas_ata.h  |   4 +-
 9 files changed, 340 insertions(+), 109 deletions(-)

diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 763f012..877efa8 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -619,32 +619,22 @@ static int sas_get_ata_command_set(struct domain_device 
*dev)
return ata_dev_classify();
 }
 
-void sas_probe_sata(struct asd_sas_port *port)
+void sas_probe_sata_device(struct domain_device *dev)
 {
-   struct domain_device *dev, *n;
-
-   mutex_lock(>ha->disco_mutex);
-   list_for_each_entry(dev, >disco_list, disco_list_node) {
-   if (!dev_is_sata(dev))
-   continue;
-
-   ata_sas_async_probe(dev->sata_dev.ap);
-   }
-   mutex_unlock(>ha->disco_mutex);
+   struct asd_sas_port *port = dev->port;
 
-   list_for_each_entry_safe(dev, n, >disco_list, disco_list_node) {
-   if (!dev_is_sata(dev))
-   continue;
+   if (!port || !port->ha || !dev_is_sata(dev))
+   return;
 
-   sas_ata_wait_eh(dev);
+   ata_sas_async_probe(dev->sata_dev.ap);
 
-   /* if libata could not bring the link up, don't surface
-* the device
-*/
-   if (ata_dev_disabled(sas_to_ata_dev(dev)))
-   sas_fail_probe(dev, __func__, -ENODEV);
-   }
+   sas_ata_wait_eh(dev);
 
+   /* if libata could not bring the link up, don't surface
+* the device
+*/
+   if (ata_dev_disabled(sas_to_ata_dev(dev)))
+   sas_fail_probe(dev, __func__, -ENODEV);
 }
 
 static void sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
@@ -729,7 +719,7 @@ int sas_discover_sata(struct domain_device *dev)
if (res)
return res;
 
-   sas_discover_event(dev->port, DISCE_PROBE);
+   sas_notify_device_event(dev, SAS_DEVICE_ADD);
return 0;
 }
 
diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 60de662..ea57c66 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -34,6 +34,12 @@
 #include 
 #include "../scsi_sas_internal.h"
 
+
+static void sas_unregister_common_dev(struct asd_sas_port *port,
+   struct domain_device *dev);
+static void sas_unregister_fail_dev(struct asd_sas_port *port,
+   struct domain_device *dev);
+
 /* -- Basic task processing for discovery purposes -- */
 
 void sas_init_dev(struct domain_device *dev)
@@ -158,11 +164,8 @@ static int sas_get_port_device(struct asd_sas_port *port)
 
if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEVICE)
list_add_tail(>disco_list_node, >disco_list);
-   else {
-   spin_lock_irq(>dev_list_lock);
-   list_add_tail(>dev_list_node, >dev_list);
-   spin_unlock_irq(>dev_list_lock);
-   }
+   else
+   list_add_tail(>dev_list_node, >expander_list);
 
spin_lock_irq(>phy_list_lock);
list_for_each_entry(phy, >phy_list, port_phy_el)
@@ -212,34 +215,83 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
}
 }
 
-static void sas_probe_devices

[RFC][PATCH v1 2/2] libsas: Fix hotplug issue in libsas

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

The root cause of the issues is we use one workqueue(shost->work_q) to
process libsas event, and we divide a hot-on or hot-remove flow to several
events to process. E.g. we start a new work and queue it into the same
workqueue in sas_deform_port() to remove the children devices after
the sas port. So if there is one hot-on event between remove sas port
and destruct the children devices, some unexpected errors would
be caused.

This patch modify hotplug event process mechanism to solve the
hotplug problems in libsas. We move device add/del operation to
a new workqueue(named sas_dev_wq).

And we use sas_port_alloc_num to replace sas_port_alloc function
because when discovery is concurrently executing with the device
adding or destroying, the old sas port resource may have not
completely deleted, the new sas port resource of the same name
will be created, and this will cause calltrace about sysfs
device node.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
Signed-off-by: Yousong He <heyous...@huawei.com>
Signed-off-by: Qilin Chen <chenqil...@huawei.com>
---
 drivers/scsi/libsas/sas_ata.c   |   34 ++---
 drivers/scsi/libsas/sas_discover.c  |  245 +-
 drivers/scsi/libsas/sas_expander.c  |   54 ++--
 drivers/scsi/libsas/sas_init.c  |   26 -
 drivers/scsi/libsas/sas_internal.h  |   46 ++-
 drivers/scsi/libsas/sas_port.c  |   12 ++-
 drivers/scsi/libsas/sas_scsi_host.c |   23 
 include/scsi/libsas.h   |5 +-
 include/scsi/sas_ata.h  |4 +-
 9 files changed, 340 insertions(+), 109 deletions(-)

diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 763f012..877efa8 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -619,32 +619,22 @@ static int sas_get_ata_command_set(struct domain_device 
*dev)
return ata_dev_classify();
 }
 
-void sas_probe_sata(struct asd_sas_port *port)
+void sas_probe_sata_device(struct domain_device *dev)
 {
-   struct domain_device *dev, *n;
-
-   mutex_lock(>ha->disco_mutex);
-   list_for_each_entry(dev, >disco_list, disco_list_node) {
-   if (!dev_is_sata(dev))
-   continue;
-
-   ata_sas_async_probe(dev->sata_dev.ap);
-   }
-   mutex_unlock(>ha->disco_mutex);
+   struct asd_sas_port *port = dev->port;
 
-   list_for_each_entry_safe(dev, n, >disco_list, disco_list_node) {
-   if (!dev_is_sata(dev))
-   continue;
+   if (!port || !port->ha || !dev_is_sata(dev))
+   return;
 
-   sas_ata_wait_eh(dev);
+   ata_sas_async_probe(dev->sata_dev.ap);
 
-   /* if libata could not bring the link up, don't surface
-* the device
-*/
-   if (ata_dev_disabled(sas_to_ata_dev(dev)))
-   sas_fail_probe(dev, __func__, -ENODEV);
-   }
+   sas_ata_wait_eh(dev);
 
+   /* if libata could not bring the link up, don't surface
+* the device
+*/
+   if (ata_dev_disabled(sas_to_ata_dev(dev)))
+   sas_fail_probe(dev, __func__, -ENODEV);
 }
 
 static void sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
@@ -729,7 +719,7 @@ int sas_discover_sata(struct domain_device *dev)
if (res)
return res;
 
-   sas_discover_event(dev->port, DISCE_PROBE);
+   sas_notify_device_event(dev, SAS_DEVICE_ADD);
return 0;
 }
 
diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 60de662..ea57c66 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -34,6 +34,12 @@
 #include 
 #include "../scsi_sas_internal.h"
 
+
+static void sas_unregister_common_dev(struct asd_sas_port *port,
+   struct domain_device *dev);
+static void sas_unregister_fail_dev(struct asd_sas_port *port,
+   struct domain_device *dev);
+
 /* -- Basic task processing for discovery purposes -- */
 
 void sas_init_dev(struct domain_device *dev)
@@ -158,11 +164,8 @@ static int sas_get_port_device(struct asd_sas_port *port)
 
if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEVICE)
list_add_tail(>disco_list_node, >disco_list);
-   else {
-   spin_lock_irq(>dev_list_lock);
-   list_add_tail(>dev_list_node, >dev_list);
-   spin_unlock_irq(>dev_list_lock);
-   }
+   else
+   list_add_tail(>dev_list_node, >expander_list);
 
spin_lock_irq(>phy_list_lock);
list_for_each_entry(phy, >phy_list, port_phy_el)
@@ -212,34 +215,83 @@ void 

[RFC][PATCH v1 2/2] libsas: Fix hotplug issue in libsas

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

The root cause of the issues is we use one workqueue(shost->work_q) to
process libsas event, and we divide a hot-on or hot-remove flow to several
events to process. E.g. we start a new work and queue it into the same
workqueue in sas_deform_port() to remove the children devices after
the sas port. So if there is one hot-on event between remove sas port
and destruct the children devices, some unexpected errors would
be caused.

This patch modify hotplug event process mechanism to solve the
hotplug problems in libsas. We move device add/del operation to
a new workqueue(named sas_dev_wq).

And we use sas_port_alloc_num to replace sas_port_alloc function
because when discovery is concurrently executing with the device
adding or destroying, the old sas port resource may have not
completely deleted, the new sas port resource of the same name
will be created, and this will cause calltrace about sysfs
device node.

Signed-off-by: Yijing Wang 
Signed-off-by: Yousong He 
Signed-off-by: Qilin Chen 
---
 drivers/scsi/libsas/sas_ata.c   |   34 ++---
 drivers/scsi/libsas/sas_discover.c  |  245 +-
 drivers/scsi/libsas/sas_expander.c  |   54 ++--
 drivers/scsi/libsas/sas_init.c  |   26 -
 drivers/scsi/libsas/sas_internal.h  |   46 ++-
 drivers/scsi/libsas/sas_port.c  |   12 ++-
 drivers/scsi/libsas/sas_scsi_host.c |   23 
 include/scsi/libsas.h   |5 +-
 include/scsi/sas_ata.h  |4 +-
 9 files changed, 340 insertions(+), 109 deletions(-)

diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 763f012..877efa8 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -619,32 +619,22 @@ static int sas_get_ata_command_set(struct domain_device 
*dev)
return ata_dev_classify();
 }
 
-void sas_probe_sata(struct asd_sas_port *port)
+void sas_probe_sata_device(struct domain_device *dev)
 {
-   struct domain_device *dev, *n;
-
-   mutex_lock(>ha->disco_mutex);
-   list_for_each_entry(dev, >disco_list, disco_list_node) {
-   if (!dev_is_sata(dev))
-   continue;
-
-   ata_sas_async_probe(dev->sata_dev.ap);
-   }
-   mutex_unlock(>ha->disco_mutex);
+   struct asd_sas_port *port = dev->port;
 
-   list_for_each_entry_safe(dev, n, >disco_list, disco_list_node) {
-   if (!dev_is_sata(dev))
-   continue;
+   if (!port || !port->ha || !dev_is_sata(dev))
+   return;
 
-   sas_ata_wait_eh(dev);
+   ata_sas_async_probe(dev->sata_dev.ap);
 
-   /* if libata could not bring the link up, don't surface
-* the device
-*/
-   if (ata_dev_disabled(sas_to_ata_dev(dev)))
-   sas_fail_probe(dev, __func__, -ENODEV);
-   }
+   sas_ata_wait_eh(dev);
 
+   /* if libata could not bring the link up, don't surface
+* the device
+*/
+   if (ata_dev_disabled(sas_to_ata_dev(dev)))
+   sas_fail_probe(dev, __func__, -ENODEV);
 }
 
 static void sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
@@ -729,7 +719,7 @@ int sas_discover_sata(struct domain_device *dev)
if (res)
return res;
 
-   sas_discover_event(dev->port, DISCE_PROBE);
+   sas_notify_device_event(dev, SAS_DEVICE_ADD);
return 0;
 }
 
diff --git a/drivers/scsi/libsas/sas_discover.c 
b/drivers/scsi/libsas/sas_discover.c
index 60de662..ea57c66 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -34,6 +34,12 @@
 #include 
 #include "../scsi_sas_internal.h"
 
+
+static void sas_unregister_common_dev(struct asd_sas_port *port,
+   struct domain_device *dev);
+static void sas_unregister_fail_dev(struct asd_sas_port *port,
+   struct domain_device *dev);
+
 /* -- Basic task processing for discovery purposes -- */
 
 void sas_init_dev(struct domain_device *dev)
@@ -158,11 +164,8 @@ static int sas_get_port_device(struct asd_sas_port *port)
 
if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEVICE)
list_add_tail(>disco_list_node, >disco_list);
-   else {
-   spin_lock_irq(>dev_list_lock);
-   list_add_tail(>dev_list_node, >dev_list);
-   spin_unlock_irq(>dev_list_lock);
-   }
+   else
+   list_add_tail(>dev_list_node, >expander_list);
 
spin_lock_irq(>phy_list_lock);
list_for_each_entry(phy, >phy_list, port_phy_el)
@@ -212,34 +215,83 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
}
 }
 
-static void

[RFC][PATCH v1 1/2] libsas: Alloc dynamic work to avoid missing sas events

2016-09-12 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 event to libsas, the hotplug
events may pending in the workqueue like

shost->workq
tail | PHYE_LOSS_OF_SIGNAL  | PORTE_BYTES_DMAED | head

In this case, if a new PORTE_BYTES_DMAED event coming,
it would be lost, because we can not queue a work which
is already pending in the workqueue, also libsas has a
pending bit to avoid queue the same event.

The lost hotplug event make something confusing, e.g.
we have sas disks connected hardware, but we can not
found them in kernel.

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

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
Signed-off-by: Yousong He <heyous...@huawei.com>
Signed-off-by: Qilin Chen <chenqil...@huawei.com>
---
 drivers/scsi/libsas/sas_event.c|   61 ---
 drivers/scsi/libsas/sas_init.c |5 +--
 drivers/scsi/libsas/sas_internal.h |3 ++
 drivers/scsi/libsas/sas_phy.c  |   50 -
 drivers/scsi/libsas/sas_port.c |   23 --
 include/scsi/libsas.h  |8 -
 6 files changed, 66 insertions(+), 84 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index aadbd53..993156c 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,60 @@ 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 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_KERNEL);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, sas_ha_event_fns[event]);
+   ev->ha = sas_ha;
+   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_KERNEL);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, sas_port_event_fns[event]);
+   ev->phy = phy;
+   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_KERNEL);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, sas_phy_event_fns[event]);
+   ev->phy = phy;
+   sas_queue_event(event, >work, ha);
 }
 
 int sas_init_events(struct sas_ha_struct *sas_ha)
 {
-   static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = {
-   [HAE_RESET] = sas_hae_reset,
-   };
-
-   int i;
-
-   for (i = 0; i < HA_NUM_EVENTS; i++) {
-   INIT_SAS_WORK(_ha->ha_events[i].work, sas_ha_event_fns[i]);
-   sas_ha->ha_events[i].ha = sas_ha;
-   }
-
sas_ha->notif

[RFC][PATCH v1 1/2] libsas: Alloc dynamic work to avoid missing sas events

2016-09-12 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 event to libsas, the hotplug
events may pending in the workqueue like

shost->workq
tail | PHYE_LOSS_OF_SIGNAL  | PORTE_BYTES_DMAED | head

In this case, if a new PORTE_BYTES_DMAED event coming,
it would be lost, because we can not queue a work which
is already pending in the workqueue, also libsas has a
pending bit to avoid queue the same event.

The lost hotplug event make something confusing, e.g.
we have sas disks connected hardware, but we can not
found them in kernel.

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|   61 ---
 drivers/scsi/libsas/sas_init.c |5 +--
 drivers/scsi/libsas/sas_internal.h |3 ++
 drivers/scsi/libsas/sas_phy.c  |   50 -
 drivers/scsi/libsas/sas_port.c |   23 --
 include/scsi/libsas.h  |8 -
 6 files changed, 66 insertions(+), 84 deletions(-)

diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index aadbd53..993156c 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,60 @@ 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 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_KERNEL);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, sas_ha_event_fns[event]);
+   ev->ha = sas_ha;
+   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_KERNEL);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, sas_port_event_fns[event]);
+   ev->phy = phy;
+   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_KERNEL);
+   if (!ev)
+   return;
+
+   INIT_SAS_WORK(>work, sas_phy_event_fns[event]);
+   ev->phy = phy;
+   sas_queue_event(event, >work, ha);
 }
 
 int sas_init_events(struct sas_ha_struct *sas_ha)
 {
-   static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = {
-   [HAE_RESET] = sas_hae_reset,
-   };
-
-   int i;
-
-   for (i = 0; i < HA_NUM_EVENTS; i++) {
-   INIT_SAS_WORK(_ha->ha_events[i].work, sas_ha_event_fns[i]);
-   sas_ha->ha_events[i].ha = sas_ha;
-   }
-
sas_ha->notify_ha_event = notify_ha_event;
sas_ha->notify_port_event = notify_port_event;
  

[PATCH v3 2/3] bcache: update document info

2016-07-03 Thread Yijing Wang
There is no return in continue_at(), update the documentation.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 drivers/md/bcache/closure.c |2 +-
 drivers/md/bcache/closure.h |3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c
index 9eaf1d6..864e673 100644
--- a/drivers/md/bcache/closure.c
+++ b/drivers/md/bcache/closure.c
@@ -112,7 +112,7 @@ bool closure_wait(struct closure_waitlist *waitlist, struct 
closure *cl)
 EXPORT_SYMBOL(closure_wait);
 
 /**
- * closure_sync - sleep until a closure a closure has nothing left to wait on
+ * closure_sync - sleep until a closure has nothing left to wait on
  *
  * Sleeps until the refcount hits 1 - the thread that's running the closure 
owns
  * the last refcount.
diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h
index 782cc2c..9b2fe2d 100644
--- a/drivers/md/bcache/closure.h
+++ b/drivers/md/bcache/closure.h
@@ -31,7 +31,8 @@
  * passing it, as you might expect, the function to run when nothing is pending
  * and the workqueue to run that function out of.
  *
- * continue_at() also, critically, is a macro that returns the calling 
function.
+ * continue_at() also, critically, requires a 'return' immediately following 
the
+ * location where this macro is referenced, to return to the calling function.
  * There's good reason for this.
  *
  * To use safely closures asynchronously, they must always have a refcount 
while
-- 
1.7.1



[PATCH v3 3/3] bcache: Remove redundant block_size assignment

2016-07-03 Thread Yijing Wang
We have assigned sb->block_size before the switch,
so remove the redundant one.

Reviewed-by: Coly Li <col...@suse.de>
Signed-off-by: Yijing Wang <wangyij...@huawei.com>
Acked-by: Eric Wheeler <bca...@lists.ewheeler.net>
---
 drivers/md/bcache/super.c |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index aecaace..bf4b100 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -134,7 +134,6 @@ static const char *read_super(struct cache_sb *sb, struct 
block_device *bdev,
case BCACHE_SB_VERSION_CDEV:
case BCACHE_SB_VERSION_CDEV_WITH_UUID:
sb->nbuckets= le64_to_cpu(s->nbuckets);
-   sb->block_size  = le16_to_cpu(s->block_size);
sb->bucket_size = le16_to_cpu(s->bucket_size);
 
sb->nr_in_set   = le16_to_cpu(s->nr_in_set);
-- 
1.7.1



[PATCH v3 2/3] bcache: update document info

2016-07-03 Thread Yijing Wang
There is no return in continue_at(), update the documentation.

Signed-off-by: Yijing Wang 
---
 drivers/md/bcache/closure.c |2 +-
 drivers/md/bcache/closure.h |3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c
index 9eaf1d6..864e673 100644
--- a/drivers/md/bcache/closure.c
+++ b/drivers/md/bcache/closure.c
@@ -112,7 +112,7 @@ bool closure_wait(struct closure_waitlist *waitlist, struct 
closure *cl)
 EXPORT_SYMBOL(closure_wait);
 
 /**
- * closure_sync - sleep until a closure a closure has nothing left to wait on
+ * closure_sync - sleep until a closure has nothing left to wait on
  *
  * Sleeps until the refcount hits 1 - the thread that's running the closure 
owns
  * the last refcount.
diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h
index 782cc2c..9b2fe2d 100644
--- a/drivers/md/bcache/closure.h
+++ b/drivers/md/bcache/closure.h
@@ -31,7 +31,8 @@
  * passing it, as you might expect, the function to run when nothing is pending
  * and the workqueue to run that function out of.
  *
- * continue_at() also, critically, is a macro that returns the calling 
function.
+ * continue_at() also, critically, requires a 'return' immediately following 
the
+ * location where this macro is referenced, to return to the calling function.
  * There's good reason for this.
  *
  * To use safely closures asynchronously, they must always have a refcount 
while
-- 
1.7.1



[PATCH v3 3/3] bcache: Remove redundant block_size assignment

2016-07-03 Thread Yijing Wang
We have assigned sb->block_size before the switch,
so remove the redundant one.

Reviewed-by: Coly Li 
Signed-off-by: Yijing Wang 
Acked-by: Eric Wheeler 
---
 drivers/md/bcache/super.c |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index aecaace..bf4b100 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -134,7 +134,6 @@ static const char *read_super(struct cache_sb *sb, struct 
block_device *bdev,
case BCACHE_SB_VERSION_CDEV:
case BCACHE_SB_VERSION_CDEV_WITH_UUID:
sb->nbuckets= le64_to_cpu(s->nbuckets);
-   sb->block_size  = le16_to_cpu(s->block_size);
sb->bucket_size = le16_to_cpu(s->bucket_size);
 
sb->nr_in_set   = le16_to_cpu(s->nr_in_set);
-- 
1.7.1



[PATCH v3 1/3] bcache: Remove redundant parameter for cache_alloc()

2016-07-03 Thread Yijing Wang
Cache_sb is not used in cache_alloc, and we have copied
sb info to cache->sb already, remove it.

Reviewed-by: Coly Li <col...@suse.de>
Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 drivers/md/bcache/super.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index f5dbb4e..aecaace 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1803,7 +1803,7 @@ void bch_cache_release(struct kobject *kobj)
module_put(THIS_MODULE);
 }
 
-static int cache_alloc(struct cache_sb *sb, struct cache *ca)
+static int cache_alloc(struct cache *ca)
 {
size_t free;
struct bucket *b;
@@ -1858,7 +1858,7 @@ static int register_cache(struct cache_sb *sb, struct 
page *sb_page,
if (blk_queue_discard(bdev_get_queue(ca->bdev)))
ca->discard = CACHE_DISCARD(>sb);
 
-   ret = cache_alloc(sb, ca);
+   ret = cache_alloc(ca);
if (ret != 0)
goto err;
 
-- 
1.7.1



[PATCH v3 1/3] bcache: Remove redundant parameter for cache_alloc()

2016-07-03 Thread Yijing Wang
Cache_sb is not used in cache_alloc, and we have copied
sb info to cache->sb already, remove it.

Reviewed-by: Coly Li 
Signed-off-by: Yijing Wang 
---
 drivers/md/bcache/super.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index f5dbb4e..aecaace 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1803,7 +1803,7 @@ void bch_cache_release(struct kobject *kobj)
module_put(THIS_MODULE);
 }
 
-static int cache_alloc(struct cache_sb *sb, struct cache *ca)
+static int cache_alloc(struct cache *ca)
 {
size_t free;
struct bucket *b;
@@ -1858,7 +1858,7 @@ static int register_cache(struct cache_sb *sb, struct 
page *sb_page,
if (blk_queue_discard(bdev_get_queue(ca->bdev)))
ca->discard = CACHE_DISCARD(>sb);
 
-   ret = cache_alloc(sb, ca);
+   ret = cache_alloc(ca);
if (ret != 0)
goto err;
 
-- 
1.7.1



[PATCH v2 1/3] bcache: Remove redundant parameter for cache_alloc()

2016-07-01 Thread Yijing Wang
Cache_sb is not used in cache_alloc, and we have copied
sb info to cache->sb already, remove it.

Reviewed-by: Coly Li <col...@suse.de>
Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 drivers/md/bcache/super.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index f5dbb4e..aecaace 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1803,7 +1803,7 @@ void bch_cache_release(struct kobject *kobj)
module_put(THIS_MODULE);
 }
 
-static int cache_alloc(struct cache_sb *sb, struct cache *ca)
+static int cache_alloc(struct cache *ca)
 {
size_t free;
struct bucket *b;
@@ -1858,7 +1858,7 @@ static int register_cache(struct cache_sb *sb, struct 
page *sb_page,
if (blk_queue_discard(bdev_get_queue(ca->bdev)))
ca->discard = CACHE_DISCARD(>sb);
 
-   ret = cache_alloc(sb, ca);
+   ret = cache_alloc(ca);
if (ret != 0)
goto err;
 
-- 
1.7.1



[PATCH v2 1/3] bcache: Remove redundant parameter for cache_alloc()

2016-07-01 Thread Yijing Wang
Cache_sb is not used in cache_alloc, and we have copied
sb info to cache->sb already, remove it.

Reviewed-by: Coly Li 
Signed-off-by: Yijing Wang 
---
 drivers/md/bcache/super.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index f5dbb4e..aecaace 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1803,7 +1803,7 @@ void bch_cache_release(struct kobject *kobj)
module_put(THIS_MODULE);
 }
 
-static int cache_alloc(struct cache_sb *sb, struct cache *ca)
+static int cache_alloc(struct cache *ca)
 {
size_t free;
struct bucket *b;
@@ -1858,7 +1858,7 @@ static int register_cache(struct cache_sb *sb, struct 
page *sb_page,
if (blk_queue_discard(bdev_get_queue(ca->bdev)))
ca->discard = CACHE_DISCARD(>sb);
 
-   ret = cache_alloc(sb, ca);
+   ret = cache_alloc(ca);
if (ret != 0)
goto err;
 
-- 
1.7.1



[PATCH v2 2/3] bcache: update document info

2016-07-01 Thread Yijing Wang
There is no return in continue_at(), update the documentation.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 drivers/md/bcache/closure.c |2 +-
 drivers/md/bcache/closure.h |3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c
index 9eaf1d6..864e673 100644
--- a/drivers/md/bcache/closure.c
+++ b/drivers/md/bcache/closure.c
@@ -112,7 +112,7 @@ bool closure_wait(struct closure_waitlist *waitlist, struct 
closure *cl)
 EXPORT_SYMBOL(closure_wait);
 
 /**
- * closure_sync - sleep until a closure a closure has nothing left to wait on
+ * closure_sync - sleep until a closure has nothing left to wait on
  *
  * Sleeps until the refcount hits 1 - the thread that's running the closure 
owns
  * the last refcount.
diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h
index 782cc2c..5935c3c 100644
--- a/drivers/md/bcache/closure.h
+++ b/drivers/md/bcache/closure.h
@@ -31,7 +31,8 @@
  * passing it, as you might expect, the function to run when nothing is pending
  * and the workqueue to run that function out of.
  *
- * continue_at() also, critically, is a macro that returns the calling 
function.
+ * continue_at() also, critically, is a macro that needs a return followed to 
+ * return the calling function.
  * There's good reason for this.
  *
  * To use safely closures asynchronously, they must always have a refcount 
while
-- 
1.7.1



[PATCH v2 3/3] bcache: Remove redundant block_size assignment

2016-07-01 Thread Yijing Wang
We have assigned sb->block_size before the switch,
so remove the redundant one.

Reviewed-by: Coly Li <col...@suse.de>
Signed-off-by: Yijing Wang <wangyij...@huawei.com>
Acked-by: Eric Wheeler <bca...@lists.ewheeler.net>
---
 drivers/md/bcache/super.c |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index aecaace..bf4b100 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -134,7 +134,6 @@ static const char *read_super(struct cache_sb *sb, struct 
block_device *bdev,
case BCACHE_SB_VERSION_CDEV:
case BCACHE_SB_VERSION_CDEV_WITH_UUID:
sb->nbuckets= le64_to_cpu(s->nbuckets);
-   sb->block_size  = le16_to_cpu(s->block_size);
sb->bucket_size = le16_to_cpu(s->bucket_size);
 
sb->nr_in_set   = le16_to_cpu(s->nr_in_set);
-- 
1.7.1



[PATCH v2 2/3] bcache: update document info

2016-07-01 Thread Yijing Wang
There is no return in continue_at(), update the documentation.

Signed-off-by: Yijing Wang 
---
 drivers/md/bcache/closure.c |2 +-
 drivers/md/bcache/closure.h |3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c
index 9eaf1d6..864e673 100644
--- a/drivers/md/bcache/closure.c
+++ b/drivers/md/bcache/closure.c
@@ -112,7 +112,7 @@ bool closure_wait(struct closure_waitlist *waitlist, struct 
closure *cl)
 EXPORT_SYMBOL(closure_wait);
 
 /**
- * closure_sync - sleep until a closure a closure has nothing left to wait on
+ * closure_sync - sleep until a closure has nothing left to wait on
  *
  * Sleeps until the refcount hits 1 - the thread that's running the closure 
owns
  * the last refcount.
diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h
index 782cc2c..5935c3c 100644
--- a/drivers/md/bcache/closure.h
+++ b/drivers/md/bcache/closure.h
@@ -31,7 +31,8 @@
  * passing it, as you might expect, the function to run when nothing is pending
  * and the workqueue to run that function out of.
  *
- * continue_at() also, critically, is a macro that returns the calling 
function.
+ * continue_at() also, critically, is a macro that needs a return followed to 
+ * return the calling function.
  * There's good reason for this.
  *
  * To use safely closures asynchronously, they must always have a refcount 
while
-- 
1.7.1



[PATCH v2 3/3] bcache: Remove redundant block_size assignment

2016-07-01 Thread Yijing Wang
We have assigned sb->block_size before the switch,
so remove the redundant one.

Reviewed-by: Coly Li 
Signed-off-by: Yijing Wang 
Acked-by: Eric Wheeler 
---
 drivers/md/bcache/super.c |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index aecaace..bf4b100 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -134,7 +134,6 @@ static const char *read_super(struct cache_sb *sb, struct 
block_device *bdev,
case BCACHE_SB_VERSION_CDEV:
case BCACHE_SB_VERSION_CDEV_WITH_UUID:
sb->nbuckets= le64_to_cpu(s->nbuckets);
-   sb->block_size  = le16_to_cpu(s->block_size);
sb->bucket_size = le16_to_cpu(s->bucket_size);
 
sb->nr_in_set   = le16_to_cpu(s->nr_in_set);
-- 
1.7.1



[RESEND PATCH 3/3] bcache: Remove redundant block_size assignment

2016-06-21 Thread Yijing Wang
We have assigned sb->block_size before the switch,
so remove the redundant one.

Reviewed-by: Coly Li <col...@suse.de>
Signed-off-by: Yijing Wang <wangyij...@huawei.com>
Acked-by: Eric Wheeler <bca...@lists.ewheeler.net>
---
 drivers/md/bcache/super.c |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index aecaace..bf4b100 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -134,7 +134,6 @@ static const char *read_super(struct cache_sb *sb, struct 
block_device *bdev,
case BCACHE_SB_VERSION_CDEV:
case BCACHE_SB_VERSION_CDEV_WITH_UUID:
sb->nbuckets= le64_to_cpu(s->nbuckets);
-   sb->block_size  = le16_to_cpu(s->block_size);
sb->bucket_size = le16_to_cpu(s->bucket_size);
 
sb->nr_in_set   = le16_to_cpu(s->nr_in_set);
-- 
1.7.1



[RESEND PATCH 2/3] bcache: update document info

2016-06-21 Thread Yijing Wang
There is no return in continue_at(), update the documentation.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 drivers/md/bcache/closure.c |2 +-
 drivers/md/bcache/closure.h |3 ---
 2 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c
index 9eaf1d6..864e673 100644
--- a/drivers/md/bcache/closure.c
+++ b/drivers/md/bcache/closure.c
@@ -112,7 +112,7 @@ bool closure_wait(struct closure_waitlist *waitlist, struct 
closure *cl)
 EXPORT_SYMBOL(closure_wait);
 
 /**
- * closure_sync - sleep until a closure a closure has nothing left to wait on
+ * closure_sync - sleep until a closure has nothing left to wait on
  *
  * Sleeps until the refcount hits 1 - the thread that's running the closure 
owns
  * the last refcount.
diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h
index 782cc2c..f51188d 100644
--- a/drivers/md/bcache/closure.h
+++ b/drivers/md/bcache/closure.h
@@ -31,9 +31,6 @@
  * passing it, as you might expect, the function to run when nothing is pending
  * and the workqueue to run that function out of.
  *
- * continue_at() also, critically, is a macro that returns the calling 
function.
- * There's good reason for this.
- *
  * To use safely closures asynchronously, they must always have a refcount 
while
  * they are running owned by the thread that is running them. Otherwise, 
suppose
  * you submit some bios and wish to have a function run when they all complete:
-- 
1.7.1



[RESEND PATCH 3/3] bcache: Remove redundant block_size assignment

2016-06-21 Thread Yijing Wang
We have assigned sb->block_size before the switch,
so remove the redundant one.

Reviewed-by: Coly Li 
Signed-off-by: Yijing Wang 
Acked-by: Eric Wheeler 
---
 drivers/md/bcache/super.c |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index aecaace..bf4b100 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -134,7 +134,6 @@ static const char *read_super(struct cache_sb *sb, struct 
block_device *bdev,
case BCACHE_SB_VERSION_CDEV:
case BCACHE_SB_VERSION_CDEV_WITH_UUID:
sb->nbuckets= le64_to_cpu(s->nbuckets);
-   sb->block_size  = le16_to_cpu(s->block_size);
sb->bucket_size = le16_to_cpu(s->bucket_size);
 
sb->nr_in_set   = le16_to_cpu(s->nr_in_set);
-- 
1.7.1



[RESEND PATCH 2/3] bcache: update document info

2016-06-21 Thread Yijing Wang
There is no return in continue_at(), update the documentation.

Signed-off-by: Yijing Wang 
---
 drivers/md/bcache/closure.c |2 +-
 drivers/md/bcache/closure.h |3 ---
 2 files changed, 1 insertions(+), 4 deletions(-)

diff --git a/drivers/md/bcache/closure.c b/drivers/md/bcache/closure.c
index 9eaf1d6..864e673 100644
--- a/drivers/md/bcache/closure.c
+++ b/drivers/md/bcache/closure.c
@@ -112,7 +112,7 @@ bool closure_wait(struct closure_waitlist *waitlist, struct 
closure *cl)
 EXPORT_SYMBOL(closure_wait);
 
 /**
- * closure_sync - sleep until a closure a closure has nothing left to wait on
+ * closure_sync - sleep until a closure has nothing left to wait on
  *
  * Sleeps until the refcount hits 1 - the thread that's running the closure 
owns
  * the last refcount.
diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h
index 782cc2c..f51188d 100644
--- a/drivers/md/bcache/closure.h
+++ b/drivers/md/bcache/closure.h
@@ -31,9 +31,6 @@
  * passing it, as you might expect, the function to run when nothing is pending
  * and the workqueue to run that function out of.
  *
- * continue_at() also, critically, is a macro that returns the calling 
function.
- * There's good reason for this.
- *
  * To use safely closures asynchronously, they must always have a refcount 
while
  * they are running owned by the thread that is running them. Otherwise, 
suppose
  * you submit some bios and wish to have a function run when they all complete:
-- 
1.7.1



[RESEND PATCH 1/3] bcache: Remove redundant parameter for cache_alloc()

2016-06-21 Thread Yijing Wang
Cache_sb is not used in cache_alloc, and we have copied
sb info to cache->sb already, remove it.

Signed-off-by: Yijing Wang <wangyij...@huawei.com>
---
 drivers/md/bcache/super.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index f5dbb4e..aecaace 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1803,7 +1803,7 @@ void bch_cache_release(struct kobject *kobj)
module_put(THIS_MODULE);
 }
 
-static int cache_alloc(struct cache_sb *sb, struct cache *ca)
+static int cache_alloc(struct cache *ca)
 {
size_t free;
struct bucket *b;
@@ -1858,7 +1858,7 @@ static int register_cache(struct cache_sb *sb, struct 
page *sb_page,
if (blk_queue_discard(bdev_get_queue(ca->bdev)))
ca->discard = CACHE_DISCARD(>sb);
 
-   ret = cache_alloc(sb, ca);
+   ret = cache_alloc(ca);
if (ret != 0)
goto err;
 
-- 
1.7.1



[RESEND PATCH 1/3] bcache: Remove redundant parameter for cache_alloc()

2016-06-21 Thread Yijing Wang
Cache_sb is not used in cache_alloc, and we have copied
sb info to cache->sb already, remove it.

Signed-off-by: Yijing Wang 
---
 drivers/md/bcache/super.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index f5dbb4e..aecaace 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1803,7 +1803,7 @@ void bch_cache_release(struct kobject *kobj)
module_put(THIS_MODULE);
 }
 
-static int cache_alloc(struct cache_sb *sb, struct cache *ca)
+static int cache_alloc(struct cache *ca)
 {
size_t free;
struct bucket *b;
@@ -1858,7 +1858,7 @@ static int register_cache(struct cache_sb *sb, struct 
page *sb_page,
if (blk_queue_discard(bdev_get_queue(ca->bdev)))
ca->discard = CACHE_DISCARD(>sb);
 
-   ret = cache_alloc(sb, ca);
+   ret = cache_alloc(ca);
if (ret != 0)
goto err;
 
-- 
1.7.1



[PATCH part3 v12 05/10] powerpc/PCI: Rename pcibios_root_bridge_prepare() to pcibios_root_bus_prepare()

2015-07-20 Thread Yijing Wang
Pcibios_root_bridge_prepare() in powerpc set root bus
speed, it's not the preparation for pci host bridge.
For better separation of host bridge and root bus creation,
It's need to rename it to another weak function.

Signed-off-by: Yijing Wang 
---
 arch/powerpc/include/asm/machdep.h   |2 +-
 arch/powerpc/kernel/pci-common.c |6 +++---
 arch/powerpc/platforms/pseries/pci.c |2 +-
 arch/powerpc/platforms/pseries/pseries.h |2 +-
 arch/powerpc/platforms/pseries/setup.c   |2 +-
 drivers/pci/probe.c  |9 +
 6 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/include/asm/machdep.h 
b/arch/powerpc/include/asm/machdep.h
index 952579f..dbd5e8b 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -100,7 +100,7 @@ struct machdep_calls {
/* Called after allocating resources */
void(*pcibios_fixup)(void);
void(*pci_irq_fixup)(struct pci_dev *dev);
-   int (*pcibios_root_bridge_prepare)(struct pci_host_bridge
+   int (*pcibios_root_bus_prepare)(struct pci_host_bridge
*bridge);
 
/* To setup PHBs when using automatic OF platform driver for PCI */
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index df7f018..3e398c8 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -782,10 +782,10 @@ int pci_proc_domain(struct pci_bus *bus)
return 1;
 }
 
-int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+int pcibios_root_bus_prepare(struct pci_host_bridge *bridge)
 {
-   if (ppc_md.pcibios_root_bridge_prepare)
-   return ppc_md.pcibios_root_bridge_prepare(bridge);
+   if (ppc_md.pcibios_root_bus_prepare)
+   return ppc_md.pcibios_root_bus_prepare(bridge);
 
return 0;
 }
diff --git a/arch/powerpc/platforms/pseries/pci.c 
b/arch/powerpc/platforms/pseries/pci.c
index fe16a50..885f9ff 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -110,7 +110,7 @@ static void fixup_winbond_82c105(struct pci_dev* dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105,
 fixup_winbond_82c105);
 
-int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
+int pseries_root_bus_prepare(struct pci_host_bridge *bridge)
 {
struct device_node *dn, *pdn;
struct pci_bus *bus;
diff --git a/arch/powerpc/platforms/pseries/pseries.h 
b/arch/powerpc/platforms/pseries/pseries.h
index 8411c27..41310dc 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -75,7 +75,7 @@ static inline int dlpar_memory(struct pseries_hp_errorlog 
*hp_elog)
 
 /* PCI root bridge prepare function override for pseries */
 struct pci_host_bridge;
-int pseries_root_bridge_prepare(struct pci_host_bridge *bridge);
+int pseries_root_bus_prepare(struct pci_host_bridge *bridge);
 
 extern struct pci_controller_ops pseries_pci_controller_ops;
 
diff --git a/arch/powerpc/platforms/pseries/setup.c 
b/arch/powerpc/platforms/pseries/setup.c
index df6a704..2815309 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -537,7 +537,7 @@ static void __init pSeries_setup_arch(void)
ppc_md.enable_pmcs = power4_enable_pmcs;
}
 
-   ppc_md.pcibios_root_bridge_prepare = pseries_root_bridge_prepare;
+   ppc_md.pcibios_root_bus_prepare = pseries_root_bus_prepare;
 
if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
long rc;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b49deb8..0eba126 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1919,6 +1919,11 @@ int __weak pcibios_root_bridge_prepare(struct 
pci_host_bridge *bridge)
return 0;
 }
 
+int __weak pcibios_root_bus_prepare(struct pci_host_bridge *bridge)
+{
+   return 0;
+}
+
 void __weak pcibios_add_bus(struct pci_bus *bus)
 {
 }
@@ -1984,6 +1989,10 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
b->dev.class = _class;
b->dev.parent = b->bridge;
dev_set_name(>dev, "%04x:%02x", pci_domain_nr(b), bus);
+   error = pcibios_root_bus_prepare(bridge);
+   if (error)
+   goto class_dev_reg_err;
+
error = device_register(>dev);
if (error)
goto class_dev_reg_err;
-- 
1.7.1

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


[PATCH part3 v12 01/10] PCI: Save domain in pci_host_bridge

2015-07-20 Thread Yijing Wang
Save domain in pci_host_bridge, so we could get domain
from pci_host_bridge, and at the end of series, we could
clean up the arch specific pci_domain_nr(). For arm/arm64,
the domain argument is pointless, because they enable
CONFIG_PCI_DOMAINS_GENERIC, PCI core would assign domain
number for them, so introduce pci_create_root_bus_generic
and pci_scan_root_bus_generic() which simply assign domain
number to -1.

Tested-by: Gregory CLEMENT  #mvebu part
Signed-off-by: Yijing Wang 
---
 arch/alpha/kernel/pci.c|4 ++--
 arch/alpha/kernel/sys_nautilus.c   |2 +-
 arch/arm/kernel/bios32.c   |2 +-
 arch/arm/mach-dove/pcie.c  |2 +-
 arch/arm/mach-iop13xx/pci.c|4 ++--
 arch/arm/mach-mv78xx0/pcie.c   |2 +-
 arch/arm/mach-orion5x/pci.c|4 ++--
 arch/frv/mb93090-mb00/pci-vdk.c|3 ++-
 arch/ia64/pci/pci.c|4 ++--
 arch/ia64/sn/kernel/io_init.c  |4 ++--
 arch/m68k/coldfire/pci.c   |2 +-
 arch/microblaze/pci/pci-common.c   |4 ++--
 arch/mips/pci/pci.c|4 ++--
 arch/mn10300/unit-asb2305/pci.c|3 ++-
 arch/powerpc/kernel/pci-common.c   |4 ++--
 arch/s390/pci/pci.c|4 ++--
 arch/sh/drivers/pci/pci.c  |4 ++--
 arch/sparc/kernel/leon_pci.c   |2 +-
 arch/sparc/kernel/pci.c|4 ++--
 arch/sparc/kernel/pcic.c   |2 +-
 arch/tile/kernel/pci.c |4 ++--
 arch/tile/kernel/pci_gx.c  |4 ++--
 arch/unicore32/kernel/pci.c|2 +-
 arch/x86/pci/acpi.c|4 ++--
 arch/x86/pci/common.c  |2 +-
 arch/xtensa/kernel/pci.c   |2 +-
 drivers/parisc/dino.c  |2 +-
 drivers/parisc/lba_pci.c   |2 +-
 drivers/pci/host/pci-versatile.c   |3 ++-
 drivers/pci/host/pci-xgene.c   |2 +-
 drivers/pci/host/pcie-designware.c |2 +-
 drivers/pci/host/pcie-iproc.c  |2 +-
 drivers/pci/host/pcie-xilinx.c |2 +-
 drivers/pci/hotplug/ibmphp_core.c  |2 +-
 drivers/pci/probe.c|   21 +
 drivers/pci/xen-pcifront.c |2 +-
 include/linux/pci.h|   20 +---
 37 files changed, 82 insertions(+), 60 deletions(-)

diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 82f738e..2b0bce9 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -336,8 +336,8 @@ common_init_pci(void)
pci_add_resource_offset(, hose->mem_space,
hose->mem_space->start);
 
-   bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops,
-   hose, );
+   bus = pci_scan_root_bus(NULL, hose->index, next_busno,
+   alpha_mv.pci_ops, hose, );
if (!bus)
continue;
hose->bus = bus;
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 2cfaa0e..5d4f56f 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -205,7 +205,7 @@ nautilus_init_pci(void)
unsigned long memtop = max_low_pfn << PAGE_SHIFT;
 
/* Scan our single hose.  */
-   bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
+   bus = pci_scan_bus(hose->index, 0, alpha_mv.pci_ops, hose);
if (!bus)
return;
 
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index fc1..c7919c5 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -486,7 +486,7 @@ static void pcibios_init_hw(struct device *parent, struct 
hw_pci *hw,
if (hw->scan)
sys->bus = hw->scan(nr, sys);
else
-   sys->bus = pci_scan_root_bus(parent, sys->busnr,
+   sys->bus = pci_scan_root_bus_generic(parent, 
sys->busnr,
hw->ops, sys, >resources);
 
if (!sys->bus)
diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c
index 91fe971..2bbdd3f 100644
--- a/arch/arm/mach-dove/pcie.c
+++ b/arch/arm/mach-dove/pcie.c
@@ -160,7 +160,7 @@ dove_pcie_scan_bus(int nr, struct pci_sys_data *sys)
return NULL;
}
 
-   return pci_scan_root_bus(NULL, sys->busnr, _ops, sys,
+   return pci_scan_root_bus_generic(NULL, sys->busnr, _ops, sys,
 >resources);
 }
 
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 9082b84..0b60464 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -535,12 +535,12 @@ struct pci_bus *iop13xx_scan_bus(int nr, struct 
pci_sys_data *sys)
while(time_before(jiffies, atux_trhfa_timeout))
   

[PATCH part3 v12 00/10] Cleanup platform pci_domain_nr()

2015-07-20 Thread Yijing Wang
This series is splitted out from previous patchset
"Refine PCI scan interfaces and make generic pci host bridge".
It try to clean up all platform pci_domain_nr(), save domain
in pci_host_bridge, so we could get domain number from the
common interface. 

v11->v12:
  Introduce wrap function pci_create_root_bus_generic()
  and pci_create_root_bus_generic() for arm/arm64 which
  enable CONFIG_PCI_DOMAINS_GENERIC.
  Rebased this series based 4.2-rc1

Yijing Wang (10):
  PCI: Save domain in pci_host_bridge
  PCI: Move pci_bus_assign_domain_nr() declaration into
drivers/pci/pci.h
  PCI: Remove declaration for pci_get_new_domain_nr()
  PCI: Introduce pci_host_assign_domain_nr() to assign domain
  powerpc/PCI: Rename pcibios_root_bridge_prepare() to
pcibios_root_bus_prepare()
  PCI: Make pci_host_bridge hold sysdata in drvdata
  PCI: Create pci host bridge prior to root bus
  PCI: Introduce common pci_domain_nr() and remove platform specific
code
  PCI: Remove pci_bus_assign_domain_nr()
  IA64/PCI: Fix build warning found by kbuild test

 arch/alpha/include/asm/pci.h |2 -
 arch/alpha/kernel/pci.c  |4 +-
 arch/alpha/kernel/sys_nautilus.c |2 +-
 arch/arm/kernel/bios32.c |2 +-
 arch/arm/mach-dove/pcie.c|2 +-
 arch/arm/mach-iop13xx/pci.c  |4 +-
 arch/arm/mach-mv78xx0/pcie.c |2 +-
 arch/arm/mach-orion5x/pci.c  |4 +-
 arch/frv/mb93090-mb00/pci-vdk.c  |3 +-
 arch/ia64/include/asm/pci.h  |1 -
 arch/ia64/pci/pci.c  |6 +-
 arch/ia64/sn/kernel/io_acpi_init.c   |6 +-
 arch/ia64/sn/kernel/io_init.c|6 +-
 arch/m68k/coldfire/pci.c |2 +-
 arch/microblaze/include/asm/pci.h|2 -
 arch/microblaze/pci/pci-common.c |   15 +
 arch/mips/include/asm/pci.h  |2 -
 arch/mips/pci/pci.c  |4 +-
 arch/mn10300/unit-asb2305/pci.c  |3 +-
 arch/powerpc/include/asm/machdep.h   |2 +-
 arch/powerpc/include/asm/pci.h   |2 -
 arch/powerpc/kernel/pci-common.c |   21 ++-
 arch/powerpc/platforms/pseries/pci.c |2 +-
 arch/powerpc/platforms/pseries/pseries.h |2 +-
 arch/powerpc/platforms/pseries/setup.c   |2 +-
 arch/s390/include/asm/pci.h  |1 -
 arch/s390/pci/pci.c  |   10 +---
 arch/sh/drivers/pci/pci.c|4 +-
 arch/sh/include/asm/pci.h|2 -
 arch/sparc/include/asm/pci_64.h  |1 -
 arch/sparc/kernel/leon_pci.c |2 +-
 arch/sparc/kernel/pci.c  |   21 +--
 arch/sparc/kernel/pcic.c |2 +-
 arch/tile/include/asm/pci.h  |2 -
 arch/tile/kernel/pci.c   |4 +-
 arch/tile/kernel/pci_gx.c|4 +-
 arch/unicore32/kernel/pci.c  |2 +-
 arch/x86/include/asm/pci.h   |6 --
 arch/x86/pci/acpi.c  |6 +-
 arch/x86/pci/common.c|2 +-
 arch/xtensa/kernel/pci.c |2 +-
 drivers/parisc/dino.c|2 +-
 drivers/parisc/lba_pci.c |2 +-
 drivers/pci/host/pci-versatile.c |3 +-
 drivers/pci/host/pci-xgene.c |2 +-
 drivers/pci/host/pcie-designware.c   |2 +-
 drivers/pci/host/pcie-iproc.c|2 +-
 drivers/pci/host/pcie-xilinx.c   |2 +-
 drivers/pci/hotplug/ibmphp_core.c|2 +-
 drivers/pci/pci.c|   31 --
 drivers/pci/pci.h|1 +
 drivers/pci/probe.c  |   92 +-
 drivers/pci/xen-pcifront.c   |2 +-
 include/linux/pci.h  |   39 ++---
 54 files changed, 161 insertions(+), 195 deletions(-)

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


[PATCH part3 v12 08/10] PCI: Introduce common pci_domain_nr() and remove platform specific code

2015-07-20 Thread Yijing Wang
Now pci_host_bridge holds the domain number, we could
introduce common pci_domain_nr(), and remove platform specific code.

Signed-off-by: Yijing Wang 
---
 arch/alpha/include/asm/pci.h  |2 --
 arch/ia64/include/asm/pci.h   |1 -
 arch/microblaze/include/asm/pci.h |2 --
 arch/microblaze/pci/pci-common.c  |   11 ---
 arch/mips/include/asm/pci.h   |2 --
 arch/powerpc/include/asm/pci.h|2 --
 arch/powerpc/kernel/pci-common.c  |   11 ---
 arch/s390/include/asm/pci.h   |1 -
 arch/s390/pci/pci.c   |6 --
 arch/sh/include/asm/pci.h |2 --
 arch/sparc/include/asm/pci_64.h   |1 -
 arch/sparc/kernel/pci.c   |   17 -
 arch/tile/include/asm/pci.h   |2 --
 arch/x86/include/asm/pci.h|6 --
 drivers/pci/pci.c |8 
 include/linux/pci.h   |7 +--
 16 files changed, 9 insertions(+), 72 deletions(-)

diff --git a/arch/alpha/include/asm/pci.h b/arch/alpha/include/asm/pci.h
index 98f2eee..1f50c81 100644
--- a/arch/alpha/include/asm/pci.h
+++ b/arch/alpha/include/asm/pci.h
@@ -79,8 +79,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, 
int channel)
return channel ? 15 : 14;
 }
 
-#define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
-
 static inline int pci_proc_domain(struct pci_bus *bus)
 {
struct pci_controller *hose = bus->sysdata;
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 36d2c1e..ba6c40a 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -80,7 +80,6 @@ struct pci_controller {
 
 
 #define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata)
-#define pci_domain_nr(busdev)(PCI_CONTROLLER(busdev)->segment)
 
 extern struct pci_ops pci_root_ops;
 
diff --git a/arch/microblaze/include/asm/pci.h 
b/arch/microblaze/include/asm/pci.h
index dc9eb66..a452163 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -42,8 +42,6 @@
  */
 #define pcibios_assign_all_busses()0
 
-extern int pci_domain_nr(struct pci_bus *bus);
-
 /* Decide whether to display the domain number in /proc */
 extern int pci_proc_domain(struct pci_bus *bus);
 
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index d232c8a..6f64908 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -123,17 +123,6 @@ unsigned long pci_address_to_pio(phys_addr_t address)
 }
 EXPORT_SYMBOL_GPL(pci_address_to_pio);
 
-/*
- * Return the domain number for this bus.
- */
-int pci_domain_nr(struct pci_bus *bus)
-{
-   struct pci_controller *hose = pci_bus_to_host(bus);
-
-   return hose->global_number;
-}
-EXPORT_SYMBOL(pci_domain_nr);
-
 /* This routine is meant to be used early during boot, when the
  * PCI bus numbers have not yet been assigned, and you need to
  * issue PCI config cycles to an OF device.
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 98c31e5..8757775 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -114,8 +114,6 @@ struct pci_dev;
 extern unsigned int PCI_DMA_BUS_IS_PHYS;
 
 #ifdef CONFIG_PCI_DOMAINS
-#define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
-
 static inline int pci_proc_domain(struct pci_bus *bus)
 {
struct pci_controller *hose = bus->sysdata;
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 3453bd8..f83b8c8 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -73,8 +73,6 @@ extern struct dma_map_ops *get_pci_dma_ops(void);
 
 #endif /* CONFIG_PPC64 */
 
-extern int pci_domain_nr(struct pci_bus *bus);
-
 /* Decide whether to display the domain number in /proc */
 extern int pci_proc_domain(struct pci_bus *bus);
 
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 3e398c8..42928a0 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -196,17 +196,6 @@ unsigned long pci_address_to_pio(phys_addr_t address)
 }
 EXPORT_SYMBOL_GPL(pci_address_to_pio);
 
-/*
- * Return the domain number for this bus.
- */
-int pci_domain_nr(struct pci_bus *bus)
-{
-   struct pci_controller *hose = pci_bus_to_host(bus);
-
-   return hose->global_number;
-}
-EXPORT_SYMBOL(pci_domain_nr);
-
 /* This routine is meant to be used early during boot, when the
  * PCI bus numbers have not yet been assigned, and you need to
  * issue PCI config cycles to an OF device.
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index a648338..fe605b5 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -20,7 +20,6 @@
 
 void __iomem *pci_iomap(struct pci_dev *, int, unsigned long);
 void pci_iounmap(struct pci_dev *, void __iomem *);
-int pci_domain_nr(struct pc

[PATCH part3 v12 09/10] PCI: Remove pci_bus_assign_domain_nr()

2015-07-20 Thread Yijing Wang
Now we save the domain number in pci_host_bridge,
we could remove pci_bus_assign_domain_nr() and
clean the domain member in pci_bus.

Signed-off-by: Yijing Wang 
---
 drivers/pci/pci.c   |5 -
 drivers/pci/pci.h   |9 -
 drivers/pci/probe.c |   11 +++
 include/linux/pci.h |3 ---
 4 files changed, 3 insertions(+), 25 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0074420..cac136a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4536,11 +4536,6 @@ static int pci_assign_domain_nr(struct device *dev)
 
return domain;
 }
-
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
-{
-   bus->domain_nr = pci_assign_domain_nr(parent);
-}
 #endif
 #endif
 
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4a815c9..5c4b0dd 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -335,14 +335,5 @@ static inline int pci_dev_specific_reset(struct pci_dev 
*dev, int probe)
 
 struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
 
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
-#else
-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
-   struct device *parent)
-{
-}
-#endif
-
 void pci_host_assign_domain_nr(struct pci_host_bridge *host, int domain);
 #endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index cb525aa..5f2388b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -481,7 +481,7 @@ void pci_read_bridge_bases(struct pci_bus *child)
}
 }
 
-static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)
+static struct pci_bus *pci_alloc_bus(void)
 {
struct pci_bus *b;
 
@@ -496,10 +496,6 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus 
*parent)
INIT_LIST_HEAD(>resources);
b->max_bus_speed = PCI_SPEED_UNKNOWN;
b->cur_bus_speed = PCI_SPEED_UNKNOWN;
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
-   if (parent)
-   b->domain_nr = parent->domain_nr;
-#endif
return b;
 }
 
@@ -670,7 +666,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus 
*parent,
/*
 * Allocate a new bus, and inherit stuff from the parent..
 */
-   child = pci_alloc_bus(parent);
+   child = pci_alloc_bus();
if (!child)
return NULL;
 
@@ -1974,7 +1970,7 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
return NULL;
}
 
-   b = pci_alloc_bus(NULL);
+   b = pci_alloc_bus();
if (!b)
goto unregister_host;
 
@@ -1982,7 +1978,6 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
b->sysdata = sysdata;
b->ops = ops;
b->number = b->busn_res.start = bus;
-   pci_bus_assign_domain_nr(b, parent);
 
b->bridge = get_device(>dev);
device_enable_async_suspend(b->bridge);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 6b4789c..8293f61 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -461,9 +461,6 @@ struct pci_bus {
unsigned char   primary;/* number of primary bridge */
unsigned char   max_bus_speed;  /* enum pci_bus_speed */
unsigned char   cur_bus_speed;  /* enum pci_bus_speed */
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
-   int domain_nr;
-#endif
 
charname[48];
 
-- 
1.7.1

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


[PATCH part3 v12 04/10] PCI: Introduce pci_host_assign_domain_nr() to assign domain

2015-07-20 Thread Yijing Wang
Introduce pci_host_assign_domain_nr() to assign domain number
for pci_host_bridge.

Signed-off-by: Yijing Wang 
---
 drivers/pci/pci.c |   24 +++-
 drivers/pci/pci.h |1 +
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 59032e2..79d01e4 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4484,10 +4484,10 @@ static int pci_get_new_domain_nr(void)
return atomic_inc_return(&__domain_nr);
 }
 
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+static int pci_assign_domain_nr(struct device *dev)
 {
static int use_dt_domains = -1;
-   int domain = of_get_pci_domain_nr(parent->of_node);
+   int domain = of_get_pci_domain_nr(dev->of_node);
 
/*
 * Check DT domain and use_dt_domains values.
@@ -4521,16 +4521,30 @@ void pci_bus_assign_domain_nr(struct pci_bus *bus, 
struct device *parent)
use_dt_domains = 0;
domain = pci_get_new_domain_nr();
} else {
-   dev_err(parent, "Node %s has inconsistent \"linux,pci-domain\" 
property in DT\n",
-   parent->of_node->full_name);
+   dev_err(dev, "Node %s has inconsistent \"linux,pci-domain\" 
property in DT\n",
+   dev->of_node->full_name);
domain = -1;
}
 
-   bus->domain_nr = domain;
+   return domain;
+}
+
+void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+{
+   bus->domain_nr = pci_assign_domain_nr(parent);
 }
 #endif
 #endif
 
+void pci_host_assign_domain_nr(struct pci_host_bridge *host, int domain)
+{
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+   host->domain = pci_assign_domain_nr(host->dev.parent);
+#else
+   host->domain = domain;
+#endif
+}
+
 /**
  * pci_ext_cfg_avail - can we access extended PCI config space?
  *
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 02192aa..4a815c9 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -344,4 +344,5 @@ static inline void pci_bus_assign_domain_nr(struct pci_bus 
*bus,
 }
 #endif
 
+void pci_host_assign_domain_nr(struct pci_host_bridge *host, int domain);
 #endif /* DRIVERS_PCI_H */
-- 
1.7.1

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


[PATCH part3 v12 02/10] PCI: Move pci_bus_assign_domain_nr() declaration into drivers/pci/pci.h

2015-07-20 Thread Yijing Wang
pci_bus_assign_domain_nr() is only called in probe.c,
Move pci_bus_assign_domain_nr() declaration into
drivers/pci/pci.h.

Signed-off-by: Yijing Wang 
---
 drivers/pci/pci.h   |9 +
 include/linux/pci.h |6 --
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4ff0ff1..02192aa 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -335,4 +335,13 @@ static inline int pci_dev_specific_reset(struct pci_dev 
*dev, int probe)
 
 struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
 
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
+#else
+static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
+   struct device *parent)
+{
+}
+#endif
+
 #endif /* DRIVERS_PCI_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 50c0c47..f7e4204 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1337,12 +1337,6 @@ static inline int pci_domain_nr(struct pci_bus *bus)
 {
return bus->domain_nr;
 }
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
-#else
-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
-   struct device *parent)
-{
-}
 #endif
 
 /* some architectures require additional setup to direct VGA traffic */
-- 
1.7.1

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


[PATCH part3 v12 07/10] PCI: Create pci host bridge prior to root bus

2015-07-20 Thread Yijing Wang
Pci_host_bridge hold the domain number, we need
to assign domain number prior to root bus creation,
because root bus need to know the domain number
to check whether it's alreay exist. Also it's
preparation for separating pci_host_bridge creation
from pci_create_root_bus().

Signed-off-by: Yijing Wang 
---
 drivers/pci/probe.c |   58 +++---
 1 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 0ae8bf2..cb525aa 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -515,7 +515,7 @@ static void pci_release_host_bridge_dev(struct device *dev)
kfree(bridge);
 }
 
-static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
+static struct pci_host_bridge *pci_alloc_host_bridge(void)
 {
struct pci_host_bridge *bridge;
 
@@ -524,7 +524,6 @@ static struct pci_host_bridge *pci_alloc_host_bridge(struct 
pci_bus *b)
return NULL;
 
INIT_LIST_HEAD(>windows);
-   bridge->bus = b;
return bridge;
 }
 
@@ -1938,48 +1937,53 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
 {
int error;
struct pci_host_bridge *bridge;
-   struct pci_bus *b, *b2;
+   struct pci_bus *b;
struct resource_entry *window, *n;
struct resource *res;
resource_size_t offset;
char bus_addr[64];
char *fmt;
 
-   b = pci_alloc_bus(NULL);
-   if (!b)
+   bridge = pci_alloc_host_bridge();
+   if (!bridge)
return NULL;
 
-   b->sysdata = sysdata;
-   b->ops = ops;
-   b->number = b->busn_res.start = bus;
-   pci_bus_assign_domain_nr(b, parent);
-   b2 = pci_find_bus(pci_domain_nr(b), bus);
-   if (b2) {
+   bridge->dev.parent = parent;
+   pci_host_assign_domain_nr(bridge, domain);
+
+   b = pci_find_bus(bridge->domain, bus);
+   if (b) {
/* If we already got to this bus through a different bridge, 
ignore it */
-   dev_dbg(>dev, "bus already known\n");
-   goto err_out;
+   dev_dbg(>dev, "bus already known\n");
+   kfree(bridge);
+   return NULL;
}
 
-   bridge = pci_alloc_host_bridge(b);
-   if (!bridge)
-   goto err_out;
-
-   bridge->domain = domain;
-   bridge->dev.parent = parent;
bridge->dev.release = pci_release_host_bridge_dev;
dev_set_drvdata(>dev, sysdata);
-   dev_set_name(>dev, "pci%04x:%02x", pci_domain_nr(b), bus);
+   dev_set_name(>dev, "pci%04x:%02x", bridge->domain, bus);
error = pcibios_root_bridge_prepare(bridge);
if (error) {
kfree(bridge);
-   goto err_out;
+   return NULL;
}
 
error = device_register(>dev);
if (error) {
put_device(>dev);
-   goto err_out;
+   return NULL;
}
+
+   b = pci_alloc_bus(NULL);
+   if (!b)
+   goto unregister_host;
+
+   bridge->bus = b;
+   b->sysdata = sysdata;
+   b->ops = ops;
+   b->number = b->busn_res.start = bus;
+   pci_bus_assign_domain_nr(b, parent);
+
b->bridge = get_device(>dev);
device_enable_async_suspend(b->bridge);
pci_set_bus_of_node(b);
@@ -1992,11 +1996,11 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
dev_set_name(>dev, "%04x:%02x", pci_domain_nr(b), bus);
error = pcibios_root_bus_prepare(bridge);
if (error)
-   goto class_dev_reg_err;
+   goto free_bus;
 
error = device_register(>dev);
if (error)
-   goto class_dev_reg_err;
+   goto free_bus;
 
pcibios_add_bus(b);
 
@@ -2036,11 +2040,11 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
 
return b;
 
-class_dev_reg_err:
+free_bus:
+   kfree(b);
put_device(>dev);
+unregister_host:
device_unregister(>dev);
-err_out:
-   kfree(b);
return NULL;
 }
 EXPORT_SYMBOL_GPL(pci_create_root_bus);
-- 
1.7.1

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


[PATCH part3 v12 03/10] PCI: Remove declaration for pci_get_new_domain_nr()

2015-07-20 Thread Yijing Wang
pci_get_new_domain_nr() is only used in drivers/pci/pci.c,
remove the declaration in include/linux/pci.h.

Signed-off-by: Yijing Wang 
---
 drivers/pci/pci.c   |4 ++--
 include/linux/pci.h |3 ---
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0008c95..59032e2 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4476,14 +4476,14 @@ static void pci_no_domains(void)
 }
 
 #ifdef CONFIG_PCI_DOMAINS
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
 static atomic_t __domain_nr = ATOMIC_INIT(-1);
 
-int pci_get_new_domain_nr(void)
+static int pci_get_new_domain_nr(void)
 {
return atomic_inc_return(&__domain_nr);
 }
 
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
 void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
 {
static int use_dt_domains = -1;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index f7e4204..4524592 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1319,12 +1319,10 @@ void pci_cfg_access_unlock(struct pci_dev *dev);
  */
 #ifdef CONFIG_PCI_DOMAINS
 extern int pci_domains_supported;
-int pci_get_new_domain_nr(void);
 #else
 enum { pci_domains_supported = 0 };
 static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
 static inline int pci_proc_domain(struct pci_bus *bus) { return 0; }
-static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
 #endif /* CONFIG_PCI_DOMAINS */
 
 /*
@@ -1445,7 +1443,6 @@ static inline struct pci_dev 
*pci_get_bus_and_slot(unsigned int bus,
 
 static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
 static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; }
-static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
 
 #define dev_is_pci(d) (false)
 #define dev_is_pf(d) (false)
-- 
1.7.1

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


[PATCH part3 v12 10/10] IA64/PCI: Fix build warning found by kbuild test

2015-07-20 Thread Yijing Wang
Kbuild test robot found we passed a pci_dev * to
pci_domain_nr(). In old IA64 specific pci_domain_nr()
It was macro defines:

#define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata)
#define pci_domain_nr(busdev)(PCI_CONTROLLER(busdev)->segment)

Both pci_dev * and pci_bus * have opaque sysdata, so IA64 specific
pci_domain_nr() could get the pci_controller and return the exact
domain number, but now we use common pci_domain_nr() functions, so we
should fix this warning.

Signed-off-by: Yijing Wang 
---
 arch/ia64/sn/kernel/io_acpi_init.c |6 +++---
 arch/ia64/sn/kernel/io_init.c  |2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/ia64/sn/kernel/io_acpi_init.c 
b/arch/ia64/sn/kernel/io_acpi_init.c
index 0640739..2fd7414 100644
--- a/arch/ia64/sn/kernel/io_acpi_init.c
+++ b/arch/ia64/sn/kernel/io_acpi_init.c
@@ -364,12 +364,12 @@ sn_acpi_get_pcidev_info(struct pci_dev *dev, struct 
pcidev_info **pcidev_info,
 status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL,
);
 if (ACPI_SUCCESS(status)) {
-   if (segment != pci_domain_nr(dev)) {
+   if (segment != pci_domain_nr(dev->bus)) {
acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME,
_buffer);
printk(KERN_ERR
   "%s: Segment number mismatch, 0x%llx vs 0x%x 
for: %s\n",
-  __func__, segment, pci_domain_nr(dev),
+  __func__, segment, pci_domain_nr(dev->bus),
   (char *)name_buffer.pointer);
kfree(name_buffer.pointer);
return 1;
@@ -407,7 +407,7 @@ sn_acpi_get_pcidev_info(struct pci_dev *dev, struct 
pcidev_info **pcidev_info,
/* Build up the pcidev_info.pdi_slot_host_handle */
host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle);
(*pcidev_info)->pdi_slot_host_handle =
-   ((unsigned long) pci_domain_nr(dev) << 40) |
+   ((unsigned long) pci_domain_nr(dev->bus) << 40) |
/* bus == 0 */
host_devfn;
return 0;
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index d528814..0bdab82 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -164,7 +164,7 @@ sn_io_slot_fixup(struct pci_dev *dev)
panic("%s: Unable to alloc memory for sn_irq_info", __func__);
 
/* Call to retrieve pci device information needed by kernel. */
-   status = sal_get_pcidev_info((u64) pci_domain_nr(dev),
+   status = sal_get_pcidev_info((u64) pci_domain_nr(dev->bus),
(u64) dev->bus->number,
dev->devfn,
(u64) __pa(pcidev_info),
-- 
1.7.1

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


[PATCH part3 v12 06/10] PCI: Make pci_host_bridge hold sysdata in drvdata

2015-07-20 Thread Yijing Wang
Now platform specific sysdata is saved in pci_bus,
and pcibios_root_bridge_prepare() need to know
the sysdata. Later, we would move pcibios_root_bridge_prepare()
prior to root bus creation, so we need to make
pci_host_bridge hold sysdata.

Signed-off-by: Yijing Wang 
---
 arch/ia64/pci/pci.c |2 +-
 arch/x86/pci/acpi.c |2 +-
 drivers/pci/probe.c |1 +
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 67ffe1f..8f79852 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -485,7 +485,7 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge 
*bridge)
 * that case.
 */
if (!bridge->dev.parent) {
-   struct pci_controller *controller = bridge->bus->sysdata;
+   struct pci_controller *controller = 
dev_get_drvdata(>dev);
ACPI_COMPANION_SET(>dev, controller->companion);
}
return 0;
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 629fc3b..38ce348 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -502,7 +502,7 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge 
*bridge)
 * that case.
 */
if (!bridge->dev.parent) {
-   struct pci_sysdata *sd = bridge->bus->sysdata;
+   struct pci_sysdata *sd = dev_get_drvdata(>dev);
ACPI_COMPANION_SET(>dev, sd->companion);
}
return 0;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 0eba126..0ae8bf2 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1967,6 +1967,7 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
bridge->domain = domain;
bridge->dev.parent = parent;
bridge->dev.release = pci_release_host_bridge_dev;
+   dev_set_drvdata(>dev, sysdata);
dev_set_name(>dev, "pci%04x:%02x", pci_domain_nr(b), bus);
error = pcibios_root_bridge_prepare(bridge);
if (error) {
-- 
1.7.1

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


[PATCH part3 v12 08/10] PCI: Introduce common pci_domain_nr() and remove platform specific code

2015-07-20 Thread Yijing Wang
Now pci_host_bridge holds the domain number, we could
introduce common pci_domain_nr(), and remove platform specific code.

Signed-off-by: Yijing Wang wangyij...@huawei.com
---
 arch/alpha/include/asm/pci.h  |2 --
 arch/ia64/include/asm/pci.h   |1 -
 arch/microblaze/include/asm/pci.h |2 --
 arch/microblaze/pci/pci-common.c  |   11 ---
 arch/mips/include/asm/pci.h   |2 --
 arch/powerpc/include/asm/pci.h|2 --
 arch/powerpc/kernel/pci-common.c  |   11 ---
 arch/s390/include/asm/pci.h   |1 -
 arch/s390/pci/pci.c   |6 --
 arch/sh/include/asm/pci.h |2 --
 arch/sparc/include/asm/pci_64.h   |1 -
 arch/sparc/kernel/pci.c   |   17 -
 arch/tile/include/asm/pci.h   |2 --
 arch/x86/include/asm/pci.h|6 --
 drivers/pci/pci.c |8 
 include/linux/pci.h   |7 +--
 16 files changed, 9 insertions(+), 72 deletions(-)

diff --git a/arch/alpha/include/asm/pci.h b/arch/alpha/include/asm/pci.h
index 98f2eee..1f50c81 100644
--- a/arch/alpha/include/asm/pci.h
+++ b/arch/alpha/include/asm/pci.h
@@ -79,8 +79,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, 
int channel)
return channel ? 15 : 14;
 }
 
-#define pci_domain_nr(bus) ((struct pci_controller *)(bus)-sysdata)-index
-
 static inline int pci_proc_domain(struct pci_bus *bus)
 {
struct pci_controller *hose = bus-sysdata;
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 36d2c1e..ba6c40a 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -80,7 +80,6 @@ struct pci_controller {
 
 
 #define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev-sysdata)
-#define pci_domain_nr(busdev)(PCI_CONTROLLER(busdev)-segment)
 
 extern struct pci_ops pci_root_ops;
 
diff --git a/arch/microblaze/include/asm/pci.h 
b/arch/microblaze/include/asm/pci.h
index dc9eb66..a452163 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -42,8 +42,6 @@
  */
 #define pcibios_assign_all_busses()0
 
-extern int pci_domain_nr(struct pci_bus *bus);
-
 /* Decide whether to display the domain number in /proc */
 extern int pci_proc_domain(struct pci_bus *bus);
 
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index d232c8a..6f64908 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -123,17 +123,6 @@ unsigned long pci_address_to_pio(phys_addr_t address)
 }
 EXPORT_SYMBOL_GPL(pci_address_to_pio);
 
-/*
- * Return the domain number for this bus.
- */
-int pci_domain_nr(struct pci_bus *bus)
-{
-   struct pci_controller *hose = pci_bus_to_host(bus);
-
-   return hose-global_number;
-}
-EXPORT_SYMBOL(pci_domain_nr);
-
 /* This routine is meant to be used early during boot, when the
  * PCI bus numbers have not yet been assigned, and you need to
  * issue PCI config cycles to an OF device.
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 98c31e5..8757775 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -114,8 +114,6 @@ struct pci_dev;
 extern unsigned int PCI_DMA_BUS_IS_PHYS;
 
 #ifdef CONFIG_PCI_DOMAINS
-#define pci_domain_nr(bus) ((struct pci_controller *)(bus)-sysdata)-index
-
 static inline int pci_proc_domain(struct pci_bus *bus)
 {
struct pci_controller *hose = bus-sysdata;
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 3453bd8..f83b8c8 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -73,8 +73,6 @@ extern struct dma_map_ops *get_pci_dma_ops(void);
 
 #endif /* CONFIG_PPC64 */
 
-extern int pci_domain_nr(struct pci_bus *bus);
-
 /* Decide whether to display the domain number in /proc */
 extern int pci_proc_domain(struct pci_bus *bus);
 
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 3e398c8..42928a0 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -196,17 +196,6 @@ unsigned long pci_address_to_pio(phys_addr_t address)
 }
 EXPORT_SYMBOL_GPL(pci_address_to_pio);
 
-/*
- * Return the domain number for this bus.
- */
-int pci_domain_nr(struct pci_bus *bus)
-{
-   struct pci_controller *hose = pci_bus_to_host(bus);
-
-   return hose-global_number;
-}
-EXPORT_SYMBOL(pci_domain_nr);
-
 /* This routine is meant to be used early during boot, when the
  * PCI bus numbers have not yet been assigned, and you need to
  * issue PCI config cycles to an OF device.
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index a648338..fe605b5 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -20,7 +20,6 @@
 
 void __iomem *pci_iomap(struct pci_dev *, int, unsigned long);
 void pci_iounmap(struct pci_dev *, void __iomem *);
-int pci_domain_nr(struct pci_bus *);
 int

[PATCH part3 v12 00/10] Cleanup platform pci_domain_nr()

2015-07-20 Thread Yijing Wang
This series is splitted out from previous patchset
Refine PCI scan interfaces and make generic pci host bridge.
It try to clean up all platform pci_domain_nr(), save domain
in pci_host_bridge, so we could get domain number from the
common interface. 

v11-v12:
  Introduce wrap function pci_create_root_bus_generic()
  and pci_create_root_bus_generic() for arm/arm64 which
  enable CONFIG_PCI_DOMAINS_GENERIC.
  Rebased this series based 4.2-rc1

Yijing Wang (10):
  PCI: Save domain in pci_host_bridge
  PCI: Move pci_bus_assign_domain_nr() declaration into
drivers/pci/pci.h
  PCI: Remove declaration for pci_get_new_domain_nr()
  PCI: Introduce pci_host_assign_domain_nr() to assign domain
  powerpc/PCI: Rename pcibios_root_bridge_prepare() to
pcibios_root_bus_prepare()
  PCI: Make pci_host_bridge hold sysdata in drvdata
  PCI: Create pci host bridge prior to root bus
  PCI: Introduce common pci_domain_nr() and remove platform specific
code
  PCI: Remove pci_bus_assign_domain_nr()
  IA64/PCI: Fix build warning found by kbuild test

 arch/alpha/include/asm/pci.h |2 -
 arch/alpha/kernel/pci.c  |4 +-
 arch/alpha/kernel/sys_nautilus.c |2 +-
 arch/arm/kernel/bios32.c |2 +-
 arch/arm/mach-dove/pcie.c|2 +-
 arch/arm/mach-iop13xx/pci.c  |4 +-
 arch/arm/mach-mv78xx0/pcie.c |2 +-
 arch/arm/mach-orion5x/pci.c  |4 +-
 arch/frv/mb93090-mb00/pci-vdk.c  |3 +-
 arch/ia64/include/asm/pci.h  |1 -
 arch/ia64/pci/pci.c  |6 +-
 arch/ia64/sn/kernel/io_acpi_init.c   |6 +-
 arch/ia64/sn/kernel/io_init.c|6 +-
 arch/m68k/coldfire/pci.c |2 +-
 arch/microblaze/include/asm/pci.h|2 -
 arch/microblaze/pci/pci-common.c |   15 +
 arch/mips/include/asm/pci.h  |2 -
 arch/mips/pci/pci.c  |4 +-
 arch/mn10300/unit-asb2305/pci.c  |3 +-
 arch/powerpc/include/asm/machdep.h   |2 +-
 arch/powerpc/include/asm/pci.h   |2 -
 arch/powerpc/kernel/pci-common.c |   21 ++-
 arch/powerpc/platforms/pseries/pci.c |2 +-
 arch/powerpc/platforms/pseries/pseries.h |2 +-
 arch/powerpc/platforms/pseries/setup.c   |2 +-
 arch/s390/include/asm/pci.h  |1 -
 arch/s390/pci/pci.c  |   10 +---
 arch/sh/drivers/pci/pci.c|4 +-
 arch/sh/include/asm/pci.h|2 -
 arch/sparc/include/asm/pci_64.h  |1 -
 arch/sparc/kernel/leon_pci.c |2 +-
 arch/sparc/kernel/pci.c  |   21 +--
 arch/sparc/kernel/pcic.c |2 +-
 arch/tile/include/asm/pci.h  |2 -
 arch/tile/kernel/pci.c   |4 +-
 arch/tile/kernel/pci_gx.c|4 +-
 arch/unicore32/kernel/pci.c  |2 +-
 arch/x86/include/asm/pci.h   |6 --
 arch/x86/pci/acpi.c  |6 +-
 arch/x86/pci/common.c|2 +-
 arch/xtensa/kernel/pci.c |2 +-
 drivers/parisc/dino.c|2 +-
 drivers/parisc/lba_pci.c |2 +-
 drivers/pci/host/pci-versatile.c |3 +-
 drivers/pci/host/pci-xgene.c |2 +-
 drivers/pci/host/pcie-designware.c   |2 +-
 drivers/pci/host/pcie-iproc.c|2 +-
 drivers/pci/host/pcie-xilinx.c   |2 +-
 drivers/pci/hotplug/ibmphp_core.c|2 +-
 drivers/pci/pci.c|   31 --
 drivers/pci/pci.h|1 +
 drivers/pci/probe.c  |   92 +-
 drivers/pci/xen-pcifront.c   |2 +-
 include/linux/pci.h  |   39 ++---
 54 files changed, 161 insertions(+), 195 deletions(-)

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH part3 v12 02/10] PCI: Move pci_bus_assign_domain_nr() declaration into drivers/pci/pci.h

2015-07-20 Thread Yijing Wang
pci_bus_assign_domain_nr() is only called in probe.c,
Move pci_bus_assign_domain_nr() declaration into
drivers/pci/pci.h.

Signed-off-by: Yijing Wang wangyij...@huawei.com
---
 drivers/pci/pci.h   |9 +
 include/linux/pci.h |6 --
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4ff0ff1..02192aa 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -335,4 +335,13 @@ static inline int pci_dev_specific_reset(struct pci_dev 
*dev, int probe)
 
 struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
 
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
+#else
+static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
+   struct device *parent)
+{
+}
+#endif
+
 #endif /* DRIVERS_PCI_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 50c0c47..f7e4204 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1337,12 +1337,6 @@ static inline int pci_domain_nr(struct pci_bus *bus)
 {
return bus-domain_nr;
 }
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
-#else
-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
-   struct device *parent)
-{
-}
 #endif
 
 /* some architectures require additional setup to direct VGA traffic */
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH part3 v12 07/10] PCI: Create pci host bridge prior to root bus

2015-07-20 Thread Yijing Wang
Pci_host_bridge hold the domain number, we need
to assign domain number prior to root bus creation,
because root bus need to know the domain number
to check whether it's alreay exist. Also it's
preparation for separating pci_host_bridge creation
from pci_create_root_bus().

Signed-off-by: Yijing Wang wangyij...@huawei.com
---
 drivers/pci/probe.c |   58 +++---
 1 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 0ae8bf2..cb525aa 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -515,7 +515,7 @@ static void pci_release_host_bridge_dev(struct device *dev)
kfree(bridge);
 }
 
-static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
+static struct pci_host_bridge *pci_alloc_host_bridge(void)
 {
struct pci_host_bridge *bridge;
 
@@ -524,7 +524,6 @@ static struct pci_host_bridge *pci_alloc_host_bridge(struct 
pci_bus *b)
return NULL;
 
INIT_LIST_HEAD(bridge-windows);
-   bridge-bus = b;
return bridge;
 }
 
@@ -1938,48 +1937,53 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
 {
int error;
struct pci_host_bridge *bridge;
-   struct pci_bus *b, *b2;
+   struct pci_bus *b;
struct resource_entry *window, *n;
struct resource *res;
resource_size_t offset;
char bus_addr[64];
char *fmt;
 
-   b = pci_alloc_bus(NULL);
-   if (!b)
+   bridge = pci_alloc_host_bridge();
+   if (!bridge)
return NULL;
 
-   b-sysdata = sysdata;
-   b-ops = ops;
-   b-number = b-busn_res.start = bus;
-   pci_bus_assign_domain_nr(b, parent);
-   b2 = pci_find_bus(pci_domain_nr(b), bus);
-   if (b2) {
+   bridge-dev.parent = parent;
+   pci_host_assign_domain_nr(bridge, domain);
+
+   b = pci_find_bus(bridge-domain, bus);
+   if (b) {
/* If we already got to this bus through a different bridge, 
ignore it */
-   dev_dbg(b2-dev, bus already known\n);
-   goto err_out;
+   dev_dbg(b-dev, bus already known\n);
+   kfree(bridge);
+   return NULL;
}
 
-   bridge = pci_alloc_host_bridge(b);
-   if (!bridge)
-   goto err_out;
-
-   bridge-domain = domain;
-   bridge-dev.parent = parent;
bridge-dev.release = pci_release_host_bridge_dev;
dev_set_drvdata(bridge-dev, sysdata);
-   dev_set_name(bridge-dev, pci%04x:%02x, pci_domain_nr(b), bus);
+   dev_set_name(bridge-dev, pci%04x:%02x, bridge-domain, bus);
error = pcibios_root_bridge_prepare(bridge);
if (error) {
kfree(bridge);
-   goto err_out;
+   return NULL;
}
 
error = device_register(bridge-dev);
if (error) {
put_device(bridge-dev);
-   goto err_out;
+   return NULL;
}
+
+   b = pci_alloc_bus(NULL);
+   if (!b)
+   goto unregister_host;
+
+   bridge-bus = b;
+   b-sysdata = sysdata;
+   b-ops = ops;
+   b-number = b-busn_res.start = bus;
+   pci_bus_assign_domain_nr(b, parent);
+
b-bridge = get_device(bridge-dev);
device_enable_async_suspend(b-bridge);
pci_set_bus_of_node(b);
@@ -1992,11 +1996,11 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
dev_set_name(b-dev, %04x:%02x, pci_domain_nr(b), bus);
error = pcibios_root_bus_prepare(bridge);
if (error)
-   goto class_dev_reg_err;
+   goto free_bus;
 
error = device_register(b-dev);
if (error)
-   goto class_dev_reg_err;
+   goto free_bus;
 
pcibios_add_bus(b);
 
@@ -2036,11 +2040,11 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
 
return b;
 
-class_dev_reg_err:
+free_bus:
+   kfree(b);
put_device(bridge-dev);
+unregister_host:
device_unregister(bridge-dev);
-err_out:
-   kfree(b);
return NULL;
 }
 EXPORT_SYMBOL_GPL(pci_create_root_bus);
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH part3 v12 09/10] PCI: Remove pci_bus_assign_domain_nr()

2015-07-20 Thread Yijing Wang
Now we save the domain number in pci_host_bridge,
we could remove pci_bus_assign_domain_nr() and
clean the domain member in pci_bus.

Signed-off-by: Yijing Wang wangyij...@huawei.com
---
 drivers/pci/pci.c   |5 -
 drivers/pci/pci.h   |9 -
 drivers/pci/probe.c |   11 +++
 include/linux/pci.h |3 ---
 4 files changed, 3 insertions(+), 25 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0074420..cac136a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4536,11 +4536,6 @@ static int pci_assign_domain_nr(struct device *dev)
 
return domain;
 }
-
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
-{
-   bus-domain_nr = pci_assign_domain_nr(parent);
-}
 #endif
 #endif
 
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4a815c9..5c4b0dd 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -335,14 +335,5 @@ static inline int pci_dev_specific_reset(struct pci_dev 
*dev, int probe)
 
 struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
 
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent);
-#else
-static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,
-   struct device *parent)
-{
-}
-#endif
-
 void pci_host_assign_domain_nr(struct pci_host_bridge *host, int domain);
 #endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index cb525aa..5f2388b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -481,7 +481,7 @@ void pci_read_bridge_bases(struct pci_bus *child)
}
 }
 
-static struct pci_bus *pci_alloc_bus(struct pci_bus *parent)
+static struct pci_bus *pci_alloc_bus(void)
 {
struct pci_bus *b;
 
@@ -496,10 +496,6 @@ static struct pci_bus *pci_alloc_bus(struct pci_bus 
*parent)
INIT_LIST_HEAD(b-resources);
b-max_bus_speed = PCI_SPEED_UNKNOWN;
b-cur_bus_speed = PCI_SPEED_UNKNOWN;
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
-   if (parent)
-   b-domain_nr = parent-domain_nr;
-#endif
return b;
 }
 
@@ -670,7 +666,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus 
*parent,
/*
 * Allocate a new bus, and inherit stuff from the parent..
 */
-   child = pci_alloc_bus(parent);
+   child = pci_alloc_bus();
if (!child)
return NULL;
 
@@ -1974,7 +1970,7 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
return NULL;
}
 
-   b = pci_alloc_bus(NULL);
+   b = pci_alloc_bus();
if (!b)
goto unregister_host;
 
@@ -1982,7 +1978,6 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
b-sysdata = sysdata;
b-ops = ops;
b-number = b-busn_res.start = bus;
-   pci_bus_assign_domain_nr(b, parent);
 
b-bridge = get_device(bridge-dev);
device_enable_async_suspend(b-bridge);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 6b4789c..8293f61 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -461,9 +461,6 @@ struct pci_bus {
unsigned char   primary;/* number of primary bridge */
unsigned char   max_bus_speed;  /* enum pci_bus_speed */
unsigned char   cur_bus_speed;  /* enum pci_bus_speed */
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
-   int domain_nr;
-#endif
 
charname[48];
 
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH part3 v12 04/10] PCI: Introduce pci_host_assign_domain_nr() to assign domain

2015-07-20 Thread Yijing Wang
Introduce pci_host_assign_domain_nr() to assign domain number
for pci_host_bridge.

Signed-off-by: Yijing Wang wangyij...@huawei.com
---
 drivers/pci/pci.c |   24 +++-
 drivers/pci/pci.h |1 +
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 59032e2..79d01e4 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4484,10 +4484,10 @@ static int pci_get_new_domain_nr(void)
return atomic_inc_return(__domain_nr);
 }
 
-void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+static int pci_assign_domain_nr(struct device *dev)
 {
static int use_dt_domains = -1;
-   int domain = of_get_pci_domain_nr(parent-of_node);
+   int domain = of_get_pci_domain_nr(dev-of_node);
 
/*
 * Check DT domain and use_dt_domains values.
@@ -4521,16 +4521,30 @@ void pci_bus_assign_domain_nr(struct pci_bus *bus, 
struct device *parent)
use_dt_domains = 0;
domain = pci_get_new_domain_nr();
} else {
-   dev_err(parent, Node %s has inconsistent \linux,pci-domain\ 
property in DT\n,
-   parent-of_node-full_name);
+   dev_err(dev, Node %s has inconsistent \linux,pci-domain\ 
property in DT\n,
+   dev-of_node-full_name);
domain = -1;
}
 
-   bus-domain_nr = domain;
+   return domain;
+}
+
+void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+{
+   bus-domain_nr = pci_assign_domain_nr(parent);
 }
 #endif
 #endif
 
+void pci_host_assign_domain_nr(struct pci_host_bridge *host, int domain)
+{
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+   host-domain = pci_assign_domain_nr(host-dev.parent);
+#else
+   host-domain = domain;
+#endif
+}
+
 /**
  * pci_ext_cfg_avail - can we access extended PCI config space?
  *
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 02192aa..4a815c9 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -344,4 +344,5 @@ static inline void pci_bus_assign_domain_nr(struct pci_bus 
*bus,
 }
 #endif
 
+void pci_host_assign_domain_nr(struct pci_host_bridge *host, int domain);
 #endif /* DRIVERS_PCI_H */
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH part3 v12 10/10] IA64/PCI: Fix build warning found by kbuild test

2015-07-20 Thread Yijing Wang
Kbuild test robot found we passed a pci_dev * to
pci_domain_nr(). In old IA64 specific pci_domain_nr()
It was macro defines:

#define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev-sysdata)
#define pci_domain_nr(busdev)(PCI_CONTROLLER(busdev)-segment)

Both pci_dev * and pci_bus * have opaque sysdata, so IA64 specific
pci_domain_nr() could get the pci_controller and return the exact
domain number, but now we use common pci_domain_nr() functions, so we
should fix this warning.

Signed-off-by: Yijing Wang wangyij...@huawei.com
---
 arch/ia64/sn/kernel/io_acpi_init.c |6 +++---
 arch/ia64/sn/kernel/io_init.c  |2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/ia64/sn/kernel/io_acpi_init.c 
b/arch/ia64/sn/kernel/io_acpi_init.c
index 0640739..2fd7414 100644
--- a/arch/ia64/sn/kernel/io_acpi_init.c
+++ b/arch/ia64/sn/kernel/io_acpi_init.c
@@ -364,12 +364,12 @@ sn_acpi_get_pcidev_info(struct pci_dev *dev, struct 
pcidev_info **pcidev_info,
 status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL,
segment);
 if (ACPI_SUCCESS(status)) {
-   if (segment != pci_domain_nr(dev)) {
+   if (segment != pci_domain_nr(dev-bus)) {
acpi_get_name(rootbus_handle, ACPI_FULL_PATHNAME,
name_buffer);
printk(KERN_ERR
   %s: Segment number mismatch, 0x%llx vs 0x%x 
for: %s\n,
-  __func__, segment, pci_domain_nr(dev),
+  __func__, segment, pci_domain_nr(dev-bus),
   (char *)name_buffer.pointer);
kfree(name_buffer.pointer);
return 1;
@@ -407,7 +407,7 @@ sn_acpi_get_pcidev_info(struct pci_dev *dev, struct 
pcidev_info **pcidev_info,
/* Build up the pcidev_info.pdi_slot_host_handle */
host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle);
(*pcidev_info)-pdi_slot_host_handle =
-   ((unsigned long) pci_domain_nr(dev)  40) |
+   ((unsigned long) pci_domain_nr(dev-bus)  40) |
/* bus == 0 */
host_devfn;
return 0;
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index d528814..0bdab82 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -164,7 +164,7 @@ sn_io_slot_fixup(struct pci_dev *dev)
panic(%s: Unable to alloc memory for sn_irq_info, __func__);
 
/* Call to retrieve pci device information needed by kernel. */
-   status = sal_get_pcidev_info((u64) pci_domain_nr(dev),
+   status = sal_get_pcidev_info((u64) pci_domain_nr(dev-bus),
(u64) dev-bus-number,
dev-devfn,
(u64) __pa(pcidev_info),
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH part3 v12 06/10] PCI: Make pci_host_bridge hold sysdata in drvdata

2015-07-20 Thread Yijing Wang
Now platform specific sysdata is saved in pci_bus,
and pcibios_root_bridge_prepare() need to know
the sysdata. Later, we would move pcibios_root_bridge_prepare()
prior to root bus creation, so we need to make
pci_host_bridge hold sysdata.

Signed-off-by: Yijing Wang wangyij...@huawei.com
---
 arch/ia64/pci/pci.c |2 +-
 arch/x86/pci/acpi.c |2 +-
 drivers/pci/probe.c |1 +
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 67ffe1f..8f79852 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -485,7 +485,7 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge 
*bridge)
 * that case.
 */
if (!bridge-dev.parent) {
-   struct pci_controller *controller = bridge-bus-sysdata;
+   struct pci_controller *controller = 
dev_get_drvdata(bridge-dev);
ACPI_COMPANION_SET(bridge-dev, controller-companion);
}
return 0;
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 629fc3b..38ce348 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -502,7 +502,7 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge 
*bridge)
 * that case.
 */
if (!bridge-dev.parent) {
-   struct pci_sysdata *sd = bridge-bus-sysdata;
+   struct pci_sysdata *sd = dev_get_drvdata(bridge-dev);
ACPI_COMPANION_SET(bridge-dev, sd-companion);
}
return 0;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 0eba126..0ae8bf2 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1967,6 +1967,7 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
bridge-domain = domain;
bridge-dev.parent = parent;
bridge-dev.release = pci_release_host_bridge_dev;
+   dev_set_drvdata(bridge-dev, sysdata);
dev_set_name(bridge-dev, pci%04x:%02x, pci_domain_nr(b), bus);
error = pcibios_root_bridge_prepare(bridge);
if (error) {
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH part3 v12 05/10] powerpc/PCI: Rename pcibios_root_bridge_prepare() to pcibios_root_bus_prepare()

2015-07-20 Thread Yijing Wang
Pcibios_root_bridge_prepare() in powerpc set root bus
speed, it's not the preparation for pci host bridge.
For better separation of host bridge and root bus creation,
It's need to rename it to another weak function.

Signed-off-by: Yijing Wang wangyij...@huawei.com
---
 arch/powerpc/include/asm/machdep.h   |2 +-
 arch/powerpc/kernel/pci-common.c |6 +++---
 arch/powerpc/platforms/pseries/pci.c |2 +-
 arch/powerpc/platforms/pseries/pseries.h |2 +-
 arch/powerpc/platforms/pseries/setup.c   |2 +-
 drivers/pci/probe.c  |9 +
 6 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/include/asm/machdep.h 
b/arch/powerpc/include/asm/machdep.h
index 952579f..dbd5e8b 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -100,7 +100,7 @@ struct machdep_calls {
/* Called after allocating resources */
void(*pcibios_fixup)(void);
void(*pci_irq_fixup)(struct pci_dev *dev);
-   int (*pcibios_root_bridge_prepare)(struct pci_host_bridge
+   int (*pcibios_root_bus_prepare)(struct pci_host_bridge
*bridge);
 
/* To setup PHBs when using automatic OF platform driver for PCI */
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index df7f018..3e398c8 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -782,10 +782,10 @@ int pci_proc_domain(struct pci_bus *bus)
return 1;
 }
 
-int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+int pcibios_root_bus_prepare(struct pci_host_bridge *bridge)
 {
-   if (ppc_md.pcibios_root_bridge_prepare)
-   return ppc_md.pcibios_root_bridge_prepare(bridge);
+   if (ppc_md.pcibios_root_bus_prepare)
+   return ppc_md.pcibios_root_bus_prepare(bridge);
 
return 0;
 }
diff --git a/arch/powerpc/platforms/pseries/pci.c 
b/arch/powerpc/platforms/pseries/pci.c
index fe16a50..885f9ff 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -110,7 +110,7 @@ static void fixup_winbond_82c105(struct pci_dev* dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105,
 fixup_winbond_82c105);
 
-int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
+int pseries_root_bus_prepare(struct pci_host_bridge *bridge)
 {
struct device_node *dn, *pdn;
struct pci_bus *bus;
diff --git a/arch/powerpc/platforms/pseries/pseries.h 
b/arch/powerpc/platforms/pseries/pseries.h
index 8411c27..41310dc 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -75,7 +75,7 @@ static inline int dlpar_memory(struct pseries_hp_errorlog 
*hp_elog)
 
 /* PCI root bridge prepare function override for pseries */
 struct pci_host_bridge;
-int pseries_root_bridge_prepare(struct pci_host_bridge *bridge);
+int pseries_root_bus_prepare(struct pci_host_bridge *bridge);
 
 extern struct pci_controller_ops pseries_pci_controller_ops;
 
diff --git a/arch/powerpc/platforms/pseries/setup.c 
b/arch/powerpc/platforms/pseries/setup.c
index df6a704..2815309 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -537,7 +537,7 @@ static void __init pSeries_setup_arch(void)
ppc_md.enable_pmcs = power4_enable_pmcs;
}
 
-   ppc_md.pcibios_root_bridge_prepare = pseries_root_bridge_prepare;
+   ppc_md.pcibios_root_bus_prepare = pseries_root_bus_prepare;
 
if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
long rc;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b49deb8..0eba126 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1919,6 +1919,11 @@ int __weak pcibios_root_bridge_prepare(struct 
pci_host_bridge *bridge)
return 0;
 }
 
+int __weak pcibios_root_bus_prepare(struct pci_host_bridge *bridge)
+{
+   return 0;
+}
+
 void __weak pcibios_add_bus(struct pci_bus *bus)
 {
 }
@@ -1984,6 +1989,10 @@ struct pci_bus *pci_create_root_bus(struct device 
*parent, int domain,
b-dev.class = pcibus_class;
b-dev.parent = b-bridge;
dev_set_name(b-dev, %04x:%02x, pci_domain_nr(b), bus);
+   error = pcibios_root_bus_prepare(bridge);
+   if (error)
+   goto class_dev_reg_err;
+
error = device_register(b-dev);
if (error)
goto class_dev_reg_err;
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH part3 v12 01/10] PCI: Save domain in pci_host_bridge

2015-07-20 Thread Yijing Wang
Save domain in pci_host_bridge, so we could get domain
from pci_host_bridge, and at the end of series, we could
clean up the arch specific pci_domain_nr(). For arm/arm64,
the domain argument is pointless, because they enable
CONFIG_PCI_DOMAINS_GENERIC, PCI core would assign domain
number for them, so introduce pci_create_root_bus_generic
and pci_scan_root_bus_generic() which simply assign domain
number to -1.

Tested-by: Gregory CLEMENT gregory.clem...@free-electrons.com #mvebu part
Signed-off-by: Yijing Wang wangyij...@huawei.com
---
 arch/alpha/kernel/pci.c|4 ++--
 arch/alpha/kernel/sys_nautilus.c   |2 +-
 arch/arm/kernel/bios32.c   |2 +-
 arch/arm/mach-dove/pcie.c  |2 +-
 arch/arm/mach-iop13xx/pci.c|4 ++--
 arch/arm/mach-mv78xx0/pcie.c   |2 +-
 arch/arm/mach-orion5x/pci.c|4 ++--
 arch/frv/mb93090-mb00/pci-vdk.c|3 ++-
 arch/ia64/pci/pci.c|4 ++--
 arch/ia64/sn/kernel/io_init.c  |4 ++--
 arch/m68k/coldfire/pci.c   |2 +-
 arch/microblaze/pci/pci-common.c   |4 ++--
 arch/mips/pci/pci.c|4 ++--
 arch/mn10300/unit-asb2305/pci.c|3 ++-
 arch/powerpc/kernel/pci-common.c   |4 ++--
 arch/s390/pci/pci.c|4 ++--
 arch/sh/drivers/pci/pci.c  |4 ++--
 arch/sparc/kernel/leon_pci.c   |2 +-
 arch/sparc/kernel/pci.c|4 ++--
 arch/sparc/kernel/pcic.c   |2 +-
 arch/tile/kernel/pci.c |4 ++--
 arch/tile/kernel/pci_gx.c  |4 ++--
 arch/unicore32/kernel/pci.c|2 +-
 arch/x86/pci/acpi.c|4 ++--
 arch/x86/pci/common.c  |2 +-
 arch/xtensa/kernel/pci.c   |2 +-
 drivers/parisc/dino.c  |2 +-
 drivers/parisc/lba_pci.c   |2 +-
 drivers/pci/host/pci-versatile.c   |3 ++-
 drivers/pci/host/pci-xgene.c   |2 +-
 drivers/pci/host/pcie-designware.c |2 +-
 drivers/pci/host/pcie-iproc.c  |2 +-
 drivers/pci/host/pcie-xilinx.c |2 +-
 drivers/pci/hotplug/ibmphp_core.c  |2 +-
 drivers/pci/probe.c|   21 +
 drivers/pci/xen-pcifront.c |2 +-
 include/linux/pci.h|   20 +---
 37 files changed, 82 insertions(+), 60 deletions(-)

diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 82f738e..2b0bce9 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -336,8 +336,8 @@ common_init_pci(void)
pci_add_resource_offset(resources, hose-mem_space,
hose-mem_space-start);
 
-   bus = pci_scan_root_bus(NULL, next_busno, alpha_mv.pci_ops,
-   hose, resources);
+   bus = pci_scan_root_bus(NULL, hose-index, next_busno,
+   alpha_mv.pci_ops, hose, resources);
if (!bus)
continue;
hose-bus = bus;
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 2cfaa0e..5d4f56f 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -205,7 +205,7 @@ nautilus_init_pci(void)
unsigned long memtop = max_low_pfn  PAGE_SHIFT;
 
/* Scan our single hose.  */
-   bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
+   bus = pci_scan_bus(hose-index, 0, alpha_mv.pci_ops, hose);
if (!bus)
return;
 
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index fc1..c7919c5 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -486,7 +486,7 @@ static void pcibios_init_hw(struct device *parent, struct 
hw_pci *hw,
if (hw-scan)
sys-bus = hw-scan(nr, sys);
else
-   sys-bus = pci_scan_root_bus(parent, sys-busnr,
+   sys-bus = pci_scan_root_bus_generic(parent, 
sys-busnr,
hw-ops, sys, sys-resources);
 
if (!sys-bus)
diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c
index 91fe971..2bbdd3f 100644
--- a/arch/arm/mach-dove/pcie.c
+++ b/arch/arm/mach-dove/pcie.c
@@ -160,7 +160,7 @@ dove_pcie_scan_bus(int nr, struct pci_sys_data *sys)
return NULL;
}
 
-   return pci_scan_root_bus(NULL, sys-busnr, pcie_ops, sys,
+   return pci_scan_root_bus_generic(NULL, sys-busnr, pcie_ops, sys,
 sys-resources);
 }
 
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 9082b84..0b60464 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -535,12 +535,12 @@ struct pci_bus *iop13xx_scan_bus(int nr, struct 
pci_sys_data *sys)
while(time_before(jiffies

[PATCH part3 v12 03/10] PCI: Remove declaration for pci_get_new_domain_nr()

2015-07-20 Thread Yijing Wang
pci_get_new_domain_nr() is only used in drivers/pci/pci.c,
remove the declaration in include/linux/pci.h.

Signed-off-by: Yijing Wang wangyij...@huawei.com
---
 drivers/pci/pci.c   |4 ++--
 include/linux/pci.h |3 ---
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0008c95..59032e2 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4476,14 +4476,14 @@ static void pci_no_domains(void)
 }
 
 #ifdef CONFIG_PCI_DOMAINS
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
 static atomic_t __domain_nr = ATOMIC_INIT(-1);
 
-int pci_get_new_domain_nr(void)
+static int pci_get_new_domain_nr(void)
 {
return atomic_inc_return(__domain_nr);
 }
 
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
 void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
 {
static int use_dt_domains = -1;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index f7e4204..4524592 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1319,12 +1319,10 @@ void pci_cfg_access_unlock(struct pci_dev *dev);
  */
 #ifdef CONFIG_PCI_DOMAINS
 extern int pci_domains_supported;
-int pci_get_new_domain_nr(void);
 #else
 enum { pci_domains_supported = 0 };
 static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
 static inline int pci_proc_domain(struct pci_bus *bus) { return 0; }
-static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
 #endif /* CONFIG_PCI_DOMAINS */
 
 /*
@@ -1445,7 +1443,6 @@ static inline struct pci_dev 
*pci_get_bus_and_slot(unsigned int bus,
 
 static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
 static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; }
-static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
 
 #define dev_is_pci(d) (false)
 #define dev_is_pf(d) (false)
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 17/36] PCI: Add support for more than two alt_size under same bridge

2015-07-14 Thread Yijing Wang
On 2015/7/15 13:08, Yinghai Lu wrote:
> On Tue, Jul 14, 2015 at 8:07 PM, Yijing Wang  wrote:
>> On 2015/7/7 7:39, Yinghai Lu wrote:
>>> Need to increase size to make sure it could fit all alt entries.
>>>
>>> So at last, we use 8M/17M as parent bridge alt_align/alt_size.
>>
>> Tested-by: Yijing Wang 
> 
> Thanks for testing.
> 
>>
>> Hi Yinghai, does this patch depend on the previous items in this patchset ?
> 
> Yes, it depends most of patches from patch1 to this patch.
> 
>> Could you provide another version of this patch for stable branch, eg. 3.10 
>> stable ?
> 
> That is RHEL 7 kernel, right ?

Yes.

> 
> After those patches get into upstream, I will try to port them to 3.10 stable.

Thanks very much!

> 
> Thanks
> 
> Yinghai
> 
> .
> 


-- 
Thanks!
Yijing

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


Re: [PATCH 17/36] PCI: Add support for more than two alt_size under same bridge

2015-07-14 Thread Yijing Wang
On 2015/7/7 7:39, Yinghai Lu wrote:
> Need to increase size to make sure it could fit all alt entries.
> 
> In the patch, we first select one big size, and then keep reducing
> the size and retrying to get the minimum value for alt_size.
> 
> Example:
> two bridges: one have 8M/8M, and 1M/1M children res.
>one have 4M/4M, and 1M/1M children res.
> 
> Then we have child pridges alt_align/alt_size: 8M/9M, 4M/5M.
> Before this patch, parent bridge alt_align/alt_size is 8M/14M
> that is wrong.
> With this patch   parent bridge alt_align/alt_size: 8M/17M.
> 
> At same time, child bridges must align/size: 4M/12M, 2M/6M.
> and prarent bridge must align/size: 4M/20M.
> 
> So at last, we use 8M/17M as parent bridge alt_align/alt_size.

Tested-by: Yijing Wang 

Hi Yinghai, does this patch depend on the previous items in this patchset ?
Could you provide another version of this patch for stable branch, eg. 3.10 
stable ?

Thanks!
Yijing.

> 
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=100451
> Reported-by: Yijing Wang 
> Signed-off-by: Yinghai Lu 
> ---
>  drivers/pci/setup-bus.c | 53 
> +
>  1 file changed, 53 insertions(+)
> 
> diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> index c0090d4..9427baa 100644
> --- a/drivers/pci/setup-bus.c
> +++ b/drivers/pci/setup-bus.c
> @@ -1304,6 +1304,47 @@ out:
>   return good_align;
>  }
>  
> +static resource_size_t calculate_mem_alt_size(struct list_head *head,
> + resource_size_t max_align, resource_size_t size,
> + resource_size_t align_low)
> +{
> + struct align_test_res *p;
> + resource_size_t tmp;
> + resource_size_t good_size, bad_size;
> + int count = 0, order;
> +
> + good_size = ALIGN(size, align_low);
> +
> + list_for_each_entry(p, head, list)
> + count++;
> +
> + if (count <= 1)
> + goto out;
> +
> + __sort_align_test(head);
> +
> + tmp = max(size, max_align);
> + order = __fls(count);
> + if ((1ULL << order) < count)
> + order++;
> + good_size = ALIGN((tmp << order), align_low);
> + bad_size = ALIGN(size, align_low) - align_low;
> + size = good_size;
> + while (size > bad_size) {
> + /* check if align/size fit all entries */
> + if (is_align_size_good(head, max_align, size, 0))
> + good_size = size;
> + else
> + bad_size = size;
> +
> + size = bad_size + ((good_size - bad_size) >> 1);
> + size = round_down(size, align_low);
> + }
> +
> +out:
> + return good_size;
> +}
> +
>  static inline bool is_optional(int i)
>  {
>  
> @@ -1350,6 +1391,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned 
> long mask,
>   mask | IORESOURCE_PREFETCH, type);
>   LIST_HEAD(align_test_list);
>   LIST_HEAD(align_test_add_list);
> + LIST_HEAD(align_test_alt_list);
>   resource_size_t alt_size = 0, alt_align = 0;
>   resource_size_t window_align;
>  
> @@ -1418,6 +1460,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned 
> long mask,
>  
>   dev_res = res_to_dev_res(realloc_head, r);
>   if (dev_res && dev_res->alt_size) {
> + add_to_align_test_list(
> + _test_alt_list,
> + dev_res->alt_align,
> + dev_res->alt_size);
>   alt_size += dev_res->alt_size;
>   if (alt_align < dev_res->alt_align)
>   alt_align = dev_res->alt_align;
> @@ -1440,6 +1486,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned 
> long mask,
>   alt_align = max_align;
>   alt_size = calculate_memsize(size, min_size,
>0, window_align);
> + } else  {
> + /* need to increase size to fit more alt */
> + alt_align = max(alt_align, window_align);
> + alt_size = calculate_mem_alt_size(_test_alt_list,
> +   alt_align, alt_size,
> +   window_align);
>   }
>   /* must is better ? */
>  

Re: [PATCH 17/36] PCI: Add support for more than two alt_size under same bridge

2015-07-14 Thread Yijing Wang
On 2015/7/7 7:39, Yinghai Lu wrote:
 Need to increase size to make sure it could fit all alt entries.
 
 In the patch, we first select one big size, and then keep reducing
 the size and retrying to get the minimum value for alt_size.
 
 Example:
 two bridges: one have 8M/8M, and 1M/1M children res.
one have 4M/4M, and 1M/1M children res.
 
 Then we have child pridges alt_align/alt_size: 8M/9M, 4M/5M.
 Before this patch, parent bridge alt_align/alt_size is 8M/14M
 that is wrong.
 With this patch   parent bridge alt_align/alt_size: 8M/17M.
 
 At same time, child bridges must align/size: 4M/12M, 2M/6M.
 and prarent bridge must align/size: 4M/20M.
 
 So at last, we use 8M/17M as parent bridge alt_align/alt_size.

Tested-by: Yijing Wang wangyij...@huawei.com

Hi Yinghai, does this patch depend on the previous items in this patchset ?
Could you provide another version of this patch for stable branch, eg. 3.10 
stable ?

Thanks!
Yijing.

 
 Link: https://bugzilla.kernel.org/show_bug.cgi?id=100451
 Reported-by: Yijing Wang wangyij...@huawei.com
 Signed-off-by: Yinghai Lu ying...@kernel.org
 ---
  drivers/pci/setup-bus.c | 53 
 +
  1 file changed, 53 insertions(+)
 
 diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
 index c0090d4..9427baa 100644
 --- a/drivers/pci/setup-bus.c
 +++ b/drivers/pci/setup-bus.c
 @@ -1304,6 +1304,47 @@ out:
   return good_align;
  }
  
 +static resource_size_t calculate_mem_alt_size(struct list_head *head,
 + resource_size_t max_align, resource_size_t size,
 + resource_size_t align_low)
 +{
 + struct align_test_res *p;
 + resource_size_t tmp;
 + resource_size_t good_size, bad_size;
 + int count = 0, order;
 +
 + good_size = ALIGN(size, align_low);
 +
 + list_for_each_entry(p, head, list)
 + count++;
 +
 + if (count = 1)
 + goto out;
 +
 + __sort_align_test(head);
 +
 + tmp = max(size, max_align);
 + order = __fls(count);
 + if ((1ULL  order)  count)
 + order++;
 + good_size = ALIGN((tmp  order), align_low);
 + bad_size = ALIGN(size, align_low) - align_low;
 + size = good_size;
 + while (size  bad_size) {
 + /* check if align/size fit all entries */
 + if (is_align_size_good(head, max_align, size, 0))
 + good_size = size;
 + else
 + bad_size = size;
 +
 + size = bad_size + ((good_size - bad_size)  1);
 + size = round_down(size, align_low);
 + }
 +
 +out:
 + return good_size;
 +}
 +
  static inline bool is_optional(int i)
  {
  
 @@ -1350,6 +1391,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned 
 long mask,
   mask | IORESOURCE_PREFETCH, type);
   LIST_HEAD(align_test_list);
   LIST_HEAD(align_test_add_list);
 + LIST_HEAD(align_test_alt_list);
   resource_size_t alt_size = 0, alt_align = 0;
   resource_size_t window_align;
  
 @@ -1418,6 +1460,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned 
 long mask,
  
   dev_res = res_to_dev_res(realloc_head, r);
   if (dev_res  dev_res-alt_size) {
 + add_to_align_test_list(
 + align_test_alt_list,
 + dev_res-alt_align,
 + dev_res-alt_size);
   alt_size += dev_res-alt_size;
   if (alt_align  dev_res-alt_align)
   alt_align = dev_res-alt_align;
 @@ -1440,6 +1486,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned 
 long mask,
   alt_align = max_align;
   alt_size = calculate_memsize(size, min_size,
0, window_align);
 + } else  {
 + /* need to increase size to fit more alt */
 + alt_align = max(alt_align, window_align);
 + alt_size = calculate_mem_alt_size(align_test_alt_list,
 +   alt_align, alt_size,
 +   window_align);
   }
   /* must is better ? */
   if (alt_size = size0) {
 @@ -1447,6 +1499,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned 
 long mask,
   alt_size = size0;
   }
   }
 + free_align_test_list(align_test_alt_list);
  
   if (sum_add_size == size)
   sum_add_size = add_size;
 


-- 
Thanks!
Yijing

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord

Re: [PATCH 17/36] PCI: Add support for more than two alt_size under same bridge

2015-07-14 Thread Yijing Wang
On 2015/7/15 13:08, Yinghai Lu wrote:
 On Tue, Jul 14, 2015 at 8:07 PM, Yijing Wang wangyij...@huawei.com wrote:
 On 2015/7/7 7:39, Yinghai Lu wrote:
 Need to increase size to make sure it could fit all alt entries.

 So at last, we use 8M/17M as parent bridge alt_align/alt_size.

 Tested-by: Yijing Wang wangyij...@huawei.com
 
 Thanks for testing.
 

 Hi Yinghai, does this patch depend on the previous items in this patchset ?
 
 Yes, it depends most of patches from patch1 to this patch.
 
 Could you provide another version of this patch for stable branch, eg. 3.10 
 stable ?
 
 That is RHEL 7 kernel, right ?

Yes.

 
 After those patches get into upstream, I will try to port them to 3.10 stable.

Thanks very much!

 
 Thanks
 
 Yinghai
 
 .
 


-- 
Thanks!
Yijing

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC Patch V1 00/12] Reorganize struct msi_desc to prepare for support of generic MSI

2015-07-09 Thread Yijing Wang
On 2015/7/9 16:00, Jiang Liu wrote:
> Recently Marc Zyngier  has posted a patch set at
> https://lkml.org/lkml/2015/7/7/712
> to enhance PCI MSI code to support generic MSI.
> 
> This is a companion patch set to refine struct msi_desc and related data
> structures to support generic MSI, and it would be better to combined with
> Marc's patch set.  It's also requested by
> Stuart Yoder 
> 
> It first introduces a helper function msi_desc_to_pci_sysdata(), and
> convert current PCI drivers to use helper functions to access fields
> in struct msi_desc.
> Then it moves msi_list from struct pci_dev into struct device and
> refines struct msi_desc.
> At last it moves alloc_msi_entry() into kernel/irq/msi.c for reuse.
> 
> Currently msi_desc_to_pci_sysdata() and msi_desc_to_pci_dev() are
> implemented as normal functions instead of inlines to avoid header file
> inclusion issue. If inlined version is preferred for performance, we could
> move all of first_pci_msi_entry, for_each_pci_msi_entry, msi_desc_to_pci_dev
> and msi_desc_to_pci_sysdata from linxu/kernel/msi.h into linux/kernel/pci.h.
> 
> This patch set is based on v4.2-rc1 and passes 0day test suite. You
> may access the code at:
> https://github.com/jiangliu/linux.git msi_desc_v1
> 
> Thanks!
> Gerry
> 
> Jiang Liu (12):
>   PCI: Add helper function msi_desc_to_pci_sysdata()
>   MIPS, PCI: Use for_pci_msi_entry() to access MSI device list
>   PowerPC, PCI: Use for_pci_msi_entry() to access MSI device list
>   s390/pci: Use for_pci_msi_entry() to access MSI device list
>   x86, PCI: Use for_pci_msi_entry() to access MSI device list
>   PCI: Use for_pci_msi_entry() to access MSI device list
>   sparc, PCI: Use helper functions to access fields in struct msi_desc
>   PCI: Use helper functions to access fields in struct msi_desc
>   genirq: Move msi_list from struct pci_dev to struct device
>   genirq, PCI: Store 'struct device *' instead 'struct pci_dev *' in
> struct msi_desc
>   genirq, PCI: Reorginize struct msi_desc to prepare for support of
> generic MSI
>   genirq, PCI: Move alloc_msi_entry() from PCI MSI code into generic
> MSI code

Great, it loos good to me, for patch 1,6,8,9,10,11,12, Reviewed-by: Yijing Wang 


> 
>  arch/mips/pci/msi-octeon.c |2 +-
>  arch/powerpc/platforms/cell/axon_msi.c |6 +--
>  arch/powerpc/platforms/pasemi/msi.c|4 +-
>  arch/powerpc/platforms/powernv/pci.c   |4 +-
>  arch/powerpc/platforms/pseries/msi.c   |6 +--
>  arch/powerpc/sysdev/fsl_msi.c  |4 +-
>  arch/powerpc/sysdev/mpic_u3msi.c   |4 +-
>  arch/powerpc/sysdev/ppc4xx_hsta_msi.c  |4 +-
>  arch/powerpc/sysdev/ppc4xx_msi.c   |4 +-
>  arch/s390/pci/pci.c|6 +--
>  arch/sparc/kernel/pci.c|2 +-
>  arch/x86/pci/xen.c |8 ++--
>  drivers/base/core.c|3 ++
>  drivers/pci/host/pci-keystone-dw.c |6 +--
>  drivers/pci/host/pcie-designware.c |4 +-
>  drivers/pci/host/pcie-xilinx.c |   12 ++---
>  drivers/pci/msi.c  |   82 
> +---
>  drivers/pci/xen-pcifront.c |2 +-
>  include/linux/device.h |4 ++
>  include/linux/msi.h|   55 +++--
>  include/linux/pci.h|1 -
>  kernel/irq/msi.c   |   17 +++
>  22 files changed, 136 insertions(+), 104 deletions(-)
> 


-- 
Thanks!
Yijing

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


Re: [RFC Patch V1 00/12] Reorganize struct msi_desc to prepare for support of generic MSI

2015-07-09 Thread Yijing Wang
On 2015/7/9 16:00, Jiang Liu wrote:
 Recently Marc Zyngier marc.zyng...@arm.com has posted a patch set at
 https://lkml.org/lkml/2015/7/7/712
 to enhance PCI MSI code to support generic MSI.
 
 This is a companion patch set to refine struct msi_desc and related data
 structures to support generic MSI, and it would be better to combined with
 Marc's patch set.  It's also requested by
 Stuart Yoder stuart.yo...@freescale.com
 
 It first introduces a helper function msi_desc_to_pci_sysdata(), and
 convert current PCI drivers to use helper functions to access fields
 in struct msi_desc.
 Then it moves msi_list from struct pci_dev into struct device and
 refines struct msi_desc.
 At last it moves alloc_msi_entry() into kernel/irq/msi.c for reuse.
 
 Currently msi_desc_to_pci_sysdata() and msi_desc_to_pci_dev() are
 implemented as normal functions instead of inlines to avoid header file
 inclusion issue. If inlined version is preferred for performance, we could
 move all of first_pci_msi_entry, for_each_pci_msi_entry, msi_desc_to_pci_dev
 and msi_desc_to_pci_sysdata from linxu/kernel/msi.h into linux/kernel/pci.h.
 
 This patch set is based on v4.2-rc1 and passes 0day test suite. You
 may access the code at:
 https://github.com/jiangliu/linux.git msi_desc_v1
 
 Thanks!
 Gerry
 
 Jiang Liu (12):
   PCI: Add helper function msi_desc_to_pci_sysdata()
   MIPS, PCI: Use for_pci_msi_entry() to access MSI device list
   PowerPC, PCI: Use for_pci_msi_entry() to access MSI device list
   s390/pci: Use for_pci_msi_entry() to access MSI device list
   x86, PCI: Use for_pci_msi_entry() to access MSI device list
   PCI: Use for_pci_msi_entry() to access MSI device list
   sparc, PCI: Use helper functions to access fields in struct msi_desc
   PCI: Use helper functions to access fields in struct msi_desc
   genirq: Move msi_list from struct pci_dev to struct device
   genirq, PCI: Store 'struct device *' instead 'struct pci_dev *' in
 struct msi_desc
   genirq, PCI: Reorginize struct msi_desc to prepare for support of
 generic MSI
   genirq, PCI: Move alloc_msi_entry() from PCI MSI code into generic
 MSI code

Great, it loos good to me, for patch 1,6,8,9,10,11,12, Reviewed-by: Yijing Wang 
wangyij...@huawei.com

 
  arch/mips/pci/msi-octeon.c |2 +-
  arch/powerpc/platforms/cell/axon_msi.c |6 +--
  arch/powerpc/platforms/pasemi/msi.c|4 +-
  arch/powerpc/platforms/powernv/pci.c   |4 +-
  arch/powerpc/platforms/pseries/msi.c   |6 +--
  arch/powerpc/sysdev/fsl_msi.c  |4 +-
  arch/powerpc/sysdev/mpic_u3msi.c   |4 +-
  arch/powerpc/sysdev/ppc4xx_hsta_msi.c  |4 +-
  arch/powerpc/sysdev/ppc4xx_msi.c   |4 +-
  arch/s390/pci/pci.c|6 +--
  arch/sparc/kernel/pci.c|2 +-
  arch/x86/pci/xen.c |8 ++--
  drivers/base/core.c|3 ++
  drivers/pci/host/pci-keystone-dw.c |6 +--
  drivers/pci/host/pcie-designware.c |4 +-
  drivers/pci/host/pcie-xilinx.c |   12 ++---
  drivers/pci/msi.c  |   82 
 +---
  drivers/pci/xen-pcifront.c |2 +-
  include/linux/device.h |4 ++
  include/linux/msi.h|   55 +++--
  include/linux/pci.h|1 -
  kernel/irq/msi.c   |   17 +++
  22 files changed, 136 insertions(+), 104 deletions(-)
 


-- 
Thanks!
Yijing

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: e1000e pci_disable_link_state_locked() issues

2015-05-22 Thread Yijing Wang
On 2015/5/21 3:47, Bjorn Helgaas wrote:
> I think we have some issues with the e1000e usage of
> pci_disable_link_state_locked(), which Yinghai added with 9f728f53dd70
> ("PCI/e1000e: Add and use pci_disable_link_state_locked()").
> 
> That fixed an AER deadlock in the following path, where pci_bus_sem is held
> by pci_walk_bus(), and we deadlocked when we tried to re-acquire it in
> pci_disable_link_state():
> 
>   do_recovery
> broadcast_error_message(..., report_slot_reset)
>   pci_walk_bus
> down_read(_bus_sem)
>   cb(...)   # report_slot_reset
> report_slot_reset
>   dev->driver->err_handler->slot_reset  # e1000_io_slot_reset
> e1000_io_slot_reset
>   e1000e_disable_aspm
> pci_disable_link_state
>   down_read(_bus_sem)
> 
> 9f728f53dd70 fixed that by changing e1000e_disable_aspm() to use
> pci_disable_link_state_locked() instead, which assumes pci_bus_sem is
> already held.
> 
> That's fine for the e1000_io_slot_reset() path, where pci_bus_sem really
> *is* held.  But e1000e_disable_aspm() is also called from e1000_probe() and
> __e1000_resume(), and in those paths, we *don't* hold pci_bus_sem.
> 
> In effect, the caller of pci_disable_link_state_locked() is promising that
> pci_bus_sem is held, and __pci_disable_link_state() relies on that promise
> for its locking.  But e1000e isn't upholding its end of the bargain.
> 
> I'm not 100% sure __pci_disable_link_state() actually *needs* that locking:
> it is only called from a driver, and it should be impossible for a device
> or any upstream bridge to go away while a driver is bound to it.  If

Another question, when pci_disable_link_state() is called in driver,  the 
device and
its upstream bridge do not go away while a driver is bound to it, but what 
about a new
function device adding to the upstream bridge secondary bus. In this case, 
traverse
the pci_bus->devices list may be not safe.


> somebody wanted to analyze this further and propose a patch to remove the
> locking (if it seems safe), that would be great.
> 
> But in any case, __pci_disable_link_state() should be able to rely on its
> callers following the rules, so I'd like to see an e1000e change to use
> pci_disable_link_state() from the paths where pci_bus_sem is not held.
> 
> Bjorn
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 


-- 
Thanks!
Yijing

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


Re: e1000e pci_disable_link_state_locked() issues

2015-05-22 Thread Yijing Wang
On 2015/5/21 3:47, Bjorn Helgaas wrote:
> I think we have some issues with the e1000e usage of
> pci_disable_link_state_locked(), which Yinghai added with 9f728f53dd70
> ("PCI/e1000e: Add and use pci_disable_link_state_locked()").
> 
> That fixed an AER deadlock in the following path, where pci_bus_sem is held
> by pci_walk_bus(), and we deadlocked when we tried to re-acquire it in
> pci_disable_link_state():
> 
>   do_recovery
> broadcast_error_message(..., report_slot_reset)
>   pci_walk_bus
> down_read(_bus_sem)
>   cb(...)   # report_slot_reset
> report_slot_reset
>   dev->driver->err_handler->slot_reset  # e1000_io_slot_reset
> e1000_io_slot_reset
>   e1000e_disable_aspm
> pci_disable_link_state
>   down_read(_bus_sem)
> 
> 9f728f53dd70 fixed that by changing e1000e_disable_aspm() to use
> pci_disable_link_state_locked() instead, which assumes pci_bus_sem is
> already held.
> 
> That's fine for the e1000_io_slot_reset() path, where pci_bus_sem really
> *is* held.  But e1000e_disable_aspm() is also called from e1000_probe() and
> __e1000_resume(), and in those paths, we *don't* hold pci_bus_sem.
> 
> In effect, the caller of pci_disable_link_state_locked() is promising that
> pci_bus_sem is held, and __pci_disable_link_state() relies on that promise
> for its locking.  But e1000e isn't upholding its end of the bargain.
> 
> I'm not 100% sure __pci_disable_link_state() actually *needs* that locking:
> it is only called from a driver, and it should be impossible for a device

pci_disable_link_state()/pci_disable_link_state_locked() almost always be 
called in drivers,
one exception is a quirk function quirk_disable_aspm_l0s(). Since the final 
fixup is called
in pci_bus_add_device(), and we have big lock pci_rescan_remove_lock to protect 
the add/remove,
so I think it's still safe to call pci_disable_link_state() in 
quirk_disable_aspm_l0s() without
the pci_bus_sem lock.

/*
 * The 82575 and 82598 may experience data corruption issues when transitioning
 * out of L0S.  To prevent this we need to disable L0S on the pci-e link
 */
static void quirk_disable_aspm_l0s(struct pci_dev *dev)
{
dev_info(>dev, "Disabling L0s\n");
pci_disable_link_state(dev, PCIE_LINK_STATE_L0S);
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10a7, quirk_disable_aspm_l0s);
...


> or any upstream bridge to go away while a driver is bound to it.  If
> somebody wanted to analyze this further and propose a patch to remove the
> locking (if it seems safe), that would be great.
> 
> But in any case, __pci_disable_link_state() should be able to rely on its
> callers following the rules, so I'd like to see an e1000e change to use
> pci_disable_link_state() from the paths where pci_bus_sem is not held.
> 
> Bjorn
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 


-- 
Thanks!
Yijing

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


  1   2   3   4   5   6   7   8   9   10   >