diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-31 14:23:28 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-31 14:23:28 -0500 |
commit | 28bc6fb9596fe1e577d09fc17ee6e1bb051c6ba3 (patch) | |
tree | 6293b282a960720fc5008e3e5fa4d096d974b2f1 /drivers/scsi/libsas | |
parent | 0be600a5add76e8e8b9e1119f2a7426ff849aca8 (diff) | |
parent | a2390348c19d0819d525d375414a7cfdacb51a68 (diff) |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"This is mostly updates of the usual driver suspects: arcmsr,
scsi_debug, mpt3sas, lpfc, cxlflash, qla2xxx, aacraid, megaraid_sas,
hisi_sas.
We also have a rework of the libsas hotplug handling to make it more
robust, a slew of 32 bit time conversions and fixes, and a host of the
usual minor updates and style changes. The biggest potential for
regressions is the libsas hotplug changes, but so far they seem stable
under testing"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (313 commits)
scsi: qla2xxx: Fix logo flag for qlt_free_session_done()
scsi: arcmsr: avoid do_gettimeofday
scsi: core: Add VENDOR_SPECIFIC sense code definitions
scsi: qedi: Drop cqe response during connection recovery
scsi: fas216: fix sense buffer initialization
scsi: ibmvfc: Remove unneeded semicolons
scsi: hisi_sas: fix a bug in hisi_sas_dev_gone()
scsi: hisi_sas: directly attached disk LED feature for v2 hw
scsi: hisi_sas: devicetree: bindings: add LED feature for v2 hw
scsi: megaraid_sas: NVMe passthrough command support
scsi: megaraid: use ktime_get_real for firmware time
scsi: fnic: use 64-bit timestamps
scsi: qedf: Fix error return code in __qedf_probe()
scsi: devinfo: fix format of the device list
scsi: qla2xxx: Update driver version to 10.00.00.05-k
scsi: qla2xxx: Add XCB counters to debugfs
scsi: qla2xxx: Fix queue ID for async abort with Multiqueue
scsi: qla2xxx: Fix warning for code intentation in __qla24xx_handle_gpdb_event()
scsi: qla2xxx: Fix warning during port_name debug print
scsi: qla2xxx: Fix warning in qla2x00_async_iocb_timeout()
...
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 1 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 34 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_event.c | 86 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 12 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 107 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_internal.h | 7 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_phy.c | 69 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_port.c | 25 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 20 |
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 | ||
215 | static void sas_probe_devices(struct work_struct *work) | 215 | static 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 | ||
356 | static void sas_destruct_devices(struct work_struct *work) | 351 | void 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 | ||
364 | static 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 | |||
373 | void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) | 374 | void 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 | ||
540 | static void sas_chain_event(int event, unsigned long *pending, | 546 | static 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 | ||
30 | int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) | 30 | int 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 | ||
47 | static int sas_queue_event(int event, unsigned long *pending, | 48 | static 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 | ||
65 | void __sas_drain_work(struct sas_ha_struct *ha) | 62 | void __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 | |||
135 | static 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 | |||
143 | static 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 | |||
127 | static int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event) | 151 | static 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 | ||
137 | int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) | 172 | int 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 | ||
147 | int sas_init_events(struct sas_ha_struct *sas_ha) | 193 | int 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 | ||
41 | static struct kmem_cache *sas_task_cache; | 41 | static struct kmem_cache *sas_task_cache; |
42 | static struct kmem_cache *sas_event_cache; | ||
42 | 43 | ||
43 | struct sas_task *sas_alloc_task(gfp_t flags) | 44 | struct 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 | ||
110 | int sas_register_ha(struct sas_ha_struct *sas_ha) | 111 | int 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 | |||
163 | Undo_event_q: | ||
164 | destroy_workqueue(sas_ha->event_q); | ||
147 | Undo_ports: | 165 | Undo_ports: |
148 | sas_unregister_ports(sas_ha); | 166 | sas_unregister_ports(sas_ha); |
149 | Undo_phys: | 167 | Undo_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 | ||
559 | static 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 | |||
568 | static 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 | |||
584 | DEVICE_ATTR(phy_event_threshold, | ||
585 | S_IRUGO|S_IWUSR, | ||
586 | phy_event_threshold_show, | ||
587 | phy_event_threshold_store); | ||
588 | EXPORT_SYMBOL_GPL(dev_attr_phy_event_threshold); | ||
589 | |||
540 | struct scsi_transport_template * | 590 | struct scsi_transport_template * |
541 | sas_domain_attach_transport(struct sas_domain_function_template *dft) | 591 | sas_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 | } |
556 | EXPORT_SYMBOL_GPL(sas_domain_attach_transport); | 606 | EXPORT_SYMBOL_GPL(sas_domain_attach_transport); |
557 | 607 | ||
608 | |||
609 | struct 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 | |||
642 | void 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 | ||
560 | static int __init sas_class_init(void) | 652 | static 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; |
663 | free_task_kmem: | ||
664 | kmem_cache_destroy(sas_task_cache); | ||
665 | out: | ||
666 | return -ENOMEM; | ||
567 | } | 667 | } |
568 | 668 | ||
569 | static void __exit sas_class_exit(void) | 669 | static 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 | ||
574 | MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>"); | 675 | MODULE_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); | |||
61 | int sas_register_phys(struct sas_ha_struct *sas_ha); | 61 | int sas_register_phys(struct sas_ha_struct *sas_ha); |
62 | void sas_unregister_phys(struct sas_ha_struct *sas_ha); | 62 | void sas_unregister_phys(struct sas_ha_struct *sas_ha); |
63 | 63 | ||
64 | struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy); | ||
65 | void sas_free_event(struct asd_sas_event *event); | ||
66 | |||
64 | int sas_register_ports(struct sas_ha_struct *sas_ha); | 67 | int sas_register_ports(struct sas_ha_struct *sas_ha); |
65 | void sas_unregister_ports(struct sas_ha_struct *sas_ha); | 68 | void 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); | |||
98 | void sas_hae_reset(struct work_struct *work); | 101 | void sas_hae_reset(struct work_struct *work); |
99 | 102 | ||
100 | void sas_free_device(struct kref *kref); | 103 | void sas_free_device(struct kref *kref); |
104 | void sas_destruct_devices(struct asd_sas_port *port); | ||
105 | |||
106 | extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS]; | ||
107 | extern 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 |
103 | extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost); | 110 | extern 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 | ||
110 | static 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 | ||
118 | int sas_register_phys(struct sas_ha_struct *sas_ha) | 134 | int 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 | |||
173 | const 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 | ||
286 | void sas_porte_link_reset_err(struct work_struct *work) | 288 | void 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 | |||
354 | const 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 | ||
962 | static 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 | ||
979 | int sas_request_addr(struct Scsi_Host *shost, u8 *addr) | 965 | int 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 | ||
995 | out: | 983 | out: |
996 | release_firmware(fw); | 984 | release_firmware(fw); |