summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/sas_ata.c1
-rw-r--r--drivers/scsi/libsas/sas_discover.c34
-rw-r--r--drivers/scsi/libsas/sas_event.c86
-rw-r--r--drivers/scsi/libsas/sas_expander.c12
-rw-r--r--drivers/scsi/libsas/sas_init.c107
-rw-r--r--drivers/scsi/libsas/sas_internal.h7
-rw-r--r--drivers/scsi/libsas/sas_phy.c69
-rw-r--r--drivers/scsi/libsas/sas_port.c25
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c20
9 files changed, 255 insertions, 106 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 70be4425ae0b..2b3637b40dde 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -730,7 +730,6 @@ int sas_discover_sata(struct domain_device *dev)
730 if (res) 730 if (res)
731 return res; 731 return res;
732 732
733 sas_discover_event(dev->port, DISCE_PROBE);
734 return 0; 733 return 0;
735} 734}
736 735
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 60de66252fa2..e4fd078e4175 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -212,13 +212,9 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
212 } 212 }
213} 213}
214 214
215static void sas_probe_devices(struct work_struct *work) 215static void sas_probe_devices(struct asd_sas_port *port)
216{ 216{
217 struct domain_device *dev, *n; 217 struct domain_device *dev, *n;
218 struct sas_discovery_event *ev = to_sas_discovery_event(work);
219 struct asd_sas_port *port = ev->port;
220
221 clear_bit(DISCE_PROBE, &port->disc.pending);
222 218
223 /* devices must be domain members before link recovery and probe */ 219 /* devices must be domain members before link recovery and probe */
224 list_for_each_entry(dev, &port->disco_list, disco_list_node) { 220 list_for_each_entry(dev, &port->disco_list, disco_list_node) {
@@ -294,7 +290,6 @@ int sas_discover_end_dev(struct domain_device *dev)
294 res = sas_notify_lldd_dev_found(dev); 290 res = sas_notify_lldd_dev_found(dev);
295 if (res) 291 if (res)
296 return res; 292 return res;
297 sas_discover_event(dev->port, DISCE_PROBE);
298 293
299 return 0; 294 return 0;
300} 295}
@@ -353,13 +348,9 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d
353 sas_put_device(dev); 348 sas_put_device(dev);
354} 349}
355 350
356static void sas_destruct_devices(struct work_struct *work) 351void sas_destruct_devices(struct asd_sas_port *port)
357{ 352{
358 struct domain_device *dev, *n; 353 struct domain_device *dev, *n;
359 struct sas_discovery_event *ev = to_sas_discovery_event(work);
360 struct asd_sas_port *port = ev->port;
361
362 clear_bit(DISCE_DESTRUCT, &port->disc.pending);
363 354
364 list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) { 355 list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) {
365 list_del_init(&dev->disco_list_node); 356 list_del_init(&dev->disco_list_node);
@@ -370,6 +361,16 @@ static void sas_destruct_devices(struct work_struct *work)
370 } 361 }
371} 362}
372 363
364static void sas_destruct_ports(struct asd_sas_port *port)
365{
366 struct sas_port *sas_port, *p;
367
368 list_for_each_entry_safe(sas_port, p, &port->sas_port_del_list, del_list) {
369 list_del_init(&sas_port->del_list);
370 sas_port_delete(sas_port);
371 }
372}
373
373void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) 374void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
374{ 375{
375 if (!test_bit(SAS_DEV_DESTROY, &dev->state) && 376 if (!test_bit(SAS_DEV_DESTROY, &dev->state) &&
@@ -384,7 +385,6 @@ void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
384 if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { 385 if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {
385 sas_rphy_unlink(dev->rphy); 386 sas_rphy_unlink(dev->rphy);
386 list_move_tail(&dev->disco_list_node, &port->destroy_list); 387 list_move_tail(&dev->disco_list_node, &port->destroy_list);
387 sas_discover_event(dev->port, DISCE_DESTRUCT);
388 } 388 }
389} 389}
390 390
@@ -490,6 +490,8 @@ static void sas_discover_domain(struct work_struct *work)
490 port->port_dev = NULL; 490 port->port_dev = NULL;
491 } 491 }
492 492
493 sas_probe_devices(port);
494
493 SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id, 495 SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
494 task_pid_nr(current), error); 496 task_pid_nr(current), error);
495} 497}
@@ -523,6 +525,10 @@ static void sas_revalidate_domain(struct work_struct *work)
523 port->id, task_pid_nr(current), res); 525 port->id, task_pid_nr(current), res);
524 out: 526 out:
525 mutex_unlock(&ha->disco_mutex); 527 mutex_unlock(&ha->disco_mutex);
528
529 sas_destruct_devices(port);
530 sas_destruct_ports(port);
531 sas_probe_devices(port);
526} 532}
527 533
528/* ---------- Events ---------- */ 534/* ---------- Events ---------- */
@@ -534,7 +540,7 @@ static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw)
534 * workqueue, or known to be submitted from a context that is 540 * workqueue, or known to be submitted from a context that is
535 * not racing against draining 541 * not racing against draining
536 */ 542 */
537 scsi_queue_work(ha->core.shost, &sw->work); 543 queue_work(ha->disco_q, &sw->work);
538} 544}
539 545
540static void sas_chain_event(int event, unsigned long *pending, 546static void sas_chain_event(int event, unsigned long *pending,
@@ -578,10 +584,8 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
578 static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { 584 static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
579 [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, 585 [DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
580 [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, 586 [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
581 [DISCE_PROBE] = sas_probe_devices,
582 [DISCE_SUSPEND] = sas_suspend_devices, 587 [DISCE_SUSPEND] = sas_suspend_devices,
583 [DISCE_RESUME] = sas_resume_devices, 588 [DISCE_RESUME] = sas_resume_devices,
584 [DISCE_DESTRUCT] = sas_destruct_devices,
585 }; 589 };
586 590
587 disc->pending = 0; 591 disc->pending = 0;
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index 0bb9eefc08c8..ae923eb6de95 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -29,7 +29,8 @@
29 29
30int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) 30int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
31{ 31{
32 int rc = 0; 32 /* it's added to the defer_q when draining so return succeed */
33 int rc = 1;
33 34
34 if (!test_bit(SAS_HA_REGISTERED, &ha->state)) 35 if (!test_bit(SAS_HA_REGISTERED, &ha->state))
35 return 0; 36 return 0;
@@ -39,24 +40,20 @@ int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw)
39 if (list_empty(&sw->drain_node)) 40 if (list_empty(&sw->drain_node))
40 list_add_tail(&sw->drain_node, &ha->defer_q); 41 list_add_tail(&sw->drain_node, &ha->defer_q);
41 } else 42 } else
42 rc = scsi_queue_work(ha->core.shost, &sw->work); 43 rc = queue_work(ha->event_q, &sw->work);
43 44
44 return rc; 45 return rc;
45} 46}
46 47
47static int sas_queue_event(int event, unsigned long *pending, 48static int sas_queue_event(int event, struct sas_work *work,
48 struct sas_work *work,
49 struct sas_ha_struct *ha) 49 struct sas_ha_struct *ha)
50{ 50{
51 int rc = 0; 51 unsigned long flags;
52 int rc;
52 53
53 if (!test_and_set_bit(event, pending)) { 54 spin_lock_irqsave(&ha->lock, flags);
54 unsigned long flags; 55 rc = sas_queue_work(ha, work);
55 56 spin_unlock_irqrestore(&ha->lock, flags);
56 spin_lock_irqsave(&ha->lock, flags);
57 rc = sas_queue_work(ha, work);
58 spin_unlock_irqrestore(&ha->lock, flags);
59 }
60 57
61 return rc; 58 return rc;
62} 59}
@@ -64,21 +61,25 @@ static int sas_queue_event(int event, unsigned long *pending,
64 61
65void __sas_drain_work(struct sas_ha_struct *ha) 62void __sas_drain_work(struct sas_ha_struct *ha)
66{ 63{
67 struct workqueue_struct *wq = ha->core.shost->work_q;
68 struct sas_work *sw, *_sw; 64 struct sas_work *sw, *_sw;
65 int ret;
69 66
70 set_bit(SAS_HA_DRAINING, &ha->state); 67 set_bit(SAS_HA_DRAINING, &ha->state);
71 /* flush submitters */ 68 /* flush submitters */
72 spin_lock_irq(&ha->lock); 69 spin_lock_irq(&ha->lock);
73 spin_unlock_irq(&ha->lock); 70 spin_unlock_irq(&ha->lock);
74 71
75 drain_workqueue(wq); 72 drain_workqueue(ha->event_q);
73 drain_workqueue(ha->disco_q);
76 74
77 spin_lock_irq(&ha->lock); 75 spin_lock_irq(&ha->lock);
78 clear_bit(SAS_HA_DRAINING, &ha->state); 76 clear_bit(SAS_HA_DRAINING, &ha->state);
79 list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { 77 list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) {
80 list_del_init(&sw->drain_node); 78 list_del_init(&sw->drain_node);
81 sas_queue_work(ha, sw); 79 ret = sas_queue_work(ha, sw);
80 if (ret != 1)
81 sas_free_event(to_asd_sas_event(&sw->work));
82
82 } 83 }
83 spin_unlock_irq(&ha->lock); 84 spin_unlock_irq(&ha->lock);
84} 85}
@@ -115,33 +116,78 @@ void sas_enable_revalidation(struct sas_ha_struct *ha)
115 struct asd_sas_port *port = ha->sas_port[i]; 116 struct asd_sas_port *port = ha->sas_port[i];
116 const int ev = DISCE_REVALIDATE_DOMAIN; 117 const int ev = DISCE_REVALIDATE_DOMAIN;
117 struct sas_discovery *d = &port->disc; 118 struct sas_discovery *d = &port->disc;
119 struct asd_sas_phy *sas_phy;
118 120
119 if (!test_and_clear_bit(ev, &d->pending)) 121 if (!test_and_clear_bit(ev, &d->pending))
120 continue; 122 continue;
121 123
122 sas_queue_event(ev, &d->pending, &d->disc_work[ev].work, ha); 124 if (list_empty(&port->phy_list))
125 continue;
126
127 sas_phy = container_of(port->phy_list.next, struct asd_sas_phy,
128 port_phy_el);
129 ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
123 } 130 }
124 mutex_unlock(&ha->disco_mutex); 131 mutex_unlock(&ha->disco_mutex);
125} 132}
126 133
134
135static void sas_port_event_worker(struct work_struct *work)
136{
137 struct asd_sas_event *ev = to_asd_sas_event(work);
138
139 sas_port_event_fns[ev->event](work);
140 sas_free_event(ev);
141}
142
143static void sas_phy_event_worker(struct work_struct *work)
144{
145 struct asd_sas_event *ev = to_asd_sas_event(work);
146
147 sas_phy_event_fns[ev->event](work);
148 sas_free_event(ev);
149}
150
127static int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event) 151static int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event)
128{ 152{
153 struct asd_sas_event *ev;
129 struct sas_ha_struct *ha = phy->ha; 154 struct sas_ha_struct *ha = phy->ha;
155 int ret;
130 156
131 BUG_ON(event >= PORT_NUM_EVENTS); 157 BUG_ON(event >= PORT_NUM_EVENTS);
132 158
133 return sas_queue_event(event, &phy->port_events_pending, 159 ev = sas_alloc_event(phy);
134 &phy->port_events[event].work, ha); 160 if (!ev)
161 return -ENOMEM;
162
163 INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event);
164
165 ret = sas_queue_event(event, &ev->work, ha);
166 if (ret != 1)
167 sas_free_event(ev);
168
169 return ret;
135} 170}
136 171
137int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) 172int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
138{ 173{
174 struct asd_sas_event *ev;
139 struct sas_ha_struct *ha = phy->ha; 175 struct sas_ha_struct *ha = phy->ha;
176 int ret;
140 177
141 BUG_ON(event >= PHY_NUM_EVENTS); 178 BUG_ON(event >= PHY_NUM_EVENTS);
142 179
143 return sas_queue_event(event, &phy->phy_events_pending, 180 ev = sas_alloc_event(phy);
144 &phy->phy_events[event].work, ha); 181 if (!ev)
182 return -ENOMEM;
183
184 INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event);
185
186 ret = sas_queue_event(event, &ev->work, ha);
187 if (ret != 1)
188 sas_free_event(ev);
189
190 return ret;
145} 191}
146 192
147int sas_init_events(struct sas_ha_struct *sas_ha) 193int sas_init_events(struct sas_ha_struct *sas_ha)
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 3183d63de4da..6a4f8198b78e 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -293,6 +293,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)
293 phy->phy->minimum_linkrate = dr->pmin_linkrate; 293 phy->phy->minimum_linkrate = dr->pmin_linkrate;
294 phy->phy->maximum_linkrate = dr->pmax_linkrate; 294 phy->phy->maximum_linkrate = dr->pmax_linkrate;
295 phy->phy->negotiated_linkrate = phy->linkrate; 295 phy->phy->negotiated_linkrate = phy->linkrate;
296 phy->phy->enabled = (phy->linkrate != SAS_PHY_DISABLED);
296 297
297 skip: 298 skip:
298 if (new_phy) 299 if (new_phy)
@@ -686,7 +687,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy)
686 res = smp_execute_task(dev, req, RPEL_REQ_SIZE, 687 res = smp_execute_task(dev, req, RPEL_REQ_SIZE,
687 resp, RPEL_RESP_SIZE); 688 resp, RPEL_RESP_SIZE);
688 689
689 if (!res) 690 if (res)
690 goto out; 691 goto out;
691 692
692 phy->invalid_dword_count = scsi_to_u32(&resp[12]); 693 phy->invalid_dword_count = scsi_to_u32(&resp[12]);
@@ -695,6 +696,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy)
695 phy->phy_reset_problem_count = scsi_to_u32(&resp[24]); 696 phy->phy_reset_problem_count = scsi_to_u32(&resp[24]);
696 697
697 out: 698 out:
699 kfree(req);
698 kfree(resp); 700 kfree(resp);
699 return res; 701 return res;
700 702
@@ -1914,7 +1916,8 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
1914 sas_port_delete_phy(phy->port, phy->phy); 1916 sas_port_delete_phy(phy->port, phy->phy);
1915 sas_device_set_phy(found, phy->port); 1917 sas_device_set_phy(found, phy->port);
1916 if (phy->port->num_phys == 0) 1918 if (phy->port->num_phys == 0)
1917 sas_port_delete(phy->port); 1919 list_add_tail(&phy->port->del_list,
1920 &parent->port->sas_port_del_list);
1918 phy->port = NULL; 1921 phy->port = NULL;
1919 } 1922 }
1920} 1923}
@@ -2122,7 +2125,7 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
2122 struct domain_device *dev = NULL; 2125 struct domain_device *dev = NULL;
2123 2126
2124 res = sas_find_bcast_dev(port_dev, &dev); 2127 res = sas_find_bcast_dev(port_dev, &dev);
2125 while (res == 0 && dev) { 2128 if (res == 0 && dev) {
2126 struct expander_device *ex = &dev->ex_dev; 2129 struct expander_device *ex = &dev->ex_dev;
2127 int i = 0, phy_id; 2130 int i = 0, phy_id;
2128 2131
@@ -2134,9 +2137,6 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
2134 res = sas_rediscover(dev, phy_id); 2137 res = sas_rediscover(dev, phy_id);
2135 i = phy_id + 1; 2138 i = phy_id + 1;
2136 } while (i < ex->num_phys); 2139 } while (i < ex->num_phys);
2137
2138 dev = NULL;
2139 res = sas_find_bcast_dev(port_dev, &dev);
2140 } 2140 }
2141 return res; 2141 return res;
2142} 2142}
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 64fa6f53cb8b..c81a63b5dc71 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -39,6 +39,7 @@
39#include "../scsi_sas_internal.h" 39#include "../scsi_sas_internal.h"
40 40
41static struct kmem_cache *sas_task_cache; 41static struct kmem_cache *sas_task_cache;
42static struct kmem_cache *sas_event_cache;
42 43
43struct sas_task *sas_alloc_task(gfp_t flags) 44struct sas_task *sas_alloc_task(gfp_t flags)
44{ 45{
@@ -109,6 +110,7 @@ void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
109 110
110int sas_register_ha(struct sas_ha_struct *sas_ha) 111int sas_register_ha(struct sas_ha_struct *sas_ha)
111{ 112{
113 char name[64];
112 int error = 0; 114 int error = 0;
113 115
114 mutex_init(&sas_ha->disco_mutex); 116 mutex_init(&sas_ha->disco_mutex);
@@ -122,6 +124,8 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
122 INIT_LIST_HEAD(&sas_ha->defer_q); 124 INIT_LIST_HEAD(&sas_ha->defer_q);
123 INIT_LIST_HEAD(&sas_ha->eh_dev_q); 125 INIT_LIST_HEAD(&sas_ha->eh_dev_q);
124 126
127 sas_ha->event_thres = SAS_PHY_SHUTDOWN_THRES;
128
125 error = sas_register_phys(sas_ha); 129 error = sas_register_phys(sas_ha);
126 if (error) { 130 if (error) {
127 printk(KERN_NOTICE "couldn't register sas phys:%d\n", error); 131 printk(KERN_NOTICE "couldn't register sas phys:%d\n", error);
@@ -140,10 +144,24 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
140 goto Undo_ports; 144 goto Undo_ports;
141 } 145 }
142 146
147 error = -ENOMEM;
148 snprintf(name, sizeof(name), "%s_event_q", dev_name(sas_ha->dev));
149 sas_ha->event_q = create_singlethread_workqueue(name);
150 if (!sas_ha->event_q)
151 goto Undo_ports;
152
153 snprintf(name, sizeof(name), "%s_disco_q", dev_name(sas_ha->dev));
154 sas_ha->disco_q = create_singlethread_workqueue(name);
155 if (!sas_ha->disco_q)
156 goto Undo_event_q;
157
143 INIT_LIST_HEAD(&sas_ha->eh_done_q); 158 INIT_LIST_HEAD(&sas_ha->eh_done_q);
144 INIT_LIST_HEAD(&sas_ha->eh_ata_q); 159 INIT_LIST_HEAD(&sas_ha->eh_ata_q);
145 160
146 return 0; 161 return 0;
162
163Undo_event_q:
164 destroy_workqueue(sas_ha->event_q);
147Undo_ports: 165Undo_ports:
148 sas_unregister_ports(sas_ha); 166 sas_unregister_ports(sas_ha);
149Undo_phys: 167Undo_phys:
@@ -174,6 +192,9 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
174 __sas_drain_work(sas_ha); 192 __sas_drain_work(sas_ha);
175 mutex_unlock(&sas_ha->drain_mutex); 193 mutex_unlock(&sas_ha->drain_mutex);
176 194
195 destroy_workqueue(sas_ha->disco_q);
196 destroy_workqueue(sas_ha->event_q);
197
177 return 0; 198 return 0;
178} 199}
179 200
@@ -364,8 +385,6 @@ void sas_prep_resume_ha(struct sas_ha_struct *ha)
364 struct asd_sas_phy *phy = ha->sas_phy[i]; 385 struct asd_sas_phy *phy = ha->sas_phy[i];
365 386
366 memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); 387 memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
367 phy->port_events_pending = 0;
368 phy->phy_events_pending = 0;
369 phy->frame_rcvd_size = 0; 388 phy->frame_rcvd_size = 0;
370 } 389 }
371} 390}
@@ -537,6 +556,37 @@ static struct sas_function_template sft = {
537 .smp_handler = sas_smp_handler, 556 .smp_handler = sas_smp_handler,
538}; 557};
539 558
559static inline ssize_t phy_event_threshold_show(struct device *dev,
560 struct device_attribute *attr, char *buf)
561{
562 struct Scsi_Host *shost = class_to_shost(dev);
563 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
564
565 return scnprintf(buf, PAGE_SIZE, "%u\n", sha->event_thres);
566}
567
568static inline ssize_t phy_event_threshold_store(struct device *dev,
569 struct device_attribute *attr,
570 const char *buf, size_t count)
571{
572 struct Scsi_Host *shost = class_to_shost(dev);
573 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
574
575 sha->event_thres = simple_strtol(buf, NULL, 10);
576
577 /* threshold cannot be set too small */
578 if (sha->event_thres < 32)
579 sha->event_thres = 32;
580
581 return count;
582}
583
584DEVICE_ATTR(phy_event_threshold,
585 S_IRUGO|S_IWUSR,
586 phy_event_threshold_show,
587 phy_event_threshold_store);
588EXPORT_SYMBOL_GPL(dev_attr_phy_event_threshold);
589
540struct scsi_transport_template * 590struct scsi_transport_template *
541sas_domain_attach_transport(struct sas_domain_function_template *dft) 591sas_domain_attach_transport(struct sas_domain_function_template *dft)
542{ 592{
@@ -555,20 +605,71 @@ sas_domain_attach_transport(struct sas_domain_function_template *dft)
555} 605}
556EXPORT_SYMBOL_GPL(sas_domain_attach_transport); 606EXPORT_SYMBOL_GPL(sas_domain_attach_transport);
557 607
608
609struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy)
610{
611 struct asd_sas_event *event;
612 gfp_t flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
613 struct sas_ha_struct *sas_ha = phy->ha;
614 struct sas_internal *i =
615 to_sas_internal(sas_ha->core.shost->transportt);
616
617 event = kmem_cache_zalloc(sas_event_cache, flags);
618 if (!event)
619 return NULL;
620
621 atomic_inc(&phy->event_nr);
622
623 if (atomic_read(&phy->event_nr) > phy->ha->event_thres) {
624 if (i->dft->lldd_control_phy) {
625 if (cmpxchg(&phy->in_shutdown, 0, 1) == 0) {
626 sas_printk("The phy%02d bursting events, shut it down.\n",
627 phy->id);
628 sas_notify_phy_event(phy, PHYE_SHUTDOWN);
629 }
630 } else {
631 /* Do not support PHY control, stop allocating events */
632 WARN_ONCE(1, "PHY control not supported.\n");
633 kmem_cache_free(sas_event_cache, event);
634 atomic_dec(&phy->event_nr);
635 event = NULL;
636 }
637 }
638
639 return event;
640}
641
642void sas_free_event(struct asd_sas_event *event)
643{
644 struct asd_sas_phy *phy = event->phy;
645
646 kmem_cache_free(sas_event_cache, event);
647 atomic_dec(&phy->event_nr);
648}
649
558/* ---------- SAS Class register/unregister ---------- */ 650/* ---------- SAS Class register/unregister ---------- */
559 651
560static int __init sas_class_init(void) 652static int __init sas_class_init(void)
561{ 653{
562 sas_task_cache = KMEM_CACHE(sas_task, SLAB_HWCACHE_ALIGN); 654 sas_task_cache = KMEM_CACHE(sas_task, SLAB_HWCACHE_ALIGN);
563 if (!sas_task_cache) 655 if (!sas_task_cache)
564 return -ENOMEM; 656 goto out;
657
658 sas_event_cache = KMEM_CACHE(asd_sas_event, SLAB_HWCACHE_ALIGN);
659 if (!sas_event_cache)
660 goto free_task_kmem;
565 661
566 return 0; 662 return 0;
663free_task_kmem:
664 kmem_cache_destroy(sas_task_cache);
665out:
666 return -ENOMEM;
567} 667}
568 668
569static void __exit sas_class_exit(void) 669static void __exit sas_class_exit(void)
570{ 670{
571 kmem_cache_destroy(sas_task_cache); 671 kmem_cache_destroy(sas_task_cache);
672 kmem_cache_destroy(sas_event_cache);
572} 673}
573 674
574MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>"); 675MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index c07e08136491..50e12d662ffe 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -61,6 +61,9 @@ int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
61int sas_register_phys(struct sas_ha_struct *sas_ha); 61int sas_register_phys(struct sas_ha_struct *sas_ha);
62void sas_unregister_phys(struct sas_ha_struct *sas_ha); 62void sas_unregister_phys(struct sas_ha_struct *sas_ha);
63 63
64struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy);
65void sas_free_event(struct asd_sas_event *event);
66
64int sas_register_ports(struct sas_ha_struct *sas_ha); 67int sas_register_ports(struct sas_ha_struct *sas_ha);
65void sas_unregister_ports(struct sas_ha_struct *sas_ha); 68void sas_unregister_ports(struct sas_ha_struct *sas_ha);
66 69
@@ -98,6 +101,10 @@ int sas_try_ata_reset(struct asd_sas_phy *phy);
98void sas_hae_reset(struct work_struct *work); 101void sas_hae_reset(struct work_struct *work);
99 102
100void sas_free_device(struct kref *kref); 103void sas_free_device(struct kref *kref);
104void sas_destruct_devices(struct asd_sas_port *port);
105
106extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS];
107extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS];
101 108
102#ifdef CONFIG_SCSI_SAS_HOST_SMP 109#ifdef CONFIG_SCSI_SAS_HOST_SMP
103extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost); 110extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost);
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index cdee446c29e1..bf3e1b979ca6 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -35,7 +35,7 @@ static void sas_phye_loss_of_signal(struct work_struct *work)
35 struct asd_sas_event *ev = to_asd_sas_event(work); 35 struct asd_sas_event *ev = to_asd_sas_event(work);
36 struct asd_sas_phy *phy = ev->phy; 36 struct asd_sas_phy *phy = ev->phy;
37 37
38 clear_bit(PHYE_LOSS_OF_SIGNAL, &phy->phy_events_pending); 38 phy->in_shutdown = 0;
39 phy->error = 0; 39 phy->error = 0;
40 sas_deform_port(phy, 1); 40 sas_deform_port(phy, 1);
41} 41}
@@ -45,7 +45,7 @@ static void sas_phye_oob_done(struct work_struct *work)
45 struct asd_sas_event *ev = to_asd_sas_event(work); 45 struct asd_sas_event *ev = to_asd_sas_event(work);
46 struct asd_sas_phy *phy = ev->phy; 46 struct asd_sas_phy *phy = ev->phy;
47 47
48 clear_bit(PHYE_OOB_DONE, &phy->phy_events_pending); 48 phy->in_shutdown = 0;
49 phy->error = 0; 49 phy->error = 0;
50} 50}
51 51
@@ -58,8 +58,6 @@ static void sas_phye_oob_error(struct work_struct *work)
58 struct sas_internal *i = 58 struct sas_internal *i =
59 to_sas_internal(sas_ha->core.shost->transportt); 59 to_sas_internal(sas_ha->core.shost->transportt);
60 60
61 clear_bit(PHYE_OOB_ERROR, &phy->phy_events_pending);
62
63 sas_deform_port(phy, 1); 61 sas_deform_port(phy, 1);
64 62
65 if (!port && phy->enabled && i->dft->lldd_control_phy) { 63 if (!port && phy->enabled && i->dft->lldd_control_phy) {
@@ -88,8 +86,6 @@ static void sas_phye_spinup_hold(struct work_struct *work)
88 struct sas_internal *i = 86 struct sas_internal *i =
89 to_sas_internal(sas_ha->core.shost->transportt); 87 to_sas_internal(sas_ha->core.shost->transportt);
90 88
91 clear_bit(PHYE_SPINUP_HOLD, &phy->phy_events_pending);
92
93 phy->error = 0; 89 phy->error = 0;
94 i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL); 90 i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
95} 91}
@@ -99,8 +95,6 @@ static void sas_phye_resume_timeout(struct work_struct *work)
99 struct asd_sas_event *ev = to_asd_sas_event(work); 95 struct asd_sas_event *ev = to_asd_sas_event(work);
100 struct asd_sas_phy *phy = ev->phy; 96 struct asd_sas_phy *phy = ev->phy;
101 97
102 clear_bit(PHYE_RESUME_TIMEOUT, &phy->phy_events_pending);
103
104 /* phew, lldd got the phy back in the nick of time */ 98 /* phew, lldd got the phy back in the nick of time */
105 if (!phy->suspended) { 99 if (!phy->suspended) {
106 dev_info(&phy->phy->dev, "resume timeout cancelled\n"); 100 dev_info(&phy->phy->dev, "resume timeout cancelled\n");
@@ -113,45 +107,41 @@ static void sas_phye_resume_timeout(struct work_struct *work)
113} 107}
114 108
115 109
110static void sas_phye_shutdown(struct work_struct *work)
111{
112 struct asd_sas_event *ev = to_asd_sas_event(work);
113 struct asd_sas_phy *phy = ev->phy;
114 struct sas_ha_struct *sas_ha = phy->ha;
115 struct sas_internal *i =
116 to_sas_internal(sas_ha->core.shost->transportt);
117
118 if (phy->enabled) {
119 int ret;
120
121 phy->error = 0;
122 phy->enabled = 0;
123 ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
124 if (ret)
125 sas_printk("lldd disable phy%02d returned %d\n",
126 phy->id, ret);
127 } else
128 sas_printk("phy%02d is not enabled, cannot shutdown\n",
129 phy->id);
130}
131
116/* ---------- Phy class registration ---------- */ 132/* ---------- Phy class registration ---------- */
117 133
118int sas_register_phys(struct sas_ha_struct *sas_ha) 134int sas_register_phys(struct sas_ha_struct *sas_ha)
119{ 135{
120 int i; 136 int i;
121 137
122 static const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
123 [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
124 [PHYE_OOB_DONE] = sas_phye_oob_done,
125 [PHYE_OOB_ERROR] = sas_phye_oob_error,
126 [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
127 [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
128
129 };
130
131 static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
132 [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed,
133 [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd,
134 [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err,
135 [PORTE_TIMER_EVENT] = sas_porte_timer_event,
136 [PORTE_HARD_RESET] = sas_porte_hard_reset,
137 };
138
139 /* Now register the phys. */ 138 /* Now register the phys. */
140 for (i = 0; i < sas_ha->num_phys; i++) { 139 for (i = 0; i < sas_ha->num_phys; i++) {
141 int k;
142 struct asd_sas_phy *phy = sas_ha->sas_phy[i]; 140 struct asd_sas_phy *phy = sas_ha->sas_phy[i];
143 141
144 phy->error = 0; 142 phy->error = 0;
143 atomic_set(&phy->event_nr, 0);
145 INIT_LIST_HEAD(&phy->port_phy_el); 144 INIT_LIST_HEAD(&phy->port_phy_el);
146 for (k = 0; k < PORT_NUM_EVENTS; k++) {
147 INIT_SAS_WORK(&phy->port_events[k].work, sas_port_event_fns[k]);
148 phy->port_events[k].phy = phy;
149 }
150
151 for (k = 0; k < PHY_NUM_EVENTS; k++) {
152 INIT_SAS_WORK(&phy->phy_events[k].work, sas_phy_event_fns[k]);
153 phy->phy_events[k].phy = phy;
154 }
155 145
156 phy->port = NULL; 146 phy->port = NULL;
157 phy->ha = sas_ha; 147 phy->ha = sas_ha;
@@ -179,3 +169,12 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
179 169
180 return 0; 170 return 0;
181} 171}
172
173const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
174 [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
175 [PHYE_OOB_DONE] = sas_phye_oob_done,
176 [PHYE_OOB_ERROR] = sas_phye_oob_error,
177 [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
178 [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
179 [PHYE_SHUTDOWN] = sas_phye_shutdown,
180};
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index d3c5297c6c89..f07e55d3aa73 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -66,6 +66,7 @@ static void sas_resume_port(struct asd_sas_phy *phy)
66 rc = sas_notify_lldd_dev_found(dev); 66 rc = sas_notify_lldd_dev_found(dev);
67 if (rc) { 67 if (rc) {
68 sas_unregister_dev(port, dev); 68 sas_unregister_dev(port, dev);
69 sas_destruct_devices(port);
69 continue; 70 continue;
70 } 71 }
71 72
@@ -192,6 +193,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
192 si->dft->lldd_port_formed(phy); 193 si->dft->lldd_port_formed(phy);
193 194
194 sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN); 195 sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);
196 flush_workqueue(sas_ha->disco_q);
195} 197}
196 198
197/** 199/**
@@ -219,6 +221,7 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
219 221
220 if (port->num_phys == 1) { 222 if (port->num_phys == 1) {
221 sas_unregister_domain_devices(port, gone); 223 sas_unregister_domain_devices(port, gone);
224 sas_destruct_devices(port);
222 sas_port_delete(port->port); 225 sas_port_delete(port->port);
223 port->port = NULL; 226 port->port = NULL;
224 } else { 227 } else {
@@ -261,8 +264,6 @@ void sas_porte_bytes_dmaed(struct work_struct *work)
261 struct asd_sas_event *ev = to_asd_sas_event(work); 264 struct asd_sas_event *ev = to_asd_sas_event(work);
262 struct asd_sas_phy *phy = ev->phy; 265 struct asd_sas_phy *phy = ev->phy;
263 266
264 clear_bit(PORTE_BYTES_DMAED, &phy->port_events_pending);
265
266 sas_form_port(phy); 267 sas_form_port(phy);
267} 268}
268 269
@@ -273,14 +274,15 @@ void sas_porte_broadcast_rcvd(struct work_struct *work)
273 unsigned long flags; 274 unsigned long flags;
274 u32 prim; 275 u32 prim;
275 276
276 clear_bit(PORTE_BROADCAST_RCVD, &phy->port_events_pending);
277
278 spin_lock_irqsave(&phy->sas_prim_lock, flags); 277 spin_lock_irqsave(&phy->sas_prim_lock, flags);
279 prim = phy->sas_prim; 278 prim = phy->sas_prim;
280 spin_unlock_irqrestore(&phy->sas_prim_lock, flags); 279 spin_unlock_irqrestore(&phy->sas_prim_lock, flags);
281 280
282 SAS_DPRINTK("broadcast received: %d\n", prim); 281 SAS_DPRINTK("broadcast received: %d\n", prim);
283 sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN); 282 sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN);
283
284 if (phy->port)
285 flush_workqueue(phy->port->ha->disco_q);
284} 286}
285 287
286void sas_porte_link_reset_err(struct work_struct *work) 288void sas_porte_link_reset_err(struct work_struct *work)
@@ -288,8 +290,6 @@ void sas_porte_link_reset_err(struct work_struct *work)
288 struct asd_sas_event *ev = to_asd_sas_event(work); 290 struct asd_sas_event *ev = to_asd_sas_event(work);
289 struct asd_sas_phy *phy = ev->phy; 291 struct asd_sas_phy *phy = ev->phy;
290 292
291 clear_bit(PORTE_LINK_RESET_ERR, &phy->port_events_pending);
292
293 sas_deform_port(phy, 1); 293 sas_deform_port(phy, 1);
294} 294}
295 295
@@ -298,8 +298,6 @@ void sas_porte_timer_event(struct work_struct *work)
298 struct asd_sas_event *ev = to_asd_sas_event(work); 298 struct asd_sas_event *ev = to_asd_sas_event(work);
299 struct asd_sas_phy *phy = ev->phy; 299 struct asd_sas_phy *phy = ev->phy;
300 300
301 clear_bit(PORTE_TIMER_EVENT, &phy->port_events_pending);
302
303 sas_deform_port(phy, 1); 301 sas_deform_port(phy, 1);
304} 302}
305 303
@@ -308,8 +306,6 @@ void sas_porte_hard_reset(struct work_struct *work)
308 struct asd_sas_event *ev = to_asd_sas_event(work); 306 struct asd_sas_event *ev = to_asd_sas_event(work);
309 struct asd_sas_phy *phy = ev->phy; 307 struct asd_sas_phy *phy = ev->phy;
310 308
311 clear_bit(PORTE_HARD_RESET, &phy->port_events_pending);
312
313 sas_deform_port(phy, 1); 309 sas_deform_port(phy, 1);
314} 310}
315 311
@@ -323,6 +319,7 @@ static void sas_init_port(struct asd_sas_port *port,
323 INIT_LIST_HEAD(&port->dev_list); 319 INIT_LIST_HEAD(&port->dev_list);
324 INIT_LIST_HEAD(&port->disco_list); 320 INIT_LIST_HEAD(&port->disco_list);
325 INIT_LIST_HEAD(&port->destroy_list); 321 INIT_LIST_HEAD(&port->destroy_list);
322 INIT_LIST_HEAD(&port->sas_port_del_list);
326 spin_lock_init(&port->phy_list_lock); 323 spin_lock_init(&port->phy_list_lock);
327 INIT_LIST_HEAD(&port->phy_list); 324 INIT_LIST_HEAD(&port->phy_list);
328 port->ha = sas_ha; 325 port->ha = sas_ha;
@@ -353,3 +350,11 @@ void sas_unregister_ports(struct sas_ha_struct *sas_ha)
353 sas_deform_port(sas_ha->sas_phy[i], 0); 350 sas_deform_port(sas_ha->sas_phy[i], 0);
354 351
355} 352}
353
354const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
355 [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed,
356 [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd,
357 [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err,
358 [PORTE_TIMER_EVENT] = sas_porte_timer_event,
359 [PORTE_HARD_RESET] = sas_porte_hard_reset,
360};
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index c9406852c3e9..6de9681ace82 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -27,6 +27,7 @@
27#include <linux/firmware.h> 27#include <linux/firmware.h>
28#include <linux/export.h> 28#include <linux/export.h>
29#include <linux/ctype.h> 29#include <linux/ctype.h>
30#include <linux/kernel.h>
30 31
31#include "sas_internal.h" 32#include "sas_internal.h"
32 33
@@ -959,21 +960,6 @@ void sas_target_destroy(struct scsi_target *starget)
959 sas_put_device(found_dev); 960 sas_put_device(found_dev);
960} 961}
961 962
962static void sas_parse_addr(u8 *sas_addr, const char *p)
963{
964 int i;
965 for (i = 0; i < SAS_ADDR_SIZE; i++) {
966 u8 h, l;
967 if (!*p)
968 break;
969 h = isdigit(*p) ? *p-'0' : toupper(*p)-'A'+10;
970 p++;
971 l = isdigit(*p) ? *p-'0' : toupper(*p)-'A'+10;
972 p++;
973 sas_addr[i] = (h<<4) | l;
974 }
975}
976
977#define SAS_STRING_ADDR_SIZE 16 963#define SAS_STRING_ADDR_SIZE 16
978 964
979int sas_request_addr(struct Scsi_Host *shost, u8 *addr) 965int sas_request_addr(struct Scsi_Host *shost, u8 *addr)
@@ -990,7 +976,9 @@ int sas_request_addr(struct Scsi_Host *shost, u8 *addr)
990 goto out; 976 goto out;
991 } 977 }
992 978
993 sas_parse_addr(addr, fw->data); 979 res = hex2bin(addr, fw->data, strnlen(fw->data, SAS_ADDR_SIZE * 2) / 2);
980 if (res)
981 goto out;
994 982
995out: 983out:
996 release_firmware(fw); 984 release_firmware(fw);