diff options
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 62 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_event.c | 6 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 48 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 52 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_internal.h | 9 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_port.c | 14 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 290 |
7 files changed, 364 insertions, 117 deletions
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index fb7df7b75811..a65598b1e536 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c | |||
@@ -548,7 +548,7 @@ int sas_discover_sata(struct domain_device *dev) | |||
548 | 548 | ||
549 | res = sas_notify_lldd_dev_found(dev); | 549 | res = sas_notify_lldd_dev_found(dev); |
550 | if (res) | 550 | if (res) |
551 | return res; | 551 | goto out_err2; |
552 | 552 | ||
553 | switch (dev->dev_type) { | 553 | switch (dev->dev_type) { |
554 | case SATA_DEV: | 554 | case SATA_DEV: |
@@ -560,11 +560,23 @@ int sas_discover_sata(struct domain_device *dev) | |||
560 | default: | 560 | default: |
561 | break; | 561 | break; |
562 | } | 562 | } |
563 | if (res) | ||
564 | goto out_err; | ||
563 | 565 | ||
564 | sas_notify_lldd_dev_gone(dev); | 566 | sas_notify_lldd_dev_gone(dev); |
565 | if (!res) { | 567 | res = sas_notify_lldd_dev_found(dev); |
566 | sas_notify_lldd_dev_found(dev); | 568 | if (res) |
567 | } | 569 | goto out_err2; |
570 | |||
571 | res = sas_rphy_add(dev->rphy); | ||
572 | if (res) | ||
573 | goto out_err; | ||
574 | |||
575 | return res; | ||
576 | |||
577 | out_err: | ||
578 | sas_notify_lldd_dev_gone(dev); | ||
579 | out_err2: | ||
568 | return res; | 580 | return res; |
569 | } | 581 | } |
570 | 582 | ||
@@ -580,21 +592,17 @@ int sas_discover_end_dev(struct domain_device *dev) | |||
580 | 592 | ||
581 | res = sas_notify_lldd_dev_found(dev); | 593 | res = sas_notify_lldd_dev_found(dev); |
582 | if (res) | 594 | if (res) |
583 | return res; | 595 | goto out_err2; |
584 | 596 | ||
585 | res = sas_rphy_add(dev->rphy); | 597 | res = sas_rphy_add(dev->rphy); |
586 | if (res) | 598 | if (res) |
587 | goto out_err; | 599 | goto out_err; |
588 | 600 | ||
589 | /* do this to get the end device port attributes which will have | ||
590 | * been scanned in sas_rphy_add */ | ||
591 | sas_notify_lldd_dev_gone(dev); | ||
592 | sas_notify_lldd_dev_found(dev); | ||
593 | |||
594 | return 0; | 601 | return 0; |
595 | 602 | ||
596 | out_err: | 603 | out_err: |
597 | sas_notify_lldd_dev_gone(dev); | 604 | sas_notify_lldd_dev_gone(dev); |
605 | out_err2: | ||
598 | return res; | 606 | return res; |
599 | } | 607 | } |
600 | 608 | ||
@@ -649,6 +657,7 @@ void sas_unregister_domain_devices(struct asd_sas_port *port) | |||
649 | */ | 657 | */ |
650 | static void sas_discover_domain(struct work_struct *work) | 658 | static void sas_discover_domain(struct work_struct *work) |
651 | { | 659 | { |
660 | struct domain_device *dev; | ||
652 | int error = 0; | 661 | int error = 0; |
653 | struct sas_discovery_event *ev = | 662 | struct sas_discovery_event *ev = |
654 | container_of(work, struct sas_discovery_event, work); | 663 | container_of(work, struct sas_discovery_event, work); |
@@ -658,35 +667,42 @@ static void sas_discover_domain(struct work_struct *work) | |||
658 | &port->disc.pending); | 667 | &port->disc.pending); |
659 | 668 | ||
660 | if (port->port_dev) | 669 | if (port->port_dev) |
661 | return ; | 670 | return; |
662 | else { | 671 | |
663 | error = sas_get_port_device(port); | 672 | error = sas_get_port_device(port); |
664 | if (error) | 673 | if (error) |
665 | return; | 674 | return; |
666 | } | 675 | dev = port->port_dev; |
667 | 676 | ||
668 | SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id, | 677 | SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id, |
669 | current->pid); | 678 | current->pid); |
670 | 679 | ||
671 | switch (port->port_dev->dev_type) { | 680 | switch (dev->dev_type) { |
672 | case SAS_END_DEV: | 681 | case SAS_END_DEV: |
673 | error = sas_discover_end_dev(port->port_dev); | 682 | error = sas_discover_end_dev(dev); |
674 | break; | 683 | break; |
675 | case EDGE_DEV: | 684 | case EDGE_DEV: |
676 | case FANOUT_DEV: | 685 | case FANOUT_DEV: |
677 | error = sas_discover_root_expander(port->port_dev); | 686 | error = sas_discover_root_expander(dev); |
678 | break; | 687 | break; |
679 | case SATA_DEV: | 688 | case SATA_DEV: |
680 | case SATA_PM: | 689 | case SATA_PM: |
681 | error = sas_discover_sata(port->port_dev); | 690 | error = sas_discover_sata(dev); |
682 | break; | 691 | break; |
683 | default: | 692 | default: |
684 | SAS_DPRINTK("unhandled device %d\n", port->port_dev->dev_type); | 693 | SAS_DPRINTK("unhandled device %d\n", dev->dev_type); |
685 | break; | 694 | break; |
686 | } | 695 | } |
687 | 696 | ||
688 | if (error) { | 697 | if (error) { |
689 | kfree(port->port_dev); /* not kobject_register-ed yet */ | 698 | sas_rphy_free(dev->rphy); |
699 | dev->rphy = NULL; | ||
700 | |||
701 | spin_lock(&port->dev_list_lock); | ||
702 | list_del_init(&dev->dev_list_node); | ||
703 | spin_unlock(&port->dev_list_lock); | ||
704 | |||
705 | kfree(dev); /* not kobject_register-ed yet */ | ||
690 | port->port_dev = NULL; | 706 | port->port_dev = NULL; |
691 | } | 707 | } |
692 | 708 | ||
@@ -726,7 +742,7 @@ int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) | |||
726 | BUG_ON(ev >= DISC_NUM_EVENTS); | 742 | BUG_ON(ev >= DISC_NUM_EVENTS); |
727 | 743 | ||
728 | sas_queue_event(ev, &disc->disc_event_lock, &disc->pending, | 744 | sas_queue_event(ev, &disc->disc_event_lock, &disc->pending, |
729 | &disc->disc_work[ev].work, port->ha->core.shost); | 745 | &disc->disc_work[ev].work, port->ha); |
730 | 746 | ||
731 | return 0; | 747 | return 0; |
732 | } | 748 | } |
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index d83392ee6823..9db30fb5caf2 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c | |||
@@ -31,7 +31,7 @@ static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event) | |||
31 | BUG_ON(event >= HA_NUM_EVENTS); | 31 | BUG_ON(event >= HA_NUM_EVENTS); |
32 | 32 | ||
33 | sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending, | 33 | sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending, |
34 | &sas_ha->ha_events[event].work, sas_ha->core.shost); | 34 | &sas_ha->ha_events[event].work, sas_ha); |
35 | } | 35 | } |
36 | 36 | ||
37 | static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) | 37 | static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) |
@@ -41,7 +41,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) | |||
41 | BUG_ON(event >= PORT_NUM_EVENTS); | 41 | BUG_ON(event >= PORT_NUM_EVENTS); |
42 | 42 | ||
43 | sas_queue_event(event, &ha->event_lock, &phy->port_events_pending, | 43 | sas_queue_event(event, &ha->event_lock, &phy->port_events_pending, |
44 | &phy->port_events[event].work, ha->core.shost); | 44 | &phy->port_events[event].work, ha); |
45 | } | 45 | } |
46 | 46 | ||
47 | static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) | 47 | static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) |
@@ -51,7 +51,7 @@ static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) | |||
51 | BUG_ON(event >= PHY_NUM_EVENTS); | 51 | BUG_ON(event >= PHY_NUM_EVENTS); |
52 | 52 | ||
53 | sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending, | 53 | sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending, |
54 | &phy->phy_events[event].work, ha->core.shost); | 54 | &phy->phy_events[event].work, ha); |
55 | } | 55 | } |
56 | 56 | ||
57 | int sas_init_events(struct sas_ha_struct *sas_ha) | 57 | 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 d31e6fa466f7..dc70c180e115 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c | |||
@@ -667,8 +667,9 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
667 | return child; | 667 | return child; |
668 | 668 | ||
669 | out_list_del: | 669 | out_list_del: |
670 | sas_rphy_free(child->rphy); | ||
671 | child->rphy = NULL; | ||
670 | list_del(&child->dev_list_node); | 672 | list_del(&child->dev_list_node); |
671 | sas_rphy_free(rphy); | ||
672 | out_free: | 673 | out_free: |
673 | sas_port_delete(phy->port); | 674 | sas_port_delete(phy->port); |
674 | out_err: | 675 | out_err: |
@@ -677,6 +678,29 @@ static struct domain_device *sas_ex_discover_end_dev( | |||
677 | return NULL; | 678 | return NULL; |
678 | } | 679 | } |
679 | 680 | ||
681 | /* See if this phy is part of a wide port */ | ||
682 | static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id) | ||
683 | { | ||
684 | struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id]; | ||
685 | int i; | ||
686 | |||
687 | for (i = 0; i < parent->ex_dev.num_phys; i++) { | ||
688 | struct ex_phy *ephy = &parent->ex_dev.ex_phy[i]; | ||
689 | |||
690 | if (ephy == phy) | ||
691 | continue; | ||
692 | |||
693 | if (!memcmp(phy->attached_sas_addr, ephy->attached_sas_addr, | ||
694 | SAS_ADDR_SIZE) && ephy->port) { | ||
695 | sas_port_add_phy(ephy->port, phy->phy); | ||
696 | phy->phy_state = PHY_DEVICE_DISCOVERED; | ||
697 | return 0; | ||
698 | } | ||
699 | } | ||
700 | |||
701 | return -ENODEV; | ||
702 | } | ||
703 | |||
680 | static struct domain_device *sas_ex_discover_expander( | 704 | static struct domain_device *sas_ex_discover_expander( |
681 | struct domain_device *parent, int phy_id) | 705 | struct domain_device *parent, int phy_id) |
682 | { | 706 | { |
@@ -809,6 +833,13 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) | |||
809 | return res; | 833 | return res; |
810 | } | 834 | } |
811 | 835 | ||
836 | res = sas_ex_join_wide_port(dev, phy_id); | ||
837 | if (!res) { | ||
838 | SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n", | ||
839 | phy_id, SAS_ADDR(ex_phy->attached_sas_addr)); | ||
840 | return res; | ||
841 | } | ||
842 | |||
812 | switch (ex_phy->attached_dev_type) { | 843 | switch (ex_phy->attached_dev_type) { |
813 | case SAS_END_DEV: | 844 | case SAS_END_DEV: |
814 | child = sas_ex_discover_end_dev(dev, phy_id); | 845 | child = sas_ex_discover_end_dev(dev, phy_id); |
@@ -1431,14 +1462,23 @@ int sas_discover_root_expander(struct domain_device *dev) | |||
1431 | int res; | 1462 | int res; |
1432 | struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy); | 1463 | struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy); |
1433 | 1464 | ||
1434 | sas_rphy_add(dev->rphy); | 1465 | res = sas_rphy_add(dev->rphy); |
1466 | if (res) | ||
1467 | goto out_err; | ||
1435 | 1468 | ||
1436 | ex->level = dev->port->disc.max_level; /* 0 */ | 1469 | ex->level = dev->port->disc.max_level; /* 0 */ |
1437 | res = sas_discover_expander(dev); | 1470 | res = sas_discover_expander(dev); |
1438 | if (!res) | 1471 | if (res) |
1439 | sas_ex_bfs_disc(dev->port); | 1472 | goto out_err2; |
1473 | |||
1474 | sas_ex_bfs_disc(dev->port); | ||
1440 | 1475 | ||
1441 | return res; | 1476 | return res; |
1477 | |||
1478 | out_err2: | ||
1479 | sas_rphy_remove(dev->rphy); | ||
1480 | out_err: | ||
1481 | return res; | ||
1442 | } | 1482 | } |
1443 | 1483 | ||
1444 | /* ---------- Domain revalidation ---------- */ | 1484 | /* ---------- Domain revalidation ---------- */ |
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 2f0c07fc3f48..965698c8b7bf 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c | |||
@@ -87,6 +87,9 @@ int sas_register_ha(struct sas_ha_struct *sas_ha) | |||
87 | else if (sas_ha->lldd_queue_size == -1) | 87 | else if (sas_ha->lldd_queue_size == -1) |
88 | sas_ha->lldd_queue_size = 128; /* Sanity */ | 88 | sas_ha->lldd_queue_size = 128; /* Sanity */ |
89 | 89 | ||
90 | sas_ha->state = SAS_HA_REGISTERED; | ||
91 | spin_lock_init(&sas_ha->state_lock); | ||
92 | |||
90 | error = sas_register_phys(sas_ha); | 93 | error = sas_register_phys(sas_ha); |
91 | if (error) { | 94 | if (error) { |
92 | printk(KERN_NOTICE "couldn't register sas phys:%d\n", error); | 95 | printk(KERN_NOTICE "couldn't register sas phys:%d\n", error); |
@@ -127,12 +130,22 @@ Undo_phys: | |||
127 | 130 | ||
128 | int sas_unregister_ha(struct sas_ha_struct *sas_ha) | 131 | int sas_unregister_ha(struct sas_ha_struct *sas_ha) |
129 | { | 132 | { |
133 | unsigned long flags; | ||
134 | |||
135 | /* Set the state to unregistered to avoid further | ||
136 | * events to be queued */ | ||
137 | spin_lock_irqsave(&sas_ha->state_lock, flags); | ||
138 | sas_ha->state = SAS_HA_UNREGISTERED; | ||
139 | spin_unlock_irqrestore(&sas_ha->state_lock, flags); | ||
140 | scsi_flush_work(sas_ha->core.shost); | ||
141 | |||
142 | sas_unregister_ports(sas_ha); | ||
143 | |||
130 | if (sas_ha->lldd_max_execute_num > 1) { | 144 | if (sas_ha->lldd_max_execute_num > 1) { |
131 | sas_shutdown_queue(sas_ha); | 145 | sas_shutdown_queue(sas_ha); |
146 | sas_ha->lldd_max_execute_num = 1; | ||
132 | } | 147 | } |
133 | 148 | ||
134 | sas_unregister_ports(sas_ha); | ||
135 | |||
136 | return 0; | 149 | return 0; |
137 | } | 150 | } |
138 | 151 | ||
@@ -146,6 +159,36 @@ static int sas_get_linkerrors(struct sas_phy *phy) | |||
146 | return sas_smp_get_phy_events(phy); | 159 | return sas_smp_get_phy_events(phy); |
147 | } | 160 | } |
148 | 161 | ||
162 | int sas_phy_enable(struct sas_phy *phy, int enable) | ||
163 | { | ||
164 | int ret; | ||
165 | enum phy_func command; | ||
166 | |||
167 | if (enable) | ||
168 | command = PHY_FUNC_LINK_RESET; | ||
169 | else | ||
170 | command = PHY_FUNC_DISABLE; | ||
171 | |||
172 | if (scsi_is_sas_phy_local(phy)) { | ||
173 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | ||
174 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); | ||
175 | struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; | ||
176 | struct sas_internal *i = | ||
177 | to_sas_internal(sas_ha->core.shost->transportt); | ||
178 | |||
179 | if (!enable) { | ||
180 | sas_phy_disconnected(asd_phy); | ||
181 | sas_ha->notify_phy_event(asd_phy, PHYE_LOSS_OF_SIGNAL); | ||
182 | } | ||
183 | ret = i->dft->lldd_control_phy(asd_phy, command, NULL); | ||
184 | } else { | ||
185 | struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); | ||
186 | struct domain_device *ddev = sas_find_dev_by_rphy(rphy); | ||
187 | ret = sas_smp_phy_control(ddev, phy->number, command, NULL); | ||
188 | } | ||
189 | return ret; | ||
190 | } | ||
191 | |||
149 | int sas_phy_reset(struct sas_phy *phy, int hard_reset) | 192 | int sas_phy_reset(struct sas_phy *phy, int hard_reset) |
150 | { | 193 | { |
151 | int ret; | 194 | int ret; |
@@ -172,8 +215,8 @@ int sas_phy_reset(struct sas_phy *phy, int hard_reset) | |||
172 | return ret; | 215 | return ret; |
173 | } | 216 | } |
174 | 217 | ||
175 | static int sas_set_phy_speed(struct sas_phy *phy, | 218 | int sas_set_phy_speed(struct sas_phy *phy, |
176 | struct sas_phy_linkrates *rates) | 219 | struct sas_phy_linkrates *rates) |
177 | { | 220 | { |
178 | int ret; | 221 | int ret; |
179 | 222 | ||
@@ -212,6 +255,7 @@ static int sas_set_phy_speed(struct sas_phy *phy, | |||
212 | } | 255 | } |
213 | 256 | ||
214 | static struct sas_function_template sft = { | 257 | static struct sas_function_template sft = { |
258 | .phy_enable = sas_phy_enable, | ||
215 | .phy_reset = sas_phy_reset, | 259 | .phy_reset = sas_phy_reset, |
216 | .set_phy_speed = sas_set_phy_speed, | 260 | .set_phy_speed = sas_set_phy_speed, |
217 | .get_linkerrors = sas_get_linkerrors, | 261 | .get_linkerrors = sas_get_linkerrors, |
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 137d7e496b6d..a78638df2018 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h | |||
@@ -80,7 +80,7 @@ void sas_hae_reset(struct work_struct *work); | |||
80 | static inline void sas_queue_event(int event, spinlock_t *lock, | 80 | static inline void sas_queue_event(int event, spinlock_t *lock, |
81 | unsigned long *pending, | 81 | unsigned long *pending, |
82 | struct work_struct *work, | 82 | struct work_struct *work, |
83 | struct Scsi_Host *shost) | 83 | struct sas_ha_struct *sas_ha) |
84 | { | 84 | { |
85 | unsigned long flags; | 85 | unsigned long flags; |
86 | 86 | ||
@@ -91,7 +91,12 @@ static inline void sas_queue_event(int event, spinlock_t *lock, | |||
91 | } | 91 | } |
92 | __set_bit(event, pending); | 92 | __set_bit(event, pending); |
93 | spin_unlock_irqrestore(lock, flags); | 93 | spin_unlock_irqrestore(lock, flags); |
94 | scsi_queue_work(shost, work); | 94 | |
95 | spin_lock_irqsave(&sas_ha->state_lock, flags); | ||
96 | if (sas_ha->state != SAS_HA_UNREGISTERED) { | ||
97 | scsi_queue_work(sas_ha->core.shost, work); | ||
98 | } | ||
99 | spin_unlock_irqrestore(&sas_ha->state_lock, flags); | ||
95 | } | 100 | } |
96 | 101 | ||
97 | static inline void sas_begin_event(int event, spinlock_t *lock, | 102 | static inline void sas_begin_event(int event, spinlock_t *lock, |
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 971c37ceecb4..e1e2d085c920 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c | |||
@@ -42,10 +42,11 @@ static void sas_form_port(struct asd_sas_phy *phy) | |||
42 | struct asd_sas_port *port = phy->port; | 42 | struct asd_sas_port *port = phy->port; |
43 | struct sas_internal *si = | 43 | struct sas_internal *si = |
44 | to_sas_internal(sas_ha->core.shost->transportt); | 44 | to_sas_internal(sas_ha->core.shost->transportt); |
45 | unsigned long flags; | ||
45 | 46 | ||
46 | if (port) { | 47 | if (port) { |
47 | if (memcmp(port->attached_sas_addr, phy->attached_sas_addr, | 48 | if (memcmp(port->attached_sas_addr, phy->attached_sas_addr, |
48 | SAS_ADDR_SIZE) == 0) | 49 | SAS_ADDR_SIZE) != 0) |
49 | sas_deform_port(phy); | 50 | sas_deform_port(phy); |
50 | else { | 51 | else { |
51 | SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n", | 52 | SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n", |
@@ -56,7 +57,7 @@ static void sas_form_port(struct asd_sas_phy *phy) | |||
56 | } | 57 | } |
57 | 58 | ||
58 | /* find a port */ | 59 | /* find a port */ |
59 | spin_lock(&sas_ha->phy_port_lock); | 60 | spin_lock_irqsave(&sas_ha->phy_port_lock, flags); |
60 | for (i = 0; i < sas_ha->num_phys; i++) { | 61 | for (i = 0; i < sas_ha->num_phys; i++) { |
61 | port = sas_ha->sas_port[i]; | 62 | port = sas_ha->sas_port[i]; |
62 | spin_lock(&port->phy_list_lock); | 63 | spin_lock(&port->phy_list_lock); |
@@ -78,7 +79,7 @@ static void sas_form_port(struct asd_sas_phy *phy) | |||
78 | if (i >= sas_ha->num_phys) { | 79 | if (i >= sas_ha->num_phys) { |
79 | printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n", | 80 | printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n", |
80 | __FUNCTION__); | 81 | __FUNCTION__); |
81 | spin_unlock(&sas_ha->phy_port_lock); | 82 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); |
82 | return; | 83 | return; |
83 | } | 84 | } |
84 | 85 | ||
@@ -105,7 +106,7 @@ static void sas_form_port(struct asd_sas_phy *phy) | |||
105 | } else | 106 | } else |
106 | port->linkrate = max(port->linkrate, phy->linkrate); | 107 | port->linkrate = max(port->linkrate, phy->linkrate); |
107 | spin_unlock(&port->phy_list_lock); | 108 | spin_unlock(&port->phy_list_lock); |
108 | spin_unlock(&sas_ha->phy_port_lock); | 109 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); |
109 | 110 | ||
110 | if (!port->port) { | 111 | if (!port->port) { |
111 | port->port = sas_port_alloc(phy->phy->dev.parent, port->id); | 112 | port->port = sas_port_alloc(phy->phy->dev.parent, port->id); |
@@ -137,6 +138,7 @@ void sas_deform_port(struct asd_sas_phy *phy) | |||
137 | struct asd_sas_port *port = phy->port; | 138 | struct asd_sas_port *port = phy->port; |
138 | struct sas_internal *si = | 139 | struct sas_internal *si = |
139 | to_sas_internal(sas_ha->core.shost->transportt); | 140 | to_sas_internal(sas_ha->core.shost->transportt); |
141 | unsigned long flags; | ||
140 | 142 | ||
141 | if (!port) | 143 | if (!port) |
142 | return; /* done by a phy event */ | 144 | return; /* done by a phy event */ |
@@ -155,7 +157,7 @@ void sas_deform_port(struct asd_sas_phy *phy) | |||
155 | if (si->dft->lldd_port_deformed) | 157 | if (si->dft->lldd_port_deformed) |
156 | si->dft->lldd_port_deformed(phy); | 158 | si->dft->lldd_port_deformed(phy); |
157 | 159 | ||
158 | spin_lock(&sas_ha->phy_port_lock); | 160 | spin_lock_irqsave(&sas_ha->phy_port_lock, flags); |
159 | spin_lock(&port->phy_list_lock); | 161 | spin_lock(&port->phy_list_lock); |
160 | 162 | ||
161 | list_del_init(&phy->port_phy_el); | 163 | list_del_init(&phy->port_phy_el); |
@@ -174,7 +176,7 @@ void sas_deform_port(struct asd_sas_phy *phy) | |||
174 | port->phy_mask = 0; | 176 | port->phy_mask = 0; |
175 | } | 177 | } |
176 | spin_unlock(&port->phy_list_lock); | 178 | spin_unlock(&port->phy_list_lock); |
177 | spin_unlock(&sas_ha->phy_port_lock); | 179 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); |
178 | 180 | ||
179 | return; | 181 | return; |
180 | } | 182 | } |
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 22672d54aa27..897a5e2c55e4 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <scsi/scsi_transport_sas.h> | 34 | #include <scsi/scsi_transport_sas.h> |
35 | #include "../scsi_sas_internal.h" | 35 | #include "../scsi_sas_internal.h" |
36 | #include "../scsi_transport_api.h" | 36 | #include "../scsi_transport_api.h" |
37 | #include "../scsi_priv.h" | ||
37 | 38 | ||
38 | #include <linux/err.h> | 39 | #include <linux/err.h> |
39 | #include <linux/blkdev.h> | 40 | #include <linux/blkdev.h> |
@@ -130,7 +131,7 @@ static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd) | |||
130 | if (cmd->request && blk_rq_tagged(cmd->request)) { | 131 | if (cmd->request && blk_rq_tagged(cmd->request)) { |
131 | if (cmd->device->ordered_tags && | 132 | if (cmd->device->ordered_tags && |
132 | (cmd->request->cmd_flags & REQ_HARDBARRIER)) | 133 | (cmd->request->cmd_flags & REQ_HARDBARRIER)) |
133 | ta = TASK_ATTR_HOQ; | 134 | ta = TASK_ATTR_ORDERED; |
134 | } | 135 | } |
135 | return ta; | 136 | return ta; |
136 | } | 137 | } |
@@ -281,6 +282,7 @@ enum task_disposition { | |||
281 | TASK_IS_ABORTED, | 282 | TASK_IS_ABORTED, |
282 | TASK_IS_AT_LU, | 283 | TASK_IS_AT_LU, |
283 | TASK_IS_NOT_AT_LU, | 284 | TASK_IS_NOT_AT_LU, |
285 | TASK_ABORT_FAILED, | ||
284 | }; | 286 | }; |
285 | 287 | ||
286 | static enum task_disposition sas_scsi_find_task(struct sas_task *task) | 288 | static enum task_disposition sas_scsi_find_task(struct sas_task *task) |
@@ -310,15 +312,6 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) | |||
310 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | 312 | spin_unlock_irqrestore(&core->task_queue_lock, flags); |
311 | } | 313 | } |
312 | 314 | ||
313 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
314 | if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { | ||
315 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
316 | SAS_DPRINTK("%s: task 0x%p already aborted\n", | ||
317 | __FUNCTION__, task); | ||
318 | return TASK_IS_ABORTED; | ||
319 | } | ||
320 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
321 | |||
322 | for (i = 0; i < 5; i++) { | 315 | for (i = 0; i < 5; i++) { |
323 | SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); | 316 | SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); |
324 | res = si->dft->lldd_abort_task(task); | 317 | res = si->dft->lldd_abort_task(task); |
@@ -340,15 +333,21 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) | |||
340 | SAS_DPRINTK("%s: querying task 0x%p\n", | 333 | SAS_DPRINTK("%s: querying task 0x%p\n", |
341 | __FUNCTION__, task); | 334 | __FUNCTION__, task); |
342 | res = si->dft->lldd_query_task(task); | 335 | res = si->dft->lldd_query_task(task); |
343 | if (res == TMF_RESP_FUNC_SUCC) { | 336 | switch (res) { |
337 | case TMF_RESP_FUNC_SUCC: | ||
344 | SAS_DPRINTK("%s: task 0x%p at LU\n", | 338 | SAS_DPRINTK("%s: task 0x%p at LU\n", |
345 | __FUNCTION__, task); | 339 | __FUNCTION__, task); |
346 | return TASK_IS_AT_LU; | 340 | return TASK_IS_AT_LU; |
347 | } else if (res == TMF_RESP_FUNC_COMPLETE) { | 341 | case TMF_RESP_FUNC_COMPLETE: |
348 | SAS_DPRINTK("%s: task 0x%p not at LU\n", | 342 | SAS_DPRINTK("%s: task 0x%p not at LU\n", |
349 | __FUNCTION__, task); | 343 | __FUNCTION__, task); |
350 | return TASK_IS_NOT_AT_LU; | 344 | return TASK_IS_NOT_AT_LU; |
351 | } | 345 | case TMF_RESP_FUNC_FAILED: |
346 | SAS_DPRINTK("%s: task 0x%p failed to abort\n", | ||
347 | __FUNCTION__, task); | ||
348 | return TASK_ABORT_FAILED; | ||
349 | } | ||
350 | |||
352 | } | 351 | } |
353 | } | 352 | } |
354 | return res; | 353 | return res; |
@@ -398,35 +397,113 @@ static int sas_recover_I_T(struct domain_device *dev) | |||
398 | return res; | 397 | return res; |
399 | } | 398 | } |
400 | 399 | ||
401 | void sas_scsi_recover_host(struct Scsi_Host *shost) | 400 | /* Find the sas_phy that's attached to this device */ |
401 | struct sas_phy *find_local_sas_phy(struct domain_device *dev) | ||
402 | { | ||
403 | struct domain_device *pdev = dev->parent; | ||
404 | struct ex_phy *exphy = NULL; | ||
405 | int i; | ||
406 | |||
407 | /* Directly attached device */ | ||
408 | if (!pdev) | ||
409 | return dev->port->phy; | ||
410 | |||
411 | /* Otherwise look in the expander */ | ||
412 | for (i = 0; i < pdev->ex_dev.num_phys; i++) | ||
413 | if (!memcmp(dev->sas_addr, | ||
414 | pdev->ex_dev.ex_phy[i].attached_sas_addr, | ||
415 | SAS_ADDR_SIZE)) { | ||
416 | exphy = &pdev->ex_dev.ex_phy[i]; | ||
417 | break; | ||
418 | } | ||
419 | |||
420 | BUG_ON(!exphy); | ||
421 | return exphy->phy; | ||
422 | } | ||
423 | |||
424 | /* Attempt to send a LUN reset message to a device */ | ||
425 | int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) | ||
426 | { | ||
427 | struct domain_device *dev = cmd_to_domain_dev(cmd); | ||
428 | struct sas_internal *i = | ||
429 | to_sas_internal(dev->port->ha->core.shost->transportt); | ||
430 | struct scsi_lun lun; | ||
431 | int res; | ||
432 | |||
433 | int_to_scsilun(cmd->device->lun, &lun); | ||
434 | |||
435 | if (!i->dft->lldd_lu_reset) | ||
436 | return FAILED; | ||
437 | |||
438 | res = i->dft->lldd_lu_reset(dev, lun.scsi_lun); | ||
439 | if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) | ||
440 | return SUCCESS; | ||
441 | |||
442 | return FAILED; | ||
443 | } | ||
444 | |||
445 | /* Attempt to send a phy (bus) reset */ | ||
446 | int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) | ||
447 | { | ||
448 | struct domain_device *dev = cmd_to_domain_dev(cmd); | ||
449 | struct sas_phy *phy = find_local_sas_phy(dev); | ||
450 | int res; | ||
451 | |||
452 | res = sas_phy_reset(phy, 1); | ||
453 | if (res) | ||
454 | SAS_DPRINTK("Bus reset of %s failed 0x%x\n", | ||
455 | phy->dev.kobj.k_name, | ||
456 | res); | ||
457 | if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) | ||
458 | return SUCCESS; | ||
459 | |||
460 | return FAILED; | ||
461 | } | ||
462 | |||
463 | /* Try to reset a device */ | ||
464 | static int try_to_reset_cmd_device(struct Scsi_Host *shost, | ||
465 | struct scsi_cmnd *cmd) | ||
466 | { | ||
467 | int res; | ||
468 | |||
469 | if (!shost->hostt->eh_device_reset_handler) | ||
470 | goto try_bus_reset; | ||
471 | |||
472 | res = shost->hostt->eh_device_reset_handler(cmd); | ||
473 | if (res == SUCCESS) | ||
474 | return res; | ||
475 | |||
476 | try_bus_reset: | ||
477 | if (shost->hostt->eh_bus_reset_handler) | ||
478 | return shost->hostt->eh_bus_reset_handler(cmd); | ||
479 | |||
480 | return FAILED; | ||
481 | } | ||
482 | |||
483 | static int sas_eh_handle_sas_errors(struct Scsi_Host *shost, | ||
484 | struct list_head *work_q, | ||
485 | struct list_head *done_q) | ||
402 | { | 486 | { |
403 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | ||
404 | unsigned long flags; | ||
405 | LIST_HEAD(error_q); | ||
406 | struct scsi_cmnd *cmd, *n; | 487 | struct scsi_cmnd *cmd, *n; |
407 | enum task_disposition res = TASK_IS_DONE; | 488 | enum task_disposition res = TASK_IS_DONE; |
408 | int tmf_resp; | 489 | int tmf_resp, need_reset; |
409 | struct sas_internal *i = to_sas_internal(shost->transportt); | 490 | struct sas_internal *i = to_sas_internal(shost->transportt); |
491 | unsigned long flags; | ||
492 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | ||
410 | 493 | ||
411 | spin_lock_irqsave(shost->host_lock, flags); | ||
412 | list_splice_init(&shost->eh_cmd_q, &error_q); | ||
413 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
414 | |||
415 | SAS_DPRINTK("Enter %s\n", __FUNCTION__); | ||
416 | |||
417 | /* All tasks on this list were marked SAS_TASK_STATE_ABORTED | ||
418 | * by sas_scsi_timed_out() callback. | ||
419 | */ | ||
420 | Again: | 494 | Again: |
421 | SAS_DPRINTK("going over list...\n"); | 495 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { |
422 | list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { | ||
423 | struct sas_task *task = TO_SAS_TASK(cmd); | 496 | struct sas_task *task = TO_SAS_TASK(cmd); |
424 | list_del_init(&cmd->eh_entry); | ||
425 | 497 | ||
426 | if (!task) { | 498 | if (!task) |
427 | SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__); | ||
428 | continue; | 499 | continue; |
429 | } | 500 | |
501 | list_del_init(&cmd->eh_entry); | ||
502 | |||
503 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
504 | need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; | ||
505 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
506 | |||
430 | SAS_DPRINTK("trying to find task 0x%p\n", task); | 507 | SAS_DPRINTK("trying to find task 0x%p\n", task); |
431 | res = sas_scsi_find_task(task); | 508 | res = sas_scsi_find_task(task); |
432 | 509 | ||
@@ -437,11 +514,15 @@ Again: | |||
437 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, | 514 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, |
438 | task); | 515 | task); |
439 | task->task_done(task); | 516 | task->task_done(task); |
517 | if (need_reset) | ||
518 | try_to_reset_cmd_device(shost, cmd); | ||
440 | continue; | 519 | continue; |
441 | case TASK_IS_ABORTED: | 520 | case TASK_IS_ABORTED: |
442 | SAS_DPRINTK("%s: task 0x%p is aborted\n", | 521 | SAS_DPRINTK("%s: task 0x%p is aborted\n", |
443 | __FUNCTION__, task); | 522 | __FUNCTION__, task); |
444 | task->task_done(task); | 523 | task->task_done(task); |
524 | if (need_reset) | ||
525 | try_to_reset_cmd_device(shost, cmd); | ||
445 | continue; | 526 | continue; |
446 | case TASK_IS_AT_LU: | 527 | case TASK_IS_AT_LU: |
447 | SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); | 528 | SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); |
@@ -452,11 +533,14 @@ Again: | |||
452 | SAS_ADDR(task->dev), | 533 | SAS_ADDR(task->dev), |
453 | cmd->device->lun); | 534 | cmd->device->lun); |
454 | task->task_done(task); | 535 | task->task_done(task); |
455 | sas_scsi_clear_queue_lu(&error_q, cmd); | 536 | if (need_reset) |
537 | try_to_reset_cmd_device(shost, cmd); | ||
538 | sas_scsi_clear_queue_lu(work_q, cmd); | ||
456 | goto Again; | 539 | goto Again; |
457 | } | 540 | } |
458 | /* fallthrough */ | 541 | /* fallthrough */ |
459 | case TASK_IS_NOT_AT_LU: | 542 | case TASK_IS_NOT_AT_LU: |
543 | case TASK_ABORT_FAILED: | ||
460 | SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n", | 544 | SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n", |
461 | task); | 545 | task); |
462 | tmf_resp = sas_recover_I_T(task->dev); | 546 | tmf_resp = sas_recover_I_T(task->dev); |
@@ -464,7 +548,9 @@ Again: | |||
464 | SAS_DPRINTK("I_T %016llx recovered\n", | 548 | SAS_DPRINTK("I_T %016llx recovered\n", |
465 | SAS_ADDR(task->dev->sas_addr)); | 549 | SAS_ADDR(task->dev->sas_addr)); |
466 | task->task_done(task); | 550 | task->task_done(task); |
467 | sas_scsi_clear_queue_I_T(&error_q, task->dev); | 551 | if (need_reset) |
552 | try_to_reset_cmd_device(shost, cmd); | ||
553 | sas_scsi_clear_queue_I_T(work_q, task->dev); | ||
468 | goto Again; | 554 | goto Again; |
469 | } | 555 | } |
470 | /* Hammer time :-) */ | 556 | /* Hammer time :-) */ |
@@ -477,7 +563,9 @@ Again: | |||
477 | SAS_DPRINTK("clear nexus port:%d " | 563 | SAS_DPRINTK("clear nexus port:%d " |
478 | "succeeded\n", port->id); | 564 | "succeeded\n", port->id); |
479 | task->task_done(task); | 565 | task->task_done(task); |
480 | sas_scsi_clear_queue_port(&error_q, | 566 | if (need_reset) |
567 | try_to_reset_cmd_device(shost, cmd); | ||
568 | sas_scsi_clear_queue_port(work_q, | ||
481 | port); | 569 | port); |
482 | goto Again; | 570 | goto Again; |
483 | } | 571 | } |
@@ -489,6 +577,8 @@ Again: | |||
489 | SAS_DPRINTK("clear nexus ha " | 577 | SAS_DPRINTK("clear nexus ha " |
490 | "succeeded\n"); | 578 | "succeeded\n"); |
491 | task->task_done(task); | 579 | task->task_done(task); |
580 | if (need_reset) | ||
581 | try_to_reset_cmd_device(shost, cmd); | ||
492 | goto out; | 582 | goto out; |
493 | } | 583 | } |
494 | } | 584 | } |
@@ -502,20 +592,54 @@ Again: | |||
502 | cmd->device->lun); | 592 | cmd->device->lun); |
503 | 593 | ||
504 | task->task_done(task); | 594 | task->task_done(task); |
595 | if (need_reset) | ||
596 | try_to_reset_cmd_device(shost, cmd); | ||
505 | goto clear_q; | 597 | goto clear_q; |
506 | } | 598 | } |
507 | } | 599 | } |
508 | out: | 600 | out: |
509 | scsi_eh_flush_done_q(&ha->eh_done_q); | 601 | return list_empty(work_q); |
510 | SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); | ||
511 | return; | ||
512 | clear_q: | 602 | clear_q: |
513 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); | 603 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); |
514 | list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { | 604 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { |
515 | struct sas_task *task = TO_SAS_TASK(cmd); | 605 | struct sas_task *task = TO_SAS_TASK(cmd); |
516 | list_del_init(&cmd->eh_entry); | 606 | list_del_init(&cmd->eh_entry); |
517 | task->task_done(task); | 607 | task->task_done(task); |
518 | } | 608 | } |
609 | return list_empty(work_q); | ||
610 | } | ||
611 | |||
612 | void sas_scsi_recover_host(struct Scsi_Host *shost) | ||
613 | { | ||
614 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | ||
615 | unsigned long flags; | ||
616 | LIST_HEAD(eh_work_q); | ||
617 | |||
618 | spin_lock_irqsave(shost->host_lock, flags); | ||
619 | list_splice_init(&shost->eh_cmd_q, &eh_work_q); | ||
620 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
621 | |||
622 | SAS_DPRINTK("Enter %s\n", __FUNCTION__); | ||
623 | /* | ||
624 | * Deal with commands that still have SAS tasks (i.e. they didn't | ||
625 | * complete via the normal sas_task completion mechanism) | ||
626 | */ | ||
627 | if (sas_eh_handle_sas_errors(shost, &eh_work_q, &ha->eh_done_q)) | ||
628 | goto out; | ||
629 | |||
630 | /* | ||
631 | * Now deal with SCSI commands that completed ok but have a an error | ||
632 | * code (and hopefully sense data) attached. This is roughly what | ||
633 | * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any | ||
634 | * command we see here has no sas_task and is thus unknown to the HA. | ||
635 | */ | ||
636 | if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q)) | ||
637 | scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); | ||
638 | |||
639 | out: | ||
640 | scsi_eh_flush_done_q(&ha->eh_done_q); | ||
641 | SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); | ||
642 | return; | ||
519 | } | 643 | } |
520 | 644 | ||
521 | enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | 645 | enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) |
@@ -524,24 +648,30 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | |||
524 | unsigned long flags; | 648 | unsigned long flags; |
525 | 649 | ||
526 | if (!task) { | 650 | if (!task) { |
527 | SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n", | 651 | cmd->timeout_per_command /= 2; |
528 | cmd, task); | 652 | SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n", |
529 | return EH_HANDLED; | 653 | cmd, task, (cmd->timeout_per_command ? |
654 | "EH_RESET_TIMER" : "EH_NOT_HANDLED")); | ||
655 | if (!cmd->timeout_per_command) | ||
656 | return EH_NOT_HANDLED; | ||
657 | return EH_RESET_TIMER; | ||
530 | } | 658 | } |
531 | 659 | ||
532 | spin_lock_irqsave(&task->task_state_lock, flags); | 660 | spin_lock_irqsave(&task->task_state_lock, flags); |
533 | if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { | 661 | BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED); |
534 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
535 | SAS_DPRINTK("command 0x%p, task 0x%p, aborted by initiator: " | ||
536 | "EH_NOT_HANDLED\n", cmd, task); | ||
537 | return EH_NOT_HANDLED; | ||
538 | } | ||
539 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | 662 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { |
540 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 663 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
541 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", | 664 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", |
542 | cmd, task); | 665 | cmd, task); |
543 | return EH_HANDLED; | 666 | return EH_HANDLED; |
544 | } | 667 | } |
668 | if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) { | ||
669 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
670 | SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: " | ||
671 | "EH_RESET_TIMER\n", | ||
672 | cmd, task); | ||
673 | return EH_RESET_TIMER; | ||
674 | } | ||
545 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | 675 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; |
546 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 676 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
547 | 677 | ||
@@ -557,8 +687,9 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) | |||
557 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | 687 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); |
558 | struct domain_device *found_dev = NULL; | 688 | struct domain_device *found_dev = NULL; |
559 | int i; | 689 | int i; |
690 | unsigned long flags; | ||
560 | 691 | ||
561 | spin_lock(&ha->phy_port_lock); | 692 | spin_lock_irqsave(&ha->phy_port_lock, flags); |
562 | for (i = 0; i < ha->num_phys; i++) { | 693 | for (i = 0; i < ha->num_phys; i++) { |
563 | struct asd_sas_port *port = ha->sas_port[i]; | 694 | struct asd_sas_port *port = ha->sas_port[i]; |
564 | struct domain_device *dev; | 695 | struct domain_device *dev; |
@@ -574,7 +705,7 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) | |||
574 | spin_unlock(&port->dev_list_lock); | 705 | spin_unlock(&port->dev_list_lock); |
575 | } | 706 | } |
576 | found: | 707 | found: |
577 | spin_unlock(&ha->phy_port_lock); | 708 | spin_unlock_irqrestore(&ha->phy_port_lock, flags); |
578 | 709 | ||
579 | return found_dev; | 710 | return found_dev; |
580 | } | 711 | } |
@@ -623,6 +754,8 @@ int sas_slave_configure(struct scsi_device *scsi_dev) | |||
623 | scsi_deactivate_tcq(scsi_dev, 1); | 754 | scsi_deactivate_tcq(scsi_dev, 1); |
624 | } | 755 | } |
625 | 756 | ||
757 | scsi_dev->allow_restart = 1; | ||
758 | |||
626 | return 0; | 759 | return 0; |
627 | } | 760 | } |
628 | 761 | ||
@@ -799,46 +932,42 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha) | |||
799 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | 932 | spin_unlock_irqrestore(&core->task_queue_lock, flags); |
800 | } | 933 | } |
801 | 934 | ||
802 | static int do_sas_task_abort(struct sas_task *task) | 935 | /* |
936 | * Call the LLDD task abort routine directly. This function is intended for | ||
937 | * use by upper layers that need to tell the LLDD to abort a task. | ||
938 | */ | ||
939 | int __sas_task_abort(struct sas_task *task) | ||
803 | { | 940 | { |
804 | struct scsi_cmnd *sc = task->uldd_task; | ||
805 | struct sas_internal *si = | 941 | struct sas_internal *si = |
806 | to_sas_internal(task->dev->port->ha->core.shost->transportt); | 942 | to_sas_internal(task->dev->port->ha->core.shost->transportt); |
807 | unsigned long flags; | 943 | unsigned long flags; |
808 | int res; | 944 | int res; |
809 | 945 | ||
810 | spin_lock_irqsave(&task->task_state_lock, flags); | 946 | spin_lock_irqsave(&task->task_state_lock, flags); |
811 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { | 947 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED || |
948 | task->task_state_flags & SAS_TASK_STATE_DONE) { | ||
812 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 949 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
813 | SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__, | 950 | SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__, |
814 | task); | 951 | task); |
815 | return 0; | 952 | return 0; |
816 | } | 953 | } |
817 | 954 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | |
818 | task->task_state_flags |= SAS_TASK_INITIATOR_ABORTED; | ||
819 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | ||
820 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | ||
821 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 955 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
822 | 956 | ||
823 | if (!si->dft->lldd_abort_task) | 957 | if (!si->dft->lldd_abort_task) |
824 | return -ENODEV; | 958 | return -ENODEV; |
825 | 959 | ||
826 | res = si->dft->lldd_abort_task(task); | 960 | res = si->dft->lldd_abort_task(task); |
961 | |||
962 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
827 | if ((task->task_state_flags & SAS_TASK_STATE_DONE) || | 963 | if ((task->task_state_flags & SAS_TASK_STATE_DONE) || |
828 | (res == TMF_RESP_FUNC_COMPLETE)) | 964 | (res == TMF_RESP_FUNC_COMPLETE)) |
829 | { | 965 | { |
830 | /* SMP commands don't have scsi_cmds(?) */ | 966 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
831 | if (!sc) { | 967 | task->task_done(task); |
832 | task->task_done(task); | ||
833 | return 0; | ||
834 | } | ||
835 | scsi_req_abort_cmd(sc); | ||
836 | scsi_schedule_eh(sc->device->host); | ||
837 | return 0; | 968 | return 0; |
838 | } | 969 | } |
839 | 970 | ||
840 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
841 | task->task_state_flags &= ~SAS_TASK_INITIATOR_ABORTED; | ||
842 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | 971 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) |
843 | task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; | 972 | task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; |
844 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 973 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
@@ -846,17 +975,24 @@ static int do_sas_task_abort(struct sas_task *task) | |||
846 | return -EAGAIN; | 975 | return -EAGAIN; |
847 | } | 976 | } |
848 | 977 | ||
849 | void sas_task_abort(struct work_struct *work) | 978 | /* |
979 | * Tell an upper layer that it needs to initiate an abort for a given task. | ||
980 | * This should only ever be called by an LLDD. | ||
981 | */ | ||
982 | void sas_task_abort(struct sas_task *task) | ||
850 | { | 983 | { |
851 | struct sas_task *task = | 984 | struct scsi_cmnd *sc = task->uldd_task; |
852 | container_of(work, struct sas_task, abort_work); | ||
853 | int i; | ||
854 | 985 | ||
855 | for (i = 0; i < 5; i++) | 986 | /* Escape for libsas internal commands */ |
856 | if (!do_sas_task_abort(task)) | 987 | if (!sc) { |
988 | if (!del_timer(&task->timer)) | ||
857 | return; | 989 | return; |
990 | task->timer.function(task->timer.data); | ||
991 | return; | ||
992 | } | ||
858 | 993 | ||
859 | SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__); | 994 | scsi_req_abort_cmd(sc); |
995 | scsi_schedule_eh(sc->device->host); | ||
860 | } | 996 | } |
861 | 997 | ||
862 | EXPORT_SYMBOL_GPL(sas_queuecommand); | 998 | EXPORT_SYMBOL_GPL(sas_queuecommand); |
@@ -866,5 +1002,9 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy); | |||
866 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); | 1002 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); |
867 | EXPORT_SYMBOL_GPL(sas_change_queue_type); | 1003 | EXPORT_SYMBOL_GPL(sas_change_queue_type); |
868 | EXPORT_SYMBOL_GPL(sas_bios_param); | 1004 | EXPORT_SYMBOL_GPL(sas_bios_param); |
1005 | EXPORT_SYMBOL_GPL(__sas_task_abort); | ||
869 | EXPORT_SYMBOL_GPL(sas_task_abort); | 1006 | EXPORT_SYMBOL_GPL(sas_task_abort); |
870 | EXPORT_SYMBOL_GPL(sas_phy_reset); | 1007 | EXPORT_SYMBOL_GPL(sas_phy_reset); |
1008 | EXPORT_SYMBOL_GPL(sas_phy_enable); | ||
1009 | EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); | ||
1010 | EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler); | ||