diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 55 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 63 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_event.c | 26 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 5 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 2 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_internal.h | 3 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_port.c | 2 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 18 |
8 files changed, 158 insertions, 16 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 2fc5a3961ca6..4b6365c6410f 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c | |||
@@ -758,6 +758,35 @@ static int sas_discover_sata_pm(struct domain_device *dev) | |||
758 | return -ENODEV; | 758 | return -ENODEV; |
759 | } | 759 | } |
760 | 760 | ||
761 | void sas_probe_sata(struct work_struct *work) | ||
762 | { | ||
763 | struct domain_device *dev, *n; | ||
764 | struct sas_discovery_event *ev = | ||
765 | container_of(work, struct sas_discovery_event, work); | ||
766 | struct asd_sas_port *port = ev->port; | ||
767 | |||
768 | clear_bit(DISCE_PROBE, &port->disc.pending); | ||
769 | |||
770 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { | ||
771 | int err; | ||
772 | |||
773 | spin_lock_irq(&port->dev_list_lock); | ||
774 | list_add_tail(&dev->dev_list_node, &port->dev_list); | ||
775 | spin_unlock_irq(&port->dev_list_lock); | ||
776 | |||
777 | err = sas_rphy_add(dev->rphy); | ||
778 | |||
779 | if (err) { | ||
780 | SAS_DPRINTK("%s: for %s device %16llx returned %d\n", | ||
781 | __func__, dev->parent ? "exp-attached" : | ||
782 | "direct-attached", | ||
783 | SAS_ADDR(dev->sas_addr), err); | ||
784 | sas_unregister_dev(port, dev); | ||
785 | } else | ||
786 | list_del_init(&dev->disco_list_node); | ||
787 | } | ||
788 | } | ||
789 | |||
761 | /** | 790 | /** |
762 | * sas_discover_sata -- discover an STP/SATA domain device | 791 | * sas_discover_sata -- discover an STP/SATA domain device |
763 | * @dev: pointer to struct domain_device of interest | 792 | * @dev: pointer to struct domain_device of interest |
@@ -794,10 +823,15 @@ int sas_discover_sata(struct domain_device *dev) | |||
794 | break; | 823 | break; |
795 | } | 824 | } |
796 | sas_notify_lldd_dev_gone(dev); | 825 | sas_notify_lldd_dev_gone(dev); |
797 | if (!res) { | 826 | |
798 | sas_notify_lldd_dev_found(dev); | 827 | if (res) |
799 | res = sas_rphy_add(dev->rphy); | 828 | return res; |
800 | } | 829 | |
830 | res = sas_notify_lldd_dev_found(dev); | ||
831 | if (res) | ||
832 | return res; | ||
833 | |||
834 | sas_discover_event(dev->port, DISCE_PROBE); | ||
801 | 835 | ||
802 | return res; | 836 | return res; |
803 | } | 837 | } |
@@ -805,6 +839,17 @@ int sas_discover_sata(struct domain_device *dev) | |||
805 | void sas_ata_strategy_handler(struct Scsi_Host *shost) | 839 | void sas_ata_strategy_handler(struct Scsi_Host *shost) |
806 | { | 840 | { |
807 | struct scsi_device *sdev; | 841 | struct scsi_device *sdev; |
842 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); | ||
843 | |||
844 | /* it's ok to defer revalidation events during ata eh, these | ||
845 | * disks are in one of three states: | ||
846 | * 1/ present for initial domain discovery, and these | ||
847 | * resets will cause bcn flutters | ||
848 | * 2/ hot removed, we'll discover that after eh fails | ||
849 | * 3/ hot added after initial discovery, lost the race, and need | ||
850 | * to catch the next train. | ||
851 | */ | ||
852 | sas_disable_revalidation(sas_ha); | ||
808 | 853 | ||
809 | shost_for_each_device(sdev, shost) { | 854 | shost_for_each_device(sdev, shost) { |
810 | struct domain_device *ddev = sdev_to_domain_dev(sdev); | 855 | struct domain_device *ddev = sdev_to_domain_dev(sdev); |
@@ -816,6 +861,8 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost) | |||
816 | ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata port error handler"); | 861 | ata_port_printk(ap, KERN_DEBUG, "sas eh calling libata port error handler"); |
817 | ata_scsi_port_error_handler(shost, ap); | 862 | ata_scsi_port_error_handler(shost, ap); |
818 | } | 863 | } |
864 | |||
865 | sas_enable_revalidation(sas_ha); | ||
819 | } | 866 | } |
820 | 867 | ||
821 | int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task, | 868 | int sas_ata_timed_out(struct scsi_cmnd *cmd, struct sas_task *task, |
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 32e011766046..7e8fdcb202b7 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c | |||
@@ -148,9 +148,14 @@ static int sas_get_port_device(struct asd_sas_port *port) | |||
148 | port->disc.max_level = 0; | 148 | port->disc.max_level = 0; |
149 | 149 | ||
150 | dev->rphy = rphy; | 150 | dev->rphy = rphy; |
151 | spin_lock_irq(&port->dev_list_lock); | 151 | |
152 | list_add_tail(&dev->dev_list_node, &port->dev_list); | 152 | if (dev_is_sata(dev)) |
153 | spin_unlock_irq(&port->dev_list_lock); | 153 | list_add_tail(&dev->disco_list_node, &port->disco_list); |
154 | else { | ||
155 | spin_lock_irq(&port->dev_list_lock); | ||
156 | list_add_tail(&dev->dev_list_node, &port->dev_list); | ||
157 | spin_unlock_irq(&port->dev_list_lock); | ||
158 | } | ||
154 | 159 | ||
155 | return 0; | 160 | return 0; |
156 | } | 161 | } |
@@ -255,14 +260,43 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d | |||
255 | sas_put_device(dev); | 260 | sas_put_device(dev); |
256 | } | 261 | } |
257 | 262 | ||
258 | void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) | 263 | static void sas_destruct_devices(struct work_struct *work) |
259 | { | 264 | { |
260 | if (dev->rphy) { | 265 | struct domain_device *dev, *n; |
266 | struct sas_discovery_event *ev = | ||
267 | container_of(work, struct sas_discovery_event, work); | ||
268 | struct asd_sas_port *port = ev->port; | ||
269 | |||
270 | clear_bit(DISCE_DESTRUCT, &port->disc.pending); | ||
271 | |||
272 | list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) { | ||
273 | list_del_init(&dev->disco_list_node); | ||
274 | |||
261 | sas_remove_children(&dev->rphy->dev); | 275 | sas_remove_children(&dev->rphy->dev); |
262 | sas_rphy_delete(dev->rphy); | 276 | sas_rphy_delete(dev->rphy); |
263 | dev->rphy = NULL; | 277 | dev->rphy = NULL; |
278 | sas_unregister_common_dev(port, dev); | ||
279 | |||
280 | sas_put_device(dev); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) | ||
285 | { | ||
286 | if (!test_bit(SAS_DEV_DESTROY, &dev->state) && | ||
287 | !list_empty(&dev->disco_list_node)) { | ||
288 | /* this rphy never saw sas_rphy_add */ | ||
289 | list_del_init(&dev->disco_list_node); | ||
290 | sas_rphy_free(dev->rphy); | ||
291 | dev->rphy = NULL; | ||
292 | sas_unregister_common_dev(port, dev); | ||
293 | } | ||
294 | |||
295 | if (dev->rphy && !test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { | ||
296 | sas_rphy_unlink(dev->rphy); | ||
297 | list_move_tail(&dev->disco_list_node, &port->destroy_list); | ||
298 | sas_discover_event(dev->port, DISCE_DESTRUCT); | ||
264 | } | 299 | } |
265 | sas_unregister_common_dev(port, dev); | ||
266 | } | 300 | } |
267 | 301 | ||
268 | void sas_unregister_domain_devices(struct asd_sas_port *port) | 302 | void sas_unregister_domain_devices(struct asd_sas_port *port) |
@@ -271,6 +305,8 @@ void sas_unregister_domain_devices(struct asd_sas_port *port) | |||
271 | 305 | ||
272 | list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) | 306 | list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) |
273 | sas_unregister_dev(port, dev); | 307 | sas_unregister_dev(port, dev); |
308 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) | ||
309 | sas_unregister_dev(port, dev); | ||
274 | 310 | ||
275 | port->port->rphy = NULL; | 311 | port->port->rphy = NULL; |
276 | 312 | ||
@@ -335,6 +371,7 @@ static void sas_discover_domain(struct work_struct *work) | |||
335 | sas_rphy_free(dev->rphy); | 371 | sas_rphy_free(dev->rphy); |
336 | dev->rphy = NULL; | 372 | dev->rphy = NULL; |
337 | 373 | ||
374 | list_del_init(&dev->disco_list_node); | ||
338 | spin_lock_irq(&port->dev_list_lock); | 375 | spin_lock_irq(&port->dev_list_lock); |
339 | list_del_init(&dev->dev_list_node); | 376 | list_del_init(&dev->dev_list_node); |
340 | spin_unlock_irq(&port->dev_list_lock); | 377 | spin_unlock_irq(&port->dev_list_lock); |
@@ -353,16 +390,28 @@ static void sas_revalidate_domain(struct work_struct *work) | |||
353 | struct sas_discovery_event *ev = | 390 | struct sas_discovery_event *ev = |
354 | container_of(work, struct sas_discovery_event, work); | 391 | container_of(work, struct sas_discovery_event, work); |
355 | struct asd_sas_port *port = ev->port; | 392 | struct asd_sas_port *port = ev->port; |
393 | struct sas_ha_struct *ha = port->ha; | ||
394 | |||
395 | /* prevent revalidation from finding sata links in recovery */ | ||
396 | mutex_lock(&ha->disco_mutex); | ||
397 | if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) { | ||
398 | SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n", | ||
399 | port->id, task_pid_nr(current)); | ||
400 | goto out; | ||
401 | } | ||
356 | 402 | ||
357 | clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending); | 403 | clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending); |
358 | 404 | ||
359 | SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, | 405 | SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, |
360 | task_pid_nr(current)); | 406 | task_pid_nr(current)); |
407 | |||
361 | if (port->port_dev) | 408 | if (port->port_dev) |
362 | res = sas_ex_revalidate_domain(port->port_dev); | 409 | res = sas_ex_revalidate_domain(port->port_dev); |
363 | 410 | ||
364 | SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", | 411 | SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", |
365 | port->id, task_pid_nr(current), res); | 412 | port->id, task_pid_nr(current), res); |
413 | out: | ||
414 | mutex_unlock(&ha->disco_mutex); | ||
366 | } | 415 | } |
367 | 416 | ||
368 | /* ---------- Events ---------- */ | 417 | /* ---------- Events ---------- */ |
@@ -414,6 +463,8 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port) | |||
414 | static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { | 463 | static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { |
415 | [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, | 464 | [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, |
416 | [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, | 465 | [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, |
466 | [DISCE_PROBE] = sas_probe_sata, | ||
467 | [DISCE_DESTRUCT] = sas_destruct_devices, | ||
417 | }; | 468 | }; |
418 | 469 | ||
419 | disc->pending = 0; | 470 | disc->pending = 0; |
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index e5035aa4c2a6..933d757499b5 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c | |||
@@ -81,6 +81,32 @@ int sas_drain_work(struct sas_ha_struct *ha) | |||
81 | } | 81 | } |
82 | EXPORT_SYMBOL_GPL(sas_drain_work); | 82 | EXPORT_SYMBOL_GPL(sas_drain_work); |
83 | 83 | ||
84 | void sas_disable_revalidation(struct sas_ha_struct *ha) | ||
85 | { | ||
86 | mutex_lock(&ha->disco_mutex); | ||
87 | set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state); | ||
88 | mutex_unlock(&ha->disco_mutex); | ||
89 | } | ||
90 | |||
91 | void sas_enable_revalidation(struct sas_ha_struct *ha) | ||
92 | { | ||
93 | int i; | ||
94 | |||
95 | mutex_lock(&ha->disco_mutex); | ||
96 | clear_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state); | ||
97 | for (i = 0; i < ha->num_phys; i++) { | ||
98 | struct asd_sas_port *port = ha->sas_port[i]; | ||
99 | const int ev = DISCE_REVALIDATE_DOMAIN; | ||
100 | struct sas_discovery *d = &port->disc; | ||
101 | |||
102 | if (!test_and_clear_bit(ev, &d->pending)) | ||
103 | continue; | ||
104 | |||
105 | sas_queue_event(ev, &d->pending, &d->disc_work[ev].work, ha); | ||
106 | } | ||
107 | mutex_unlock(&ha->disco_mutex); | ||
108 | } | ||
109 | |||
84 | static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event) | 110 | static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event) |
85 | { | 111 | { |
86 | BUG_ON(event >= HA_NUM_EVENTS); | 112 | BUG_ON(event >= HA_NUM_EVENTS); |
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index f33d0c9911c4..e45b259dac4c 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c | |||
@@ -704,9 +704,7 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
704 | 704 | ||
705 | child->rphy = rphy; | 705 | child->rphy = rphy; |
706 | 706 | ||
707 | spin_lock_irq(&parent->port->dev_list_lock); | 707 | list_add_tail(&child->disco_list_node, &parent->port->disco_list); |
708 | list_add_tail(&child->dev_list_node, &parent->port->dev_list); | ||
709 | spin_unlock_irq(&parent->port->dev_list_lock); | ||
710 | 708 | ||
711 | res = sas_discover_sata(child); | 709 | res = sas_discover_sata(child); |
712 | if (res) { | 710 | if (res) { |
@@ -756,6 +754,7 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
756 | sas_rphy_free(child->rphy); | 754 | sas_rphy_free(child->rphy); |
757 | child->rphy = NULL; | 755 | child->rphy = NULL; |
758 | 756 | ||
757 | list_del(&child->disco_list_node); | ||
759 | spin_lock_irq(&parent->port->dev_list_lock); | 758 | spin_lock_irq(&parent->port->dev_list_lock); |
760 | list_del(&child->dev_list_node); | 759 | list_del(&child->dev_list_node); |
761 | spin_unlock_irq(&parent->port->dev_list_lock); | 760 | spin_unlock_irq(&parent->port->dev_list_lock); |
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 572b943d7603..52cd11d76664 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c | |||
@@ -104,6 +104,7 @@ int sas_register_ha(struct sas_ha_struct *sas_ha) | |||
104 | { | 104 | { |
105 | int error = 0; | 105 | int error = 0; |
106 | 106 | ||
107 | mutex_init(&sas_ha->disco_mutex); | ||
107 | spin_lock_init(&sas_ha->phy_port_lock); | 108 | spin_lock_init(&sas_ha->phy_port_lock); |
108 | sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr); | 109 | sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr); |
109 | 110 | ||
@@ -168,6 +169,7 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha) | |||
168 | sas_drain_work(sas_ha); | 169 | sas_drain_work(sas_ha); |
169 | 170 | ||
170 | sas_unregister_ports(sas_ha); | 171 | sas_unregister_ports(sas_ha); |
172 | sas_drain_work(sas_ha); | ||
171 | 173 | ||
172 | if (sas_ha->lldd_max_execute_num > 1) { | 174 | if (sas_ha->lldd_max_execute_num > 1) { |
173 | sas_shutdown_queue(sas_ha); | 175 | sas_shutdown_queue(sas_ha); |
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 948ea64cc2eb..ebe9b81ddef5 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h | |||
@@ -56,6 +56,8 @@ enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *); | |||
56 | int sas_init_queue(struct sas_ha_struct *sas_ha); | 56 | int sas_init_queue(struct sas_ha_struct *sas_ha); |
57 | int sas_init_events(struct sas_ha_struct *sas_ha); | 57 | int sas_init_events(struct sas_ha_struct *sas_ha); |
58 | void sas_shutdown_queue(struct sas_ha_struct *sas_ha); | 58 | void sas_shutdown_queue(struct sas_ha_struct *sas_ha); |
59 | void sas_disable_revalidation(struct sas_ha_struct *ha); | ||
60 | void sas_enable_revalidation(struct sas_ha_struct *ha); | ||
59 | 61 | ||
60 | void sas_deform_port(struct asd_sas_phy *phy, int gone); | 62 | void sas_deform_port(struct asd_sas_phy *phy, int gone); |
61 | 63 | ||
@@ -138,6 +140,7 @@ static inline struct domain_device *sas_alloc_device(void) | |||
138 | if (dev) { | 140 | if (dev) { |
139 | INIT_LIST_HEAD(&dev->siblings); | 141 | INIT_LIST_HEAD(&dev->siblings); |
140 | INIT_LIST_HEAD(&dev->dev_list_node); | 142 | INIT_LIST_HEAD(&dev->dev_list_node); |
143 | INIT_LIST_HEAD(&dev->disco_list_node); | ||
141 | kref_init(&dev->kref); | 144 | kref_init(&dev->kref); |
142 | } | 145 | } |
143 | return dev; | 146 | return dev; |
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index d88e55f9732b..2980bde4e34a 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c | |||
@@ -277,6 +277,8 @@ static void sas_init_port(struct asd_sas_port *port, | |||
277 | memset(port, 0, sizeof(*port)); | 277 | memset(port, 0, sizeof(*port)); |
278 | port->id = i; | 278 | port->id = i; |
279 | INIT_LIST_HEAD(&port->dev_list); | 279 | INIT_LIST_HEAD(&port->dev_list); |
280 | INIT_LIST_HEAD(&port->disco_list); | ||
281 | INIT_LIST_HEAD(&port->destroy_list); | ||
280 | spin_lock_init(&port->phy_list_lock); | 282 | spin_lock_init(&port->phy_list_lock); |
281 | INIT_LIST_HEAD(&port->phy_list); | 283 | INIT_LIST_HEAD(&port->phy_list); |
282 | port->ha = sas_ha; | 284 | port->ha = sas_ha; |
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 9d9330ae4213..9421bae8af1a 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c | |||
@@ -1603,6 +1603,20 @@ sas_rphy_delete(struct sas_rphy *rphy) | |||
1603 | EXPORT_SYMBOL(sas_rphy_delete); | 1603 | EXPORT_SYMBOL(sas_rphy_delete); |
1604 | 1604 | ||
1605 | /** | 1605 | /** |
1606 | * sas_rphy_unlink - unlink SAS remote PHY | ||
1607 | * @rphy: SAS remote phy to unlink from its parent port | ||
1608 | * | ||
1609 | * Removes port reference to an rphy | ||
1610 | */ | ||
1611 | void sas_rphy_unlink(struct sas_rphy *rphy) | ||
1612 | { | ||
1613 | struct sas_port *parent = dev_to_sas_port(rphy->dev.parent); | ||
1614 | |||
1615 | parent->rphy = NULL; | ||
1616 | } | ||
1617 | EXPORT_SYMBOL(sas_rphy_unlink); | ||
1618 | |||
1619 | /** | ||
1606 | * sas_rphy_remove - remove SAS remote PHY | 1620 | * sas_rphy_remove - remove SAS remote PHY |
1607 | * @rphy: SAS remote phy to remove | 1621 | * @rphy: SAS remote phy to remove |
1608 | * | 1622 | * |
@@ -1612,7 +1626,6 @@ void | |||
1612 | sas_rphy_remove(struct sas_rphy *rphy) | 1626 | sas_rphy_remove(struct sas_rphy *rphy) |
1613 | { | 1627 | { |
1614 | struct device *dev = &rphy->dev; | 1628 | struct device *dev = &rphy->dev; |
1615 | struct sas_port *parent = dev_to_sas_port(dev->parent); | ||
1616 | 1629 | ||
1617 | switch (rphy->identify.device_type) { | 1630 | switch (rphy->identify.device_type) { |
1618 | case SAS_END_DEVICE: | 1631 | case SAS_END_DEVICE: |
@@ -1626,10 +1639,9 @@ sas_rphy_remove(struct sas_rphy *rphy) | |||
1626 | break; | 1639 | break; |
1627 | } | 1640 | } |
1628 | 1641 | ||
1642 | sas_rphy_unlink(rphy); | ||
1629 | transport_remove_device(dev); | 1643 | transport_remove_device(dev); |
1630 | device_del(dev); | 1644 | device_del(dev); |
1631 | |||
1632 | parent->rphy = NULL; | ||
1633 | } | 1645 | } |
1634 | EXPORT_SYMBOL(sas_rphy_remove); | 1646 | EXPORT_SYMBOL(sas_rphy_remove); |
1635 | 1647 | ||