Commit 899fcf40f3177697ccfb029d0484cb8ec09a51ca
Committed by
James Bottomley
1 parent
9a10b33caf
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
[SCSI] libsas: set attached device type and target protocols for local phys
Before: $ cat /sys/class/sas_phy/phy-6\:3/device_type none $ cat /sys/class/sas_phy/phy-6\:3/target_port_protocols none After: $ cat /sys/class/sas_phy/phy-6\:3/device_type end device $ cat /sys/class/sas_phy/phy-6\:3/target_port_protocols sata Also downgrade the phy_list_lock to _irq instead of _irqsave since libsas will never call sas_get_port_device with interrupts disbled. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Showing 3 changed files with 27 additions and 4 deletions Inline Diff
drivers/scsi/libsas/sas_discover.c
1 | /* | 1 | /* |
2 | * Serial Attached SCSI (SAS) Discover process | 2 | * Serial Attached SCSI (SAS) Discover process |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | 4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. |
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | 5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> |
6 | * | 6 | * |
7 | * This file is licensed under GPLv2. | 7 | * This file is licensed under GPLv2. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License as | 10 | * modify it under the terms of the GNU General Public License as |
11 | * published by the Free Software Foundation; either version 2 of the | 11 | * published by the Free Software Foundation; either version 2 of the |
12 | * License, or (at your option) any later version. | 12 | * License, or (at your option) any later version. |
13 | * | 13 | * |
14 | * This program is distributed in the hope that it will be useful, but | 14 | * This program is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * General Public License for more details. | 17 | * General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/scatterlist.h> | 25 | #include <linux/scatterlist.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <scsi/scsi_host.h> | 27 | #include <scsi/scsi_host.h> |
28 | #include <scsi/scsi_eh.h> | 28 | #include <scsi/scsi_eh.h> |
29 | #include "sas_internal.h" | 29 | #include "sas_internal.h" |
30 | 30 | ||
31 | #include <scsi/scsi_transport.h> | 31 | #include <scsi/scsi_transport.h> |
32 | #include <scsi/scsi_transport_sas.h> | 32 | #include <scsi/scsi_transport_sas.h> |
33 | #include <scsi/sas_ata.h> | 33 | #include <scsi/sas_ata.h> |
34 | #include "../scsi_sas_internal.h" | 34 | #include "../scsi_sas_internal.h" |
35 | 35 | ||
36 | /* ---------- Basic task processing for discovery purposes ---------- */ | 36 | /* ---------- Basic task processing for discovery purposes ---------- */ |
37 | 37 | ||
38 | void sas_init_dev(struct domain_device *dev) | 38 | void sas_init_dev(struct domain_device *dev) |
39 | { | 39 | { |
40 | switch (dev->dev_type) { | 40 | switch (dev->dev_type) { |
41 | case SAS_END_DEV: | 41 | case SAS_END_DEV: |
42 | break; | 42 | break; |
43 | case EDGE_DEV: | 43 | case EDGE_DEV: |
44 | case FANOUT_DEV: | 44 | case FANOUT_DEV: |
45 | INIT_LIST_HEAD(&dev->ex_dev.children); | 45 | INIT_LIST_HEAD(&dev->ex_dev.children); |
46 | mutex_init(&dev->ex_dev.cmd_mutex); | 46 | mutex_init(&dev->ex_dev.cmd_mutex); |
47 | break; | 47 | break; |
48 | case SATA_DEV: | 48 | case SATA_DEV: |
49 | case SATA_PM: | 49 | case SATA_PM: |
50 | case SATA_PM_PORT: | 50 | case SATA_PM_PORT: |
51 | case SATA_PENDING: | 51 | case SATA_PENDING: |
52 | INIT_LIST_HEAD(&dev->sata_dev.children); | 52 | INIT_LIST_HEAD(&dev->sata_dev.children); |
53 | break; | 53 | break; |
54 | default: | 54 | default: |
55 | break; | 55 | break; |
56 | } | 56 | } |
57 | } | 57 | } |
58 | 58 | ||
59 | /* ---------- Domain device discovery ---------- */ | 59 | /* ---------- Domain device discovery ---------- */ |
60 | 60 | ||
61 | /** | 61 | /** |
62 | * sas_get_port_device -- Discover devices which caused port creation | 62 | * sas_get_port_device -- Discover devices which caused port creation |
63 | * @port: pointer to struct sas_port of interest | 63 | * @port: pointer to struct sas_port of interest |
64 | * | 64 | * |
65 | * Devices directly attached to a HA port, have no parent. This is | 65 | * Devices directly attached to a HA port, have no parent. This is |
66 | * how we know they are (domain) "root" devices. All other devices | 66 | * how we know they are (domain) "root" devices. All other devices |
67 | * do, and should have their "parent" pointer set appropriately as | 67 | * do, and should have their "parent" pointer set appropriately as |
68 | * soon as a child device is discovered. | 68 | * soon as a child device is discovered. |
69 | */ | 69 | */ |
70 | static int sas_get_port_device(struct asd_sas_port *port) | 70 | static int sas_get_port_device(struct asd_sas_port *port) |
71 | { | 71 | { |
72 | unsigned long flags; | ||
73 | struct asd_sas_phy *phy; | 72 | struct asd_sas_phy *phy; |
74 | struct sas_rphy *rphy; | 73 | struct sas_rphy *rphy; |
75 | struct domain_device *dev; | 74 | struct domain_device *dev; |
76 | 75 | ||
77 | dev = sas_alloc_device(); | 76 | dev = sas_alloc_device(); |
78 | if (!dev) | 77 | if (!dev) |
79 | return -ENOMEM; | 78 | return -ENOMEM; |
80 | 79 | ||
81 | spin_lock_irqsave(&port->phy_list_lock, flags); | 80 | spin_lock_irq(&port->phy_list_lock); |
82 | if (list_empty(&port->phy_list)) { | 81 | if (list_empty(&port->phy_list)) { |
83 | spin_unlock_irqrestore(&port->phy_list_lock, flags); | 82 | spin_unlock_irq(&port->phy_list_lock); |
84 | sas_put_device(dev); | 83 | sas_put_device(dev); |
85 | return -ENODEV; | 84 | return -ENODEV; |
86 | } | 85 | } |
87 | 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); |
88 | spin_lock(&phy->frame_rcvd_lock); | 87 | spin_lock(&phy->frame_rcvd_lock); |
89 | 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), |
90 | (size_t)phy->frame_rcvd_size)); | 89 | (size_t)phy->frame_rcvd_size)); |
91 | spin_unlock(&phy->frame_rcvd_lock); | 90 | spin_unlock(&phy->frame_rcvd_lock); |
92 | spin_unlock_irqrestore(&port->phy_list_lock, flags); | 91 | spin_unlock_irq(&port->phy_list_lock); |
93 | 92 | ||
94 | 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) { |
95 | struct dev_to_host_fis *fis = | 94 | struct dev_to_host_fis *fis = |
96 | (struct dev_to_host_fis *) dev->frame_rcvd; | 95 | (struct dev_to_host_fis *) dev->frame_rcvd; |
97 | if (fis->interrupt_reason == 1 && fis->lbal == 1 && | 96 | if (fis->interrupt_reason == 1 && fis->lbal == 1 && |
98 | fis->byte_count_low==0x69 && fis->byte_count_high == 0x96 | 97 | fis->byte_count_low==0x69 && fis->byte_count_high == 0x96 |
99 | && (fis->device & ~0x10) == 0) | 98 | && (fis->device & ~0x10) == 0) |
100 | dev->dev_type = SATA_PM; | 99 | dev->dev_type = SATA_PM; |
101 | else | 100 | else |
102 | dev->dev_type = SATA_DEV; | 101 | dev->dev_type = SATA_DEV; |
103 | dev->tproto = SAS_PROTOCOL_SATA; | 102 | dev->tproto = SAS_PROTOCOL_SATA; |
104 | } else { | 103 | } else { |
105 | struct sas_identify_frame *id = | 104 | struct sas_identify_frame *id = |
106 | (struct sas_identify_frame *) dev->frame_rcvd; | 105 | (struct sas_identify_frame *) dev->frame_rcvd; |
107 | dev->dev_type = id->dev_type; | 106 | dev->dev_type = id->dev_type; |
108 | dev->iproto = id->initiator_bits; | 107 | dev->iproto = id->initiator_bits; |
109 | dev->tproto = id->target_bits; | 108 | dev->tproto = id->target_bits; |
110 | } | 109 | } |
111 | 110 | ||
112 | sas_init_dev(dev); | 111 | sas_init_dev(dev); |
113 | 112 | ||
114 | switch (dev->dev_type) { | 113 | switch (dev->dev_type) { |
115 | case SAS_END_DEV: | 114 | case SAS_END_DEV: |
116 | case SATA_DEV: | 115 | case SATA_DEV: |
117 | rphy = sas_end_device_alloc(port->port); | 116 | rphy = sas_end_device_alloc(port->port); |
118 | break; | 117 | break; |
119 | case EDGE_DEV: | 118 | case EDGE_DEV: |
120 | rphy = sas_expander_alloc(port->port, | 119 | rphy = sas_expander_alloc(port->port, |
121 | SAS_EDGE_EXPANDER_DEVICE); | 120 | SAS_EDGE_EXPANDER_DEVICE); |
122 | break; | 121 | break; |
123 | case FANOUT_DEV: | 122 | case FANOUT_DEV: |
124 | rphy = sas_expander_alloc(port->port, | 123 | rphy = sas_expander_alloc(port->port, |
125 | SAS_FANOUT_EXPANDER_DEVICE); | 124 | SAS_FANOUT_EXPANDER_DEVICE); |
126 | break; | 125 | break; |
127 | default: | 126 | default: |
128 | printk("ERROR: Unidentified device type %d\n", dev->dev_type); | 127 | printk("ERROR: Unidentified device type %d\n", dev->dev_type); |
129 | rphy = NULL; | 128 | rphy = NULL; |
130 | break; | 129 | break; |
131 | } | 130 | } |
132 | 131 | ||
133 | if (!rphy) { | 132 | if (!rphy) { |
134 | sas_put_device(dev); | 133 | sas_put_device(dev); |
135 | return -ENODEV; | 134 | return -ENODEV; |
136 | } | 135 | } |
136 | |||
137 | spin_lock_irq(&port->phy_list_lock); | ||
138 | list_for_each_entry(phy, &port->phy_list, port_phy_el) | ||
139 | sas_phy_set_target(phy, dev); | ||
140 | spin_unlock_irq(&port->phy_list_lock); | ||
137 | rphy->identify.phy_identifier = phy->phy->identify.phy_identifier; | 141 | rphy->identify.phy_identifier = phy->phy->identify.phy_identifier; |
138 | memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE); | 142 | memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE); |
139 | sas_fill_in_rphy(dev, rphy); | 143 | sas_fill_in_rphy(dev, rphy); |
140 | sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); | 144 | sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); |
141 | port->port_dev = dev; | 145 | port->port_dev = dev; |
142 | dev->port = port; | 146 | dev->port = port; |
143 | dev->linkrate = port->linkrate; | 147 | dev->linkrate = port->linkrate; |
144 | dev->min_linkrate = port->linkrate; | 148 | dev->min_linkrate = port->linkrate; |
145 | dev->max_linkrate = port->linkrate; | 149 | dev->max_linkrate = port->linkrate; |
146 | dev->pathways = port->num_phys; | 150 | dev->pathways = port->num_phys; |
147 | memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE); | 151 | memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE); |
148 | memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE); | 152 | memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE); |
149 | memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE); | 153 | memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE); |
150 | port->disc.max_level = 0; | 154 | port->disc.max_level = 0; |
151 | sas_device_set_phy(dev, port->port); | 155 | sas_device_set_phy(dev, port->port); |
152 | 156 | ||
153 | dev->rphy = rphy; | 157 | dev->rphy = rphy; |
154 | 158 | ||
155 | if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV) | 159 | if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV) |
156 | list_add_tail(&dev->disco_list_node, &port->disco_list); | 160 | list_add_tail(&dev->disco_list_node, &port->disco_list); |
157 | else { | 161 | else { |
158 | spin_lock_irq(&port->dev_list_lock); | 162 | spin_lock_irq(&port->dev_list_lock); |
159 | list_add_tail(&dev->dev_list_node, &port->dev_list); | 163 | list_add_tail(&dev->dev_list_node, &port->dev_list); |
160 | spin_unlock_irq(&port->dev_list_lock); | 164 | spin_unlock_irq(&port->dev_list_lock); |
161 | } | 165 | } |
162 | 166 | ||
163 | return 0; | 167 | return 0; |
164 | } | 168 | } |
165 | 169 | ||
166 | /* ---------- Discover and Revalidate ---------- */ | 170 | /* ---------- Discover and Revalidate ---------- */ |
167 | 171 | ||
168 | int sas_notify_lldd_dev_found(struct domain_device *dev) | 172 | int sas_notify_lldd_dev_found(struct domain_device *dev) |
169 | { | 173 | { |
170 | int res = 0; | 174 | int res = 0; |
171 | struct sas_ha_struct *sas_ha = dev->port->ha; | 175 | struct sas_ha_struct *sas_ha = dev->port->ha; |
172 | struct Scsi_Host *shost = sas_ha->core.shost; | 176 | struct Scsi_Host *shost = sas_ha->core.shost; |
173 | struct sas_internal *i = to_sas_internal(shost->transportt); | 177 | struct sas_internal *i = to_sas_internal(shost->transportt); |
174 | 178 | ||
175 | if (i->dft->lldd_dev_found) { | 179 | if (i->dft->lldd_dev_found) { |
176 | res = i->dft->lldd_dev_found(dev); | 180 | res = i->dft->lldd_dev_found(dev); |
177 | if (res) { | 181 | if (res) { |
178 | printk("sas: driver on pcidev %s cannot handle " | 182 | printk("sas: driver on pcidev %s cannot handle " |
179 | "device %llx, error:%d\n", | 183 | "device %llx, error:%d\n", |
180 | dev_name(sas_ha->dev), | 184 | dev_name(sas_ha->dev), |
181 | SAS_ADDR(dev->sas_addr), res); | 185 | SAS_ADDR(dev->sas_addr), res); |
182 | } | 186 | } |
183 | kref_get(&dev->kref); | 187 | kref_get(&dev->kref); |
184 | } | 188 | } |
185 | return res; | 189 | return res; |
186 | } | 190 | } |
187 | 191 | ||
188 | 192 | ||
189 | void sas_notify_lldd_dev_gone(struct domain_device *dev) | 193 | void sas_notify_lldd_dev_gone(struct domain_device *dev) |
190 | { | 194 | { |
191 | struct sas_ha_struct *sas_ha = dev->port->ha; | 195 | struct sas_ha_struct *sas_ha = dev->port->ha; |
192 | struct Scsi_Host *shost = sas_ha->core.shost; | 196 | struct Scsi_Host *shost = sas_ha->core.shost; |
193 | struct sas_internal *i = to_sas_internal(shost->transportt); | 197 | struct sas_internal *i = to_sas_internal(shost->transportt); |
194 | 198 | ||
195 | if (i->dft->lldd_dev_gone) { | 199 | if (i->dft->lldd_dev_gone) { |
196 | i->dft->lldd_dev_gone(dev); | 200 | i->dft->lldd_dev_gone(dev); |
197 | sas_put_device(dev); | 201 | sas_put_device(dev); |
198 | } | 202 | } |
199 | } | 203 | } |
200 | 204 | ||
201 | static void sas_probe_devices(struct work_struct *work) | 205 | static void sas_probe_devices(struct work_struct *work) |
202 | { | 206 | { |
203 | struct domain_device *dev, *n; | 207 | struct domain_device *dev, *n; |
204 | struct sas_discovery_event *ev = | 208 | struct sas_discovery_event *ev = |
205 | container_of(work, struct sas_discovery_event, work); | 209 | container_of(work, struct sas_discovery_event, work); |
206 | struct asd_sas_port *port = ev->port; | 210 | struct asd_sas_port *port = ev->port; |
207 | 211 | ||
208 | clear_bit(DISCE_PROBE, &port->disc.pending); | 212 | clear_bit(DISCE_PROBE, &port->disc.pending); |
209 | 213 | ||
210 | /* devices must be domain members before link recovery and probe */ | 214 | /* devices must be domain members before link recovery and probe */ |
211 | list_for_each_entry(dev, &port->disco_list, disco_list_node) { | 215 | list_for_each_entry(dev, &port->disco_list, disco_list_node) { |
212 | spin_lock_irq(&port->dev_list_lock); | 216 | spin_lock_irq(&port->dev_list_lock); |
213 | list_add_tail(&dev->dev_list_node, &port->dev_list); | 217 | list_add_tail(&dev->dev_list_node, &port->dev_list); |
214 | spin_unlock_irq(&port->dev_list_lock); | 218 | spin_unlock_irq(&port->dev_list_lock); |
215 | } | 219 | } |
216 | 220 | ||
217 | sas_probe_sata(port); | 221 | sas_probe_sata(port); |
218 | 222 | ||
219 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { | 223 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { |
220 | int err; | 224 | int err; |
221 | 225 | ||
222 | err = sas_rphy_add(dev->rphy); | 226 | err = sas_rphy_add(dev->rphy); |
223 | if (err) | 227 | if (err) |
224 | sas_fail_probe(dev, __func__, err); | 228 | sas_fail_probe(dev, __func__, err); |
225 | else | 229 | else |
226 | list_del_init(&dev->disco_list_node); | 230 | list_del_init(&dev->disco_list_node); |
227 | } | 231 | } |
228 | } | 232 | } |
229 | 233 | ||
230 | /** | 234 | /** |
231 | * sas_discover_end_dev -- discover an end device (SSP, etc) | 235 | * sas_discover_end_dev -- discover an end device (SSP, etc) |
232 | * @end: pointer to domain device of interest | 236 | * @end: pointer to domain device of interest |
233 | * | 237 | * |
234 | * See comment in sas_discover_sata(). | 238 | * See comment in sas_discover_sata(). |
235 | */ | 239 | */ |
236 | int sas_discover_end_dev(struct domain_device *dev) | 240 | int sas_discover_end_dev(struct domain_device *dev) |
237 | { | 241 | { |
238 | int res; | 242 | int res; |
239 | 243 | ||
240 | res = sas_notify_lldd_dev_found(dev); | 244 | res = sas_notify_lldd_dev_found(dev); |
241 | if (res) | 245 | if (res) |
242 | return res; | 246 | return res; |
243 | sas_discover_event(dev->port, DISCE_PROBE); | 247 | sas_discover_event(dev->port, DISCE_PROBE); |
244 | 248 | ||
245 | return 0; | 249 | return 0; |
246 | } | 250 | } |
247 | 251 | ||
248 | /* ---------- Device registration and unregistration ---------- */ | 252 | /* ---------- Device registration and unregistration ---------- */ |
249 | 253 | ||
250 | void sas_free_device(struct kref *kref) | 254 | void sas_free_device(struct kref *kref) |
251 | { | 255 | { |
252 | struct domain_device *dev = container_of(kref, typeof(*dev), kref); | 256 | struct domain_device *dev = container_of(kref, typeof(*dev), kref); |
253 | 257 | ||
254 | if (dev->parent) | 258 | if (dev->parent) |
255 | sas_put_device(dev->parent); | 259 | sas_put_device(dev->parent); |
256 | 260 | ||
257 | sas_port_put_phy(dev->phy); | 261 | sas_port_put_phy(dev->phy); |
258 | dev->phy = NULL; | 262 | dev->phy = NULL; |
259 | 263 | ||
260 | /* remove the phys and ports, everything else should be gone */ | 264 | /* remove the phys and ports, everything else should be gone */ |
261 | if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) | 265 | if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) |
262 | kfree(dev->ex_dev.ex_phy); | 266 | kfree(dev->ex_dev.ex_phy); |
263 | 267 | ||
264 | if (dev_is_sata(dev) && dev->sata_dev.ap) { | 268 | if (dev_is_sata(dev) && dev->sata_dev.ap) { |
265 | ata_sas_port_destroy(dev->sata_dev.ap); | 269 | ata_sas_port_destroy(dev->sata_dev.ap); |
266 | dev->sata_dev.ap = NULL; | 270 | dev->sata_dev.ap = NULL; |
267 | } | 271 | } |
268 | 272 | ||
269 | kfree(dev); | 273 | kfree(dev); |
270 | } | 274 | } |
271 | 275 | ||
272 | static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev) | 276 | static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev) |
273 | { | 277 | { |
274 | sas_notify_lldd_dev_gone(dev); | 278 | sas_notify_lldd_dev_gone(dev); |
275 | if (!dev->parent) | 279 | if (!dev->parent) |
276 | dev->port->port_dev = NULL; | 280 | dev->port->port_dev = NULL; |
277 | else | 281 | else |
278 | list_del_init(&dev->siblings); | 282 | list_del_init(&dev->siblings); |
279 | 283 | ||
280 | spin_lock_irq(&port->dev_list_lock); | 284 | spin_lock_irq(&port->dev_list_lock); |
281 | list_del_init(&dev->dev_list_node); | 285 | list_del_init(&dev->dev_list_node); |
282 | spin_unlock_irq(&port->dev_list_lock); | 286 | spin_unlock_irq(&port->dev_list_lock); |
283 | 287 | ||
284 | sas_put_device(dev); | 288 | sas_put_device(dev); |
285 | } | 289 | } |
286 | 290 | ||
287 | static void sas_destruct_devices(struct work_struct *work) | 291 | static void sas_destruct_devices(struct work_struct *work) |
288 | { | 292 | { |
289 | struct domain_device *dev, *n; | 293 | struct domain_device *dev, *n; |
290 | struct sas_discovery_event *ev = | 294 | struct sas_discovery_event *ev = |
291 | container_of(work, struct sas_discovery_event, work); | 295 | container_of(work, struct sas_discovery_event, work); |
292 | struct asd_sas_port *port = ev->port; | 296 | struct asd_sas_port *port = ev->port; |
293 | 297 | ||
294 | clear_bit(DISCE_DESTRUCT, &port->disc.pending); | 298 | clear_bit(DISCE_DESTRUCT, &port->disc.pending); |
295 | 299 | ||
296 | list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) { | 300 | list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) { |
297 | list_del_init(&dev->disco_list_node); | 301 | list_del_init(&dev->disco_list_node); |
298 | 302 | ||
299 | sas_remove_children(&dev->rphy->dev); | 303 | sas_remove_children(&dev->rphy->dev); |
300 | sas_rphy_delete(dev->rphy); | 304 | sas_rphy_delete(dev->rphy); |
301 | dev->rphy = NULL; | 305 | dev->rphy = NULL; |
302 | sas_unregister_common_dev(port, dev); | 306 | sas_unregister_common_dev(port, dev); |
303 | } | 307 | } |
304 | } | 308 | } |
305 | 309 | ||
306 | void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) | 310 | void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) |
307 | { | 311 | { |
308 | if (!test_bit(SAS_DEV_DESTROY, &dev->state) && | 312 | if (!test_bit(SAS_DEV_DESTROY, &dev->state) && |
309 | !list_empty(&dev->disco_list_node)) { | 313 | !list_empty(&dev->disco_list_node)) { |
310 | /* this rphy never saw sas_rphy_add */ | 314 | /* this rphy never saw sas_rphy_add */ |
311 | list_del_init(&dev->disco_list_node); | 315 | list_del_init(&dev->disco_list_node); |
312 | sas_rphy_free(dev->rphy); | 316 | sas_rphy_free(dev->rphy); |
313 | dev->rphy = NULL; | 317 | dev->rphy = NULL; |
314 | sas_unregister_common_dev(port, dev); | 318 | sas_unregister_common_dev(port, dev); |
315 | } | 319 | } |
316 | 320 | ||
317 | if (dev->rphy && !test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { | 321 | if (dev->rphy && !test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { |
318 | sas_rphy_unlink(dev->rphy); | 322 | sas_rphy_unlink(dev->rphy); |
319 | list_move_tail(&dev->disco_list_node, &port->destroy_list); | 323 | list_move_tail(&dev->disco_list_node, &port->destroy_list); |
320 | sas_discover_event(dev->port, DISCE_DESTRUCT); | 324 | sas_discover_event(dev->port, DISCE_DESTRUCT); |
321 | } | 325 | } |
322 | } | 326 | } |
323 | 327 | ||
324 | void sas_unregister_domain_devices(struct asd_sas_port *port, int gone) | 328 | void sas_unregister_domain_devices(struct asd_sas_port *port, int gone) |
325 | { | 329 | { |
326 | struct domain_device *dev, *n; | 330 | struct domain_device *dev, *n; |
327 | 331 | ||
328 | list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) { | 332 | list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) { |
329 | if (gone) | 333 | if (gone) |
330 | set_bit(SAS_DEV_GONE, &dev->state); | 334 | set_bit(SAS_DEV_GONE, &dev->state); |
331 | sas_unregister_dev(port, dev); | 335 | sas_unregister_dev(port, dev); |
332 | } | 336 | } |
333 | 337 | ||
334 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) | 338 | list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) |
335 | sas_unregister_dev(port, dev); | 339 | sas_unregister_dev(port, dev); |
336 | 340 | ||
337 | port->port->rphy = NULL; | 341 | port->port->rphy = NULL; |
338 | 342 | ||
339 | } | 343 | } |
340 | 344 | ||
341 | void sas_device_set_phy(struct domain_device *dev, struct sas_port *port) | 345 | void sas_device_set_phy(struct domain_device *dev, struct sas_port *port) |
342 | { | 346 | { |
343 | struct sas_ha_struct *ha; | 347 | struct sas_ha_struct *ha; |
344 | struct sas_phy *new_phy; | 348 | struct sas_phy *new_phy; |
345 | 349 | ||
346 | if (!dev) | 350 | if (!dev) |
347 | return; | 351 | return; |
348 | 352 | ||
349 | ha = dev->port->ha; | 353 | ha = dev->port->ha; |
350 | new_phy = sas_port_get_phy(port); | 354 | new_phy = sas_port_get_phy(port); |
351 | 355 | ||
352 | /* pin and record last seen phy */ | 356 | /* pin and record last seen phy */ |
353 | spin_lock_irq(&ha->phy_port_lock); | 357 | spin_lock_irq(&ha->phy_port_lock); |
354 | if (new_phy) { | 358 | if (new_phy) { |
355 | sas_port_put_phy(dev->phy); | 359 | sas_port_put_phy(dev->phy); |
356 | dev->phy = new_phy; | 360 | dev->phy = new_phy; |
357 | } | 361 | } |
358 | spin_unlock_irq(&ha->phy_port_lock); | 362 | spin_unlock_irq(&ha->phy_port_lock); |
359 | } | 363 | } |
360 | 364 | ||
361 | /* ---------- Discovery and Revalidation ---------- */ | 365 | /* ---------- Discovery and Revalidation ---------- */ |
362 | 366 | ||
363 | /** | 367 | /** |
364 | * sas_discover_domain -- discover the domain | 368 | * sas_discover_domain -- discover the domain |
365 | * @port: port to the domain of interest | 369 | * @port: port to the domain of interest |
366 | * | 370 | * |
367 | * NOTE: this process _must_ quit (return) as soon as any connection | 371 | * NOTE: this process _must_ quit (return) as soon as any connection |
368 | * errors are encountered. Connection recovery is done elsewhere. | 372 | * errors are encountered. Connection recovery is done elsewhere. |
369 | * Discover process only interrogates devices in order to discover the | 373 | * Discover process only interrogates devices in order to discover the |
370 | * domain. | 374 | * domain. |
371 | */ | 375 | */ |
372 | static void sas_discover_domain(struct work_struct *work) | 376 | static void sas_discover_domain(struct work_struct *work) |
373 | { | 377 | { |
374 | struct domain_device *dev; | 378 | struct domain_device *dev; |
375 | int error = 0; | 379 | int error = 0; |
376 | struct sas_discovery_event *ev = | 380 | struct sas_discovery_event *ev = |
377 | container_of(work, struct sas_discovery_event, work); | 381 | container_of(work, struct sas_discovery_event, work); |
378 | struct asd_sas_port *port = ev->port; | 382 | struct asd_sas_port *port = ev->port; |
379 | 383 | ||
380 | clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending); | 384 | clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending); |
381 | 385 | ||
382 | if (port->port_dev) | 386 | if (port->port_dev) |
383 | return; | 387 | return; |
384 | 388 | ||
385 | error = sas_get_port_device(port); | 389 | error = sas_get_port_device(port); |
386 | if (error) | 390 | if (error) |
387 | return; | 391 | return; |
388 | dev = port->port_dev; | 392 | dev = port->port_dev; |
389 | 393 | ||
390 | SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id, | 394 | SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id, |
391 | task_pid_nr(current)); | 395 | task_pid_nr(current)); |
392 | 396 | ||
393 | switch (dev->dev_type) { | 397 | switch (dev->dev_type) { |
394 | case SAS_END_DEV: | 398 | case SAS_END_DEV: |
395 | error = sas_discover_end_dev(dev); | 399 | error = sas_discover_end_dev(dev); |
396 | break; | 400 | break; |
397 | case EDGE_DEV: | 401 | case EDGE_DEV: |
398 | case FANOUT_DEV: | 402 | case FANOUT_DEV: |
399 | error = sas_discover_root_expander(dev); | 403 | error = sas_discover_root_expander(dev); |
400 | break; | 404 | break; |
401 | case SATA_DEV: | 405 | case SATA_DEV: |
402 | case SATA_PM: | 406 | case SATA_PM: |
403 | #ifdef CONFIG_SCSI_SAS_ATA | 407 | #ifdef CONFIG_SCSI_SAS_ATA |
404 | error = sas_discover_sata(dev); | 408 | error = sas_discover_sata(dev); |
405 | break; | 409 | break; |
406 | #else | 410 | #else |
407 | SAS_DPRINTK("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n"); | 411 | SAS_DPRINTK("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n"); |
408 | /* Fall through */ | 412 | /* Fall through */ |
409 | #endif | 413 | #endif |
410 | default: | 414 | default: |
411 | error = -ENXIO; | 415 | error = -ENXIO; |
412 | SAS_DPRINTK("unhandled device %d\n", dev->dev_type); | 416 | SAS_DPRINTK("unhandled device %d\n", dev->dev_type); |
413 | break; | 417 | break; |
414 | } | 418 | } |
415 | 419 | ||
416 | if (error) { | 420 | if (error) { |
417 | sas_rphy_free(dev->rphy); | 421 | sas_rphy_free(dev->rphy); |
418 | dev->rphy = NULL; | 422 | dev->rphy = NULL; |
419 | 423 | ||
420 | list_del_init(&dev->disco_list_node); | 424 | list_del_init(&dev->disco_list_node); |
421 | spin_lock_irq(&port->dev_list_lock); | 425 | spin_lock_irq(&port->dev_list_lock); |
422 | list_del_init(&dev->dev_list_node); | 426 | list_del_init(&dev->dev_list_node); |
423 | spin_unlock_irq(&port->dev_list_lock); | 427 | spin_unlock_irq(&port->dev_list_lock); |
424 | 428 | ||
425 | sas_put_device(dev); | 429 | sas_put_device(dev); |
426 | port->port_dev = NULL; | 430 | port->port_dev = NULL; |
427 | } | 431 | } |
428 | 432 | ||
429 | SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id, | 433 | SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id, |
430 | task_pid_nr(current), error); | 434 | task_pid_nr(current), error); |
431 | } | 435 | } |
432 | 436 | ||
433 | static void sas_revalidate_domain(struct work_struct *work) | 437 | static void sas_revalidate_domain(struct work_struct *work) |
434 | { | 438 | { |
435 | int res = 0; | 439 | int res = 0; |
436 | struct sas_discovery_event *ev = | 440 | struct sas_discovery_event *ev = |
437 | container_of(work, struct sas_discovery_event, work); | 441 | container_of(work, struct sas_discovery_event, work); |
438 | struct asd_sas_port *port = ev->port; | 442 | struct asd_sas_port *port = ev->port; |
439 | struct sas_ha_struct *ha = port->ha; | 443 | struct sas_ha_struct *ha = port->ha; |
440 | 444 | ||
441 | /* prevent revalidation from finding sata links in recovery */ | 445 | /* prevent revalidation from finding sata links in recovery */ |
442 | mutex_lock(&ha->disco_mutex); | 446 | mutex_lock(&ha->disco_mutex); |
443 | if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) { | 447 | if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) { |
444 | SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n", | 448 | SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n", |
445 | port->id, task_pid_nr(current)); | 449 | port->id, task_pid_nr(current)); |
446 | goto out; | 450 | goto out; |
447 | } | 451 | } |
448 | 452 | ||
449 | clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending); | 453 | clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending); |
450 | 454 | ||
451 | SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, | 455 | SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, |
452 | task_pid_nr(current)); | 456 | task_pid_nr(current)); |
453 | 457 | ||
454 | if (port->port_dev) | 458 | if (port->port_dev) |
455 | res = sas_ex_revalidate_domain(port->port_dev); | 459 | res = sas_ex_revalidate_domain(port->port_dev); |
456 | 460 | ||
457 | SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", | 461 | SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", |
458 | port->id, task_pid_nr(current), res); | 462 | port->id, task_pid_nr(current), res); |
459 | out: | 463 | out: |
460 | mutex_unlock(&ha->disco_mutex); | 464 | mutex_unlock(&ha->disco_mutex); |
461 | } | 465 | } |
462 | 466 | ||
463 | /* ---------- Events ---------- */ | 467 | /* ---------- Events ---------- */ |
464 | 468 | ||
465 | static void sas_chain_work(struct sas_ha_struct *ha, struct work_struct *work) | 469 | static void sas_chain_work(struct sas_ha_struct *ha, struct work_struct *work) |
466 | { | 470 | { |
467 | /* chained work is not subject to SA_HA_DRAINING or SAS_HA_REGISTERED */ | 471 | /* chained work is not subject to SA_HA_DRAINING or SAS_HA_REGISTERED */ |
468 | scsi_queue_work(ha->core.shost, work); | 472 | scsi_queue_work(ha->core.shost, work); |
469 | } | 473 | } |
470 | 474 | ||
471 | static void sas_chain_event(int event, unsigned long *pending, | 475 | static void sas_chain_event(int event, unsigned long *pending, |
472 | struct work_struct *work, | 476 | struct work_struct *work, |
473 | struct sas_ha_struct *ha) | 477 | struct sas_ha_struct *ha) |
474 | { | 478 | { |
475 | if (!test_and_set_bit(event, pending)) { | 479 | if (!test_and_set_bit(event, pending)) { |
476 | unsigned long flags; | 480 | unsigned long flags; |
477 | 481 | ||
478 | spin_lock_irqsave(&ha->state_lock, flags); | 482 | spin_lock_irqsave(&ha->state_lock, flags); |
479 | sas_chain_work(ha, work); | 483 | sas_chain_work(ha, work); |
480 | spin_unlock_irqrestore(&ha->state_lock, flags); | 484 | spin_unlock_irqrestore(&ha->state_lock, flags); |
481 | } | 485 | } |
482 | } | 486 | } |
483 | 487 | ||
484 | int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) | 488 | int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) |
485 | { | 489 | { |
486 | struct sas_discovery *disc; | 490 | struct sas_discovery *disc; |
487 | 491 | ||
488 | if (!port) | 492 | if (!port) |
489 | return 0; | 493 | return 0; |
490 | disc = &port->disc; | 494 | disc = &port->disc; |
491 | 495 | ||
492 | BUG_ON(ev >= DISC_NUM_EVENTS); | 496 | BUG_ON(ev >= DISC_NUM_EVENTS); |
493 | 497 | ||
494 | sas_chain_event(ev, &disc->pending, &disc->disc_work[ev].work, port->ha); | 498 | sas_chain_event(ev, &disc->pending, &disc->disc_work[ev].work, port->ha); |
495 | 499 | ||
496 | return 0; | 500 | return 0; |
497 | } | 501 | } |
498 | 502 | ||
499 | /** | 503 | /** |
500 | * sas_init_disc -- initialize the discovery struct in the port | 504 | * sas_init_disc -- initialize the discovery struct in the port |
501 | * @port: pointer to struct port | 505 | * @port: pointer to struct port |
502 | * | 506 | * |
503 | * Called when the ports are being initialized. | 507 | * Called when the ports are being initialized. |
504 | */ | 508 | */ |
505 | void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port) | 509 | void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port) |
506 | { | 510 | { |
507 | int i; | 511 | int i; |
508 | 512 | ||
509 | static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { | 513 | static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { |
510 | [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, | 514 | [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, |
511 | [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, | 515 | [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, |
512 | [DISCE_PROBE] = sas_probe_devices, | 516 | [DISCE_PROBE] = sas_probe_devices, |
513 | [DISCE_DESTRUCT] = sas_destruct_devices, | 517 | [DISCE_DESTRUCT] = sas_destruct_devices, |
514 | }; | 518 | }; |
515 | 519 | ||
516 | disc->pending = 0; | 520 | disc->pending = 0; |
517 | for (i = 0; i < DISC_NUM_EVENTS; i++) { | 521 | for (i = 0; i < DISC_NUM_EVENTS; i++) { |
518 | INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]); | 522 | INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]); |
519 | disc->disc_work[i].port = port; | 523 | disc->disc_work[i].port = port; |
520 | } | 524 | } |
521 | } | 525 | } |
drivers/scsi/libsas/sas_internal.h
1 | /* | 1 | /* |
2 | * Serial Attached SCSI (SAS) class internal header file | 2 | * Serial Attached SCSI (SAS) class internal header file |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | 4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. |
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | 5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> |
6 | * | 6 | * |
7 | * This file is licensed under GPLv2. | 7 | * This file is licensed under GPLv2. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License as | 10 | * modify it under the terms of the GNU General Public License as |
11 | * published by the Free Software Foundation; either version 2 of the | 11 | * published by the Free Software Foundation; either version 2 of the |
12 | * License, or (at your option) any later version. | 12 | * License, or (at your option) any later version. |
13 | * | 13 | * |
14 | * This program is distributed in the hope that it will be useful, but | 14 | * This program is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * General Public License for more details. | 17 | * General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
22 | * USA | 22 | * USA |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #ifndef _SAS_INTERNAL_H_ | 26 | #ifndef _SAS_INTERNAL_H_ |
27 | #define _SAS_INTERNAL_H_ | 27 | #define _SAS_INTERNAL_H_ |
28 | 28 | ||
29 | #include <scsi/scsi.h> | 29 | #include <scsi/scsi.h> |
30 | #include <scsi/scsi_host.h> | 30 | #include <scsi/scsi_host.h> |
31 | #include <scsi/scsi_transport_sas.h> | 31 | #include <scsi/scsi_transport_sas.h> |
32 | #include <scsi/libsas.h> | 32 | #include <scsi/libsas.h> |
33 | #include <scsi/sas_ata.h> | ||
33 | 34 | ||
34 | #define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__) | 35 | #define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__) |
35 | 36 | ||
36 | #define SAS_DPRINTK(fmt, ...) printk(KERN_DEBUG "sas: " fmt, ## __VA_ARGS__) | 37 | #define SAS_DPRINTK(fmt, ...) printk(KERN_DEBUG "sas: " fmt, ## __VA_ARGS__) |
37 | 38 | ||
38 | #define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble) | 39 | #define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble) |
39 | #define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0) | 40 | #define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0) |
40 | 41 | ||
41 | struct sas_phy_data { | 42 | struct sas_phy_data { |
42 | /* let reset be performed in sas_queue_work() context */ | 43 | /* let reset be performed in sas_queue_work() context */ |
43 | struct sas_phy *phy; | 44 | struct sas_phy *phy; |
44 | struct mutex event_lock; | 45 | struct mutex event_lock; |
45 | int hard_reset; | 46 | int hard_reset; |
46 | int reset_result; | 47 | int reset_result; |
47 | struct work_struct reset_work; | 48 | struct work_struct reset_work; |
48 | int enable; | 49 | int enable; |
49 | int enable_result; | 50 | int enable_result; |
50 | struct work_struct enable_work; | 51 | struct work_struct enable_work; |
51 | }; | 52 | }; |
52 | 53 | ||
53 | void sas_scsi_recover_host(struct Scsi_Host *shost); | 54 | void sas_scsi_recover_host(struct Scsi_Host *shost); |
54 | 55 | ||
55 | int sas_show_class(enum sas_class class, char *buf); | 56 | int sas_show_class(enum sas_class class, char *buf); |
56 | int sas_show_proto(enum sas_protocol proto, char *buf); | 57 | int sas_show_proto(enum sas_protocol proto, char *buf); |
57 | int sas_show_linkrate(enum sas_linkrate linkrate, char *buf); | 58 | int sas_show_linkrate(enum sas_linkrate linkrate, char *buf); |
58 | int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf); | 59 | int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf); |
59 | 60 | ||
60 | int sas_register_phys(struct sas_ha_struct *sas_ha); | 61 | int sas_register_phys(struct sas_ha_struct *sas_ha); |
61 | void sas_unregister_phys(struct sas_ha_struct *sas_ha); | 62 | void sas_unregister_phys(struct sas_ha_struct *sas_ha); |
62 | 63 | ||
63 | int sas_register_ports(struct sas_ha_struct *sas_ha); | 64 | int sas_register_ports(struct sas_ha_struct *sas_ha); |
64 | void sas_unregister_ports(struct sas_ha_struct *sas_ha); | 65 | void sas_unregister_ports(struct sas_ha_struct *sas_ha); |
65 | 66 | ||
66 | enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *); | 67 | enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *); |
67 | 68 | ||
68 | int sas_init_queue(struct sas_ha_struct *sas_ha); | 69 | int sas_init_queue(struct sas_ha_struct *sas_ha); |
69 | int sas_init_events(struct sas_ha_struct *sas_ha); | 70 | int sas_init_events(struct sas_ha_struct *sas_ha); |
70 | void sas_shutdown_queue(struct sas_ha_struct *sas_ha); | 71 | void sas_shutdown_queue(struct sas_ha_struct *sas_ha); |
71 | void sas_disable_revalidation(struct sas_ha_struct *ha); | 72 | void sas_disable_revalidation(struct sas_ha_struct *ha); |
72 | void sas_enable_revalidation(struct sas_ha_struct *ha); | 73 | void sas_enable_revalidation(struct sas_ha_struct *ha); |
73 | void __sas_drain_work(struct sas_ha_struct *ha); | 74 | void __sas_drain_work(struct sas_ha_struct *ha); |
74 | 75 | ||
75 | void sas_deform_port(struct asd_sas_phy *phy, int gone); | 76 | void sas_deform_port(struct asd_sas_phy *phy, int gone); |
76 | 77 | ||
77 | void sas_porte_bytes_dmaed(struct work_struct *work); | 78 | void sas_porte_bytes_dmaed(struct work_struct *work); |
78 | void sas_porte_broadcast_rcvd(struct work_struct *work); | 79 | void sas_porte_broadcast_rcvd(struct work_struct *work); |
79 | void sas_porte_link_reset_err(struct work_struct *work); | 80 | void sas_porte_link_reset_err(struct work_struct *work); |
80 | void sas_porte_timer_event(struct work_struct *work); | 81 | void sas_porte_timer_event(struct work_struct *work); |
81 | void sas_porte_hard_reset(struct work_struct *work); | 82 | void sas_porte_hard_reset(struct work_struct *work); |
82 | void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work); | 83 | void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work); |
83 | 84 | ||
84 | int sas_notify_lldd_dev_found(struct domain_device *); | 85 | int sas_notify_lldd_dev_found(struct domain_device *); |
85 | void sas_notify_lldd_dev_gone(struct domain_device *); | 86 | void sas_notify_lldd_dev_gone(struct domain_device *); |
86 | 87 | ||
87 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, | 88 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, |
88 | enum phy_func phy_func, struct sas_phy_linkrates *); | 89 | enum phy_func phy_func, struct sas_phy_linkrates *); |
89 | int sas_smp_get_phy_events(struct sas_phy *phy); | 90 | int sas_smp_get_phy_events(struct sas_phy *phy); |
90 | 91 | ||
91 | void sas_device_set_phy(struct domain_device *dev, struct sas_port *port); | 92 | void sas_device_set_phy(struct domain_device *dev, struct sas_port *port); |
92 | struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); | 93 | struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); |
93 | struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); | 94 | struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); |
94 | int sas_ex_phy_discover(struct domain_device *dev, int single); | 95 | int sas_ex_phy_discover(struct domain_device *dev, int single); |
95 | int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, | 96 | int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, |
96 | struct smp_resp *rps_resp); | 97 | struct smp_resp *rps_resp); |
97 | int sas_try_ata_reset(struct asd_sas_phy *phy); | 98 | int sas_try_ata_reset(struct asd_sas_phy *phy); |
98 | void sas_hae_reset(struct work_struct *work); | 99 | void sas_hae_reset(struct work_struct *work); |
99 | 100 | ||
100 | void sas_free_device(struct kref *kref); | 101 | void sas_free_device(struct kref *kref); |
101 | 102 | ||
102 | #ifdef CONFIG_SCSI_SAS_HOST_SMP | 103 | #ifdef CONFIG_SCSI_SAS_HOST_SMP |
103 | extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, | 104 | extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, |
104 | struct request *rsp); | 105 | struct request *rsp); |
105 | #else | 106 | #else |
106 | static inline int sas_smp_host_handler(struct Scsi_Host *shost, | 107 | static inline int sas_smp_host_handler(struct Scsi_Host *shost, |
107 | struct request *req, | 108 | struct request *req, |
108 | struct request *rsp) | 109 | struct request *rsp) |
109 | { | 110 | { |
110 | shost_printk(KERN_ERR, shost, | 111 | shost_printk(KERN_ERR, shost, |
111 | "Cannot send SMP to a sas host (not enabled in CONFIG)\n"); | 112 | "Cannot send SMP to a sas host (not enabled in CONFIG)\n"); |
112 | return -EINVAL; | 113 | return -EINVAL; |
113 | } | 114 | } |
114 | #endif | 115 | #endif |
115 | 116 | ||
116 | static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err) | 117 | static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err) |
117 | { | 118 | { |
118 | SAS_DPRINTK("%s: for %s device %16llx returned %d\n", | 119 | SAS_DPRINTK("%s: for %s device %16llx returned %d\n", |
119 | func, dev->parent ? "exp-attached" : | 120 | func, dev->parent ? "exp-attached" : |
120 | "direct-attached", | 121 | "direct-attached", |
121 | SAS_ADDR(dev->sas_addr), err); | 122 | SAS_ADDR(dev->sas_addr), err); |
122 | sas_unregister_dev(dev->port, dev); | 123 | sas_unregister_dev(dev->port, dev); |
123 | } | 124 | } |
124 | 125 | ||
125 | static inline void sas_fill_in_rphy(struct domain_device *dev, | 126 | static inline void sas_fill_in_rphy(struct domain_device *dev, |
126 | struct sas_rphy *rphy) | 127 | struct sas_rphy *rphy) |
127 | { | 128 | { |
128 | rphy->identify.sas_address = SAS_ADDR(dev->sas_addr); | 129 | rphy->identify.sas_address = SAS_ADDR(dev->sas_addr); |
129 | rphy->identify.initiator_port_protocols = dev->iproto; | 130 | rphy->identify.initiator_port_protocols = dev->iproto; |
130 | rphy->identify.target_port_protocols = dev->tproto; | 131 | rphy->identify.target_port_protocols = dev->tproto; |
131 | switch (dev->dev_type) { | 132 | switch (dev->dev_type) { |
132 | case SATA_DEV: | 133 | case SATA_DEV: |
133 | /* FIXME: need sata device type */ | 134 | /* FIXME: need sata device type */ |
134 | case SAS_END_DEV: | 135 | case SAS_END_DEV: |
135 | case SATA_PENDING: | 136 | case SATA_PENDING: |
136 | rphy->identify.device_type = SAS_END_DEVICE; | 137 | rphy->identify.device_type = SAS_END_DEVICE; |
137 | break; | 138 | break; |
138 | case EDGE_DEV: | 139 | case EDGE_DEV: |
139 | rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE; | 140 | rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE; |
140 | break; | 141 | break; |
141 | case FANOUT_DEV: | 142 | case FANOUT_DEV: |
142 | rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE; | 143 | rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE; |
143 | break; | 144 | break; |
144 | default: | 145 | default: |
145 | rphy->identify.device_type = SAS_PHY_UNUSED; | 146 | rphy->identify.device_type = SAS_PHY_UNUSED; |
146 | break; | 147 | break; |
148 | } | ||
149 | } | ||
150 | |||
151 | static inline void sas_phy_set_target(struct asd_sas_phy *p, struct domain_device *dev) | ||
152 | { | ||
153 | struct sas_phy *phy = p->phy; | ||
154 | |||
155 | if (dev) { | ||
156 | if (dev_is_sata(dev)) | ||
157 | phy->identify.device_type = SAS_END_DEVICE; | ||
158 | else | ||
159 | phy->identify.device_type = dev->dev_type; | ||
160 | phy->identify.target_port_protocols = dev->tproto; | ||
161 | } else { | ||
162 | phy->identify.device_type = SAS_PHY_UNUSED; | ||
163 | phy->identify.target_port_protocols = 0; | ||
147 | } | 164 | } |
148 | } | 165 | } |
149 | 166 | ||
150 | static inline void sas_add_parent_port(struct domain_device *dev, int phy_id) | 167 | static inline void sas_add_parent_port(struct domain_device *dev, int phy_id) |
151 | { | 168 | { |
152 | struct expander_device *ex = &dev->ex_dev; | 169 | struct expander_device *ex = &dev->ex_dev; |
153 | struct ex_phy *ex_phy = &ex->ex_phy[phy_id]; | 170 | struct ex_phy *ex_phy = &ex->ex_phy[phy_id]; |
154 | 171 | ||
155 | if (!ex->parent_port) { | 172 | if (!ex->parent_port) { |
156 | ex->parent_port = sas_port_alloc(&dev->rphy->dev, phy_id); | 173 | ex->parent_port = sas_port_alloc(&dev->rphy->dev, phy_id); |
157 | /* FIXME: error handling */ | 174 | /* FIXME: error handling */ |
158 | BUG_ON(!ex->parent_port); | 175 | BUG_ON(!ex->parent_port); |
159 | BUG_ON(sas_port_add(ex->parent_port)); | 176 | BUG_ON(sas_port_add(ex->parent_port)); |
160 | sas_port_mark_backlink(ex->parent_port); | 177 | sas_port_mark_backlink(ex->parent_port); |
161 | } | 178 | } |
162 | sas_port_add_phy(ex->parent_port, ex_phy->phy); | 179 | sas_port_add_phy(ex->parent_port, ex_phy->phy); |
163 | } | 180 | } |
164 | 181 | ||
165 | static inline struct domain_device *sas_alloc_device(void) | 182 | static inline struct domain_device *sas_alloc_device(void) |
166 | { | 183 | { |
167 | struct domain_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 184 | struct domain_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
168 | 185 | ||
169 | if (dev) { | 186 | if (dev) { |
170 | INIT_LIST_HEAD(&dev->siblings); | 187 | INIT_LIST_HEAD(&dev->siblings); |
171 | INIT_LIST_HEAD(&dev->dev_list_node); | 188 | INIT_LIST_HEAD(&dev->dev_list_node); |
172 | INIT_LIST_HEAD(&dev->disco_list_node); | 189 | INIT_LIST_HEAD(&dev->disco_list_node); |
173 | kref_init(&dev->kref); | 190 | kref_init(&dev->kref); |
174 | spin_lock_init(&dev->done_lock); | 191 | spin_lock_init(&dev->done_lock); |
175 | } | 192 | } |
176 | return dev; | 193 | return dev; |
177 | } | 194 | } |
178 | 195 | ||
179 | static inline void sas_put_device(struct domain_device *dev) | 196 | static inline void sas_put_device(struct domain_device *dev) |
180 | { | 197 | { |
181 | kref_put(&dev->kref, sas_free_device); | 198 | kref_put(&dev->kref, sas_free_device); |
182 | } | 199 | } |
183 | 200 | ||
184 | #endif /* _SAS_INTERNAL_H_ */ | 201 | #endif /* _SAS_INTERNAL_H_ */ |
185 | 202 |
drivers/scsi/libsas/sas_port.c
1 | /* | 1 | /* |
2 | * Serial Attached SCSI (SAS) Port class | 2 | * Serial Attached SCSI (SAS) Port class |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | 4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. |
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | 5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> |
6 | * | 6 | * |
7 | * This file is licensed under GPLv2. | 7 | * This file is licensed under GPLv2. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License as | 10 | * modify it under the terms of the GNU General Public License as |
11 | * published by the Free Software Foundation; either version 2 of the | 11 | * published by the Free Software Foundation; either version 2 of the |
12 | * License, or (at your option) any later version. | 12 | * License, or (at your option) any later version. |
13 | * | 13 | * |
14 | * This program is distributed in the hope that it will be useful, but | 14 | * This program is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * General Public License for more details. | 17 | * General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "sas_internal.h" | 25 | #include "sas_internal.h" |
26 | 26 | ||
27 | #include <scsi/scsi_transport.h> | 27 | #include <scsi/scsi_transport.h> |
28 | #include <scsi/scsi_transport_sas.h> | 28 | #include <scsi/scsi_transport_sas.h> |
29 | #include "../scsi_sas_internal.h" | 29 | #include "../scsi_sas_internal.h" |
30 | 30 | ||
31 | static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy *phy) | 31 | static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy *phy) |
32 | { | 32 | { |
33 | struct sas_ha_struct *sas_ha = phy->ha; | 33 | struct sas_ha_struct *sas_ha = phy->ha; |
34 | 34 | ||
35 | if (memcmp(port->attached_sas_addr, phy->attached_sas_addr, | 35 | if (memcmp(port->attached_sas_addr, phy->attached_sas_addr, |
36 | SAS_ADDR_SIZE) != 0 || (sas_ha->strict_wide_ports && | 36 | SAS_ADDR_SIZE) != 0 || (sas_ha->strict_wide_ports && |
37 | memcmp(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE) != 0)) | 37 | memcmp(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE) != 0)) |
38 | return false; | 38 | return false; |
39 | return true; | 39 | return true; |
40 | } | 40 | } |
41 | 41 | ||
42 | /** | 42 | /** |
43 | * sas_form_port -- add this phy to a port | 43 | * sas_form_port -- add this phy to a port |
44 | * @phy: the phy of interest | 44 | * @phy: the phy of interest |
45 | * | 45 | * |
46 | * This function adds this phy to an existing port, thus creating a wide | 46 | * This function adds this phy to an existing port, thus creating a wide |
47 | * port, or it creates a port and adds the phy to the port. | 47 | * port, or it creates a port and adds the phy to the port. |
48 | */ | 48 | */ |
49 | static void sas_form_port(struct asd_sas_phy *phy) | 49 | static void sas_form_port(struct asd_sas_phy *phy) |
50 | { | 50 | { |
51 | int i; | 51 | int i; |
52 | struct sas_ha_struct *sas_ha = phy->ha; | 52 | struct sas_ha_struct *sas_ha = phy->ha; |
53 | struct asd_sas_port *port = phy->port; | 53 | struct asd_sas_port *port = phy->port; |
54 | struct sas_internal *si = | 54 | struct sas_internal *si = |
55 | to_sas_internal(sas_ha->core.shost->transportt); | 55 | to_sas_internal(sas_ha->core.shost->transportt); |
56 | unsigned long flags; | 56 | unsigned long flags; |
57 | 57 | ||
58 | if (port) { | 58 | if (port) { |
59 | if (!phy_is_wideport_member(port, phy)) | 59 | if (!phy_is_wideport_member(port, phy)) |
60 | sas_deform_port(phy, 0); | 60 | sas_deform_port(phy, 0); |
61 | else { | 61 | else { |
62 | SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n", | 62 | SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n", |
63 | __func__, phy->id, phy->port->id, | 63 | __func__, phy->id, phy->port->id, |
64 | phy->port->num_phys); | 64 | phy->port->num_phys); |
65 | return; | 65 | return; |
66 | } | 66 | } |
67 | } | 67 | } |
68 | 68 | ||
69 | /* see if the phy should be part of a wide port */ | 69 | /* see if the phy should be part of a wide port */ |
70 | spin_lock_irqsave(&sas_ha->phy_port_lock, flags); | 70 | spin_lock_irqsave(&sas_ha->phy_port_lock, flags); |
71 | for (i = 0; i < sas_ha->num_phys; i++) { | 71 | for (i = 0; i < sas_ha->num_phys; i++) { |
72 | port = sas_ha->sas_port[i]; | 72 | port = sas_ha->sas_port[i]; |
73 | spin_lock(&port->phy_list_lock); | 73 | spin_lock(&port->phy_list_lock); |
74 | if (*(u64 *) port->sas_addr && | 74 | if (*(u64 *) port->sas_addr && |
75 | phy_is_wideport_member(port, phy) && port->num_phys > 0) { | 75 | phy_is_wideport_member(port, phy) && port->num_phys > 0) { |
76 | /* wide port */ | 76 | /* wide port */ |
77 | SAS_DPRINTK("phy%d matched wide port%d\n", phy->id, | 77 | SAS_DPRINTK("phy%d matched wide port%d\n", phy->id, |
78 | port->id); | 78 | port->id); |
79 | break; | 79 | break; |
80 | } | 80 | } |
81 | spin_unlock(&port->phy_list_lock); | 81 | spin_unlock(&port->phy_list_lock); |
82 | } | 82 | } |
83 | /* The phy does not match any existing port, create a new one */ | 83 | /* The phy does not match any existing port, create a new one */ |
84 | if (i == sas_ha->num_phys) { | 84 | if (i == sas_ha->num_phys) { |
85 | for (i = 0; i < sas_ha->num_phys; i++) { | 85 | for (i = 0; i < sas_ha->num_phys; i++) { |
86 | port = sas_ha->sas_port[i]; | 86 | port = sas_ha->sas_port[i]; |
87 | spin_lock(&port->phy_list_lock); | 87 | spin_lock(&port->phy_list_lock); |
88 | if (*(u64 *)port->sas_addr == 0 | 88 | if (*(u64 *)port->sas_addr == 0 |
89 | && port->num_phys == 0) { | 89 | && port->num_phys == 0) { |
90 | memcpy(port->sas_addr, phy->sas_addr, | 90 | memcpy(port->sas_addr, phy->sas_addr, |
91 | SAS_ADDR_SIZE); | 91 | SAS_ADDR_SIZE); |
92 | break; | 92 | break; |
93 | } | 93 | } |
94 | spin_unlock(&port->phy_list_lock); | 94 | spin_unlock(&port->phy_list_lock); |
95 | } | 95 | } |
96 | } | 96 | } |
97 | 97 | ||
98 | if (i >= sas_ha->num_phys) { | 98 | if (i >= sas_ha->num_phys) { |
99 | printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n", | 99 | printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n", |
100 | __func__); | 100 | __func__); |
101 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); | 101 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); |
102 | return; | 102 | return; |
103 | } | 103 | } |
104 | 104 | ||
105 | /* add the phy to the port */ | 105 | /* add the phy to the port */ |
106 | list_add_tail(&phy->port_phy_el, &port->phy_list); | 106 | list_add_tail(&phy->port_phy_el, &port->phy_list); |
107 | sas_phy_set_target(phy, port->port_dev); | ||
107 | phy->port = port; | 108 | phy->port = port; |
108 | port->num_phys++; | 109 | port->num_phys++; |
109 | port->phy_mask |= (1U << phy->id); | 110 | port->phy_mask |= (1U << phy->id); |
110 | 111 | ||
111 | if (*(u64 *)port->attached_sas_addr == 0) { | 112 | if (*(u64 *)port->attached_sas_addr == 0) { |
112 | port->class = phy->class; | 113 | port->class = phy->class; |
113 | memcpy(port->attached_sas_addr, phy->attached_sas_addr, | 114 | memcpy(port->attached_sas_addr, phy->attached_sas_addr, |
114 | SAS_ADDR_SIZE); | 115 | SAS_ADDR_SIZE); |
115 | port->iproto = phy->iproto; | 116 | port->iproto = phy->iproto; |
116 | port->tproto = phy->tproto; | 117 | port->tproto = phy->tproto; |
117 | port->oob_mode = phy->oob_mode; | 118 | port->oob_mode = phy->oob_mode; |
118 | port->linkrate = phy->linkrate; | 119 | port->linkrate = phy->linkrate; |
119 | } else | 120 | } else |
120 | port->linkrate = max(port->linkrate, phy->linkrate); | 121 | port->linkrate = max(port->linkrate, phy->linkrate); |
121 | spin_unlock(&port->phy_list_lock); | 122 | spin_unlock(&port->phy_list_lock); |
122 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); | 123 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); |
123 | 124 | ||
124 | if (!port->port) { | 125 | if (!port->port) { |
125 | port->port = sas_port_alloc(phy->phy->dev.parent, phy->id); | 126 | port->port = sas_port_alloc(phy->phy->dev.parent, phy->id); |
126 | BUG_ON(!port->port); | 127 | BUG_ON(!port->port); |
127 | sas_port_add(port->port); | 128 | sas_port_add(port->port); |
128 | } | 129 | } |
129 | sas_port_add_phy(port->port, phy->phy); | 130 | sas_port_add_phy(port->port, phy->phy); |
130 | 131 | ||
131 | SAS_DPRINTK("%s added to %s, phy_mask:0x%x (%16llx)\n", | 132 | SAS_DPRINTK("%s added to %s, phy_mask:0x%x (%16llx)\n", |
132 | dev_name(&phy->phy->dev), dev_name(&port->port->dev), | 133 | dev_name(&phy->phy->dev), dev_name(&port->port->dev), |
133 | port->phy_mask, | 134 | port->phy_mask, |
134 | SAS_ADDR(port->attached_sas_addr)); | 135 | SAS_ADDR(port->attached_sas_addr)); |
135 | 136 | ||
136 | if (port->port_dev) | 137 | if (port->port_dev) |
137 | port->port_dev->pathways = port->num_phys; | 138 | port->port_dev->pathways = port->num_phys; |
138 | 139 | ||
139 | /* Tell the LLDD about this port formation. */ | 140 | /* Tell the LLDD about this port formation. */ |
140 | if (si->dft->lldd_port_formed) | 141 | if (si->dft->lldd_port_formed) |
141 | si->dft->lldd_port_formed(phy); | 142 | si->dft->lldd_port_formed(phy); |
142 | 143 | ||
143 | sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN); | 144 | sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN); |
144 | } | 145 | } |
145 | 146 | ||
146 | /** | 147 | /** |
147 | * sas_deform_port -- remove this phy from the port it belongs to | 148 | * sas_deform_port -- remove this phy from the port it belongs to |
148 | * @phy: the phy of interest | 149 | * @phy: the phy of interest |
149 | * | 150 | * |
150 | * This is called when the physical link to the other phy has been | 151 | * This is called when the physical link to the other phy has been |
151 | * lost (on this phy), in Event thread context. We cannot delay here. | 152 | * lost (on this phy), in Event thread context. We cannot delay here. |
152 | */ | 153 | */ |
153 | void sas_deform_port(struct asd_sas_phy *phy, int gone) | 154 | void sas_deform_port(struct asd_sas_phy *phy, int gone) |
154 | { | 155 | { |
155 | struct sas_ha_struct *sas_ha = phy->ha; | 156 | struct sas_ha_struct *sas_ha = phy->ha; |
156 | struct asd_sas_port *port = phy->port; | 157 | struct asd_sas_port *port = phy->port; |
157 | struct sas_internal *si = | 158 | struct sas_internal *si = |
158 | to_sas_internal(sas_ha->core.shost->transportt); | 159 | to_sas_internal(sas_ha->core.shost->transportt); |
159 | struct domain_device *dev; | 160 | struct domain_device *dev; |
160 | unsigned long flags; | 161 | unsigned long flags; |
161 | 162 | ||
162 | if (!port) | 163 | if (!port) |
163 | return; /* done by a phy event */ | 164 | return; /* done by a phy event */ |
164 | 165 | ||
165 | dev = port->port_dev; | 166 | dev = port->port_dev; |
166 | if (dev) | 167 | if (dev) |
167 | dev->pathways--; | 168 | dev->pathways--; |
168 | 169 | ||
169 | if (port->num_phys == 1) { | 170 | if (port->num_phys == 1) { |
170 | sas_unregister_domain_devices(port, gone); | 171 | sas_unregister_domain_devices(port, gone); |
171 | sas_port_delete(port->port); | 172 | sas_port_delete(port->port); |
172 | port->port = NULL; | 173 | port->port = NULL; |
173 | } else { | 174 | } else { |
174 | sas_port_delete_phy(port->port, phy->phy); | 175 | sas_port_delete_phy(port->port, phy->phy); |
175 | sas_device_set_phy(dev, port->port); | 176 | sas_device_set_phy(dev, port->port); |
176 | } | 177 | } |
177 | 178 | ||
178 | if (si->dft->lldd_port_deformed) | 179 | if (si->dft->lldd_port_deformed) |
179 | si->dft->lldd_port_deformed(phy); | 180 | si->dft->lldd_port_deformed(phy); |
180 | 181 | ||
181 | spin_lock_irqsave(&sas_ha->phy_port_lock, flags); | 182 | spin_lock_irqsave(&sas_ha->phy_port_lock, flags); |
182 | spin_lock(&port->phy_list_lock); | 183 | spin_lock(&port->phy_list_lock); |
183 | 184 | ||
184 | list_del_init(&phy->port_phy_el); | 185 | list_del_init(&phy->port_phy_el); |
186 | sas_phy_set_target(phy, NULL); | ||
185 | phy->port = NULL; | 187 | phy->port = NULL; |
186 | port->num_phys--; | 188 | port->num_phys--; |
187 | port->phy_mask &= ~(1U << phy->id); | 189 | port->phy_mask &= ~(1U << phy->id); |
188 | 190 | ||
189 | if (port->num_phys == 0) { | 191 | if (port->num_phys == 0) { |
190 | INIT_LIST_HEAD(&port->phy_list); | 192 | INIT_LIST_HEAD(&port->phy_list); |
191 | memset(port->sas_addr, 0, SAS_ADDR_SIZE); | 193 | memset(port->sas_addr, 0, SAS_ADDR_SIZE); |
192 | memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE); | 194 | memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE); |
193 | port->class = 0; | 195 | port->class = 0; |
194 | port->iproto = 0; | 196 | port->iproto = 0; |
195 | port->tproto = 0; | 197 | port->tproto = 0; |
196 | port->oob_mode = 0; | 198 | port->oob_mode = 0; |
197 | port->phy_mask = 0; | 199 | port->phy_mask = 0; |
198 | } | 200 | } |
199 | spin_unlock(&port->phy_list_lock); | 201 | spin_unlock(&port->phy_list_lock); |
200 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); | 202 | spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); |
201 | 203 | ||
202 | return; | 204 | return; |
203 | } | 205 | } |
204 | 206 | ||
205 | /* ---------- SAS port events ---------- */ | 207 | /* ---------- SAS port events ---------- */ |
206 | 208 | ||
207 | void sas_porte_bytes_dmaed(struct work_struct *work) | 209 | void sas_porte_bytes_dmaed(struct work_struct *work) |
208 | { | 210 | { |
209 | struct asd_sas_event *ev = | 211 | struct asd_sas_event *ev = |
210 | container_of(work, struct asd_sas_event, work); | 212 | container_of(work, struct asd_sas_event, work); |
211 | struct asd_sas_phy *phy = ev->phy; | 213 | struct asd_sas_phy *phy = ev->phy; |
212 | 214 | ||
213 | clear_bit(PORTE_BYTES_DMAED, &phy->port_events_pending); | 215 | clear_bit(PORTE_BYTES_DMAED, &phy->port_events_pending); |
214 | 216 | ||
215 | sas_form_port(phy); | 217 | sas_form_port(phy); |
216 | } | 218 | } |
217 | 219 | ||
218 | void sas_porte_broadcast_rcvd(struct work_struct *work) | 220 | void sas_porte_broadcast_rcvd(struct work_struct *work) |
219 | { | 221 | { |
220 | struct asd_sas_event *ev = | 222 | struct asd_sas_event *ev = |
221 | container_of(work, struct asd_sas_event, work); | 223 | container_of(work, struct asd_sas_event, work); |
222 | struct asd_sas_phy *phy = ev->phy; | 224 | struct asd_sas_phy *phy = ev->phy; |
223 | unsigned long flags; | 225 | unsigned long flags; |
224 | u32 prim; | 226 | u32 prim; |
225 | 227 | ||
226 | clear_bit(PORTE_BROADCAST_RCVD, &phy->port_events_pending); | 228 | clear_bit(PORTE_BROADCAST_RCVD, &phy->port_events_pending); |
227 | 229 | ||
228 | spin_lock_irqsave(&phy->sas_prim_lock, flags); | 230 | spin_lock_irqsave(&phy->sas_prim_lock, flags); |
229 | prim = phy->sas_prim; | 231 | prim = phy->sas_prim; |
230 | spin_unlock_irqrestore(&phy->sas_prim_lock, flags); | 232 | spin_unlock_irqrestore(&phy->sas_prim_lock, flags); |
231 | 233 | ||
232 | SAS_DPRINTK("broadcast received: %d\n", prim); | 234 | SAS_DPRINTK("broadcast received: %d\n", prim); |
233 | sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN); | 235 | sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN); |
234 | } | 236 | } |
235 | 237 | ||
236 | void sas_porte_link_reset_err(struct work_struct *work) | 238 | void sas_porte_link_reset_err(struct work_struct *work) |
237 | { | 239 | { |
238 | struct asd_sas_event *ev = | 240 | struct asd_sas_event *ev = |
239 | container_of(work, struct asd_sas_event, work); | 241 | container_of(work, struct asd_sas_event, work); |
240 | struct asd_sas_phy *phy = ev->phy; | 242 | struct asd_sas_phy *phy = ev->phy; |
241 | 243 | ||
242 | clear_bit(PORTE_LINK_RESET_ERR, &phy->port_events_pending); | 244 | clear_bit(PORTE_LINK_RESET_ERR, &phy->port_events_pending); |
243 | 245 | ||
244 | sas_deform_port(phy, 1); | 246 | sas_deform_port(phy, 1); |
245 | } | 247 | } |
246 | 248 | ||
247 | void sas_porte_timer_event(struct work_struct *work) | 249 | void sas_porte_timer_event(struct work_struct *work) |
248 | { | 250 | { |
249 | struct asd_sas_event *ev = | 251 | struct asd_sas_event *ev = |
250 | container_of(work, struct asd_sas_event, work); | 252 | container_of(work, struct asd_sas_event, work); |
251 | struct asd_sas_phy *phy = ev->phy; | 253 | struct asd_sas_phy *phy = ev->phy; |
252 | 254 | ||
253 | clear_bit(PORTE_TIMER_EVENT, &phy->port_events_pending); | 255 | clear_bit(PORTE_TIMER_EVENT, &phy->port_events_pending); |
254 | 256 | ||
255 | sas_deform_port(phy, 1); | 257 | sas_deform_port(phy, 1); |
256 | } | 258 | } |
257 | 259 | ||
258 | void sas_porte_hard_reset(struct work_struct *work) | 260 | void sas_porte_hard_reset(struct work_struct *work) |
259 | { | 261 | { |
260 | struct asd_sas_event *ev = | 262 | struct asd_sas_event *ev = |
261 | container_of(work, struct asd_sas_event, work); | 263 | container_of(work, struct asd_sas_event, work); |
262 | struct asd_sas_phy *phy = ev->phy; | 264 | struct asd_sas_phy *phy = ev->phy; |
263 | 265 | ||
264 | clear_bit(PORTE_HARD_RESET, &phy->port_events_pending); | 266 | clear_bit(PORTE_HARD_RESET, &phy->port_events_pending); |
265 | 267 | ||
266 | sas_deform_port(phy, 1); | 268 | sas_deform_port(phy, 1); |
267 | } | 269 | } |
268 | 270 | ||
269 | /* ---------- SAS port registration ---------- */ | 271 | /* ---------- SAS port registration ---------- */ |
270 | 272 | ||
271 | static void sas_init_port(struct asd_sas_port *port, | 273 | static void sas_init_port(struct asd_sas_port *port, |
272 | struct sas_ha_struct *sas_ha, int i) | 274 | struct sas_ha_struct *sas_ha, int i) |
273 | { | 275 | { |
274 | memset(port, 0, sizeof(*port)); | 276 | memset(port, 0, sizeof(*port)); |
275 | port->id = i; | 277 | port->id = i; |
276 | INIT_LIST_HEAD(&port->dev_list); | 278 | INIT_LIST_HEAD(&port->dev_list); |
277 | INIT_LIST_HEAD(&port->disco_list); | 279 | INIT_LIST_HEAD(&port->disco_list); |
278 | INIT_LIST_HEAD(&port->destroy_list); | 280 | INIT_LIST_HEAD(&port->destroy_list); |
279 | spin_lock_init(&port->phy_list_lock); | 281 | spin_lock_init(&port->phy_list_lock); |
280 | INIT_LIST_HEAD(&port->phy_list); | 282 | INIT_LIST_HEAD(&port->phy_list); |
281 | port->ha = sas_ha; | 283 | port->ha = sas_ha; |
282 | 284 | ||
283 | spin_lock_init(&port->dev_list_lock); | 285 | spin_lock_init(&port->dev_list_lock); |
284 | } | 286 | } |
285 | 287 | ||
286 | int sas_register_ports(struct sas_ha_struct *sas_ha) | 288 | int sas_register_ports(struct sas_ha_struct *sas_ha) |
287 | { | 289 | { |
288 | int i; | 290 | int i; |
289 | 291 | ||
290 | /* initialize the ports and discovery */ | 292 | /* initialize the ports and discovery */ |
291 | for (i = 0; i < sas_ha->num_phys; i++) { | 293 | for (i = 0; i < sas_ha->num_phys; i++) { |
292 | struct asd_sas_port *port = sas_ha->sas_port[i]; | 294 | struct asd_sas_port *port = sas_ha->sas_port[i]; |
293 | 295 | ||
294 | sas_init_port(port, sas_ha, i); | 296 | sas_init_port(port, sas_ha, i); |
295 | sas_init_disc(&port->disc, port); | 297 | sas_init_disc(&port->disc, port); |
296 | } | 298 | } |
297 | return 0; | 299 | return 0; |
298 | } | 300 | } |
299 | 301 | ||
300 | void sas_unregister_ports(struct sas_ha_struct *sas_ha) | 302 | void sas_unregister_ports(struct sas_ha_struct *sas_ha) |
301 | { | 303 | { |
302 | int i; | 304 | int i; |
303 | 305 | ||
304 | for (i = 0; i < sas_ha->num_phys; i++) | 306 | for (i = 0; i < sas_ha->num_phys; i++) |
305 | if (sas_ha->sas_phy[i]->port) | 307 | if (sas_ha->sas_phy[i]->port) |
306 | sas_deform_port(sas_ha->sas_phy[i], 0); | 308 | sas_deform_port(sas_ha->sas_phy[i], 0); |
307 | 309 | ||
308 | } | 310 | } |
309 | 311 |