diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/scsi/libsas/sas_discover.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/scsi/libsas/sas_discover.c')
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 356 |
1 files changed, 77 insertions, 279 deletions
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index a0c3003e0c7..f5831930df9 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c | |||
@@ -24,32 +24,35 @@ | |||
24 | 24 | ||
25 | #include <linux/scatterlist.h> | 25 | #include <linux/scatterlist.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/async.h> | ||
28 | #include <scsi/scsi_host.h> | 27 | #include <scsi/scsi_host.h> |
29 | #include <scsi/scsi_eh.h> | 28 | #include <scsi/scsi_eh.h> |
30 | #include "sas_internal.h" | 29 | #include "sas_internal.h" |
31 | 30 | ||
32 | #include <scsi/scsi_transport.h> | 31 | #include <scsi/scsi_transport.h> |
33 | #include <scsi/scsi_transport_sas.h> | 32 | #include <scsi/scsi_transport_sas.h> |
34 | #include <scsi/sas_ata.h> | ||
35 | #include "../scsi_sas_internal.h" | 33 | #include "../scsi_sas_internal.h" |
36 | 34 | ||
37 | /* ---------- Basic task processing for discovery purposes ---------- */ | 35 | /* ---------- Basic task processing for discovery purposes ---------- */ |
38 | 36 | ||
39 | void sas_init_dev(struct domain_device *dev) | 37 | void sas_init_dev(struct domain_device *dev) |
40 | { | 38 | { |
41 | switch (dev->dev_type) { | 39 | INIT_LIST_HEAD(&dev->siblings); |
42 | case SAS_END_DEV: | 40 | INIT_LIST_HEAD(&dev->dev_list_node); |
43 | INIT_LIST_HEAD(&dev->ssp_dev.eh_list_node); | 41 | switch (dev->dev_type) { |
44 | break; | 42 | case SAS_END_DEV: |
45 | case EDGE_DEV: | 43 | break; |
46 | case FANOUT_DEV: | 44 | case EDGE_DEV: |
47 | INIT_LIST_HEAD(&dev->ex_dev.children); | 45 | case FANOUT_DEV: |
48 | mutex_init(&dev->ex_dev.cmd_mutex); | 46 | INIT_LIST_HEAD(&dev->ex_dev.children); |
49 | break; | 47 | break; |
50 | default: | 48 | case SATA_DEV: |
51 | break; | 49 | case SATA_PM: |
52 | } | 50 | case SATA_PM_PORT: |
51 | INIT_LIST_HEAD(&dev->sata_dev.children); | ||
52 | break; | ||
53 | default: | ||
54 | break; | ||
55 | } | ||
53 | } | 56 | } |
54 | 57 | ||
55 | /* ---------- Domain device discovery ---------- */ | 58 | /* ---------- Domain device discovery ---------- */ |
@@ -65,19 +68,19 @@ void sas_init_dev(struct domain_device *dev) | |||
65 | */ | 68 | */ |
66 | static int sas_get_port_device(struct asd_sas_port *port) | 69 | static int sas_get_port_device(struct asd_sas_port *port) |
67 | { | 70 | { |
71 | unsigned long flags; | ||
68 | struct asd_sas_phy *phy; | 72 | struct asd_sas_phy *phy; |
69 | struct sas_rphy *rphy; | 73 | struct sas_rphy *rphy; |
70 | struct domain_device *dev; | 74 | struct domain_device *dev; |
71 | int rc = -ENODEV; | ||
72 | 75 | ||
73 | dev = sas_alloc_device(); | 76 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
74 | if (!dev) | 77 | if (!dev) |
75 | return -ENOMEM; | 78 | return -ENOMEM; |
76 | 79 | ||
77 | spin_lock_irq(&port->phy_list_lock); | 80 | spin_lock_irqsave(&port->phy_list_lock, flags); |
78 | if (list_empty(&port->phy_list)) { | 81 | if (list_empty(&port->phy_list)) { |
79 | spin_unlock_irq(&port->phy_list_lock); | 82 | spin_unlock_irqrestore(&port->phy_list_lock, flags); |
80 | sas_put_device(dev); | 83 | kfree(dev); |
81 | return -ENODEV; | 84 | return -ENODEV; |
82 | } | 85 | } |
83 | phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el); | 86 | phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el); |
@@ -85,7 +88,7 @@ static int sas_get_port_device(struct asd_sas_port *port) | |||
85 | memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd), | 88 | memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd), |
86 | (size_t)phy->frame_rcvd_size)); | 89 | (size_t)phy->frame_rcvd_size)); |
87 | spin_unlock(&phy->frame_rcvd_lock); | 90 | spin_unlock(&phy->frame_rcvd_lock); |
88 | spin_unlock_irq(&port->phy_list_lock); | 91 | spin_unlock_irqrestore(&port->phy_list_lock, flags); |
89 | 92 | ||
90 | if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) { | 93 | if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) { |
91 | struct dev_to_host_fis *fis = | 94 | struct dev_to_host_fis *fis = |
@@ -107,16 +110,9 @@ static int sas_get_port_device(struct asd_sas_port *port) | |||
107 | 110 | ||
108 | sas_init_dev(dev); | 111 | sas_init_dev(dev); |
109 | 112 | ||
110 | dev->port = port; | ||
111 | switch (dev->dev_type) { | 113 | switch (dev->dev_type) { |
112 | case SATA_DEV: | ||
113 | rc = sas_ata_init(dev); | ||
114 | if (rc) { | ||
115 | rphy = NULL; | ||
116 | break; | ||
117 | } | ||
118 | /* fall through */ | ||
119 | case SAS_END_DEV: | 114 | case SAS_END_DEV: |
115 | case SATA_DEV: | ||
120 | rphy = sas_end_device_alloc(port->port); | 116 | rphy = sas_end_device_alloc(port->port); |
121 | break; | 117 | break; |
122 | case EDGE_DEV: | 118 | case EDGE_DEV: |
@@ -134,15 +130,15 @@ static int sas_get_port_device(struct asd_sas_port *port) | |||
134 | } | 130 | } |
135 | 131 | ||
136 | if (!rphy) { | 132 | if (!rphy) { |
137 | sas_put_device(dev); | 133 | kfree(dev); |
138 | return rc; | 134 | return -ENODEV; |
139 | } | 135 | } |
140 | |||
141 | rphy->identify.phy_identifier = phy->phy->identify.phy_identifier; | 136 | rphy->identify.phy_identifier = phy->phy->identify.phy_identifier; |
142 | memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE); | 137 | memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE); |
143 | sas_fill_in_rphy(dev, rphy); | 138 | sas_fill_in_rphy(dev, rphy); |
144 | sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); | 139 | sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); |
145 | port->port_dev = dev; | 140 | port->port_dev = dev; |
141 | dev->port = port; | ||
146 | dev->linkrate = port->linkrate; | 142 | dev->linkrate = port->linkrate; |
147 | dev->min_linkrate = port->linkrate; | 143 | dev->min_linkrate = port->linkrate; |
148 | dev->max_linkrate = port->linkrate; | 144 | dev->max_linkrate = port->linkrate; |
@@ -151,23 +147,11 @@ static int sas_get_port_device(struct asd_sas_port *port) | |||
151 | memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE); | 147 | memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE); |
152 | memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE); | 148 | memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE); |
153 | port->disc.max_level = 0; | 149 | port->disc.max_level = 0; |
154 | sas_device_set_phy(dev, port->port); | ||
155 | 150 | ||
156 | dev->rphy = rphy; | 151 | dev->rphy = rphy; |
157 | get_device(&dev->rphy->dev); | 152 | spin_lock_irq(&port->dev_list_lock); |
158 | 153 | list_add_tail(&dev->dev_list_node, &port->dev_list); | |
159 | if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV) | 154 | spin_unlock_irq(&port->dev_list_lock); |
160 | list_add_tail(&dev->disco_list_node, &port->disco_list); | ||
161 | else { | ||
162 | spin_lock_irq(&port->dev_list_lock); | ||
163 | list_add_tail(&dev->dev_list_node, &port->dev_list); | ||
164 | spin_unlock_irq(&port->dev_list_lock); | ||
165 | } | ||
166 | |||
167 | spin_lock_irq(&port->phy_list_lock); | ||
168 | list_for_each_entry(phy, &port->phy_list, port_phy_el) | ||
169 | sas_phy_set_target(phy, dev); | ||
170 | spin_unlock_irq(&port->phy_list_lock); | ||
171 | 155 | ||
172 | return 0; | 156 | return 0; |
173 | } | 157 | } |
@@ -181,18 +165,15 @@ int sas_notify_lldd_dev_found(struct domain_device *dev) | |||
181 | struct Scsi_Host *shost = sas_ha->core.shost; | 165 | struct Scsi_Host *shost = sas_ha->core.shost; |
182 | struct sas_internal *i = to_sas_internal(shost->transportt); | 166 | struct sas_internal *i = to_sas_internal(shost->transportt); |
183 | 167 | ||
184 | if (!i->dft->lldd_dev_found) | 168 | if (i->dft->lldd_dev_found) { |
185 | return 0; | 169 | res = i->dft->lldd_dev_found(dev); |
186 | 170 | if (res) { | |
187 | res = i->dft->lldd_dev_found(dev); | 171 | printk("sas: driver on pcidev %s cannot handle " |
188 | if (res) { | 172 | "device %llx, error:%d\n", |
189 | printk("sas: driver on pcidev %s cannot handle " | 173 | dev_name(sas_ha->dev), |
190 | "device %llx, error:%d\n", | 174 | SAS_ADDR(dev->sas_addr), res); |
191 | dev_name(sas_ha->dev), | 175 | } |
192 | SAS_ADDR(dev->sas_addr), res); | ||
193 | } | 176 | } |
194 | set_bit(SAS_DEV_FOUND, &dev->state); | ||
195 | kref_get(&dev->kref); | ||
196 | return res; | 177 | return res; |
197 | } | 178 | } |
198 | 179 | ||
@@ -203,83 +184,12 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev) | |||
203 | struct Scsi_Host *shost = sas_ha->core.shost; | 184 | struct Scsi_Host *shost = sas_ha->core.shost; |
204 | struct sas_internal *i = to_sas_internal(shost->transportt); | 185 | struct sas_internal *i = to_sas_internal(shost->transportt); |
205 | 186 | ||
206 | if (!i->dft->lldd_dev_gone) | 187 | if (i->dft->lldd_dev_gone) |
207 | return; | ||
208 | |||
209 | if (test_and_clear_bit(SAS_DEV_FOUND, &dev->state)) { | ||
210 | i->dft->lldd_dev_gone(dev); | 188 | i->dft->lldd_dev_gone(dev); |
211 | sas_put_device(dev); | ||
212 | } | ||
213 | } | 189 | } |
214 | 190 | ||
215 | static void sas_probe_devices(struct work_struct *work) | 191 | /* ---------- Common/dispatchers ---------- */ |
216 | { | ||
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 | |||
223 | /* devices must be domain members before link recovery and probe */ | ||
224 | list_for_each_entry(dev, &port->disco_list, disco_list_node) { | ||
225 | spin_lock_irq(&port->dev_list_lock); | ||
226 | list_add_tail(&dev->dev_list_node, &port->dev_list); | ||
227 | spin_unlock_irq(&port->dev_list_lock); | ||
228 | } | ||
229 | |||
230 | sas_probe_sata(port); | ||
231 | |||
232 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { | ||
233 | int err; | ||
234 | |||
235 | err = sas_rphy_add(dev->rphy); | ||
236 | if (err) | ||
237 | sas_fail_probe(dev, __func__, err); | ||
238 | else | ||
239 | list_del_init(&dev->disco_list_node); | ||
240 | } | ||
241 | } | ||
242 | 192 | ||
243 | static void sas_suspend_devices(struct work_struct *work) | ||
244 | { | ||
245 | struct asd_sas_phy *phy; | ||
246 | struct domain_device *dev; | ||
247 | struct sas_discovery_event *ev = to_sas_discovery_event(work); | ||
248 | struct asd_sas_port *port = ev->port; | ||
249 | struct Scsi_Host *shost = port->ha->core.shost; | ||
250 | struct sas_internal *si = to_sas_internal(shost->transportt); | ||
251 | |||
252 | clear_bit(DISCE_SUSPEND, &port->disc.pending); | ||
253 | |||
254 | sas_suspend_sata(port); | ||
255 | |||
256 | /* lldd is free to forget the domain_device across the | ||
257 | * suspension, we force the issue here to keep the reference | ||
258 | * counts aligned | ||
259 | */ | ||
260 | list_for_each_entry(dev, &port->dev_list, dev_list_node) | ||
261 | sas_notify_lldd_dev_gone(dev); | ||
262 | |||
263 | /* we are suspending, so we know events are disabled and | ||
264 | * phy_list is not being mutated | ||
265 | */ | ||
266 | list_for_each_entry(phy, &port->phy_list, port_phy_el) { | ||
267 | if (si->dft->lldd_port_formed) | ||
268 | si->dft->lldd_port_deformed(phy); | ||
269 | phy->suspended = 1; | ||
270 | port->suspended = 1; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | static void sas_resume_devices(struct work_struct *work) | ||
275 | { | ||
276 | struct sas_discovery_event *ev = to_sas_discovery_event(work); | ||
277 | struct asd_sas_port *port = ev->port; | ||
278 | |||
279 | clear_bit(DISCE_RESUME, &port->disc.pending); | ||
280 | |||
281 | sas_resume_sata(port); | ||
282 | } | ||
283 | 193 | ||
284 | /** | 194 | /** |
285 | * sas_discover_end_dev -- discover an end device (SSP, etc) | 195 | * sas_discover_end_dev -- discover an end device (SSP, etc) |
@@ -293,138 +203,58 @@ int sas_discover_end_dev(struct domain_device *dev) | |||
293 | 203 | ||
294 | res = sas_notify_lldd_dev_found(dev); | 204 | res = sas_notify_lldd_dev_found(dev); |
295 | if (res) | 205 | if (res) |
296 | return res; | 206 | goto out_err2; |
297 | sas_discover_event(dev->port, DISCE_PROBE); | 207 | |
208 | res = sas_rphy_add(dev->rphy); | ||
209 | if (res) | ||
210 | goto out_err; | ||
298 | 211 | ||
299 | return 0; | 212 | return 0; |
213 | |||
214 | out_err: | ||
215 | sas_notify_lldd_dev_gone(dev); | ||
216 | out_err2: | ||
217 | return res; | ||
300 | } | 218 | } |
301 | 219 | ||
302 | /* ---------- Device registration and unregistration ---------- */ | 220 | /* ---------- Device registration and unregistration ---------- */ |
303 | 221 | ||
304 | void sas_free_device(struct kref *kref) | 222 | static inline void sas_unregister_common_dev(struct domain_device *dev) |
305 | { | ||
306 | struct domain_device *dev = container_of(kref, typeof(*dev), kref); | ||
307 | |||
308 | put_device(&dev->rphy->dev); | ||
309 | dev->rphy = NULL; | ||
310 | |||
311 | if (dev->parent) | ||
312 | sas_put_device(dev->parent); | ||
313 | |||
314 | sas_port_put_phy(dev->phy); | ||
315 | dev->phy = NULL; | ||
316 | |||
317 | /* remove the phys and ports, everything else should be gone */ | ||
318 | if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) | ||
319 | kfree(dev->ex_dev.ex_phy); | ||
320 | |||
321 | if (dev_is_sata(dev) && dev->sata_dev.ap) { | ||
322 | ata_sas_port_destroy(dev->sata_dev.ap); | ||
323 | dev->sata_dev.ap = NULL; | ||
324 | } | ||
325 | |||
326 | kfree(dev); | ||
327 | } | ||
328 | |||
329 | static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev) | ||
330 | { | 223 | { |
331 | struct sas_ha_struct *ha = port->ha; | ||
332 | |||
333 | sas_notify_lldd_dev_gone(dev); | 224 | sas_notify_lldd_dev_gone(dev); |
334 | if (!dev->parent) | 225 | if (!dev->parent) |
335 | dev->port->port_dev = NULL; | 226 | dev->port->port_dev = NULL; |
336 | else | 227 | else |
337 | list_del_init(&dev->siblings); | 228 | list_del_init(&dev->siblings); |
338 | |||
339 | spin_lock_irq(&port->dev_list_lock); | ||
340 | list_del_init(&dev->dev_list_node); | 229 | list_del_init(&dev->dev_list_node); |
341 | if (dev_is_sata(dev)) | ||
342 | sas_ata_end_eh(dev->sata_dev.ap); | ||
343 | spin_unlock_irq(&port->dev_list_lock); | ||
344 | |||
345 | spin_lock_irq(&ha->lock); | ||
346 | if (dev->dev_type == SAS_END_DEV && | ||
347 | !list_empty(&dev->ssp_dev.eh_list_node)) { | ||
348 | list_del_init(&dev->ssp_dev.eh_list_node); | ||
349 | ha->eh_active--; | ||
350 | } | ||
351 | spin_unlock_irq(&ha->lock); | ||
352 | |||
353 | sas_put_device(dev); | ||
354 | } | 230 | } |
355 | 231 | ||
356 | static void sas_destruct_devices(struct work_struct *work) | 232 | void sas_unregister_dev(struct domain_device *dev) |
357 | { | 233 | { |
358 | struct domain_device *dev, *n; | 234 | if (dev->rphy) { |
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 | |||
364 | list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) { | ||
365 | list_del_init(&dev->disco_list_node); | ||
366 | |||
367 | sas_remove_children(&dev->rphy->dev); | 235 | sas_remove_children(&dev->rphy->dev); |
368 | sas_rphy_delete(dev->rphy); | 236 | sas_rphy_delete(dev->rphy); |
369 | sas_unregister_common_dev(port, dev); | 237 | dev->rphy = NULL; |
370 | } | ||
371 | } | ||
372 | |||
373 | void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) | ||
374 | { | ||
375 | if (!test_bit(SAS_DEV_DESTROY, &dev->state) && | ||
376 | !list_empty(&dev->disco_list_node)) { | ||
377 | /* this rphy never saw sas_rphy_add */ | ||
378 | list_del_init(&dev->disco_list_node); | ||
379 | sas_rphy_free(dev->rphy); | ||
380 | sas_unregister_common_dev(port, dev); | ||
381 | return; | ||
382 | } | 238 | } |
383 | 239 | if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) { | |
384 | if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { | 240 | /* remove the phys and ports, everything else should be gone */ |
385 | sas_rphy_unlink(dev->rphy); | 241 | kfree(dev->ex_dev.ex_phy); |
386 | list_move_tail(&dev->disco_list_node, &port->destroy_list); | 242 | dev->ex_dev.ex_phy = NULL; |
387 | sas_discover_event(dev->port, DISCE_DESTRUCT); | ||
388 | } | 243 | } |
244 | sas_unregister_common_dev(dev); | ||
389 | } | 245 | } |
390 | 246 | ||
391 | void sas_unregister_domain_devices(struct asd_sas_port *port, int gone) | 247 | void sas_unregister_domain_devices(struct asd_sas_port *port) |
392 | { | 248 | { |
393 | struct domain_device *dev, *n; | 249 | struct domain_device *dev, *n; |
394 | 250 | ||
395 | list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) { | 251 | list_for_each_entry_safe_reverse(dev,n,&port->dev_list,dev_list_node) |
396 | if (gone) | 252 | sas_unregister_dev(dev); |
397 | set_bit(SAS_DEV_GONE, &dev->state); | ||
398 | sas_unregister_dev(port, dev); | ||
399 | } | ||
400 | |||
401 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) | ||
402 | sas_unregister_dev(port, dev); | ||
403 | 253 | ||
404 | port->port->rphy = NULL; | 254 | port->port->rphy = NULL; |
405 | 255 | ||
406 | } | 256 | } |
407 | 257 | ||
408 | void sas_device_set_phy(struct domain_device *dev, struct sas_port *port) | ||
409 | { | ||
410 | struct sas_ha_struct *ha; | ||
411 | struct sas_phy *new_phy; | ||
412 | |||
413 | if (!dev) | ||
414 | return; | ||
415 | |||
416 | ha = dev->port->ha; | ||
417 | new_phy = sas_port_get_phy(port); | ||
418 | |||
419 | /* pin and record last seen phy */ | ||
420 | spin_lock_irq(&ha->phy_port_lock); | ||
421 | if (new_phy) { | ||
422 | sas_port_put_phy(dev->phy); | ||
423 | dev->phy = new_phy; | ||
424 | } | ||
425 | spin_unlock_irq(&ha->phy_port_lock); | ||
426 | } | ||
427 | |||
428 | /* ---------- Discovery and Revalidation ---------- */ | 258 | /* ---------- Discovery and Revalidation ---------- */ |
429 | 259 | ||
430 | /** | 260 | /** |
@@ -440,10 +270,12 @@ static void sas_discover_domain(struct work_struct *work) | |||
440 | { | 270 | { |
441 | struct domain_device *dev; | 271 | struct domain_device *dev; |
442 | int error = 0; | 272 | int error = 0; |
443 | struct sas_discovery_event *ev = to_sas_discovery_event(work); | 273 | struct sas_discovery_event *ev = |
274 | container_of(work, struct sas_discovery_event, work); | ||
444 | struct asd_sas_port *port = ev->port; | 275 | struct asd_sas_port *port = ev->port; |
445 | 276 | ||
446 | clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending); | 277 | sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock, |
278 | &port->disc.pending); | ||
447 | 279 | ||
448 | if (port->port_dev) | 280 | if (port->port_dev) |
449 | return; | 281 | return; |
@@ -481,12 +313,13 @@ static void sas_discover_domain(struct work_struct *work) | |||
481 | 313 | ||
482 | if (error) { | 314 | if (error) { |
483 | sas_rphy_free(dev->rphy); | 315 | sas_rphy_free(dev->rphy); |
484 | list_del_init(&dev->disco_list_node); | 316 | dev->rphy = NULL; |
317 | |||
485 | spin_lock_irq(&port->dev_list_lock); | 318 | spin_lock_irq(&port->dev_list_lock); |
486 | list_del_init(&dev->dev_list_node); | 319 | list_del_init(&dev->dev_list_node); |
487 | spin_unlock_irq(&port->dev_list_lock); | 320 | spin_unlock_irq(&port->dev_list_lock); |
488 | 321 | ||
489 | sas_put_device(dev); | 322 | kfree(dev); /* not kobject_register-ed yet */ |
490 | port->port_dev = NULL; | 323 | port->port_dev = NULL; |
491 | } | 324 | } |
492 | 325 | ||
@@ -497,57 +330,24 @@ static void sas_discover_domain(struct work_struct *work) | |||
497 | static void sas_revalidate_domain(struct work_struct *work) | 330 | static void sas_revalidate_domain(struct work_struct *work) |
498 | { | 331 | { |
499 | int res = 0; | 332 | int res = 0; |
500 | struct sas_discovery_event *ev = to_sas_discovery_event(work); | 333 | struct sas_discovery_event *ev = |
334 | container_of(work, struct sas_discovery_event, work); | ||
501 | struct asd_sas_port *port = ev->port; | 335 | struct asd_sas_port *port = ev->port; |
502 | struct sas_ha_struct *ha = port->ha; | ||
503 | |||
504 | /* prevent revalidation from finding sata links in recovery */ | ||
505 | mutex_lock(&ha->disco_mutex); | ||
506 | if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) { | ||
507 | SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n", | ||
508 | port->id, task_pid_nr(current)); | ||
509 | goto out; | ||
510 | } | ||
511 | 336 | ||
512 | clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending); | 337 | sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock, |
338 | &port->disc.pending); | ||
513 | 339 | ||
514 | SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, | 340 | SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, |
515 | task_pid_nr(current)); | 341 | task_pid_nr(current)); |
516 | |||
517 | if (port->port_dev) | 342 | if (port->port_dev) |
518 | res = sas_ex_revalidate_domain(port->port_dev); | 343 | res = sas_ex_revalidate_domain(port->port_dev); |
519 | 344 | ||
520 | SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", | 345 | SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", |
521 | port->id, task_pid_nr(current), res); | 346 | port->id, task_pid_nr(current), res); |
522 | out: | ||
523 | mutex_unlock(&ha->disco_mutex); | ||
524 | } | 347 | } |
525 | 348 | ||
526 | /* ---------- Events ---------- */ | 349 | /* ---------- Events ---------- */ |
527 | 350 | ||
528 | static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw) | ||
529 | { | ||
530 | /* chained work is not subject to SA_HA_DRAINING or | ||
531 | * SAS_HA_REGISTERED, because it is either submitted in the | ||
532 | * workqueue, or known to be submitted from a context that is | ||
533 | * not racing against draining | ||
534 | */ | ||
535 | scsi_queue_work(ha->core.shost, &sw->work); | ||
536 | } | ||
537 | |||
538 | static void sas_chain_event(int event, unsigned long *pending, | ||
539 | struct sas_work *sw, | ||
540 | struct sas_ha_struct *ha) | ||
541 | { | ||
542 | if (!test_and_set_bit(event, pending)) { | ||
543 | unsigned long flags; | ||
544 | |||
545 | spin_lock_irqsave(&ha->lock, flags); | ||
546 | sas_chain_work(ha, sw); | ||
547 | spin_unlock_irqrestore(&ha->lock, flags); | ||
548 | } | ||
549 | } | ||
550 | |||
551 | int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) | 351 | int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) |
552 | { | 352 | { |
553 | struct sas_discovery *disc; | 353 | struct sas_discovery *disc; |
@@ -558,7 +358,8 @@ int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) | |||
558 | 358 | ||
559 | BUG_ON(ev >= DISC_NUM_EVENTS); | 359 | BUG_ON(ev >= DISC_NUM_EVENTS); |
560 | 360 | ||
561 | sas_chain_event(ev, &disc->pending, &disc->disc_work[ev].work, port->ha); | 361 | sas_queue_event(ev, &disc->disc_event_lock, &disc->pending, |
362 | &disc->disc_work[ev].work, port->ha); | ||
562 | 363 | ||
563 | return 0; | 364 | return 0; |
564 | } | 365 | } |
@@ -576,15 +377,12 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port) | |||
576 | static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { | 377 | static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { |
577 | [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, | 378 | [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, |
578 | [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, | 379 | [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, |
579 | [DISCE_PROBE] = sas_probe_devices, | ||
580 | [DISCE_SUSPEND] = sas_suspend_devices, | ||
581 | [DISCE_RESUME] = sas_resume_devices, | ||
582 | [DISCE_DESTRUCT] = sas_destruct_devices, | ||
583 | }; | 380 | }; |
584 | 381 | ||
382 | spin_lock_init(&disc->disc_event_lock); | ||
585 | disc->pending = 0; | 383 | disc->pending = 0; |
586 | for (i = 0; i < DISC_NUM_EVENTS; i++) { | 384 | for (i = 0; i < DISC_NUM_EVENTS; i++) { |
587 | INIT_SAS_WORK(&disc->disc_work[i].work, sas_event_fns[i]); | 385 | INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]); |
588 | disc->disc_work[i].port = port; | 386 | disc->disc_work[i].port = port; |
589 | } | 387 | } |
590 | } | 388 | } |