1 | /* |
2 | * linux/drivers/message/fusion/mptsas.c |
3 | * For use with LSI PCI chip/adapter(s) |
4 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
5 | * |
6 | * Copyright (c) 1999-2008 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | */ |
9 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
10 | /* |
11 | This program is free software; you can redistribute it and/or modify |
12 | it under the terms of the GNU General Public License as published by |
13 | the Free Software Foundation; version 2 of the License. |
14 | |
15 | This program is distributed in the hope that it will be useful, |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | GNU General Public License for more details. |
19 | |
20 | NO WARRANTY |
21 | THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR |
22 | CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT |
23 | LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, |
24 | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is |
25 | solely responsible for determining the appropriateness of using and |
26 | distributing the Program and assumes all risks associated with its |
27 | exercise of rights under this Agreement, including but not limited to |
28 | the risks and costs of program errors, damage to or loss of data, |
29 | programs or equipment, and unavailability or interruption of operations. |
30 | |
31 | DISCLAIMER OF LIABILITY |
32 | NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY |
33 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
34 | DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND |
35 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR |
36 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
37 | USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED |
38 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES |
39 | |
40 | You should have received a copy of the GNU General Public License |
41 | along with this program; if not, write to the Free Software |
42 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
43 | */ |
44 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
45 | |
46 | #include <linux/module.h> |
47 | #include <linux/kernel.h> |
48 | #include <linux/slab.h> |
49 | #include <linux/init.h> |
50 | #include <linux/errno.h> |
51 | #include <linux/jiffies.h> |
52 | #include <linux/workqueue.h> |
53 | #include <linux/delay.h> /* for mdelay */ |
54 | |
55 | #include <scsi/scsi.h> |
56 | #include <scsi/scsi_cmnd.h> |
57 | #include <scsi/scsi_device.h> |
58 | #include <scsi/scsi_host.h> |
59 | #include <scsi/scsi_transport_sas.h> |
60 | #include <scsi/scsi_transport.h> |
61 | #include <scsi/scsi_dbg.h> |
62 | |
63 | #include "mptbase.h" |
64 | #include "mptscsih.h" |
65 | #include "mptsas.h" |
66 | |
67 | |
68 | #define my_NAME "Fusion MPT SAS Host driver" |
69 | #define my_VERSION MPT_LINUX_VERSION_COMMON |
70 | #define MYNAM "mptsas" |
71 | |
72 | /* |
73 | * Reserved channel for integrated raid |
74 | */ |
75 | #define MPTSAS_RAID_CHANNEL 1 |
76 | |
77 | #define SAS_CONFIG_PAGE_TIMEOUT 30 |
78 | MODULE_AUTHOR(MODULEAUTHOR); |
79 | MODULE_DESCRIPTION(my_NAME); |
80 | MODULE_LICENSE("GPL" ); |
81 | MODULE_VERSION(my_VERSION); |
82 | |
83 | static int mpt_pt_clear; |
84 | module_param(mpt_pt_clear, int, 0); |
85 | MODULE_PARM_DESC(mpt_pt_clear, |
86 | " Clear persistency table: enable=1 " |
87 | "(default=MPTSCSIH_PT_CLEAR=0)" ); |
88 | |
89 | /* scsi-mid layer global parameter is max_report_luns, which is 511 */ |
90 | #define MPTSAS_MAX_LUN (16895) |
91 | static int max_lun = MPTSAS_MAX_LUN; |
92 | module_param(max_lun, int, 0); |
93 | MODULE_PARM_DESC(max_lun, " max lun, default=16895 " ); |
94 | |
95 | static int mpt_loadtime_max_sectors = 8192; |
96 | module_param(mpt_loadtime_max_sectors, int, 0); |
97 | MODULE_PARM_DESC(mpt_loadtime_max_sectors, |
98 | " Maximum sector define for Host Bus Adaptor.Range 64 to 8192 default=8192" ); |
99 | |
100 | static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; |
101 | static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; |
102 | static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ |
103 | static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; |
104 | static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; |
105 | |
106 | static void mptsas_firmware_event_work(struct work_struct *work); |
107 | static void mptsas_send_sas_event(struct fw_event_work *fw_event); |
108 | static void mptsas_send_raid_event(struct fw_event_work *fw_event); |
109 | static void mptsas_send_ir2_event(struct fw_event_work *fw_event); |
110 | static void mptsas_parse_device_info(struct sas_identify *identify, |
111 | struct mptsas_devinfo *device_info); |
112 | static inline void mptsas_set_rphy(MPT_ADAPTER *ioc, |
113 | struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy); |
114 | static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address |
115 | (MPT_ADAPTER *ioc, u64 sas_address); |
116 | static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc, |
117 | struct mptsas_devinfo *device_info, u32 form, u32 form_specific); |
118 | static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, |
119 | struct mptsas_enclosure *enclosure, u32 form, u32 form_specific); |
120 | static int mptsas_add_end_device(MPT_ADAPTER *ioc, |
121 | struct mptsas_phyinfo *phy_info); |
122 | static void mptsas_del_end_device(MPT_ADAPTER *ioc, |
123 | struct mptsas_phyinfo *phy_info); |
124 | static void mptsas_send_link_status_event(struct fw_event_work *fw_event); |
125 | static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address |
126 | (MPT_ADAPTER *ioc, u64 sas_address); |
127 | static void mptsas_expander_delete(MPT_ADAPTER *ioc, |
128 | struct mptsas_portinfo *port_info, u8 force); |
129 | static void mptsas_send_expander_event(struct fw_event_work *fw_event); |
130 | static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); |
131 | static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); |
132 | static void mptsas_broadcast_primitive_work(struct fw_event_work *fw_event); |
133 | static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); |
134 | static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); |
135 | void mptsas_schedule_target_reset(void *ioc); |
136 | |
137 | static void mptsas_print_phy_data(MPT_ADAPTER *ioc, |
138 | MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) |
139 | { |
140 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
141 | "---- IO UNIT PAGE 0 ------------\n" , ioc->name)); |
142 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n" , |
143 | ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle))); |
144 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n" , |
145 | ioc->name, le16_to_cpu(phy_data->ControllerDevHandle))); |
146 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n" , |
147 | ioc->name, phy_data->Port)); |
148 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n" , |
149 | ioc->name, phy_data->PortFlags)); |
150 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n" , |
151 | ioc->name, phy_data->PhyFlags)); |
152 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n" , |
153 | ioc->name, phy_data->NegotiatedLinkRate)); |
154 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
155 | "Controller PHY Device Info=0x%X\n" , ioc->name, |
156 | le32_to_cpu(phy_data->ControllerPhyDeviceInfo))); |
157 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n" , |
158 | ioc->name, le32_to_cpu(phy_data->DiscoveryStatus))); |
159 | } |
160 | |
161 | static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0) |
162 | { |
163 | __le64 sas_address; |
164 | |
165 | memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); |
166 | |
167 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
168 | "---- SAS PHY PAGE 0 ------------\n" , ioc->name)); |
169 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
170 | "Attached Device Handle=0x%X\n" , ioc->name, |
171 | le16_to_cpu(pg0->AttachedDevHandle))); |
172 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n" , |
173 | ioc->name, (unsigned long long)le64_to_cpu(sas_address))); |
174 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
175 | "Attached PHY Identifier=0x%X\n" , ioc->name, |
176 | pg0->AttachedPhyIdentifier)); |
177 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n" , |
178 | ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo))); |
179 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n" , |
180 | ioc->name, pg0->ProgrammedLinkRate)); |
181 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n" , |
182 | ioc->name, pg0->ChangeCount)); |
183 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n" , |
184 | ioc->name, le32_to_cpu(pg0->PhyInfo))); |
185 | } |
186 | |
187 | static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1) |
188 | { |
189 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
190 | "---- SAS PHY PAGE 1 ------------\n" , ioc->name)); |
191 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n" , |
192 | ioc->name, pg1->InvalidDwordCount)); |
193 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
194 | "Running Disparity Error Count=0x%x\n" , ioc->name, |
195 | pg1->RunningDisparityErrorCount)); |
196 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
197 | "Loss Dword Synch Count=0x%x\n" , ioc->name, |
198 | pg1->LossDwordSynchCount)); |
199 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
200 | "PHY Reset Problem Count=0x%x\n\n" , ioc->name, |
201 | pg1->PhyResetProblemCount)); |
202 | } |
203 | |
204 | static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0) |
205 | { |
206 | __le64 sas_address; |
207 | |
208 | memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); |
209 | |
210 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
211 | "---- SAS DEVICE PAGE 0 ---------\n" , ioc->name)); |
212 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n" , |
213 | ioc->name, le16_to_cpu(pg0->DevHandle))); |
214 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n" , |
215 | ioc->name, le16_to_cpu(pg0->ParentDevHandle))); |
216 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n" , |
217 | ioc->name, le16_to_cpu(pg0->EnclosureHandle))); |
218 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n" , |
219 | ioc->name, le16_to_cpu(pg0->Slot))); |
220 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n" , |
221 | ioc->name, (unsigned long long)le64_to_cpu(sas_address))); |
222 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n" , |
223 | ioc->name, pg0->TargetID)); |
224 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n" , |
225 | ioc->name, pg0->Bus)); |
226 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n" , |
227 | ioc->name, pg0->PhyNum)); |
228 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n" , |
229 | ioc->name, le16_to_cpu(pg0->AccessStatus))); |
230 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n" , |
231 | ioc->name, le32_to_cpu(pg0->DeviceInfo))); |
232 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n" , |
233 | ioc->name, le16_to_cpu(pg0->Flags))); |
234 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n" , |
235 | ioc->name, pg0->PhysicalPort)); |
236 | } |
237 | |
238 | static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) |
239 | { |
240 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
241 | "---- SAS EXPANDER PAGE 1 ------------\n" , ioc->name)); |
242 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n" , |
243 | ioc->name, pg1->PhysicalPort)); |
244 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n" , |
245 | ioc->name, pg1->PhyIdentifier)); |
246 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n" , |
247 | ioc->name, pg1->NegotiatedLinkRate)); |
248 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n" , |
249 | ioc->name, pg1->ProgrammedLinkRate)); |
250 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n" , |
251 | ioc->name, pg1->HwLinkRate)); |
252 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n" , |
253 | ioc->name, le16_to_cpu(pg1->OwnerDevHandle))); |
254 | dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
255 | "Attached Device Handle=0x%X\n\n" , ioc->name, |
256 | le16_to_cpu(pg1->AttachedDevHandle))); |
257 | } |
258 | |
259 | /* inhibit sas firmware event handling */ |
260 | static void |
261 | mptsas_fw_event_off(MPT_ADAPTER *ioc) |
262 | { |
263 | unsigned long flags; |
264 | |
265 | spin_lock_irqsave(&ioc->fw_event_lock, flags); |
266 | ioc->fw_events_off = 1; |
267 | ioc->sas_discovery_quiesce_io = 0; |
268 | spin_unlock_irqrestore(lock: &ioc->fw_event_lock, flags); |
269 | |
270 | } |
271 | |
272 | /* enable sas firmware event handling */ |
273 | static void |
274 | mptsas_fw_event_on(MPT_ADAPTER *ioc) |
275 | { |
276 | unsigned long flags; |
277 | |
278 | spin_lock_irqsave(&ioc->fw_event_lock, flags); |
279 | ioc->fw_events_off = 0; |
280 | spin_unlock_irqrestore(lock: &ioc->fw_event_lock, flags); |
281 | } |
282 | |
283 | /* queue a sas firmware event */ |
284 | static void |
285 | mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, |
286 | unsigned long delay) |
287 | { |
288 | unsigned long flags; |
289 | |
290 | spin_lock_irqsave(&ioc->fw_event_lock, flags); |
291 | list_add_tail(new: &fw_event->list, head: &ioc->fw_event_list); |
292 | fw_event->users = 1; |
293 | INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); |
294 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)" |
295 | "on cpuid %d\n" , ioc->name, __func__, |
296 | fw_event, smp_processor_id())); |
297 | queue_delayed_work_on(smp_processor_id(), wq: ioc->fw_event_q, |
298 | work: &fw_event->work, delay); |
299 | spin_unlock_irqrestore(lock: &ioc->fw_event_lock, flags); |
300 | } |
301 | |
302 | /* requeue a sas firmware event */ |
303 | static void |
304 | mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, |
305 | unsigned long delay) |
306 | { |
307 | unsigned long flags; |
308 | spin_lock_irqsave(&ioc->fw_event_lock, flags); |
309 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task " |
310 | "(fw_event=0x%p)on cpuid %d\n" , ioc->name, __func__, |
311 | fw_event, smp_processor_id())); |
312 | fw_event->retries++; |
313 | queue_delayed_work_on(smp_processor_id(), wq: ioc->fw_event_q, |
314 | work: &fw_event->work, delay: msecs_to_jiffies(m: delay)); |
315 | spin_unlock_irqrestore(lock: &ioc->fw_event_lock, flags); |
316 | } |
317 | |
318 | static void __mptsas_free_fw_event(MPT_ADAPTER *ioc, |
319 | struct fw_event_work *fw_event) |
320 | { |
321 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n" , |
322 | ioc->name, __func__, fw_event)); |
323 | list_del(entry: &fw_event->list); |
324 | kfree(objp: fw_event); |
325 | } |
326 | |
327 | /* free memory associated to a sas firmware event */ |
328 | static void |
329 | mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) |
330 | { |
331 | unsigned long flags; |
332 | |
333 | spin_lock_irqsave(&ioc->fw_event_lock, flags); |
334 | fw_event->users--; |
335 | if (!fw_event->users) |
336 | __mptsas_free_fw_event(ioc, fw_event); |
337 | spin_unlock_irqrestore(lock: &ioc->fw_event_lock, flags); |
338 | } |
339 | |
340 | /* walk the firmware event queue, and either stop or wait for |
341 | * outstanding events to complete */ |
342 | static void |
343 | mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc) |
344 | { |
345 | struct fw_event_work *fw_event; |
346 | struct mptsas_target_reset_event *target_reset_list, *n; |
347 | MPT_SCSI_HOST *hd = shost_priv(shost: ioc->sh); |
348 | unsigned long flags; |
349 | |
350 | /* flush the target_reset_list */ |
351 | if (!list_empty(head: &hd->target_reset_list)) { |
352 | list_for_each_entry_safe(target_reset_list, n, |
353 | &hd->target_reset_list, list) { |
354 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
355 | "%s: removing target reset for id=%d\n" , |
356 | ioc->name, __func__, |
357 | target_reset_list->sas_event_data.TargetID)); |
358 | list_del(entry: &target_reset_list->list); |
359 | kfree(objp: target_reset_list); |
360 | } |
361 | } |
362 | |
363 | if (list_empty(head: &ioc->fw_event_list) || !ioc->fw_event_q) |
364 | return; |
365 | |
366 | spin_lock_irqsave(&ioc->fw_event_lock, flags); |
367 | |
368 | while (!list_empty(head: &ioc->fw_event_list)) { |
369 | bool canceled = false; |
370 | |
371 | fw_event = list_first_entry(&ioc->fw_event_list, |
372 | struct fw_event_work, list); |
373 | fw_event->users++; |
374 | spin_unlock_irqrestore(lock: &ioc->fw_event_lock, flags); |
375 | if (cancel_delayed_work_sync(dwork: &fw_event->work)) |
376 | canceled = true; |
377 | |
378 | spin_lock_irqsave(&ioc->fw_event_lock, flags); |
379 | if (canceled) |
380 | fw_event->users--; |
381 | fw_event->users--; |
382 | WARN_ON_ONCE(fw_event->users); |
383 | __mptsas_free_fw_event(ioc, fw_event); |
384 | } |
385 | spin_unlock_irqrestore(lock: &ioc->fw_event_lock, flags); |
386 | } |
387 | |
388 | |
389 | static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) |
390 | { |
391 | struct Scsi_Host *shost = dev_to_shost(dev: phy->dev.parent); |
392 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; |
393 | } |
394 | |
395 | static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) |
396 | { |
397 | struct Scsi_Host *shost = dev_to_shost(dev: rphy->dev.parent->parent); |
398 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; |
399 | } |
400 | |
401 | /* |
402 | * mptsas_find_portinfo_by_handle |
403 | * |
404 | * This function should be called with the sas_topology_mutex already held |
405 | */ |
406 | static struct mptsas_portinfo * |
407 | mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) |
408 | { |
409 | struct mptsas_portinfo *port_info, *rc=NULL; |
410 | int i; |
411 | |
412 | list_for_each_entry(port_info, &ioc->sas_topology, list) |
413 | for (i = 0; i < port_info->num_phys; i++) |
414 | if (port_info->phy_info[i].identify.handle == handle) { |
415 | rc = port_info; |
416 | goto out; |
417 | } |
418 | out: |
419 | return rc; |
420 | } |
421 | |
422 | /** |
423 | * mptsas_find_portinfo_by_sas_address - find and return portinfo for |
424 | * this sas_address |
425 | * @ioc: Pointer to MPT_ADAPTER structure |
426 | * @sas_address: expander sas address |
427 | * |
428 | * This function should be called with the sas_topology_mutex already held. |
429 | * |
430 | * Return: %NULL if not found. |
431 | **/ |
432 | static struct mptsas_portinfo * |
433 | mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) |
434 | { |
435 | struct mptsas_portinfo *port_info, *rc = NULL; |
436 | int i; |
437 | |
438 | if (sas_address >= ioc->hba_port_sas_addr && |
439 | sas_address < (ioc->hba_port_sas_addr + |
440 | ioc->hba_port_num_phy)) |
441 | return ioc->hba_port_info; |
442 | |
443 | mutex_lock(&ioc->sas_topology_mutex); |
444 | list_for_each_entry(port_info, &ioc->sas_topology, list) |
445 | for (i = 0; i < port_info->num_phys; i++) |
446 | if (port_info->phy_info[i].identify.sas_address == |
447 | sas_address) { |
448 | rc = port_info; |
449 | goto out; |
450 | } |
451 | out: |
452 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
453 | return rc; |
454 | } |
455 | |
456 | /* |
457 | * Returns true if there is a scsi end device |
458 | */ |
459 | static inline int |
460 | mptsas_is_end_device(struct mptsas_devinfo * attached) |
461 | { |
462 | if ((attached->sas_address) && |
463 | (attached->device_info & |
464 | MPI_SAS_DEVICE_INFO_END_DEVICE) && |
465 | ((attached->device_info & |
466 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | |
467 | (attached->device_info & |
468 | MPI_SAS_DEVICE_INFO_STP_TARGET) | |
469 | (attached->device_info & |
470 | MPI_SAS_DEVICE_INFO_SATA_DEVICE))) |
471 | return 1; |
472 | else |
473 | return 0; |
474 | } |
475 | |
476 | /* no mutex */ |
477 | static void |
478 | mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details) |
479 | { |
480 | struct mptsas_portinfo *port_info; |
481 | struct mptsas_phyinfo *phy_info; |
482 | u8 i; |
483 | |
484 | if (!port_details) |
485 | return; |
486 | |
487 | port_info = port_details->port_info; |
488 | phy_info = port_info->phy_info; |
489 | |
490 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d " |
491 | "bitmask=0x%016llX\n" , ioc->name, __func__, port_details, |
492 | port_details->num_phys, (unsigned long long) |
493 | port_details->phy_bitmask)); |
494 | |
495 | for (i = 0; i < port_info->num_phys; i++, phy_info++) { |
496 | if(phy_info->port_details != port_details) |
497 | continue; |
498 | memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); |
499 | mptsas_set_rphy(ioc, phy_info, NULL); |
500 | phy_info->port_details = NULL; |
501 | } |
502 | kfree(objp: port_details); |
503 | } |
504 | |
505 | static inline struct sas_rphy * |
506 | mptsas_get_rphy(struct mptsas_phyinfo *phy_info) |
507 | { |
508 | if (phy_info->port_details) |
509 | return phy_info->port_details->rphy; |
510 | else |
511 | return NULL; |
512 | } |
513 | |
514 | static inline void |
515 | mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) |
516 | { |
517 | if (phy_info->port_details) { |
518 | phy_info->port_details->rphy = rphy; |
519 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n" , |
520 | ioc->name, rphy)); |
521 | } |
522 | |
523 | if (rphy) { |
524 | dsaswideprintk(ioc, dev_printk(KERN_DEBUG, |
525 | &rphy->dev, MYIOC_s_FMT "add:" , ioc->name)); |
526 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n" , |
527 | ioc->name, rphy, rphy->dev.release)); |
528 | } |
529 | } |
530 | |
531 | static inline struct sas_port * |
532 | mptsas_get_port(struct mptsas_phyinfo *phy_info) |
533 | { |
534 | if (phy_info->port_details) |
535 | return phy_info->port_details->port; |
536 | else |
537 | return NULL; |
538 | } |
539 | |
540 | static inline void |
541 | mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port) |
542 | { |
543 | if (phy_info->port_details) |
544 | phy_info->port_details->port = port; |
545 | |
546 | if (port) { |
547 | dsaswideprintk(ioc, dev_printk(KERN_DEBUG, |
548 | &port->dev, MYIOC_s_FMT "add:" , ioc->name)); |
549 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n" , |
550 | ioc->name, port, port->dev.release)); |
551 | } |
552 | } |
553 | |
554 | static inline struct scsi_target * |
555 | mptsas_get_starget(struct mptsas_phyinfo *phy_info) |
556 | { |
557 | if (phy_info->port_details) |
558 | return phy_info->port_details->starget; |
559 | else |
560 | return NULL; |
561 | } |
562 | |
563 | static inline void |
564 | mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target * |
565 | starget) |
566 | { |
567 | if (phy_info->port_details) |
568 | phy_info->port_details->starget = starget; |
569 | } |
570 | |
571 | /** |
572 | * mptsas_add_device_component - adds a new device component to our lists |
573 | * @ioc: Pointer to MPT_ADAPTER structure |
574 | * @channel: channel number |
575 | * @id: Logical Target ID for reset (if appropriate) |
576 | * @sas_address: expander sas address |
577 | * @device_info: specific bits (flags) for devices |
578 | * @slot: enclosure slot ID |
579 | * @enclosure_logical_id: enclosure WWN |
580 | * |
581 | **/ |
582 | static void |
583 | mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id, |
584 | u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id) |
585 | { |
586 | struct mptsas_device_info *sas_info, *next; |
587 | struct scsi_device *sdev; |
588 | struct scsi_target *starget; |
589 | struct sas_rphy *rphy; |
590 | |
591 | /* |
592 | * Delete all matching devices out of the list |
593 | */ |
594 | mutex_lock(&ioc->sas_device_info_mutex); |
595 | list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, |
596 | list) { |
597 | if (!sas_info->is_logical_volume && |
598 | (sas_info->sas_address == sas_address || |
599 | (sas_info->fw.channel == channel && |
600 | sas_info->fw.id == id))) { |
601 | list_del(entry: &sas_info->list); |
602 | kfree(objp: sas_info); |
603 | } |
604 | } |
605 | |
606 | sas_info = kzalloc(size: sizeof(struct mptsas_device_info), GFP_KERNEL); |
607 | if (!sas_info) |
608 | goto out; |
609 | |
610 | /* |
611 | * Set Firmware mapping |
612 | */ |
613 | sas_info->fw.id = id; |
614 | sas_info->fw.channel = channel; |
615 | |
616 | sas_info->sas_address = sas_address; |
617 | sas_info->device_info = device_info; |
618 | sas_info->slot = slot; |
619 | sas_info->enclosure_logical_id = enclosure_logical_id; |
620 | INIT_LIST_HEAD(list: &sas_info->list); |
621 | list_add_tail(new: &sas_info->list, head: &ioc->sas_device_info_list); |
622 | |
623 | /* |
624 | * Set OS mapping |
625 | */ |
626 | shost_for_each_device(sdev, ioc->sh) { |
627 | starget = scsi_target(sdev); |
628 | rphy = dev_to_rphy(starget->dev.parent); |
629 | if (rphy->identify.sas_address == sas_address) { |
630 | sas_info->os.id = starget->id; |
631 | sas_info->os.channel = starget->channel; |
632 | } |
633 | } |
634 | |
635 | out: |
636 | mutex_unlock(lock: &ioc->sas_device_info_mutex); |
637 | return; |
638 | } |
639 | |
640 | /** |
641 | * mptsas_add_device_component_by_fw - adds a new device component by FW ID |
642 | * @ioc: Pointer to MPT_ADAPTER structure |
643 | * @channel: channel number |
644 | * @id: Logical Target ID |
645 | * |
646 | **/ |
647 | static void |
648 | mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id) |
649 | { |
650 | struct mptsas_devinfo sas_device; |
651 | struct mptsas_enclosure enclosure_info; |
652 | int rc; |
653 | |
654 | rc = mptsas_sas_device_pg0(ioc, device_info: &sas_device, |
655 | form: (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
656 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
657 | form_specific: (channel << 8) + id); |
658 | if (rc) |
659 | return; |
660 | |
661 | memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); |
662 | mptsas_sas_enclosure_pg0(ioc, enclosure: &enclosure_info, |
663 | form: (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << |
664 | MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), |
665 | form_specific: sas_device.handle_enclosure); |
666 | |
667 | mptsas_add_device_component(ioc, channel: sas_device.channel, |
668 | id: sas_device.id, sas_address: sas_device.sas_address, device_info: sas_device.device_info, |
669 | slot: sas_device.slot, enclosure_logical_id: enclosure_info.enclosure_logical_id); |
670 | } |
671 | |
672 | /** |
673 | * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list |
674 | * @ioc: Pointer to MPT_ADAPTER structure |
675 | * @starget: SCSI target for this SCSI device |
676 | * |
677 | **/ |
678 | static void |
679 | mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc, |
680 | struct scsi_target *starget) |
681 | { |
682 | CONFIGPARMS cfg; |
683 | ConfigPageHeader_t hdr; |
684 | dma_addr_t dma_handle; |
685 | pRaidVolumePage0_t buffer = NULL; |
686 | int i; |
687 | RaidPhysDiskPage0_t phys_disk; |
688 | struct mptsas_device_info *sas_info, *next; |
689 | |
690 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); |
691 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); |
692 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; |
693 | /* assumption that all volumes on channel = 0 */ |
694 | cfg.pageAddr = starget->id; |
695 | cfg.cfghdr.hdr = &hdr; |
696 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
697 | cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; |
698 | |
699 | if (mpt_config(ioc, cfg: &cfg) != 0) |
700 | goto out; |
701 | |
702 | if (!hdr.PageLength) |
703 | goto out; |
704 | |
705 | buffer = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: hdr.PageLength * 4, |
706 | dma_handle: &dma_handle, GFP_KERNEL); |
707 | |
708 | if (!buffer) |
709 | goto out; |
710 | |
711 | cfg.physAddr = dma_handle; |
712 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
713 | |
714 | if (mpt_config(ioc, cfg: &cfg) != 0) |
715 | goto out; |
716 | |
717 | if (!buffer->NumPhysDisks) |
718 | goto out; |
719 | |
720 | /* |
721 | * Adding entry for hidden components |
722 | */ |
723 | for (i = 0; i < buffer->NumPhysDisks; i++) { |
724 | |
725 | if (mpt_raid_phys_disk_pg0(ioc, |
726 | phys_disk_num: buffer->PhysDisk[i].PhysDiskNum, phys_disk: &phys_disk) != 0) |
727 | continue; |
728 | |
729 | mptsas_add_device_component_by_fw(ioc, channel: phys_disk.PhysDiskBus, |
730 | id: phys_disk.PhysDiskID); |
731 | |
732 | mutex_lock(&ioc->sas_device_info_mutex); |
733 | list_for_each_entry(sas_info, &ioc->sas_device_info_list, |
734 | list) { |
735 | if (!sas_info->is_logical_volume && |
736 | (sas_info->fw.channel == phys_disk.PhysDiskBus && |
737 | sas_info->fw.id == phys_disk.PhysDiskID)) { |
738 | sas_info->is_hidden_raid_component = 1; |
739 | sas_info->volume_id = starget->id; |
740 | } |
741 | } |
742 | mutex_unlock(lock: &ioc->sas_device_info_mutex); |
743 | |
744 | } |
745 | |
746 | /* |
747 | * Delete all matching devices out of the list |
748 | */ |
749 | mutex_lock(&ioc->sas_device_info_mutex); |
750 | list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, |
751 | list) { |
752 | if (sas_info->is_logical_volume && sas_info->fw.id == |
753 | starget->id) { |
754 | list_del(entry: &sas_info->list); |
755 | kfree(objp: sas_info); |
756 | } |
757 | } |
758 | |
759 | sas_info = kzalloc(size: sizeof(struct mptsas_device_info), GFP_KERNEL); |
760 | if (sas_info) { |
761 | sas_info->fw.id = starget->id; |
762 | sas_info->os.id = starget->id; |
763 | sas_info->os.channel = starget->channel; |
764 | sas_info->is_logical_volume = 1; |
765 | INIT_LIST_HEAD(list: &sas_info->list); |
766 | list_add_tail(new: &sas_info->list, head: &ioc->sas_device_info_list); |
767 | } |
768 | mutex_unlock(lock: &ioc->sas_device_info_mutex); |
769 | |
770 | out: |
771 | if (buffer) |
772 | dma_free_coherent(dev: &ioc->pcidev->dev, size: hdr.PageLength * 4, |
773 | cpu_addr: buffer, dma_handle); |
774 | } |
775 | |
776 | /** |
777 | * mptsas_add_device_component_starget - adds a SCSI target device component |
778 | * @ioc: Pointer to MPT_ADAPTER structure |
779 | * @starget: SCSI target for this SCSI device |
780 | * |
781 | **/ |
782 | static void |
783 | mptsas_add_device_component_starget(MPT_ADAPTER *ioc, |
784 | struct scsi_target *starget) |
785 | { |
786 | struct sas_rphy *rphy; |
787 | struct mptsas_phyinfo *phy_info = NULL; |
788 | struct mptsas_enclosure enclosure_info; |
789 | |
790 | rphy = dev_to_rphy(starget->dev.parent); |
791 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
792 | sas_address: rphy->identify.sas_address); |
793 | if (!phy_info) |
794 | return; |
795 | |
796 | memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); |
797 | mptsas_sas_enclosure_pg0(ioc, enclosure: &enclosure_info, |
798 | form: (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << |
799 | MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), |
800 | form_specific: phy_info->attached.handle_enclosure); |
801 | |
802 | mptsas_add_device_component(ioc, channel: phy_info->attached.channel, |
803 | id: phy_info->attached.id, sas_address: phy_info->attached.sas_address, |
804 | device_info: phy_info->attached.device_info, |
805 | slot: phy_info->attached.slot, enclosure_logical_id: enclosure_info.enclosure_logical_id); |
806 | } |
807 | |
808 | /** |
809 | * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached |
810 | * @ioc: Pointer to MPT_ADAPTER structure |
811 | * @channel: os mapped id's |
812 | * @id: Logical Target ID |
813 | * |
814 | **/ |
815 | static void |
816 | mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id) |
817 | { |
818 | struct mptsas_device_info *sas_info, *next; |
819 | |
820 | /* |
821 | * Set is_cached flag |
822 | */ |
823 | list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, |
824 | list) { |
825 | if (sas_info->os.channel == channel && sas_info->os.id == id) |
826 | sas_info->is_cached = 1; |
827 | } |
828 | } |
829 | |
830 | /** |
831 | * mptsas_del_device_components - Cleaning the list |
832 | * @ioc: Pointer to MPT_ADAPTER structure |
833 | * |
834 | **/ |
835 | static void |
836 | mptsas_del_device_components(MPT_ADAPTER *ioc) |
837 | { |
838 | struct mptsas_device_info *sas_info, *next; |
839 | |
840 | mutex_lock(&ioc->sas_device_info_mutex); |
841 | list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list, |
842 | list) { |
843 | list_del(entry: &sas_info->list); |
844 | kfree(objp: sas_info); |
845 | } |
846 | mutex_unlock(lock: &ioc->sas_device_info_mutex); |
847 | } |
848 | |
849 | |
850 | /* |
851 | * mptsas_setup_wide_ports |
852 | * |
853 | * Updates for new and existing narrow/wide port configuration |
854 | * in the sas_topology |
855 | */ |
856 | static void |
857 | mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) |
858 | { |
859 | struct mptsas_portinfo_details * port_details; |
860 | struct mptsas_phyinfo *phy_info, *phy_info_cmp; |
861 | u64 sas_address; |
862 | int i, j; |
863 | |
864 | mutex_lock(&ioc->sas_topology_mutex); |
865 | |
866 | phy_info = port_info->phy_info; |
867 | for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { |
868 | if (phy_info->attached.handle) |
869 | continue; |
870 | port_details = phy_info->port_details; |
871 | if (!port_details) |
872 | continue; |
873 | if (port_details->num_phys < 2) |
874 | continue; |
875 | /* |
876 | * Removing a phy from a port, letting the last |
877 | * phy be removed by firmware events. |
878 | */ |
879 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
880 | "%s: [%p]: deleting phy = %d\n" , |
881 | ioc->name, __func__, port_details, i)); |
882 | port_details->num_phys--; |
883 | port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); |
884 | memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); |
885 | if (phy_info->phy) { |
886 | devtprintk(ioc, dev_printk(KERN_DEBUG, |
887 | &phy_info->phy->dev, MYIOC_s_FMT |
888 | "delete phy %d, phy-obj (0x%p)\n" , ioc->name, |
889 | phy_info->phy_id, phy_info->phy)); |
890 | sas_port_delete_phy(port_details->port, phy_info->phy); |
891 | } |
892 | phy_info->port_details = NULL; |
893 | } |
894 | |
895 | /* |
896 | * Populate and refresh the tree |
897 | */ |
898 | phy_info = port_info->phy_info; |
899 | for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { |
900 | sas_address = phy_info->attached.sas_address; |
901 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n" , |
902 | ioc->name, i, (unsigned long long)sas_address)); |
903 | if (!sas_address) |
904 | continue; |
905 | port_details = phy_info->port_details; |
906 | /* |
907 | * Forming a port |
908 | */ |
909 | if (!port_details) { |
910 | port_details = kzalloc(size: sizeof(struct |
911 | mptsas_portinfo_details), GFP_KERNEL); |
912 | if (!port_details) |
913 | goto out; |
914 | port_details->num_phys = 1; |
915 | port_details->port_info = port_info; |
916 | if (phy_info->phy_id < 64 ) |
917 | port_details->phy_bitmask |= |
918 | (1 << phy_info->phy_id); |
919 | phy_info->sas_port_add_phy=1; |
920 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t" |
921 | "phy_id=%d sas_address=0x%018llX\n" , |
922 | ioc->name, i, (unsigned long long)sas_address)); |
923 | phy_info->port_details = port_details; |
924 | } |
925 | |
926 | if (i == port_info->num_phys - 1) |
927 | continue; |
928 | phy_info_cmp = &port_info->phy_info[i + 1]; |
929 | for (j = i + 1 ; j < port_info->num_phys ; j++, |
930 | phy_info_cmp++) { |
931 | if (!phy_info_cmp->attached.sas_address) |
932 | continue; |
933 | if (sas_address != phy_info_cmp->attached.sas_address) |
934 | continue; |
935 | if (phy_info_cmp->port_details == port_details ) |
936 | continue; |
937 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
938 | "\t\tphy_id=%d sas_address=0x%018llX\n" , |
939 | ioc->name, j, (unsigned long long) |
940 | phy_info_cmp->attached.sas_address)); |
941 | if (phy_info_cmp->port_details) { |
942 | port_details->rphy = |
943 | mptsas_get_rphy(phy_info: phy_info_cmp); |
944 | port_details->port = |
945 | mptsas_get_port(phy_info: phy_info_cmp); |
946 | port_details->starget = |
947 | mptsas_get_starget(phy_info: phy_info_cmp); |
948 | port_details->num_phys = |
949 | phy_info_cmp->port_details->num_phys; |
950 | if (!phy_info_cmp->port_details->num_phys) |
951 | kfree(objp: phy_info_cmp->port_details); |
952 | } else |
953 | phy_info_cmp->sas_port_add_phy=1; |
954 | /* |
955 | * Adding a phy to a port |
956 | */ |
957 | phy_info_cmp->port_details = port_details; |
958 | if (phy_info_cmp->phy_id < 64 ) |
959 | port_details->phy_bitmask |= |
960 | (1 << phy_info_cmp->phy_id); |
961 | port_details->num_phys++; |
962 | } |
963 | } |
964 | |
965 | out: |
966 | |
967 | for (i = 0; i < port_info->num_phys; i++) { |
968 | port_details = port_info->phy_info[i].port_details; |
969 | if (!port_details) |
970 | continue; |
971 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
972 | "%s: [%p]: phy_id=%02d num_phys=%02d " |
973 | "bitmask=0x%016llX\n" , ioc->name, __func__, |
974 | port_details, i, port_details->num_phys, |
975 | (unsigned long long)port_details->phy_bitmask)); |
976 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n" , |
977 | ioc->name, port_details->port, port_details->rphy)); |
978 | } |
979 | dsaswideprintk(ioc, printk("\n" )); |
980 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
981 | } |
982 | |
983 | /** |
984 | * mptsas_find_vtarget - find a virtual target device (FC LUN device or |
985 | * SCSI target device) |
986 | * |
987 | * @ioc: Pointer to MPT_ADAPTER structure |
988 | * @channel: channel number |
989 | * @id: Logical Target ID |
990 | * |
991 | **/ |
992 | static VirtTarget * |
993 | mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) |
994 | { |
995 | struct scsi_device *sdev; |
996 | VirtDevice *vdevice; |
997 | VirtTarget *vtarget = NULL; |
998 | |
999 | shost_for_each_device(sdev, ioc->sh) { |
1000 | vdevice = sdev->hostdata; |
1001 | if ((vdevice == NULL) || |
1002 | (vdevice->vtarget == NULL)) |
1003 | continue; |
1004 | if ((vdevice->vtarget->tflags & |
1005 | MPT_TARGET_FLAGS_RAID_COMPONENT || |
1006 | vdevice->vtarget->raidVolume)) |
1007 | continue; |
1008 | if (vdevice->vtarget->id == id && |
1009 | vdevice->vtarget->channel == channel) |
1010 | vtarget = vdevice->vtarget; |
1011 | } |
1012 | return vtarget; |
1013 | } |
1014 | |
1015 | static void |
1016 | mptsas_queue_device_delete(MPT_ADAPTER *ioc, |
1017 | MpiEventDataSasDeviceStatusChange_t *sas_event_data) |
1018 | { |
1019 | struct fw_event_work *fw_event; |
1020 | |
1021 | fw_event = kzalloc(size: sizeof(*fw_event) + |
1022 | sizeof(MpiEventDataSasDeviceStatusChange_t), |
1023 | GFP_ATOMIC); |
1024 | if (!fw_event) { |
1025 | printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n" , |
1026 | ioc->name, __func__, __LINE__); |
1027 | return; |
1028 | } |
1029 | memcpy(fw_event->event_data, sas_event_data, |
1030 | sizeof(MpiEventDataSasDeviceStatusChange_t)); |
1031 | fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE; |
1032 | fw_event->ioc = ioc; |
1033 | mptsas_add_fw_event(ioc, fw_event, delay: msecs_to_jiffies(m: 1)); |
1034 | } |
1035 | |
1036 | static void |
1037 | mptsas_queue_rescan(MPT_ADAPTER *ioc) |
1038 | { |
1039 | struct fw_event_work *fw_event; |
1040 | |
1041 | fw_event = kzalloc(size: sizeof(*fw_event), GFP_ATOMIC); |
1042 | if (!fw_event) { |
1043 | printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n" , |
1044 | ioc->name, __func__, __LINE__); |
1045 | return; |
1046 | } |
1047 | fw_event->event = -1; |
1048 | fw_event->ioc = ioc; |
1049 | mptsas_add_fw_event(ioc, fw_event, delay: msecs_to_jiffies(m: 1)); |
1050 | } |
1051 | |
1052 | |
1053 | /** |
1054 | * mptsas_target_reset - Issues TARGET_RESET to end device using |
1055 | * handshaking method |
1056 | * |
1057 | * @ioc: Pointer to MPT_ADAPTER structure |
1058 | * @channel: channel number |
1059 | * @id: Logical Target ID for reset |
1060 | * |
1061 | * Return: (1) success |
1062 | * (0) failure |
1063 | * |
1064 | **/ |
1065 | static int |
1066 | mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id) |
1067 | { |
1068 | MPT_FRAME_HDR *mf; |
1069 | SCSITaskMgmt_t *pScsiTm; |
1070 | if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) |
1071 | return 0; |
1072 | |
1073 | |
1074 | mf = mpt_get_msg_frame(cb_idx: mptsasDeviceResetCtx, ioc); |
1075 | if (mf == NULL) { |
1076 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT |
1077 | "%s, no msg frames @%d!!\n" , ioc->name, |
1078 | __func__, __LINE__)); |
1079 | goto out_fail; |
1080 | } |
1081 | |
1082 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n" , |
1083 | ioc->name, mf)); |
1084 | |
1085 | /* Format the Request |
1086 | */ |
1087 | pScsiTm = (SCSITaskMgmt_t *) mf; |
1088 | memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t)); |
1089 | pScsiTm->TargetID = id; |
1090 | pScsiTm->Bus = channel; |
1091 | pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; |
1092 | pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET; |
1093 | pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION; |
1094 | |
1095 | DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf); |
1096 | |
1097 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1098 | "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n" , |
1099 | ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id)); |
1100 | |
1101 | mpt_put_msg_frame_hi_pri(cb_idx: mptsasDeviceResetCtx, ioc, mf); |
1102 | |
1103 | return 1; |
1104 | |
1105 | out_fail: |
1106 | |
1107 | mpt_clear_taskmgmt_in_progress_flag(ioc); |
1108 | return 0; |
1109 | } |
1110 | |
1111 | static void |
1112 | mptsas_block_io_sdev(struct scsi_device *sdev, void *data) |
1113 | { |
1114 | scsi_device_set_state(sdev, state: SDEV_BLOCK); |
1115 | } |
1116 | |
1117 | static void |
1118 | mptsas_block_io_starget(struct scsi_target *starget) |
1119 | { |
1120 | if (starget) |
1121 | starget_for_each_device(starget, NULL, fn: mptsas_block_io_sdev); |
1122 | } |
1123 | |
1124 | /** |
1125 | * mptsas_target_reset_queue - queue a target reset |
1126 | * |
1127 | * @ioc: Pointer to MPT_ADAPTER structure |
1128 | * @sas_event_data: SAS Device Status Change Event data |
1129 | * |
1130 | * Receive request for TARGET_RESET after receiving a firmware |
1131 | * event NOT_RESPONDING_EVENT, then put command in link list |
1132 | * and queue if task_queue already in use. |
1133 | * |
1134 | **/ |
1135 | static void |
1136 | mptsas_target_reset_queue(MPT_ADAPTER *ioc, |
1137 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) |
1138 | { |
1139 | MPT_SCSI_HOST *hd = shost_priv(shost: ioc->sh); |
1140 | VirtTarget *vtarget = NULL; |
1141 | struct mptsas_target_reset_event *target_reset_list; |
1142 | u8 id, channel; |
1143 | |
1144 | id = sas_event_data->TargetID; |
1145 | channel = sas_event_data->Bus; |
1146 | |
1147 | vtarget = mptsas_find_vtarget(ioc, channel, id); |
1148 | if (vtarget) { |
1149 | mptsas_block_io_starget(starget: vtarget->starget); |
1150 | vtarget->deleted = 1; /* block IO */ |
1151 | } |
1152 | |
1153 | target_reset_list = kzalloc(size: sizeof(struct mptsas_target_reset_event), |
1154 | GFP_ATOMIC); |
1155 | if (!target_reset_list) { |
1156 | dfailprintk(ioc, printk(MYIOC_s_WARN_FMT |
1157 | "%s, failed to allocate mem @%d..!!\n" , |
1158 | ioc->name, __func__, __LINE__)); |
1159 | return; |
1160 | } |
1161 | |
1162 | memcpy(&target_reset_list->sas_event_data, sas_event_data, |
1163 | sizeof(*sas_event_data)); |
1164 | list_add_tail(new: &target_reset_list->list, head: &hd->target_reset_list); |
1165 | |
1166 | target_reset_list->time_count = jiffies; |
1167 | |
1168 | if (mptsas_target_reset(ioc, channel, id)) { |
1169 | target_reset_list->target_reset_issued = 1; |
1170 | } |
1171 | } |
1172 | |
1173 | /** |
1174 | * mptsas_schedule_target_reset- send pending target reset |
1175 | * @iocp: per adapter object |
1176 | * |
1177 | * This function will delete scheduled target reset from the list and |
1178 | * try to send next target reset. This will be called from completion |
1179 | * context of any Task management command. |
1180 | */ |
1181 | |
1182 | void |
1183 | mptsas_schedule_target_reset(void *iocp) |
1184 | { |
1185 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp); |
1186 | MPT_SCSI_HOST *hd = shost_priv(shost: ioc->sh); |
1187 | struct list_head *head = &hd->target_reset_list; |
1188 | struct mptsas_target_reset_event *target_reset_list; |
1189 | u8 id, channel; |
1190 | /* |
1191 | * issue target reset to next device in the queue |
1192 | */ |
1193 | |
1194 | if (list_empty(head)) |
1195 | return; |
1196 | |
1197 | target_reset_list = list_entry(head->next, |
1198 | struct mptsas_target_reset_event, list); |
1199 | |
1200 | id = target_reset_list->sas_event_data.TargetID; |
1201 | channel = target_reset_list->sas_event_data.Bus; |
1202 | target_reset_list->time_count = jiffies; |
1203 | |
1204 | if (mptsas_target_reset(ioc, channel, id)) |
1205 | target_reset_list->target_reset_issued = 1; |
1206 | return; |
1207 | } |
1208 | |
1209 | |
1210 | /** |
1211 | * mptsas_taskmgmt_complete - complete SAS task management function |
1212 | * @ioc: Pointer to MPT_ADAPTER structure |
1213 | * @mf: MPT message frame |
1214 | * @mr: SCSI Task Management Reply structure ptr (may be %NULL) |
1215 | * |
1216 | * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work |
1217 | * queue to finish off removing device from upper layers, then send next |
1218 | * TARGET_RESET in the queue. |
1219 | **/ |
1220 | static int |
1221 | mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) |
1222 | { |
1223 | MPT_SCSI_HOST *hd = shost_priv(shost: ioc->sh); |
1224 | struct list_head *head = &hd->target_reset_list; |
1225 | u8 id, channel; |
1226 | struct mptsas_target_reset_event *target_reset_list; |
1227 | SCSITaskMgmtReply_t *pScsiTmReply; |
1228 | |
1229 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: " |
1230 | "(mf = %p, mr = %p)\n" , ioc->name, mf, mr)); |
1231 | |
1232 | pScsiTmReply = (SCSITaskMgmtReply_t *)mr; |
1233 | if (!pScsiTmReply) |
1234 | return 0; |
1235 | |
1236 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1237 | "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n" |
1238 | "\ttask_type = 0x%02X, iocstatus = 0x%04X " |
1239 | "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, " |
1240 | "term_cmnds = %d\n" , ioc->name, |
1241 | pScsiTmReply->Bus, pScsiTmReply->TargetID, |
1242 | pScsiTmReply->TaskType, |
1243 | le16_to_cpu(pScsiTmReply->IOCStatus), |
1244 | le32_to_cpu(pScsiTmReply->IOCLogInfo), |
1245 | pScsiTmReply->ResponseCode, |
1246 | le32_to_cpu(pScsiTmReply->TerminationCount))); |
1247 | |
1248 | if (pScsiTmReply->ResponseCode) |
1249 | mptscsih_taskmgmt_response_code(ioc, |
1250 | response_code: pScsiTmReply->ResponseCode); |
1251 | |
1252 | if (pScsiTmReply->TaskType == |
1253 | MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType == |
1254 | MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) { |
1255 | ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD; |
1256 | ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID; |
1257 | memcpy(ioc->taskmgmt_cmds.reply, mr, |
1258 | min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength)); |
1259 | if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) { |
1260 | ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; |
1261 | complete(&ioc->taskmgmt_cmds.done); |
1262 | return 1; |
1263 | } |
1264 | return 0; |
1265 | } |
1266 | |
1267 | mpt_clear_taskmgmt_in_progress_flag(ioc); |
1268 | |
1269 | if (list_empty(head)) |
1270 | return 1; |
1271 | |
1272 | target_reset_list = list_entry(head->next, |
1273 | struct mptsas_target_reset_event, list); |
1274 | |
1275 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1276 | "TaskMgmt: completed (%d seconds)\n" , |
1277 | ioc->name, jiffies_to_msecs(jiffies - |
1278 | target_reset_list->time_count)/1000)); |
1279 | |
1280 | id = pScsiTmReply->TargetID; |
1281 | channel = pScsiTmReply->Bus; |
1282 | target_reset_list->time_count = jiffies; |
1283 | |
1284 | /* |
1285 | * retry target reset |
1286 | */ |
1287 | if (!target_reset_list->target_reset_issued) { |
1288 | if (mptsas_target_reset(ioc, channel, id)) |
1289 | target_reset_list->target_reset_issued = 1; |
1290 | return 1; |
1291 | } |
1292 | |
1293 | /* |
1294 | * enable work queue to remove device from upper layers |
1295 | */ |
1296 | list_del(entry: &target_reset_list->list); |
1297 | if (!ioc->fw_events_off) |
1298 | mptsas_queue_device_delete(ioc, |
1299 | sas_event_data: &target_reset_list->sas_event_data); |
1300 | |
1301 | |
1302 | ioc->schedule_target_reset(ioc); |
1303 | |
1304 | return 1; |
1305 | } |
1306 | |
1307 | /** |
1308 | * mptsas_ioc_reset - issue an IOC reset for this reset phase |
1309 | * |
1310 | * @ioc: Pointer to MPT_ADAPTER structure |
1311 | * @reset_phase: id of phase of reset |
1312 | * |
1313 | **/ |
1314 | static int |
1315 | mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) |
1316 | { |
1317 | MPT_SCSI_HOST *hd; |
1318 | int rc; |
1319 | |
1320 | rc = mptscsih_ioc_reset(ioc, post_reset: reset_phase); |
1321 | if ((ioc->bus_type != SAS) || (!rc)) |
1322 | return rc; |
1323 | |
1324 | hd = shost_priv(shost: ioc->sh); |
1325 | if (!hd->ioc) |
1326 | goto out; |
1327 | |
1328 | switch (reset_phase) { |
1329 | case MPT_IOC_SETUP_RESET: |
1330 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1331 | "%s: MPT_IOC_SETUP_RESET\n" , ioc->name, __func__)); |
1332 | mptsas_fw_event_off(ioc); |
1333 | break; |
1334 | case MPT_IOC_PRE_RESET: |
1335 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1336 | "%s: MPT_IOC_PRE_RESET\n" , ioc->name, __func__)); |
1337 | break; |
1338 | case MPT_IOC_POST_RESET: |
1339 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1340 | "%s: MPT_IOC_POST_RESET\n" , ioc->name, __func__)); |
1341 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { |
1342 | ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET; |
1343 | complete(&ioc->sas_mgmt.done); |
1344 | } |
1345 | mptsas_cleanup_fw_event_q(ioc); |
1346 | mptsas_queue_rescan(ioc); |
1347 | break; |
1348 | default: |
1349 | break; |
1350 | } |
1351 | |
1352 | out: |
1353 | return rc; |
1354 | } |
1355 | |
1356 | |
1357 | /** |
1358 | * enum device_state - TUR device state |
1359 | * @DEVICE_RETRY: need to retry the TUR |
1360 | * @DEVICE_ERROR: TUR return error, don't add device |
1361 | * @DEVICE_READY: device can be added |
1362 | * |
1363 | */ |
1364 | enum device_state{ |
1365 | DEVICE_RETRY, |
1366 | DEVICE_ERROR, |
1367 | DEVICE_READY, |
1368 | }; |
1369 | |
1370 | static int |
1371 | mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, |
1372 | u32 form, u32 form_specific) |
1373 | { |
1374 | ConfigExtendedPageHeader_t hdr; |
1375 | CONFIGPARMS cfg; |
1376 | SasEnclosurePage0_t *buffer; |
1377 | dma_addr_t dma_handle; |
1378 | int error; |
1379 | __le64 le_identifier; |
1380 | |
1381 | memset(&hdr, 0, sizeof(hdr)); |
1382 | hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; |
1383 | hdr.PageNumber = 0; |
1384 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; |
1385 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; |
1386 | |
1387 | cfg.cfghdr.ehdr = &hdr; |
1388 | cfg.physAddr = -1; |
1389 | cfg.pageAddr = form + form_specific; |
1390 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
1391 | cfg.dir = 0; /* read */ |
1392 | cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; |
1393 | |
1394 | error = mpt_config(ioc, cfg: &cfg); |
1395 | if (error) |
1396 | goto out; |
1397 | if (!hdr.ExtPageLength) { |
1398 | error = -ENXIO; |
1399 | goto out; |
1400 | } |
1401 | |
1402 | buffer = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, |
1403 | dma_handle: &dma_handle, GFP_KERNEL); |
1404 | if (!buffer) { |
1405 | error = -ENOMEM; |
1406 | goto out; |
1407 | } |
1408 | |
1409 | cfg.physAddr = dma_handle; |
1410 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
1411 | |
1412 | error = mpt_config(ioc, cfg: &cfg); |
1413 | if (error) |
1414 | goto out_free_consistent; |
1415 | |
1416 | /* save config data */ |
1417 | memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64)); |
1418 | enclosure->enclosure_logical_id = le64_to_cpu(le_identifier); |
1419 | enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle); |
1420 | enclosure->flags = le16_to_cpu(buffer->Flags); |
1421 | enclosure->num_slot = le16_to_cpu(buffer->NumSlots); |
1422 | enclosure->start_slot = le16_to_cpu(buffer->StartSlot); |
1423 | enclosure->start_id = buffer->StartTargetID; |
1424 | enclosure->start_channel = buffer->StartBus; |
1425 | enclosure->sep_id = buffer->SEPTargetID; |
1426 | enclosure->sep_channel = buffer->SEPBus; |
1427 | |
1428 | out_free_consistent: |
1429 | dma_free_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, cpu_addr: buffer, |
1430 | dma_handle); |
1431 | out: |
1432 | return error; |
1433 | } |
1434 | |
1435 | /** |
1436 | * mptsas_add_end_device - report a new end device to sas transport layer |
1437 | * @ioc: Pointer to MPT_ADAPTER structure |
1438 | * @phy_info: describes attached device |
1439 | * |
1440 | * return (0) success (1) failure |
1441 | * |
1442 | **/ |
1443 | static int |
1444 | mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) |
1445 | { |
1446 | struct sas_rphy *rphy; |
1447 | struct sas_port *port; |
1448 | struct sas_identify identify; |
1449 | char *ds = NULL; |
1450 | u8 fw_id; |
1451 | |
1452 | if (!phy_info) { |
1453 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
1454 | "%s: exit at line=%d\n" , ioc->name, |
1455 | __func__, __LINE__)); |
1456 | return 1; |
1457 | } |
1458 | |
1459 | fw_id = phy_info->attached.id; |
1460 | |
1461 | if (mptsas_get_rphy(phy_info)) { |
1462 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
1463 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
1464 | __func__, fw_id, __LINE__)); |
1465 | return 2; |
1466 | } |
1467 | |
1468 | port = mptsas_get_port(phy_info); |
1469 | if (!port) { |
1470 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
1471 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
1472 | __func__, fw_id, __LINE__)); |
1473 | return 3; |
1474 | } |
1475 | |
1476 | if (phy_info->attached.device_info & |
1477 | MPI_SAS_DEVICE_INFO_SSP_TARGET) |
1478 | ds = "ssp" ; |
1479 | if (phy_info->attached.device_info & |
1480 | MPI_SAS_DEVICE_INFO_STP_TARGET) |
1481 | ds = "stp" ; |
1482 | if (phy_info->attached.device_info & |
1483 | MPI_SAS_DEVICE_INFO_SATA_DEVICE) |
1484 | ds = "sata" ; |
1485 | |
1486 | printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d," |
1487 | " phy %d, sas_addr 0x%llx\n" , ioc->name, ds, |
1488 | phy_info->attached.channel, phy_info->attached.id, |
1489 | phy_info->attached.phy_id, (unsigned long long) |
1490 | phy_info->attached.sas_address); |
1491 | |
1492 | mptsas_parse_device_info(identify: &identify, device_info: &phy_info->attached); |
1493 | rphy = sas_end_device_alloc(port); |
1494 | if (!rphy) { |
1495 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
1496 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
1497 | __func__, fw_id, __LINE__)); |
1498 | return 5; /* non-fatal: an rphy can be added later */ |
1499 | } |
1500 | |
1501 | rphy->identify = identify; |
1502 | if (sas_rphy_add(rphy)) { |
1503 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
1504 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
1505 | __func__, fw_id, __LINE__)); |
1506 | sas_rphy_free(rphy); |
1507 | return 6; |
1508 | } |
1509 | mptsas_set_rphy(ioc, phy_info, rphy); |
1510 | return 0; |
1511 | } |
1512 | |
1513 | /** |
1514 | * mptsas_del_end_device - report a deleted end device to sas transport layer |
1515 | * @ioc: Pointer to MPT_ADAPTER structure |
1516 | * @phy_info: describes attached device |
1517 | * |
1518 | **/ |
1519 | static void |
1520 | mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) |
1521 | { |
1522 | struct sas_rphy *rphy; |
1523 | struct sas_port *port; |
1524 | struct mptsas_portinfo *port_info; |
1525 | struct mptsas_phyinfo *phy_info_parent; |
1526 | int i; |
1527 | char *ds = NULL; |
1528 | u8 fw_id; |
1529 | u64 sas_address; |
1530 | |
1531 | if (!phy_info) |
1532 | return; |
1533 | |
1534 | fw_id = phy_info->attached.id; |
1535 | sas_address = phy_info->attached.sas_address; |
1536 | |
1537 | if (!phy_info->port_details) { |
1538 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
1539 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
1540 | __func__, fw_id, __LINE__)); |
1541 | return; |
1542 | } |
1543 | rphy = mptsas_get_rphy(phy_info); |
1544 | if (!rphy) { |
1545 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
1546 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
1547 | __func__, fw_id, __LINE__)); |
1548 | return; |
1549 | } |
1550 | |
1551 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR |
1552 | || phy_info->attached.device_info |
1553 | & MPI_SAS_DEVICE_INFO_SMP_INITIATOR |
1554 | || phy_info->attached.device_info |
1555 | & MPI_SAS_DEVICE_INFO_STP_INITIATOR) |
1556 | ds = "initiator" ; |
1557 | if (phy_info->attached.device_info & |
1558 | MPI_SAS_DEVICE_INFO_SSP_TARGET) |
1559 | ds = "ssp" ; |
1560 | if (phy_info->attached.device_info & |
1561 | MPI_SAS_DEVICE_INFO_STP_TARGET) |
1562 | ds = "stp" ; |
1563 | if (phy_info->attached.device_info & |
1564 | MPI_SAS_DEVICE_INFO_SATA_DEVICE) |
1565 | ds = "sata" ; |
1566 | |
1567 | dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT |
1568 | "removing %s device: fw_channel %d, fw_id %d, phy %d," |
1569 | "sas_addr 0x%llx\n" , ioc->name, ds, phy_info->attached.channel, |
1570 | phy_info->attached.id, phy_info->attached.phy_id, |
1571 | (unsigned long long) sas_address); |
1572 | |
1573 | port = mptsas_get_port(phy_info); |
1574 | if (!port) { |
1575 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
1576 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
1577 | __func__, fw_id, __LINE__)); |
1578 | return; |
1579 | } |
1580 | port_info = phy_info->portinfo; |
1581 | phy_info_parent = port_info->phy_info; |
1582 | for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) { |
1583 | if (!phy_info_parent->phy) |
1584 | continue; |
1585 | if (phy_info_parent->attached.sas_address != |
1586 | sas_address) |
1587 | continue; |
1588 | dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev, |
1589 | MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n" , |
1590 | ioc->name, phy_info_parent->phy_id, |
1591 | phy_info_parent->phy); |
1592 | sas_port_delete_phy(port, phy_info_parent->phy); |
1593 | } |
1594 | |
1595 | dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT |
1596 | "delete port %d, sas_addr (0x%llx)\n" , ioc->name, |
1597 | port->port_identifier, (unsigned long long)sas_address); |
1598 | sas_port_delete(port); |
1599 | mptsas_set_port(ioc, phy_info, NULL); |
1600 | mptsas_port_delete(ioc, port_details: phy_info->port_details); |
1601 | } |
1602 | |
1603 | static struct mptsas_phyinfo * |
1604 | mptsas_refreshing_device_handles(MPT_ADAPTER *ioc, |
1605 | struct mptsas_devinfo *sas_device) |
1606 | { |
1607 | struct mptsas_phyinfo *phy_info; |
1608 | struct mptsas_portinfo *port_info; |
1609 | int i; |
1610 | |
1611 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
1612 | sas_address: sas_device->sas_address); |
1613 | if (!phy_info) |
1614 | goto out; |
1615 | port_info = phy_info->portinfo; |
1616 | if (!port_info) |
1617 | goto out; |
1618 | mutex_lock(&ioc->sas_topology_mutex); |
1619 | for (i = 0; i < port_info->num_phys; i++) { |
1620 | if (port_info->phy_info[i].attached.sas_address != |
1621 | sas_device->sas_address) |
1622 | continue; |
1623 | port_info->phy_info[i].attached.channel = sas_device->channel; |
1624 | port_info->phy_info[i].attached.id = sas_device->id; |
1625 | port_info->phy_info[i].attached.sas_address = |
1626 | sas_device->sas_address; |
1627 | port_info->phy_info[i].attached.handle = sas_device->handle; |
1628 | port_info->phy_info[i].attached.handle_parent = |
1629 | sas_device->handle_parent; |
1630 | port_info->phy_info[i].attached.handle_enclosure = |
1631 | sas_device->handle_enclosure; |
1632 | } |
1633 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
1634 | out: |
1635 | return phy_info; |
1636 | } |
1637 | |
1638 | /** |
1639 | * mptsas_firmware_event_work - work thread for processing fw events |
1640 | * @work: work queue payload containing info describing the event |
1641 | * Context: user |
1642 | * |
1643 | */ |
1644 | static void |
1645 | mptsas_firmware_event_work(struct work_struct *work) |
1646 | { |
1647 | struct fw_event_work *fw_event = |
1648 | container_of(work, struct fw_event_work, work.work); |
1649 | MPT_ADAPTER *ioc = fw_event->ioc; |
1650 | |
1651 | /* special rescan topology handling */ |
1652 | if (fw_event->event == -1) { |
1653 | if (ioc->in_rescan) { |
1654 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
1655 | "%s: rescan ignored as it is in progress\n" , |
1656 | ioc->name, __func__)); |
1657 | return; |
1658 | } |
1659 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after " |
1660 | "reset\n" , ioc->name, __func__)); |
1661 | ioc->in_rescan = 1; |
1662 | mptsas_not_responding_devices(ioc); |
1663 | mptsas_scan_sas_topology(ioc); |
1664 | ioc->in_rescan = 0; |
1665 | mptsas_free_fw_event(ioc, fw_event); |
1666 | mptsas_fw_event_on(ioc); |
1667 | return; |
1668 | } |
1669 | |
1670 | /* events handling turned off during host reset */ |
1671 | if (ioc->fw_events_off) { |
1672 | mptsas_free_fw_event(ioc, fw_event); |
1673 | return; |
1674 | } |
1675 | |
1676 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), " |
1677 | "event = (0x%02x)\n" , ioc->name, __func__, fw_event, |
1678 | (fw_event->event & 0xFF))); |
1679 | |
1680 | switch (fw_event->event) { |
1681 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
1682 | mptsas_send_sas_event(fw_event); |
1683 | break; |
1684 | case MPI_EVENT_INTEGRATED_RAID: |
1685 | mptsas_send_raid_event(fw_event); |
1686 | break; |
1687 | case MPI_EVENT_IR2: |
1688 | mptsas_send_ir2_event(fw_event); |
1689 | break; |
1690 | case MPI_EVENT_PERSISTENT_TABLE_FULL: |
1691 | mptbase_sas_persist_operation(ioc, |
1692 | MPI_SAS_OP_CLEAR_NOT_PRESENT); |
1693 | mptsas_free_fw_event(ioc, fw_event); |
1694 | break; |
1695 | case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: |
1696 | mptsas_broadcast_primitive_work(fw_event); |
1697 | break; |
1698 | case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: |
1699 | mptsas_send_expander_event(fw_event); |
1700 | break; |
1701 | case MPI_EVENT_SAS_PHY_LINK_STATUS: |
1702 | mptsas_send_link_status_event(fw_event); |
1703 | break; |
1704 | case MPI_EVENT_QUEUE_FULL: |
1705 | mptsas_handle_queue_full_event(fw_event); |
1706 | break; |
1707 | } |
1708 | } |
1709 | |
1710 | |
1711 | |
1712 | static int |
1713 | mptsas_slave_configure(struct scsi_device *sdev) |
1714 | { |
1715 | struct Scsi_Host *host = sdev->host; |
1716 | MPT_SCSI_HOST *hd = shost_priv(shost: host); |
1717 | MPT_ADAPTER *ioc = hd->ioc; |
1718 | VirtDevice *vdevice = sdev->hostdata; |
1719 | |
1720 | if (vdevice->vtarget->deleted) { |
1721 | sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n" ); |
1722 | vdevice->vtarget->deleted = 0; |
1723 | } |
1724 | |
1725 | /* |
1726 | * RAID volumes placed beyond the last expected port. |
1727 | * Ignore sending sas mode pages in that case.. |
1728 | */ |
1729 | if (sdev->channel == MPTSAS_RAID_CHANNEL) { |
1730 | mptsas_add_device_component_starget_ir(ioc, starget: scsi_target(sdev)); |
1731 | goto out; |
1732 | } |
1733 | |
1734 | sas_read_port_mode_page(sdev); |
1735 | |
1736 | mptsas_add_device_component_starget(ioc, starget: scsi_target(sdev)); |
1737 | |
1738 | out: |
1739 | return mptscsih_slave_configure(device: sdev); |
1740 | } |
1741 | |
1742 | static int |
1743 | mptsas_target_alloc(struct scsi_target *starget) |
1744 | { |
1745 | struct Scsi_Host *host = dev_to_shost(dev: &starget->dev); |
1746 | MPT_SCSI_HOST *hd = shost_priv(shost: host); |
1747 | VirtTarget *vtarget; |
1748 | u8 id, channel; |
1749 | struct sas_rphy *rphy; |
1750 | struct mptsas_portinfo *p; |
1751 | int i; |
1752 | MPT_ADAPTER *ioc = hd->ioc; |
1753 | |
1754 | vtarget = kzalloc(size: sizeof(VirtTarget), GFP_KERNEL); |
1755 | if (!vtarget) |
1756 | return -ENOMEM; |
1757 | |
1758 | vtarget->starget = starget; |
1759 | vtarget->ioc_id = ioc->id; |
1760 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; |
1761 | id = starget->id; |
1762 | channel = 0; |
1763 | |
1764 | /* |
1765 | * RAID volumes placed beyond the last expected port. |
1766 | */ |
1767 | if (starget->channel == MPTSAS_RAID_CHANNEL) { |
1768 | if (!ioc->raid_data.pIocPg2) { |
1769 | kfree(objp: vtarget); |
1770 | return -ENXIO; |
1771 | } |
1772 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { |
1773 | if (id == ioc->raid_data.pIocPg2-> |
1774 | RaidVolume[i].VolumeID) { |
1775 | channel = ioc->raid_data.pIocPg2-> |
1776 | RaidVolume[i].VolumeBus; |
1777 | } |
1778 | } |
1779 | vtarget->raidVolume = 1; |
1780 | goto out; |
1781 | } |
1782 | |
1783 | rphy = dev_to_rphy(starget->dev.parent); |
1784 | mutex_lock(&ioc->sas_topology_mutex); |
1785 | list_for_each_entry(p, &ioc->sas_topology, list) { |
1786 | for (i = 0; i < p->num_phys; i++) { |
1787 | if (p->phy_info[i].attached.sas_address != |
1788 | rphy->identify.sas_address) |
1789 | continue; |
1790 | id = p->phy_info[i].attached.id; |
1791 | channel = p->phy_info[i].attached.channel; |
1792 | mptsas_set_starget(phy_info: &p->phy_info[i], starget); |
1793 | |
1794 | /* |
1795 | * Exposing hidden raid components |
1796 | */ |
1797 | if (mptscsih_is_phys_disk(ioc, channel, id)) { |
1798 | id = mptscsih_raid_id_to_num(ioc, |
1799 | channel, id); |
1800 | vtarget->tflags |= |
1801 | MPT_TARGET_FLAGS_RAID_COMPONENT; |
1802 | p->phy_info[i].attached.phys_disk_num = id; |
1803 | } |
1804 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
1805 | goto out; |
1806 | } |
1807 | } |
1808 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
1809 | |
1810 | kfree(objp: vtarget); |
1811 | return -ENXIO; |
1812 | |
1813 | out: |
1814 | vtarget->id = id; |
1815 | vtarget->channel = channel; |
1816 | starget->hostdata = vtarget; |
1817 | return 0; |
1818 | } |
1819 | |
1820 | static void |
1821 | mptsas_target_destroy(struct scsi_target *starget) |
1822 | { |
1823 | struct Scsi_Host *host = dev_to_shost(dev: &starget->dev); |
1824 | MPT_SCSI_HOST *hd = shost_priv(shost: host); |
1825 | struct sas_rphy *rphy; |
1826 | struct mptsas_portinfo *p; |
1827 | int i; |
1828 | MPT_ADAPTER *ioc = hd->ioc; |
1829 | VirtTarget *vtarget; |
1830 | |
1831 | if (!starget->hostdata) |
1832 | return; |
1833 | |
1834 | vtarget = starget->hostdata; |
1835 | |
1836 | mptsas_del_device_component_by_os(ioc, channel: starget->channel, |
1837 | id: starget->id); |
1838 | |
1839 | |
1840 | if (starget->channel == MPTSAS_RAID_CHANNEL) |
1841 | goto out; |
1842 | |
1843 | rphy = dev_to_rphy(starget->dev.parent); |
1844 | list_for_each_entry(p, &ioc->sas_topology, list) { |
1845 | for (i = 0; i < p->num_phys; i++) { |
1846 | if (p->phy_info[i].attached.sas_address != |
1847 | rphy->identify.sas_address) |
1848 | continue; |
1849 | |
1850 | starget_printk(KERN_INFO, starget, MYIOC_s_FMT |
1851 | "delete device: fw_channel %d, fw_id %d, phy %d, " |
1852 | "sas_addr 0x%llx\n" , ioc->name, |
1853 | p->phy_info[i].attached.channel, |
1854 | p->phy_info[i].attached.id, |
1855 | p->phy_info[i].attached.phy_id, (unsigned long long) |
1856 | p->phy_info[i].attached.sas_address); |
1857 | |
1858 | mptsas_set_starget(phy_info: &p->phy_info[i], NULL); |
1859 | } |
1860 | } |
1861 | |
1862 | out: |
1863 | vtarget->starget = NULL; |
1864 | kfree(objp: starget->hostdata); |
1865 | starget->hostdata = NULL; |
1866 | } |
1867 | |
1868 | |
1869 | static int |
1870 | mptsas_slave_alloc(struct scsi_device *sdev) |
1871 | { |
1872 | struct Scsi_Host *host = sdev->host; |
1873 | MPT_SCSI_HOST *hd = shost_priv(shost: host); |
1874 | struct sas_rphy *rphy; |
1875 | struct mptsas_portinfo *p; |
1876 | VirtDevice *vdevice; |
1877 | struct scsi_target *starget; |
1878 | int i; |
1879 | MPT_ADAPTER *ioc = hd->ioc; |
1880 | |
1881 | vdevice = kzalloc(size: sizeof(VirtDevice), GFP_KERNEL); |
1882 | if (!vdevice) { |
1883 | printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n" , |
1884 | ioc->name, sizeof(VirtDevice)); |
1885 | return -ENOMEM; |
1886 | } |
1887 | starget = scsi_target(sdev); |
1888 | vdevice->vtarget = starget->hostdata; |
1889 | |
1890 | if (sdev->channel == MPTSAS_RAID_CHANNEL) |
1891 | goto out; |
1892 | |
1893 | rphy = dev_to_rphy(sdev->sdev_target->dev.parent); |
1894 | mutex_lock(&ioc->sas_topology_mutex); |
1895 | list_for_each_entry(p, &ioc->sas_topology, list) { |
1896 | for (i = 0; i < p->num_phys; i++) { |
1897 | if (p->phy_info[i].attached.sas_address != |
1898 | rphy->identify.sas_address) |
1899 | continue; |
1900 | vdevice->lun = sdev->lun; |
1901 | /* |
1902 | * Exposing hidden raid components |
1903 | */ |
1904 | if (mptscsih_is_phys_disk(ioc, |
1905 | channel: p->phy_info[i].attached.channel, |
1906 | id: p->phy_info[i].attached.id)) |
1907 | sdev->no_uld_attach = 1; |
1908 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
1909 | goto out; |
1910 | } |
1911 | } |
1912 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
1913 | |
1914 | kfree(objp: vdevice); |
1915 | return -ENXIO; |
1916 | |
1917 | out: |
1918 | vdevice->vtarget->num_luns++; |
1919 | sdev->hostdata = vdevice; |
1920 | return 0; |
1921 | } |
1922 | |
1923 | static int |
1924 | mptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) |
1925 | { |
1926 | MPT_SCSI_HOST *hd; |
1927 | MPT_ADAPTER *ioc; |
1928 | VirtDevice *vdevice = SCpnt->device->hostdata; |
1929 | |
1930 | if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { |
1931 | SCpnt->result = DID_NO_CONNECT << 16; |
1932 | scsi_done(cmd: SCpnt); |
1933 | return 0; |
1934 | } |
1935 | |
1936 | hd = shost_priv(shost); |
1937 | ioc = hd->ioc; |
1938 | |
1939 | if (ioc->sas_discovery_quiesce_io) |
1940 | return SCSI_MLQUEUE_HOST_BUSY; |
1941 | |
1942 | if (ioc->debug_level & MPT_DEBUG_SCSI) |
1943 | scsi_print_command(SCpnt); |
1944 | |
1945 | return mptscsih_qcmd(SCpnt); |
1946 | } |
1947 | |
1948 | /** |
1949 | * mptsas_eh_timed_out - resets the scsi_cmnd timeout |
1950 | * if the device under question is currently in the |
1951 | * device removal delay. |
1952 | * @sc: scsi command that the midlayer is about to time out |
1953 | * |
1954 | **/ |
1955 | static enum scsi_timeout_action mptsas_eh_timed_out(struct scsi_cmnd *sc) |
1956 | { |
1957 | MPT_SCSI_HOST *hd; |
1958 | MPT_ADAPTER *ioc; |
1959 | VirtDevice *vdevice; |
1960 | enum scsi_timeout_action rc = SCSI_EH_NOT_HANDLED; |
1961 | |
1962 | hd = shost_priv(shost: sc->device->host); |
1963 | if (hd == NULL) { |
1964 | printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n" , |
1965 | __func__, sc); |
1966 | goto done; |
1967 | } |
1968 | |
1969 | ioc = hd->ioc; |
1970 | if (ioc->bus_type != SAS) { |
1971 | printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n" , |
1972 | __func__, sc); |
1973 | goto done; |
1974 | } |
1975 | |
1976 | /* In case if IOC is in reset from internal context. |
1977 | * Do not execute EEH for the same IOC. SML should to reset timer. |
1978 | */ |
1979 | if (ioc->ioc_reset_in_progress) { |
1980 | dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset," |
1981 | "SML need to reset the timer (sc=%p)\n" , |
1982 | ioc->name, __func__, sc)); |
1983 | rc = SCSI_EH_RESET_TIMER; |
1984 | } |
1985 | vdevice = sc->device->hostdata; |
1986 | if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD |
1987 | || vdevice->vtarget->deleted)) { |
1988 | dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed " |
1989 | "or in device removal delay (sc=%p)\n" , |
1990 | ioc->name, __func__, sc)); |
1991 | rc = SCSI_EH_RESET_TIMER; |
1992 | goto done; |
1993 | } |
1994 | |
1995 | done: |
1996 | return rc; |
1997 | } |
1998 | |
1999 | |
2000 | static const struct scsi_host_template mptsas_driver_template = { |
2001 | .module = THIS_MODULE, |
2002 | .proc_name = "mptsas" , |
2003 | .show_info = mptscsih_show_info, |
2004 | .name = "MPT SAS Host" , |
2005 | .info = mptscsih_info, |
2006 | .queuecommand = mptsas_qcmd, |
2007 | .target_alloc = mptsas_target_alloc, |
2008 | .slave_alloc = mptsas_slave_alloc, |
2009 | .slave_configure = mptsas_slave_configure, |
2010 | .target_destroy = mptsas_target_destroy, |
2011 | .slave_destroy = mptscsih_slave_destroy, |
2012 | .change_queue_depth = mptscsih_change_queue_depth, |
2013 | .eh_timed_out = mptsas_eh_timed_out, |
2014 | .eh_abort_handler = mptscsih_abort, |
2015 | .eh_device_reset_handler = mptscsih_dev_reset, |
2016 | .eh_host_reset_handler = mptscsih_host_reset, |
2017 | .bios_param = mptscsih_bios_param, |
2018 | .can_queue = MPT_SAS_CAN_QUEUE, |
2019 | .this_id = -1, |
2020 | .sg_tablesize = MPT_SCSI_SG_DEPTH, |
2021 | .max_sectors = 8192, |
2022 | .cmd_per_lun = 7, |
2023 | .shost_groups = mptscsih_host_attr_groups, |
2024 | .no_write_same = 1, |
2025 | }; |
2026 | |
2027 | static int mptsas_get_linkerrors(struct sas_phy *phy) |
2028 | { |
2029 | MPT_ADAPTER *ioc = phy_to_ioc(phy); |
2030 | ConfigExtendedPageHeader_t hdr; |
2031 | CONFIGPARMS cfg; |
2032 | SasPhyPage1_t *buffer; |
2033 | dma_addr_t dma_handle; |
2034 | int error; |
2035 | |
2036 | /* FIXME: only have link errors on local phys */ |
2037 | if (!scsi_is_sas_phy_local(phy)) |
2038 | return -EINVAL; |
2039 | |
2040 | hdr.PageVersion = MPI_SASPHY1_PAGEVERSION; |
2041 | hdr.ExtPageLength = 0; |
2042 | hdr.PageNumber = 1 /* page number 1*/; |
2043 | hdr.Reserved1 = 0; |
2044 | hdr.Reserved2 = 0; |
2045 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; |
2046 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; |
2047 | |
2048 | cfg.cfghdr.ehdr = &hdr; |
2049 | cfg.physAddr = -1; |
2050 | cfg.pageAddr = phy->identify.phy_identifier; |
2051 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
2052 | cfg.dir = 0; /* read */ |
2053 | cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; |
2054 | |
2055 | error = mpt_config(ioc, cfg: &cfg); |
2056 | if (error) |
2057 | return error; |
2058 | if (!hdr.ExtPageLength) |
2059 | return -ENXIO; |
2060 | |
2061 | buffer = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, |
2062 | dma_handle: &dma_handle, GFP_KERNEL); |
2063 | if (!buffer) |
2064 | return -ENOMEM; |
2065 | |
2066 | cfg.physAddr = dma_handle; |
2067 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
2068 | |
2069 | error = mpt_config(ioc, cfg: &cfg); |
2070 | if (error) |
2071 | goto out_free_consistent; |
2072 | |
2073 | mptsas_print_phy_pg1(ioc, pg1: buffer); |
2074 | |
2075 | phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount); |
2076 | phy->running_disparity_error_count = |
2077 | le32_to_cpu(buffer->RunningDisparityErrorCount); |
2078 | phy->loss_of_dword_sync_count = |
2079 | le32_to_cpu(buffer->LossDwordSynchCount); |
2080 | phy->phy_reset_problem_count = |
2081 | le32_to_cpu(buffer->PhyResetProblemCount); |
2082 | |
2083 | out_free_consistent: |
2084 | dma_free_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, cpu_addr: buffer, |
2085 | dma_handle); |
2086 | return error; |
2087 | } |
2088 | |
2089 | static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, |
2090 | MPT_FRAME_HDR *reply) |
2091 | { |
2092 | ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD; |
2093 | if (reply != NULL) { |
2094 | ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID; |
2095 | memcpy(ioc->sas_mgmt.reply, reply, |
2096 | min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); |
2097 | } |
2098 | |
2099 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) { |
2100 | ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING; |
2101 | complete(&ioc->sas_mgmt.done); |
2102 | return 1; |
2103 | } |
2104 | return 0; |
2105 | } |
2106 | |
2107 | static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) |
2108 | { |
2109 | MPT_ADAPTER *ioc = phy_to_ioc(phy); |
2110 | SasIoUnitControlRequest_t *req; |
2111 | SasIoUnitControlReply_t *reply; |
2112 | MPT_FRAME_HDR *mf; |
2113 | MPIHeader_t *hdr; |
2114 | unsigned long timeleft; |
2115 | int error = -ERESTARTSYS; |
2116 | |
2117 | /* FIXME: fusion doesn't allow non-local phy reset */ |
2118 | if (!scsi_is_sas_phy_local(phy)) |
2119 | return -EINVAL; |
2120 | |
2121 | /* not implemented for expanders */ |
2122 | if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) |
2123 | return -ENXIO; |
2124 | |
2125 | if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex)) |
2126 | goto out; |
2127 | |
2128 | mf = mpt_get_msg_frame(cb_idx: mptsasMgmtCtx, ioc); |
2129 | if (!mf) { |
2130 | error = -ENOMEM; |
2131 | goto out_unlock; |
2132 | } |
2133 | |
2134 | hdr = (MPIHeader_t *) mf; |
2135 | req = (SasIoUnitControlRequest_t *)mf; |
2136 | memset(req, 0, sizeof(SasIoUnitControlRequest_t)); |
2137 | req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; |
2138 | req->MsgContext = hdr->MsgContext; |
2139 | req->Operation = hard_reset ? |
2140 | MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; |
2141 | req->PhyNum = phy->identify.phy_identifier; |
2142 | |
2143 | INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) |
2144 | mpt_put_msg_frame(cb_idx: mptsasMgmtCtx, ioc, mf); |
2145 | |
2146 | timeleft = wait_for_completion_timeout(x: &ioc->sas_mgmt.done, |
2147 | timeout: 10 * HZ); |
2148 | if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { |
2149 | error = -ETIME; |
2150 | mpt_free_msg_frame(ioc, mf); |
2151 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) |
2152 | goto out_unlock; |
2153 | if (!timeleft) |
2154 | mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); |
2155 | goto out_unlock; |
2156 | } |
2157 | |
2158 | /* a reply frame is expected */ |
2159 | if ((ioc->sas_mgmt.status & |
2160 | MPT_MGMT_STATUS_RF_VALID) == 0) { |
2161 | error = -ENXIO; |
2162 | goto out_unlock; |
2163 | } |
2164 | |
2165 | /* process the completed Reply Message Frame */ |
2166 | reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; |
2167 | if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { |
2168 | printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n" , |
2169 | ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo); |
2170 | error = -ENXIO; |
2171 | goto out_unlock; |
2172 | } |
2173 | |
2174 | error = 0; |
2175 | |
2176 | out_unlock: |
2177 | CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) |
2178 | mutex_unlock(lock: &ioc->sas_mgmt.mutex); |
2179 | out: |
2180 | return error; |
2181 | } |
2182 | |
2183 | static int |
2184 | mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) |
2185 | { |
2186 | MPT_ADAPTER *ioc = rphy_to_ioc(rphy); |
2187 | int i, error; |
2188 | struct mptsas_portinfo *p; |
2189 | struct mptsas_enclosure enclosure_info; |
2190 | u64 enclosure_handle; |
2191 | |
2192 | mutex_lock(&ioc->sas_topology_mutex); |
2193 | list_for_each_entry(p, &ioc->sas_topology, list) { |
2194 | for (i = 0; i < p->num_phys; i++) { |
2195 | if (p->phy_info[i].attached.sas_address == |
2196 | rphy->identify.sas_address) { |
2197 | enclosure_handle = p->phy_info[i]. |
2198 | attached.handle_enclosure; |
2199 | goto found_info; |
2200 | } |
2201 | } |
2202 | } |
2203 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
2204 | return -ENXIO; |
2205 | |
2206 | found_info: |
2207 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
2208 | memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); |
2209 | error = mptsas_sas_enclosure_pg0(ioc, enclosure: &enclosure_info, |
2210 | form: (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << |
2211 | MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), form_specific: enclosure_handle); |
2212 | if (!error) |
2213 | *identifier = enclosure_info.enclosure_logical_id; |
2214 | return error; |
2215 | } |
2216 | |
2217 | static int |
2218 | mptsas_get_bay_identifier(struct sas_rphy *rphy) |
2219 | { |
2220 | MPT_ADAPTER *ioc = rphy_to_ioc(rphy); |
2221 | struct mptsas_portinfo *p; |
2222 | int i, rc; |
2223 | |
2224 | mutex_lock(&ioc->sas_topology_mutex); |
2225 | list_for_each_entry(p, &ioc->sas_topology, list) { |
2226 | for (i = 0; i < p->num_phys; i++) { |
2227 | if (p->phy_info[i].attached.sas_address == |
2228 | rphy->identify.sas_address) { |
2229 | rc = p->phy_info[i].attached.slot; |
2230 | goto out; |
2231 | } |
2232 | } |
2233 | } |
2234 | rc = -ENXIO; |
2235 | out: |
2236 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
2237 | return rc; |
2238 | } |
2239 | |
2240 | static void mptsas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, |
2241 | struct sas_rphy *rphy) |
2242 | { |
2243 | MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc; |
2244 | MPT_FRAME_HDR *mf; |
2245 | SmpPassthroughRequest_t *smpreq; |
2246 | int flagsLength; |
2247 | unsigned long timeleft; |
2248 | char *psge; |
2249 | u64 sas_address = 0; |
2250 | unsigned int reslen = 0; |
2251 | int ret = -EINVAL; |
2252 | |
2253 | /* do we need to support multiple segments? */ |
2254 | if (job->request_payload.sg_cnt > 1 || |
2255 | job->reply_payload.sg_cnt > 1) { |
2256 | printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n" , |
2257 | ioc->name, __func__, job->request_payload.payload_len, |
2258 | job->reply_payload.payload_len); |
2259 | goto out; |
2260 | } |
2261 | |
2262 | ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); |
2263 | if (ret) |
2264 | goto out; |
2265 | |
2266 | mf = mpt_get_msg_frame(cb_idx: mptsasMgmtCtx, ioc); |
2267 | if (!mf) { |
2268 | ret = -ENOMEM; |
2269 | goto out_unlock; |
2270 | } |
2271 | |
2272 | smpreq = (SmpPassthroughRequest_t *)mf; |
2273 | memset(smpreq, 0, sizeof(*smpreq)); |
2274 | |
2275 | smpreq->RequestDataLength = |
2276 | cpu_to_le16(job->request_payload.payload_len - 4); |
2277 | smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; |
2278 | |
2279 | if (rphy) |
2280 | sas_address = rphy->identify.sas_address; |
2281 | else { |
2282 | struct mptsas_portinfo *port_info; |
2283 | |
2284 | mutex_lock(&ioc->sas_topology_mutex); |
2285 | port_info = ioc->hba_port_info; |
2286 | if (port_info && port_info->phy_info) |
2287 | sas_address = |
2288 | port_info->phy_info[0].phy->identify.sas_address; |
2289 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
2290 | } |
2291 | |
2292 | *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); |
2293 | |
2294 | psge = (char *) |
2295 | (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); |
2296 | |
2297 | /* request */ |
2298 | flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | |
2299 | MPI_SGE_FLAGS_END_OF_BUFFER | |
2300 | MPI_SGE_FLAGS_DIRECTION) |
2301 | << MPI_SGE_FLAGS_SHIFT; |
2302 | |
2303 | if (!dma_map_sg(&ioc->pcidev->dev, job->request_payload.sg_list, |
2304 | 1, DMA_BIDIRECTIONAL)) |
2305 | goto put_mf; |
2306 | |
2307 | flagsLength |= (sg_dma_len(job->request_payload.sg_list) - 4); |
2308 | ioc->add_sge(psge, flagsLength, |
2309 | sg_dma_address(job->request_payload.sg_list)); |
2310 | psge += ioc->SGE_size; |
2311 | |
2312 | /* response */ |
2313 | flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | |
2314 | MPI_SGE_FLAGS_SYSTEM_ADDRESS | |
2315 | MPI_SGE_FLAGS_IOC_TO_HOST | |
2316 | MPI_SGE_FLAGS_END_OF_BUFFER; |
2317 | |
2318 | flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; |
2319 | |
2320 | if (!dma_map_sg(&ioc->pcidev->dev, job->reply_payload.sg_list, |
2321 | 1, DMA_BIDIRECTIONAL)) |
2322 | goto unmap_out; |
2323 | flagsLength |= sg_dma_len(job->reply_payload.sg_list) + 4; |
2324 | ioc->add_sge(psge, flagsLength, |
2325 | sg_dma_address(job->reply_payload.sg_list)); |
2326 | |
2327 | INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) |
2328 | mpt_put_msg_frame(cb_idx: mptsasMgmtCtx, ioc, mf); |
2329 | |
2330 | timeleft = wait_for_completion_timeout(x: &ioc->sas_mgmt.done, timeout: 10 * HZ); |
2331 | if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { |
2332 | ret = -ETIME; |
2333 | mpt_free_msg_frame(ioc, mf); |
2334 | mf = NULL; |
2335 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) |
2336 | goto unmap_in; |
2337 | if (!timeleft) |
2338 | mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); |
2339 | goto unmap_in; |
2340 | } |
2341 | mf = NULL; |
2342 | |
2343 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { |
2344 | SmpPassthroughReply_t *smprep; |
2345 | |
2346 | smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; |
2347 | memcpy(job->reply, smprep, sizeof(*smprep)); |
2348 | job->reply_len = sizeof(*smprep); |
2349 | reslen = smprep->ResponseDataLength; |
2350 | } else { |
2351 | printk(MYIOC_s_ERR_FMT |
2352 | "%s: smp passthru reply failed to be returned\n" , |
2353 | ioc->name, __func__); |
2354 | ret = -ENXIO; |
2355 | } |
2356 | |
2357 | unmap_in: |
2358 | dma_unmap_sg(&ioc->pcidev->dev, job->reply_payload.sg_list, 1, |
2359 | DMA_BIDIRECTIONAL); |
2360 | unmap_out: |
2361 | dma_unmap_sg(&ioc->pcidev->dev, job->request_payload.sg_list, 1, |
2362 | DMA_BIDIRECTIONAL); |
2363 | put_mf: |
2364 | if (mf) |
2365 | mpt_free_msg_frame(ioc, mf); |
2366 | out_unlock: |
2367 | CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) |
2368 | mutex_unlock(lock: &ioc->sas_mgmt.mutex); |
2369 | out: |
2370 | bsg_job_done(job, result: ret, reply_payload_rcv_len: reslen); |
2371 | } |
2372 | |
2373 | static struct sas_function_template mptsas_transport_functions = { |
2374 | .get_linkerrors = mptsas_get_linkerrors, |
2375 | .get_enclosure_identifier = mptsas_get_enclosure_identifier, |
2376 | .get_bay_identifier = mptsas_get_bay_identifier, |
2377 | .phy_reset = mptsas_phy_reset, |
2378 | .smp_handler = mptsas_smp_handler, |
2379 | }; |
2380 | |
2381 | static struct scsi_transport_template *mptsas_transport_template; |
2382 | |
2383 | static int |
2384 | mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) |
2385 | { |
2386 | ConfigExtendedPageHeader_t hdr; |
2387 | CONFIGPARMS cfg; |
2388 | SasIOUnitPage0_t *buffer; |
2389 | dma_addr_t dma_handle; |
2390 | int error, i; |
2391 | |
2392 | hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; |
2393 | hdr.ExtPageLength = 0; |
2394 | hdr.PageNumber = 0; |
2395 | hdr.Reserved1 = 0; |
2396 | hdr.Reserved2 = 0; |
2397 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; |
2398 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; |
2399 | |
2400 | cfg.cfghdr.ehdr = &hdr; |
2401 | cfg.physAddr = -1; |
2402 | cfg.pageAddr = 0; |
2403 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
2404 | cfg.dir = 0; /* read */ |
2405 | cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; |
2406 | |
2407 | error = mpt_config(ioc, cfg: &cfg); |
2408 | if (error) |
2409 | goto out; |
2410 | if (!hdr.ExtPageLength) { |
2411 | error = -ENXIO; |
2412 | goto out; |
2413 | } |
2414 | |
2415 | buffer = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, |
2416 | dma_handle: &dma_handle, GFP_KERNEL); |
2417 | if (!buffer) { |
2418 | error = -ENOMEM; |
2419 | goto out; |
2420 | } |
2421 | |
2422 | cfg.physAddr = dma_handle; |
2423 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
2424 | |
2425 | error = mpt_config(ioc, cfg: &cfg); |
2426 | if (error) |
2427 | goto out_free_consistent; |
2428 | |
2429 | port_info->num_phys = buffer->NumPhys; |
2430 | port_info->phy_info = kcalloc(n: port_info->num_phys, |
2431 | size: sizeof(struct mptsas_phyinfo), GFP_KERNEL); |
2432 | if (!port_info->phy_info) { |
2433 | error = -ENOMEM; |
2434 | goto out_free_consistent; |
2435 | } |
2436 | |
2437 | ioc->nvdata_version_persistent = |
2438 | le16_to_cpu(buffer->NvdataVersionPersistent); |
2439 | ioc->nvdata_version_default = |
2440 | le16_to_cpu(buffer->NvdataVersionDefault); |
2441 | |
2442 | for (i = 0; i < port_info->num_phys; i++) { |
2443 | mptsas_print_phy_data(ioc, phy_data: &buffer->PhyData[i]); |
2444 | port_info->phy_info[i].phy_id = i; |
2445 | port_info->phy_info[i].port_id = |
2446 | buffer->PhyData[i].Port; |
2447 | port_info->phy_info[i].negotiated_link_rate = |
2448 | buffer->PhyData[i].NegotiatedLinkRate; |
2449 | port_info->phy_info[i].portinfo = port_info; |
2450 | port_info->phy_info[i].handle = |
2451 | le16_to_cpu(buffer->PhyData[i].ControllerDevHandle); |
2452 | } |
2453 | |
2454 | out_free_consistent: |
2455 | dma_free_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, cpu_addr: buffer, |
2456 | dma_handle); |
2457 | out: |
2458 | return error; |
2459 | } |
2460 | |
2461 | static int |
2462 | mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) |
2463 | { |
2464 | ConfigExtendedPageHeader_t hdr; |
2465 | CONFIGPARMS cfg; |
2466 | SasIOUnitPage1_t *buffer; |
2467 | dma_addr_t dma_handle; |
2468 | int error; |
2469 | u8 device_missing_delay; |
2470 | |
2471 | memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); |
2472 | memset(&cfg, 0, sizeof(CONFIGPARMS)); |
2473 | |
2474 | cfg.cfghdr.ehdr = &hdr; |
2475 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
2476 | cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; |
2477 | cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED; |
2478 | cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; |
2479 | cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION; |
2480 | cfg.cfghdr.ehdr->PageNumber = 1; |
2481 | |
2482 | error = mpt_config(ioc, cfg: &cfg); |
2483 | if (error) |
2484 | goto out; |
2485 | if (!hdr.ExtPageLength) { |
2486 | error = -ENXIO; |
2487 | goto out; |
2488 | } |
2489 | |
2490 | buffer = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, |
2491 | dma_handle: &dma_handle, GFP_KERNEL); |
2492 | if (!buffer) { |
2493 | error = -ENOMEM; |
2494 | goto out; |
2495 | } |
2496 | |
2497 | cfg.physAddr = dma_handle; |
2498 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
2499 | |
2500 | error = mpt_config(ioc, cfg: &cfg); |
2501 | if (error) |
2502 | goto out_free_consistent; |
2503 | |
2504 | ioc->io_missing_delay = |
2505 | le16_to_cpu(buffer->IODeviceMissingDelay); |
2506 | device_missing_delay = buffer->ReportDeviceMissingDelay; |
2507 | ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ? |
2508 | (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 : |
2509 | device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK; |
2510 | |
2511 | out_free_consistent: |
2512 | dma_free_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, cpu_addr: buffer, |
2513 | dma_handle); |
2514 | out: |
2515 | return error; |
2516 | } |
2517 | |
2518 | static int |
2519 | mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, |
2520 | u32 form, u32 form_specific) |
2521 | { |
2522 | ConfigExtendedPageHeader_t hdr; |
2523 | CONFIGPARMS cfg; |
2524 | SasPhyPage0_t *buffer; |
2525 | dma_addr_t dma_handle; |
2526 | int error; |
2527 | |
2528 | hdr.PageVersion = MPI_SASPHY0_PAGEVERSION; |
2529 | hdr.ExtPageLength = 0; |
2530 | hdr.PageNumber = 0; |
2531 | hdr.Reserved1 = 0; |
2532 | hdr.Reserved2 = 0; |
2533 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; |
2534 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; |
2535 | |
2536 | cfg.cfghdr.ehdr = &hdr; |
2537 | cfg.dir = 0; /* read */ |
2538 | cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; |
2539 | |
2540 | /* Get Phy Pg 0 for each Phy. */ |
2541 | cfg.physAddr = -1; |
2542 | cfg.pageAddr = form + form_specific; |
2543 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
2544 | |
2545 | error = mpt_config(ioc, cfg: &cfg); |
2546 | if (error) |
2547 | goto out; |
2548 | |
2549 | if (!hdr.ExtPageLength) { |
2550 | error = -ENXIO; |
2551 | goto out; |
2552 | } |
2553 | |
2554 | buffer = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, |
2555 | dma_handle: &dma_handle, GFP_KERNEL); |
2556 | if (!buffer) { |
2557 | error = -ENOMEM; |
2558 | goto out; |
2559 | } |
2560 | |
2561 | cfg.physAddr = dma_handle; |
2562 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
2563 | |
2564 | error = mpt_config(ioc, cfg: &cfg); |
2565 | if (error) |
2566 | goto out_free_consistent; |
2567 | |
2568 | mptsas_print_phy_pg0(ioc, pg0: buffer); |
2569 | |
2570 | phy_info->hw_link_rate = buffer->HwLinkRate; |
2571 | phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; |
2572 | phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); |
2573 | phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); |
2574 | |
2575 | out_free_consistent: |
2576 | dma_free_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, cpu_addr: buffer, |
2577 | dma_handle); |
2578 | out: |
2579 | return error; |
2580 | } |
2581 | |
2582 | static int |
2583 | mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, |
2584 | u32 form, u32 form_specific) |
2585 | { |
2586 | ConfigExtendedPageHeader_t hdr; |
2587 | CONFIGPARMS cfg; |
2588 | SasDevicePage0_t *buffer; |
2589 | dma_addr_t dma_handle; |
2590 | __le64 sas_address; |
2591 | int error=0; |
2592 | |
2593 | hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; |
2594 | hdr.ExtPageLength = 0; |
2595 | hdr.PageNumber = 0; |
2596 | hdr.Reserved1 = 0; |
2597 | hdr.Reserved2 = 0; |
2598 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; |
2599 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; |
2600 | |
2601 | cfg.cfghdr.ehdr = &hdr; |
2602 | cfg.pageAddr = form + form_specific; |
2603 | cfg.physAddr = -1; |
2604 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
2605 | cfg.dir = 0; /* read */ |
2606 | cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; |
2607 | |
2608 | memset(device_info, 0, sizeof(struct mptsas_devinfo)); |
2609 | error = mpt_config(ioc, cfg: &cfg); |
2610 | if (error) |
2611 | goto out; |
2612 | if (!hdr.ExtPageLength) { |
2613 | error = -ENXIO; |
2614 | goto out; |
2615 | } |
2616 | |
2617 | buffer = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, |
2618 | dma_handle: &dma_handle, GFP_KERNEL); |
2619 | if (!buffer) { |
2620 | error = -ENOMEM; |
2621 | goto out; |
2622 | } |
2623 | |
2624 | cfg.physAddr = dma_handle; |
2625 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
2626 | |
2627 | error = mpt_config(ioc, cfg: &cfg); |
2628 | |
2629 | if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { |
2630 | error = -ENODEV; |
2631 | goto out_free_consistent; |
2632 | } |
2633 | |
2634 | if (error) |
2635 | goto out_free_consistent; |
2636 | |
2637 | mptsas_print_device_pg0(ioc, pg0: buffer); |
2638 | |
2639 | memset(device_info, 0, sizeof(struct mptsas_devinfo)); |
2640 | device_info->handle = le16_to_cpu(buffer->DevHandle); |
2641 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); |
2642 | device_info->handle_enclosure = |
2643 | le16_to_cpu(buffer->EnclosureHandle); |
2644 | device_info->slot = le16_to_cpu(buffer->Slot); |
2645 | device_info->phy_id = buffer->PhyNum; |
2646 | device_info->port_id = buffer->PhysicalPort; |
2647 | device_info->id = buffer->TargetID; |
2648 | device_info->phys_disk_num = ~0; |
2649 | device_info->channel = buffer->Bus; |
2650 | memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); |
2651 | device_info->sas_address = le64_to_cpu(sas_address); |
2652 | device_info->device_info = |
2653 | le32_to_cpu(buffer->DeviceInfo); |
2654 | device_info->flags = le16_to_cpu(buffer->Flags); |
2655 | |
2656 | out_free_consistent: |
2657 | dma_free_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, cpu_addr: buffer, |
2658 | dma_handle); |
2659 | out: |
2660 | return error; |
2661 | } |
2662 | |
2663 | static int |
2664 | mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, |
2665 | u32 form, u32 form_specific) |
2666 | { |
2667 | ConfigExtendedPageHeader_t hdr; |
2668 | CONFIGPARMS cfg; |
2669 | SasExpanderPage0_t *buffer; |
2670 | dma_addr_t dma_handle; |
2671 | int i, error; |
2672 | __le64 sas_address; |
2673 | |
2674 | memset(port_info, 0, sizeof(struct mptsas_portinfo)); |
2675 | hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; |
2676 | hdr.ExtPageLength = 0; |
2677 | hdr.PageNumber = 0; |
2678 | hdr.Reserved1 = 0; |
2679 | hdr.Reserved2 = 0; |
2680 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; |
2681 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; |
2682 | |
2683 | cfg.cfghdr.ehdr = &hdr; |
2684 | cfg.physAddr = -1; |
2685 | cfg.pageAddr = form + form_specific; |
2686 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
2687 | cfg.dir = 0; /* read */ |
2688 | cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; |
2689 | |
2690 | memset(port_info, 0, sizeof(struct mptsas_portinfo)); |
2691 | error = mpt_config(ioc, cfg: &cfg); |
2692 | if (error) |
2693 | goto out; |
2694 | |
2695 | if (!hdr.ExtPageLength) { |
2696 | error = -ENXIO; |
2697 | goto out; |
2698 | } |
2699 | |
2700 | buffer = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, |
2701 | dma_handle: &dma_handle, GFP_KERNEL); |
2702 | if (!buffer) { |
2703 | error = -ENOMEM; |
2704 | goto out; |
2705 | } |
2706 | |
2707 | cfg.physAddr = dma_handle; |
2708 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
2709 | |
2710 | error = mpt_config(ioc, cfg: &cfg); |
2711 | if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { |
2712 | error = -ENODEV; |
2713 | goto out_free_consistent; |
2714 | } |
2715 | |
2716 | if (error) |
2717 | goto out_free_consistent; |
2718 | |
2719 | /* save config data */ |
2720 | port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1; |
2721 | port_info->phy_info = kcalloc(n: port_info->num_phys, |
2722 | size: sizeof(struct mptsas_phyinfo), GFP_KERNEL); |
2723 | if (!port_info->phy_info) { |
2724 | error = -ENOMEM; |
2725 | goto out_free_consistent; |
2726 | } |
2727 | |
2728 | memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); |
2729 | for (i = 0; i < port_info->num_phys; i++) { |
2730 | port_info->phy_info[i].portinfo = port_info; |
2731 | port_info->phy_info[i].handle = |
2732 | le16_to_cpu(buffer->DevHandle); |
2733 | port_info->phy_info[i].identify.sas_address = |
2734 | le64_to_cpu(sas_address); |
2735 | port_info->phy_info[i].identify.handle_parent = |
2736 | le16_to_cpu(buffer->ParentDevHandle); |
2737 | } |
2738 | |
2739 | out_free_consistent: |
2740 | dma_free_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, cpu_addr: buffer, |
2741 | dma_handle); |
2742 | out: |
2743 | return error; |
2744 | } |
2745 | |
2746 | static int |
2747 | mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, |
2748 | u32 form, u32 form_specific) |
2749 | { |
2750 | ConfigExtendedPageHeader_t hdr; |
2751 | CONFIGPARMS cfg; |
2752 | SasExpanderPage1_t *buffer; |
2753 | dma_addr_t dma_handle; |
2754 | int error=0; |
2755 | |
2756 | hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION; |
2757 | hdr.ExtPageLength = 0; |
2758 | hdr.PageNumber = 1; |
2759 | hdr.Reserved1 = 0; |
2760 | hdr.Reserved2 = 0; |
2761 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; |
2762 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; |
2763 | |
2764 | cfg.cfghdr.ehdr = &hdr; |
2765 | cfg.physAddr = -1; |
2766 | cfg.pageAddr = form + form_specific; |
2767 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
2768 | cfg.dir = 0; /* read */ |
2769 | cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; |
2770 | |
2771 | error = mpt_config(ioc, cfg: &cfg); |
2772 | if (error) |
2773 | goto out; |
2774 | |
2775 | if (!hdr.ExtPageLength) { |
2776 | error = -ENXIO; |
2777 | goto out; |
2778 | } |
2779 | |
2780 | buffer = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, |
2781 | dma_handle: &dma_handle, GFP_KERNEL); |
2782 | if (!buffer) { |
2783 | error = -ENOMEM; |
2784 | goto out; |
2785 | } |
2786 | |
2787 | cfg.physAddr = dma_handle; |
2788 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
2789 | |
2790 | error = mpt_config(ioc, cfg: &cfg); |
2791 | |
2792 | if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) { |
2793 | error = -ENODEV; |
2794 | goto out_free_consistent; |
2795 | } |
2796 | |
2797 | if (error) |
2798 | goto out_free_consistent; |
2799 | |
2800 | |
2801 | mptsas_print_expander_pg1(ioc, pg1: buffer); |
2802 | |
2803 | /* save config data */ |
2804 | phy_info->phy_id = buffer->PhyIdentifier; |
2805 | phy_info->port_id = buffer->PhysicalPort; |
2806 | phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate; |
2807 | phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; |
2808 | phy_info->hw_link_rate = buffer->HwLinkRate; |
2809 | phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); |
2810 | phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); |
2811 | |
2812 | out_free_consistent: |
2813 | dma_free_coherent(dev: &ioc->pcidev->dev, size: hdr.ExtPageLength * 4, cpu_addr: buffer, |
2814 | dma_handle); |
2815 | out: |
2816 | return error; |
2817 | } |
2818 | |
2819 | struct rep_manu_request{ |
2820 | u8 smp_frame_type; |
2821 | u8 function; |
2822 | u8 reserved; |
2823 | u8 request_length; |
2824 | }; |
2825 | |
2826 | struct rep_manu_reply{ |
2827 | u8 smp_frame_type; /* 0x41 */ |
2828 | u8 function; /* 0x01 */ |
2829 | u8 function_result; |
2830 | u8 response_length; |
2831 | u16 expander_change_count; |
2832 | u8 reserved0[2]; |
2833 | u8 sas_format:1; |
2834 | u8 reserved1:7; |
2835 | u8 reserved2[3]; |
2836 | u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; |
2837 | u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; |
2838 | u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; |
2839 | u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; |
2840 | u16 component_id; |
2841 | u8 component_revision_id; |
2842 | u8 reserved3; |
2843 | u8 vendor_specific[8]; |
2844 | }; |
2845 | |
2846 | /** |
2847 | * mptsas_exp_repmanufacture_info - sets expander manufacturer info |
2848 | * @ioc: per adapter object |
2849 | * @sas_address: expander sas address |
2850 | * @edev: the sas_expander_device object |
2851 | * |
2852 | * For an edge expander or a fanout expander: |
2853 | * fills in the sas_expander_device object when SMP port is created. |
2854 | * |
2855 | * Return: 0 for success, non-zero for failure. |
2856 | */ |
2857 | static int |
2858 | mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc, |
2859 | u64 sas_address, struct sas_expander_device *edev) |
2860 | { |
2861 | MPT_FRAME_HDR *mf; |
2862 | SmpPassthroughRequest_t *smpreq; |
2863 | SmpPassthroughReply_t *smprep; |
2864 | struct rep_manu_reply *manufacture_reply; |
2865 | struct rep_manu_request *manufacture_request; |
2866 | int ret; |
2867 | int flagsLength; |
2868 | unsigned long timeleft; |
2869 | char *psge; |
2870 | unsigned long flags; |
2871 | void *data_out = NULL; |
2872 | dma_addr_t data_out_dma = 0; |
2873 | u32 sz; |
2874 | |
2875 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
2876 | if (ioc->ioc_reset_in_progress) { |
2877 | spin_unlock_irqrestore(lock: &ioc->taskmgmt_lock, flags); |
2878 | printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n" , |
2879 | __func__, ioc->name); |
2880 | return -EFAULT; |
2881 | } |
2882 | spin_unlock_irqrestore(lock: &ioc->taskmgmt_lock, flags); |
2883 | |
2884 | ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); |
2885 | if (ret) |
2886 | goto out; |
2887 | |
2888 | mf = mpt_get_msg_frame(cb_idx: mptsasMgmtCtx, ioc); |
2889 | if (!mf) { |
2890 | ret = -ENOMEM; |
2891 | goto out_unlock; |
2892 | } |
2893 | |
2894 | smpreq = (SmpPassthroughRequest_t *)mf; |
2895 | memset(smpreq, 0, sizeof(*smpreq)); |
2896 | |
2897 | sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); |
2898 | |
2899 | data_out = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: sz, dma_handle: &data_out_dma, |
2900 | GFP_KERNEL); |
2901 | if (!data_out) { |
2902 | printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n" , |
2903 | __FILE__, __LINE__, __func__); |
2904 | ret = -ENOMEM; |
2905 | goto put_mf; |
2906 | } |
2907 | |
2908 | manufacture_request = data_out; |
2909 | manufacture_request->smp_frame_type = 0x40; |
2910 | manufacture_request->function = 1; |
2911 | manufacture_request->reserved = 0; |
2912 | manufacture_request->request_length = 0; |
2913 | |
2914 | smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; |
2915 | smpreq->PhysicalPort = 0xFF; |
2916 | *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); |
2917 | smpreq->RequestDataLength = sizeof(struct rep_manu_request); |
2918 | |
2919 | psge = (char *) |
2920 | (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); |
2921 | |
2922 | flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | |
2923 | MPI_SGE_FLAGS_SYSTEM_ADDRESS | |
2924 | MPI_SGE_FLAGS_HOST_TO_IOC | |
2925 | MPI_SGE_FLAGS_END_OF_BUFFER; |
2926 | flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; |
2927 | flagsLength |= sizeof(struct rep_manu_request); |
2928 | |
2929 | ioc->add_sge(psge, flagsLength, data_out_dma); |
2930 | psge += ioc->SGE_size; |
2931 | |
2932 | flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT | |
2933 | MPI_SGE_FLAGS_SYSTEM_ADDRESS | |
2934 | MPI_SGE_FLAGS_IOC_TO_HOST | |
2935 | MPI_SGE_FLAGS_END_OF_BUFFER; |
2936 | flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT; |
2937 | flagsLength |= sizeof(struct rep_manu_reply); |
2938 | ioc->add_sge(psge, flagsLength, data_out_dma + |
2939 | sizeof(struct rep_manu_request)); |
2940 | |
2941 | INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status) |
2942 | mpt_put_msg_frame(cb_idx: mptsasMgmtCtx, ioc, mf); |
2943 | |
2944 | timeleft = wait_for_completion_timeout(x: &ioc->sas_mgmt.done, timeout: 10 * HZ); |
2945 | if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { |
2946 | ret = -ETIME; |
2947 | mpt_free_msg_frame(ioc, mf); |
2948 | mf = NULL; |
2949 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET) |
2950 | goto out_free; |
2951 | if (!timeleft) |
2952 | mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); |
2953 | goto out_free; |
2954 | } |
2955 | |
2956 | mf = NULL; |
2957 | |
2958 | if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) { |
2959 | u8 *tmp; |
2960 | |
2961 | smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; |
2962 | if (le16_to_cpu(smprep->ResponseDataLength) != |
2963 | sizeof(struct rep_manu_reply)) |
2964 | goto out_free; |
2965 | |
2966 | manufacture_reply = data_out + sizeof(struct rep_manu_request); |
2967 | strscpy(p: edev->vendor_id, q: manufacture_reply->vendor_id, |
2968 | size: sizeof(edev->vendor_id)); |
2969 | strscpy(p: edev->product_id, q: manufacture_reply->product_id, |
2970 | size: sizeof(edev->product_id)); |
2971 | strscpy(p: edev->product_rev, q: manufacture_reply->product_rev, |
2972 | size: sizeof(edev->product_rev)); |
2973 | edev->level = manufacture_reply->sas_format; |
2974 | if (manufacture_reply->sas_format) { |
2975 | strscpy(p: edev->component_vendor_id, |
2976 | q: manufacture_reply->component_vendor_id, |
2977 | size: sizeof(edev->component_vendor_id)); |
2978 | tmp = (u8 *)&manufacture_reply->component_id; |
2979 | edev->component_id = tmp[0] << 8 | tmp[1]; |
2980 | edev->component_revision_id = |
2981 | manufacture_reply->component_revision_id; |
2982 | } |
2983 | } else { |
2984 | printk(MYIOC_s_ERR_FMT |
2985 | "%s: smp passthru reply failed to be returned\n" , |
2986 | ioc->name, __func__); |
2987 | ret = -ENXIO; |
2988 | } |
2989 | out_free: |
2990 | if (data_out_dma) |
2991 | dma_free_coherent(dev: &ioc->pcidev->dev, size: sz, cpu_addr: data_out, |
2992 | dma_handle: data_out_dma); |
2993 | put_mf: |
2994 | if (mf) |
2995 | mpt_free_msg_frame(ioc, mf); |
2996 | out_unlock: |
2997 | CLEAR_MGMT_STATUS(ioc->sas_mgmt.status) |
2998 | mutex_unlock(lock: &ioc->sas_mgmt.mutex); |
2999 | out: |
3000 | return ret; |
3001 | } |
3002 | |
3003 | static void |
3004 | mptsas_parse_device_info(struct sas_identify *identify, |
3005 | struct mptsas_devinfo *device_info) |
3006 | { |
3007 | u16 protocols; |
3008 | |
3009 | identify->sas_address = device_info->sas_address; |
3010 | identify->phy_identifier = device_info->phy_id; |
3011 | |
3012 | /* |
3013 | * Fill in Phy Initiator Port Protocol. |
3014 | * Bits 6:3, more than one bit can be set, fall through cases. |
3015 | */ |
3016 | protocols = device_info->device_info & 0x78; |
3017 | identify->initiator_port_protocols = 0; |
3018 | if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) |
3019 | identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; |
3020 | if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR) |
3021 | identify->initiator_port_protocols |= SAS_PROTOCOL_STP; |
3022 | if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) |
3023 | identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; |
3024 | if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST) |
3025 | identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; |
3026 | |
3027 | /* |
3028 | * Fill in Phy Target Port Protocol. |
3029 | * Bits 10:7, more than one bit can be set, fall through cases. |
3030 | */ |
3031 | protocols = device_info->device_info & 0x780; |
3032 | identify->target_port_protocols = 0; |
3033 | if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET) |
3034 | identify->target_port_protocols |= SAS_PROTOCOL_SSP; |
3035 | if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET) |
3036 | identify->target_port_protocols |= SAS_PROTOCOL_STP; |
3037 | if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET) |
3038 | identify->target_port_protocols |= SAS_PROTOCOL_SMP; |
3039 | if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE) |
3040 | identify->target_port_protocols |= SAS_PROTOCOL_SATA; |
3041 | |
3042 | /* |
3043 | * Fill in Attached device type. |
3044 | */ |
3045 | switch (device_info->device_info & |
3046 | MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { |
3047 | case MPI_SAS_DEVICE_INFO_NO_DEVICE: |
3048 | identify->device_type = SAS_PHY_UNUSED; |
3049 | break; |
3050 | case MPI_SAS_DEVICE_INFO_END_DEVICE: |
3051 | identify->device_type = SAS_END_DEVICE; |
3052 | break; |
3053 | case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: |
3054 | identify->device_type = SAS_EDGE_EXPANDER_DEVICE; |
3055 | break; |
3056 | case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: |
3057 | identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; |
3058 | break; |
3059 | } |
3060 | } |
3061 | |
3062 | static int mptsas_probe_one_phy(struct device *dev, |
3063 | struct mptsas_phyinfo *phy_info, int index, int local) |
3064 | { |
3065 | MPT_ADAPTER *ioc; |
3066 | struct sas_phy *phy; |
3067 | struct sas_port *port; |
3068 | int error = 0; |
3069 | VirtTarget *vtarget; |
3070 | |
3071 | if (!dev) { |
3072 | error = -ENODEV; |
3073 | goto out; |
3074 | } |
3075 | |
3076 | if (!phy_info->phy) { |
3077 | phy = sas_phy_alloc(dev, index); |
3078 | if (!phy) { |
3079 | error = -ENOMEM; |
3080 | goto out; |
3081 | } |
3082 | } else |
3083 | phy = phy_info->phy; |
3084 | |
3085 | mptsas_parse_device_info(identify: &phy->identify, device_info: &phy_info->identify); |
3086 | |
3087 | /* |
3088 | * Set Negotiated link rate. |
3089 | */ |
3090 | switch (phy_info->negotiated_link_rate) { |
3091 | case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: |
3092 | phy->negotiated_linkrate = SAS_PHY_DISABLED; |
3093 | break; |
3094 | case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: |
3095 | phy->negotiated_linkrate = SAS_LINK_RATE_FAILED; |
3096 | break; |
3097 | case MPI_SAS_IOUNIT0_RATE_1_5: |
3098 | phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; |
3099 | break; |
3100 | case MPI_SAS_IOUNIT0_RATE_3_0: |
3101 | phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; |
3102 | break; |
3103 | case MPI_SAS_IOUNIT0_RATE_6_0: |
3104 | phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; |
3105 | break; |
3106 | case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: |
3107 | case MPI_SAS_IOUNIT0_RATE_UNKNOWN: |
3108 | default: |
3109 | phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; |
3110 | break; |
3111 | } |
3112 | |
3113 | /* |
3114 | * Set Max hardware link rate. |
3115 | */ |
3116 | switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { |
3117 | case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: |
3118 | phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; |
3119 | break; |
3120 | case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: |
3121 | phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; |
3122 | break; |
3123 | default: |
3124 | break; |
3125 | } |
3126 | |
3127 | /* |
3128 | * Set Max programmed link rate. |
3129 | */ |
3130 | switch (phy_info->programmed_link_rate & |
3131 | MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { |
3132 | case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: |
3133 | phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS; |
3134 | break; |
3135 | case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: |
3136 | phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; |
3137 | break; |
3138 | default: |
3139 | break; |
3140 | } |
3141 | |
3142 | /* |
3143 | * Set Min hardware link rate. |
3144 | */ |
3145 | switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { |
3146 | case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: |
3147 | phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; |
3148 | break; |
3149 | case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: |
3150 | phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; |
3151 | break; |
3152 | default: |
3153 | break; |
3154 | } |
3155 | |
3156 | /* |
3157 | * Set Min programmed link rate. |
3158 | */ |
3159 | switch (phy_info->programmed_link_rate & |
3160 | MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { |
3161 | case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: |
3162 | phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; |
3163 | break; |
3164 | case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: |
3165 | phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS; |
3166 | break; |
3167 | default: |
3168 | break; |
3169 | } |
3170 | |
3171 | if (!phy_info->phy) { |
3172 | |
3173 | error = sas_phy_add(phy); |
3174 | if (error) { |
3175 | sas_phy_free(phy); |
3176 | goto out; |
3177 | } |
3178 | phy_info->phy = phy; |
3179 | } |
3180 | |
3181 | if (!phy_info->attached.handle || |
3182 | !phy_info->port_details) |
3183 | goto out; |
3184 | |
3185 | port = mptsas_get_port(phy_info); |
3186 | ioc = phy_to_ioc(phy: phy_info->phy); |
3187 | |
3188 | if (phy_info->sas_port_add_phy) { |
3189 | |
3190 | if (!port) { |
3191 | port = sas_port_alloc_num(dev); |
3192 | if (!port) { |
3193 | error = -ENOMEM; |
3194 | goto out; |
3195 | } |
3196 | error = sas_port_add(port); |
3197 | if (error) { |
3198 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
3199 | "%s: exit at line=%d\n" , ioc->name, |
3200 | __func__, __LINE__)); |
3201 | goto out; |
3202 | } |
3203 | mptsas_set_port(ioc, phy_info, port); |
3204 | devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, |
3205 | MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n" , |
3206 | ioc->name, port->port_identifier, |
3207 | (unsigned long long)phy_info-> |
3208 | attached.sas_address)); |
3209 | } |
3210 | dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3211 | "sas_port_add_phy: phy_id=%d\n" , |
3212 | ioc->name, phy_info->phy_id)); |
3213 | sas_port_add_phy(port, phy_info->phy); |
3214 | phy_info->sas_port_add_phy = 0; |
3215 | devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev, |
3216 | MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n" , ioc->name, |
3217 | phy_info->phy_id, phy_info->phy)); |
3218 | } |
3219 | if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { |
3220 | |
3221 | struct sas_rphy *rphy; |
3222 | struct device *parent; |
3223 | struct sas_identify identify; |
3224 | |
3225 | parent = dev->parent->parent; |
3226 | /* |
3227 | * Let the hotplug_work thread handle processing |
3228 | * the adding/removing of devices that occur |
3229 | * after start of day. |
3230 | */ |
3231 | if (mptsas_is_end_device(attached: &phy_info->attached) && |
3232 | phy_info->attached.handle_parent) { |
3233 | goto out; |
3234 | } |
3235 | |
3236 | mptsas_parse_device_info(identify: &identify, device_info: &phy_info->attached); |
3237 | if (scsi_is_host_device(parent)) { |
3238 | struct mptsas_portinfo *port_info; |
3239 | int i; |
3240 | |
3241 | port_info = ioc->hba_port_info; |
3242 | |
3243 | for (i = 0; i < port_info->num_phys; i++) |
3244 | if (port_info->phy_info[i].identify.sas_address == |
3245 | identify.sas_address) { |
3246 | sas_port_mark_backlink(port); |
3247 | goto out; |
3248 | } |
3249 | |
3250 | } else if (scsi_is_sas_rphy(parent)) { |
3251 | struct sas_rphy *parent_rphy = dev_to_rphy(parent); |
3252 | if (identify.sas_address == |
3253 | parent_rphy->identify.sas_address) { |
3254 | sas_port_mark_backlink(port); |
3255 | goto out; |
3256 | } |
3257 | } |
3258 | |
3259 | switch (identify.device_type) { |
3260 | case SAS_END_DEVICE: |
3261 | rphy = sas_end_device_alloc(port); |
3262 | break; |
3263 | case SAS_EDGE_EXPANDER_DEVICE: |
3264 | case SAS_FANOUT_EXPANDER_DEVICE: |
3265 | rphy = sas_expander_alloc(port, identify.device_type); |
3266 | break; |
3267 | default: |
3268 | rphy = NULL; |
3269 | break; |
3270 | } |
3271 | if (!rphy) { |
3272 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
3273 | "%s: exit at line=%d\n" , ioc->name, |
3274 | __func__, __LINE__)); |
3275 | goto out; |
3276 | } |
3277 | |
3278 | rphy->identify = identify; |
3279 | error = sas_rphy_add(rphy); |
3280 | if (error) { |
3281 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
3282 | "%s: exit at line=%d\n" , ioc->name, |
3283 | __func__, __LINE__)); |
3284 | sas_rphy_free(rphy); |
3285 | goto out; |
3286 | } |
3287 | mptsas_set_rphy(ioc, phy_info, rphy); |
3288 | if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE || |
3289 | identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) |
3290 | mptsas_exp_repmanufacture_info(ioc, |
3291 | sas_address: identify.sas_address, |
3292 | rphy_to_expander_device(rphy)); |
3293 | } |
3294 | |
3295 | /* If the device exists, verify it wasn't previously flagged |
3296 | as a missing device. If so, clear it */ |
3297 | vtarget = mptsas_find_vtarget(ioc, |
3298 | channel: phy_info->attached.channel, |
3299 | id: phy_info->attached.id); |
3300 | if (vtarget && vtarget->inDMD) { |
3301 | printk(KERN_INFO "Device returned, unsetting inDMD\n" ); |
3302 | vtarget->inDMD = 0; |
3303 | } |
3304 | |
3305 | out: |
3306 | return error; |
3307 | } |
3308 | |
3309 | static int |
3310 | mptsas_probe_hba_phys(MPT_ADAPTER *ioc) |
3311 | { |
3312 | struct mptsas_portinfo *port_info, *hba; |
3313 | int error = -ENOMEM, i; |
3314 | |
3315 | hba = kzalloc(size: sizeof(struct mptsas_portinfo), GFP_KERNEL); |
3316 | if (! hba) |
3317 | goto out; |
3318 | |
3319 | error = mptsas_sas_io_unit_pg0(ioc, port_info: hba); |
3320 | if (error) |
3321 | goto out_free_port_info; |
3322 | |
3323 | mptsas_sas_io_unit_pg1(ioc); |
3324 | mutex_lock(&ioc->sas_topology_mutex); |
3325 | port_info = ioc->hba_port_info; |
3326 | if (!port_info) { |
3327 | ioc->hba_port_info = port_info = hba; |
3328 | ioc->hba_port_num_phy = port_info->num_phys; |
3329 | list_add_tail(new: &port_info->list, head: &ioc->sas_topology); |
3330 | } else { |
3331 | for (i = 0; i < hba->num_phys; i++) { |
3332 | port_info->phy_info[i].negotiated_link_rate = |
3333 | hba->phy_info[i].negotiated_link_rate; |
3334 | port_info->phy_info[i].handle = |
3335 | hba->phy_info[i].handle; |
3336 | port_info->phy_info[i].port_id = |
3337 | hba->phy_info[i].port_id; |
3338 | } |
3339 | kfree(objp: hba->phy_info); |
3340 | kfree(objp: hba); |
3341 | hba = NULL; |
3342 | } |
3343 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
3344 | #if defined(CPQ_CIM) |
3345 | ioc->num_ports = port_info->num_phys; |
3346 | #endif |
3347 | for (i = 0; i < port_info->num_phys; i++) { |
3348 | mptsas_sas_phy_pg0(ioc, phy_info: &port_info->phy_info[i], |
3349 | form: (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << |
3350 | MPI_SAS_PHY_PGAD_FORM_SHIFT), form_specific: i); |
3351 | port_info->phy_info[i].identify.handle = |
3352 | port_info->phy_info[i].handle; |
3353 | mptsas_sas_device_pg0(ioc, device_info: &port_info->phy_info[i].identify, |
3354 | form: (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
3355 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
3356 | form_specific: port_info->phy_info[i].identify.handle); |
3357 | if (!ioc->hba_port_sas_addr) |
3358 | ioc->hba_port_sas_addr = |
3359 | port_info->phy_info[i].identify.sas_address; |
3360 | port_info->phy_info[i].identify.phy_id = |
3361 | port_info->phy_info[i].phy_id = i; |
3362 | if (port_info->phy_info[i].attached.handle) |
3363 | mptsas_sas_device_pg0(ioc, |
3364 | device_info: &port_info->phy_info[i].attached, |
3365 | form: (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
3366 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
3367 | form_specific: port_info->phy_info[i].attached.handle); |
3368 | } |
3369 | |
3370 | mptsas_setup_wide_ports(ioc, port_info); |
3371 | |
3372 | for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) |
3373 | mptsas_probe_one_phy(dev: &ioc->sh->shost_gendev, |
3374 | phy_info: &port_info->phy_info[i], index: ioc->sas_index, local: 1); |
3375 | |
3376 | return 0; |
3377 | |
3378 | out_free_port_info: |
3379 | kfree(objp: hba); |
3380 | out: |
3381 | return error; |
3382 | } |
3383 | |
3384 | static void |
3385 | mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) |
3386 | { |
3387 | struct mptsas_portinfo *parent; |
3388 | struct device *parent_dev; |
3389 | struct sas_rphy *rphy; |
3390 | int i; |
3391 | u64 sas_address; /* expander sas address */ |
3392 | u32 handle; |
3393 | |
3394 | handle = port_info->phy_info[0].handle; |
3395 | sas_address = port_info->phy_info[0].identify.sas_address; |
3396 | for (i = 0; i < port_info->num_phys; i++) { |
3397 | mptsas_sas_expander_pg1(ioc, phy_info: &port_info->phy_info[i], |
3398 | form: (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << |
3399 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), form_specific: (i << 16) + handle); |
3400 | |
3401 | mptsas_sas_device_pg0(ioc, |
3402 | device_info: &port_info->phy_info[i].identify, |
3403 | form: (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
3404 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
3405 | form_specific: port_info->phy_info[i].identify.handle); |
3406 | port_info->phy_info[i].identify.phy_id = |
3407 | port_info->phy_info[i].phy_id; |
3408 | |
3409 | if (port_info->phy_info[i].attached.handle) { |
3410 | mptsas_sas_device_pg0(ioc, |
3411 | device_info: &port_info->phy_info[i].attached, |
3412 | form: (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
3413 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
3414 | form_specific: port_info->phy_info[i].attached.handle); |
3415 | port_info->phy_info[i].attached.phy_id = |
3416 | port_info->phy_info[i].phy_id; |
3417 | } |
3418 | } |
3419 | |
3420 | mutex_lock(&ioc->sas_topology_mutex); |
3421 | parent = mptsas_find_portinfo_by_handle(ioc, |
3422 | handle: port_info->phy_info[0].identify.handle_parent); |
3423 | if (!parent) { |
3424 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
3425 | return; |
3426 | } |
3427 | for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev; |
3428 | i++) { |
3429 | if (parent->phy_info[i].attached.sas_address == sas_address) { |
3430 | rphy = mptsas_get_rphy(phy_info: &parent->phy_info[i]); |
3431 | parent_dev = &rphy->dev; |
3432 | } |
3433 | } |
3434 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
3435 | |
3436 | mptsas_setup_wide_ports(ioc, port_info); |
3437 | for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) |
3438 | mptsas_probe_one_phy(dev: parent_dev, phy_info: &port_info->phy_info[i], |
3439 | index: ioc->sas_index, local: 0); |
3440 | } |
3441 | |
3442 | static void |
3443 | mptsas_expander_event_add(MPT_ADAPTER *ioc, |
3444 | MpiEventDataSasExpanderStatusChange_t *expander_data) |
3445 | { |
3446 | struct mptsas_portinfo *port_info; |
3447 | int i; |
3448 | __le64 sas_address; |
3449 | |
3450 | port_info = kzalloc(size: sizeof(struct mptsas_portinfo), GFP_KERNEL); |
3451 | BUG_ON(!port_info); |
3452 | port_info->num_phys = (expander_data->NumPhys) ? |
3453 | expander_data->NumPhys : 1; |
3454 | port_info->phy_info = kcalloc(n: port_info->num_phys, |
3455 | size: sizeof(struct mptsas_phyinfo), GFP_KERNEL); |
3456 | BUG_ON(!port_info->phy_info); |
3457 | memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); |
3458 | for (i = 0; i < port_info->num_phys; i++) { |
3459 | port_info->phy_info[i].portinfo = port_info; |
3460 | port_info->phy_info[i].handle = |
3461 | le16_to_cpu(expander_data->DevHandle); |
3462 | port_info->phy_info[i].identify.sas_address = |
3463 | le64_to_cpu(sas_address); |
3464 | port_info->phy_info[i].identify.handle_parent = |
3465 | le16_to_cpu(expander_data->ParentDevHandle); |
3466 | } |
3467 | |
3468 | mutex_lock(&ioc->sas_topology_mutex); |
3469 | list_add_tail(new: &port_info->list, head: &ioc->sas_topology); |
3470 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
3471 | |
3472 | printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " |
3473 | "sas_addr (0x%llx)\n" , ioc->name, port_info->num_phys, |
3474 | (unsigned long long)sas_address); |
3475 | |
3476 | mptsas_expander_refresh(ioc, port_info); |
3477 | } |
3478 | |
3479 | /** |
3480 | * mptsas_delete_expander_siblings - remove siblings attached to expander |
3481 | * @ioc: Pointer to MPT_ADAPTER structure |
3482 | * @parent: the parent port_info object |
3483 | * @expander: the expander port_info object |
3484 | **/ |
3485 | static void |
3486 | mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo |
3487 | *parent, struct mptsas_portinfo *expander) |
3488 | { |
3489 | struct mptsas_phyinfo *phy_info; |
3490 | struct mptsas_portinfo *port_info; |
3491 | struct sas_rphy *rphy; |
3492 | int i; |
3493 | |
3494 | phy_info = expander->phy_info; |
3495 | for (i = 0; i < expander->num_phys; i++, phy_info++) { |
3496 | rphy = mptsas_get_rphy(phy_info); |
3497 | if (!rphy) |
3498 | continue; |
3499 | if (rphy->identify.device_type == SAS_END_DEVICE) |
3500 | mptsas_del_end_device(ioc, phy_info); |
3501 | } |
3502 | |
3503 | phy_info = expander->phy_info; |
3504 | for (i = 0; i < expander->num_phys; i++, phy_info++) { |
3505 | rphy = mptsas_get_rphy(phy_info); |
3506 | if (!rphy) |
3507 | continue; |
3508 | if (rphy->identify.device_type == |
3509 | MPI_SAS_DEVICE_INFO_EDGE_EXPANDER || |
3510 | rphy->identify.device_type == |
3511 | MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) { |
3512 | port_info = mptsas_find_portinfo_by_sas_address(ioc, |
3513 | sas_address: rphy->identify.sas_address); |
3514 | if (!port_info) |
3515 | continue; |
3516 | if (port_info == parent) /* backlink rphy */ |
3517 | continue; |
3518 | /* |
3519 | Delete this expander even if the expdevpage is exists |
3520 | because the parent expander is already deleted |
3521 | */ |
3522 | mptsas_expander_delete(ioc, port_info, force: 1); |
3523 | } |
3524 | } |
3525 | } |
3526 | |
3527 | |
3528 | /** |
3529 | * mptsas_expander_delete - remove this expander |
3530 | * @ioc: Pointer to MPT_ADAPTER structure |
3531 | * @port_info: expander port_info struct |
3532 | * @force: Flag to forcefully delete the expander |
3533 | * |
3534 | **/ |
3535 | |
3536 | static void mptsas_expander_delete(MPT_ADAPTER *ioc, |
3537 | struct mptsas_portinfo *port_info, u8 force) |
3538 | { |
3539 | |
3540 | struct mptsas_portinfo *parent; |
3541 | int i; |
3542 | u64 expander_sas_address; |
3543 | struct mptsas_phyinfo *phy_info; |
3544 | struct mptsas_portinfo buffer; |
3545 | struct mptsas_portinfo_details *port_details; |
3546 | struct sas_port *port; |
3547 | |
3548 | if (!port_info) |
3549 | return; |
3550 | |
3551 | /* see if expander is still there before deleting */ |
3552 | mptsas_sas_expander_pg0(ioc, port_info: &buffer, |
3553 | form: (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << |
3554 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), |
3555 | form_specific: port_info->phy_info[0].identify.handle); |
3556 | |
3557 | if (buffer.num_phys) { |
3558 | kfree(objp: buffer.phy_info); |
3559 | if (!force) |
3560 | return; |
3561 | } |
3562 | |
3563 | |
3564 | /* |
3565 | * Obtain the port_info instance to the parent port |
3566 | */ |
3567 | port_details = NULL; |
3568 | expander_sas_address = |
3569 | port_info->phy_info[0].identify.sas_address; |
3570 | parent = mptsas_find_portinfo_by_handle(ioc, |
3571 | handle: port_info->phy_info[0].identify.handle_parent); |
3572 | mptsas_delete_expander_siblings(ioc, parent, expander: port_info); |
3573 | if (!parent) |
3574 | goto out; |
3575 | |
3576 | /* |
3577 | * Delete rphys in the parent that point |
3578 | * to this expander. |
3579 | */ |
3580 | phy_info = parent->phy_info; |
3581 | port = NULL; |
3582 | for (i = 0; i < parent->num_phys; i++, phy_info++) { |
3583 | if (!phy_info->phy) |
3584 | continue; |
3585 | if (phy_info->attached.sas_address != |
3586 | expander_sas_address) |
3587 | continue; |
3588 | if (!port) { |
3589 | port = mptsas_get_port(phy_info); |
3590 | port_details = phy_info->port_details; |
3591 | } |
3592 | dev_printk(KERN_DEBUG, &phy_info->phy->dev, |
3593 | MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n" , ioc->name, |
3594 | phy_info->phy_id, phy_info->phy); |
3595 | sas_port_delete_phy(port, phy_info->phy); |
3596 | } |
3597 | if (port) { |
3598 | dev_printk(KERN_DEBUG, &port->dev, |
3599 | MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n" , |
3600 | ioc->name, port->port_identifier, |
3601 | (unsigned long long)expander_sas_address); |
3602 | sas_port_delete(port); |
3603 | mptsas_port_delete(ioc, port_details); |
3604 | } |
3605 | out: |
3606 | |
3607 | printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, " |
3608 | "sas_addr (0x%llx)\n" , ioc->name, port_info->num_phys, |
3609 | (unsigned long long)expander_sas_address); |
3610 | |
3611 | /* |
3612 | * free link |
3613 | */ |
3614 | list_del(entry: &port_info->list); |
3615 | kfree(objp: port_info->phy_info); |
3616 | kfree(objp: port_info); |
3617 | } |
3618 | |
3619 | |
3620 | /** |
3621 | * mptsas_send_expander_event - expanders events |
3622 | * @fw_event: event data |
3623 | * |
3624 | * |
3625 | * This function handles adding, removing, and refreshing |
3626 | * device handles within the expander objects. |
3627 | */ |
3628 | static void |
3629 | mptsas_send_expander_event(struct fw_event_work *fw_event) |
3630 | { |
3631 | MPT_ADAPTER *ioc; |
3632 | MpiEventDataSasExpanderStatusChange_t *expander_data; |
3633 | struct mptsas_portinfo *port_info; |
3634 | __le64 sas_address; |
3635 | int i; |
3636 | |
3637 | ioc = fw_event->ioc; |
3638 | expander_data = (MpiEventDataSasExpanderStatusChange_t *) |
3639 | fw_event->event_data; |
3640 | memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64)); |
3641 | sas_address = le64_to_cpu(sas_address); |
3642 | port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); |
3643 | |
3644 | if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) { |
3645 | if (port_info) { |
3646 | for (i = 0; i < port_info->num_phys; i++) { |
3647 | port_info->phy_info[i].portinfo = port_info; |
3648 | port_info->phy_info[i].handle = |
3649 | le16_to_cpu(expander_data->DevHandle); |
3650 | port_info->phy_info[i].identify.sas_address = |
3651 | le64_to_cpu(sas_address); |
3652 | port_info->phy_info[i].identify.handle_parent = |
3653 | le16_to_cpu(expander_data->ParentDevHandle); |
3654 | } |
3655 | mptsas_expander_refresh(ioc, port_info); |
3656 | } else if (!port_info && expander_data->NumPhys) |
3657 | mptsas_expander_event_add(ioc, expander_data); |
3658 | } else if (expander_data->ReasonCode == |
3659 | MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING) |
3660 | mptsas_expander_delete(ioc, port_info, force: 0); |
3661 | |
3662 | mptsas_free_fw_event(ioc, fw_event); |
3663 | } |
3664 | |
3665 | |
3666 | /** |
3667 | * mptsas_expander_add - adds a newly discovered expander |
3668 | * @ioc: Pointer to MPT_ADAPTER structure |
3669 | * @handle: device handle |
3670 | * |
3671 | */ |
3672 | static struct mptsas_portinfo * |
3673 | mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle) |
3674 | { |
3675 | struct mptsas_portinfo buffer, *port_info; |
3676 | int i; |
3677 | |
3678 | if ((mptsas_sas_expander_pg0(ioc, port_info: &buffer, |
3679 | form: (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << |
3680 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), form_specific: handle))) |
3681 | return NULL; |
3682 | |
3683 | port_info = kzalloc(size: sizeof(struct mptsas_portinfo), GFP_KERNEL); |
3684 | if (!port_info) { |
3685 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
3686 | "%s: exit at line=%d\n" , ioc->name, |
3687 | __func__, __LINE__)); |
3688 | return NULL; |
3689 | } |
3690 | port_info->num_phys = buffer.num_phys; |
3691 | port_info->phy_info = buffer.phy_info; |
3692 | for (i = 0; i < port_info->num_phys; i++) |
3693 | port_info->phy_info[i].portinfo = port_info; |
3694 | mutex_lock(&ioc->sas_topology_mutex); |
3695 | list_add_tail(new: &port_info->list, head: &ioc->sas_topology); |
3696 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
3697 | printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " |
3698 | "sas_addr (0x%llx)\n" , ioc->name, port_info->num_phys, |
3699 | (unsigned long long)buffer.phy_info[0].identify.sas_address); |
3700 | mptsas_expander_refresh(ioc, port_info); |
3701 | return port_info; |
3702 | } |
3703 | |
3704 | static void |
3705 | mptsas_send_link_status_event(struct fw_event_work *fw_event) |
3706 | { |
3707 | MPT_ADAPTER *ioc; |
3708 | MpiEventDataSasPhyLinkStatus_t *link_data; |
3709 | struct mptsas_portinfo *port_info; |
3710 | struct mptsas_phyinfo *phy_info = NULL; |
3711 | __le64 sas_address; |
3712 | u8 phy_num; |
3713 | u8 link_rate; |
3714 | |
3715 | ioc = fw_event->ioc; |
3716 | link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data; |
3717 | |
3718 | memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64)); |
3719 | sas_address = le64_to_cpu(sas_address); |
3720 | link_rate = link_data->LinkRates >> 4; |
3721 | phy_num = link_data->PhyNum; |
3722 | |
3723 | port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address); |
3724 | if (port_info) { |
3725 | phy_info = &port_info->phy_info[phy_num]; |
3726 | if (phy_info) |
3727 | phy_info->negotiated_link_rate = link_rate; |
3728 | } |
3729 | |
3730 | if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 || |
3731 | link_rate == MPI_SAS_IOUNIT0_RATE_3_0 || |
3732 | link_rate == MPI_SAS_IOUNIT0_RATE_6_0) { |
3733 | |
3734 | if (!port_info) { |
3735 | if (ioc->old_sas_discovery_protocal) { |
3736 | port_info = mptsas_expander_add(ioc, |
3737 | le16_to_cpu(link_data->DevHandle)); |
3738 | if (port_info) |
3739 | goto out; |
3740 | } |
3741 | goto out; |
3742 | } |
3743 | |
3744 | if (port_info == ioc->hba_port_info) |
3745 | mptsas_probe_hba_phys(ioc); |
3746 | else |
3747 | mptsas_expander_refresh(ioc, port_info); |
3748 | } else if (phy_info && phy_info->phy) { |
3749 | if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED) |
3750 | phy_info->phy->negotiated_linkrate = |
3751 | SAS_PHY_DISABLED; |
3752 | else if (link_rate == |
3753 | MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) |
3754 | phy_info->phy->negotiated_linkrate = |
3755 | SAS_LINK_RATE_FAILED; |
3756 | else { |
3757 | phy_info->phy->negotiated_linkrate = |
3758 | SAS_LINK_RATE_UNKNOWN; |
3759 | if (ioc->device_missing_delay && |
3760 | mptsas_is_end_device(attached: &phy_info->attached)) { |
3761 | struct scsi_device *sdev; |
3762 | VirtDevice *vdevice; |
3763 | u8 channel, id; |
3764 | id = phy_info->attached.id; |
3765 | channel = phy_info->attached.channel; |
3766 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3767 | "Link down for fw_id %d:fw_channel %d\n" , |
3768 | ioc->name, phy_info->attached.id, |
3769 | phy_info->attached.channel)); |
3770 | |
3771 | shost_for_each_device(sdev, ioc->sh) { |
3772 | vdevice = sdev->hostdata; |
3773 | if ((vdevice == NULL) || |
3774 | (vdevice->vtarget == NULL)) |
3775 | continue; |
3776 | if ((vdevice->vtarget->tflags & |
3777 | MPT_TARGET_FLAGS_RAID_COMPONENT || |
3778 | vdevice->vtarget->raidVolume)) |
3779 | continue; |
3780 | if (vdevice->vtarget->id == id && |
3781 | vdevice->vtarget->channel == |
3782 | channel) |
3783 | devtprintk(ioc, |
3784 | printk(MYIOC_s_DEBUG_FMT |
3785 | "SDEV OUTSTANDING CMDS" |
3786 | "%d\n" , ioc->name, |
3787 | scsi_device_busy(sdev))); |
3788 | } |
3789 | |
3790 | } |
3791 | } |
3792 | } |
3793 | out: |
3794 | mptsas_free_fw_event(ioc, fw_event); |
3795 | } |
3796 | |
3797 | static void |
3798 | mptsas_not_responding_devices(MPT_ADAPTER *ioc) |
3799 | { |
3800 | struct mptsas_portinfo buffer, *port_info; |
3801 | struct mptsas_device_info *sas_info; |
3802 | struct mptsas_devinfo sas_device; |
3803 | u32 handle; |
3804 | VirtTarget *vtarget = NULL; |
3805 | struct mptsas_phyinfo *phy_info; |
3806 | u8 found_expander; |
3807 | int retval, retry_count; |
3808 | unsigned long flags; |
3809 | |
3810 | mpt_findImVolumes(ioc); |
3811 | |
3812 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
3813 | if (ioc->ioc_reset_in_progress) { |
3814 | dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3815 | "%s: exiting due to a parallel reset \n" , ioc->name, |
3816 | __func__)); |
3817 | spin_unlock_irqrestore(lock: &ioc->taskmgmt_lock, flags); |
3818 | return; |
3819 | } |
3820 | spin_unlock_irqrestore(lock: &ioc->taskmgmt_lock, flags); |
3821 | |
3822 | /* devices, logical volumes */ |
3823 | mutex_lock(&ioc->sas_device_info_mutex); |
3824 | redo_device_scan: |
3825 | list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) { |
3826 | if (sas_info->is_cached) |
3827 | continue; |
3828 | if (!sas_info->is_logical_volume) { |
3829 | sas_device.handle = 0; |
3830 | retry_count = 0; |
3831 | retry_page: |
3832 | retval = mptsas_sas_device_pg0(ioc, device_info: &sas_device, |
3833 | form: (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID |
3834 | << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
3835 | form_specific: (sas_info->fw.channel << 8) + |
3836 | sas_info->fw.id); |
3837 | |
3838 | if (sas_device.handle) |
3839 | continue; |
3840 | if (retval == -EBUSY) { |
3841 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
3842 | if (ioc->ioc_reset_in_progress) { |
3843 | dfailprintk(ioc, |
3844 | printk(MYIOC_s_DEBUG_FMT |
3845 | "%s: exiting due to reset\n" , |
3846 | ioc->name, __func__)); |
3847 | spin_unlock_irqrestore |
3848 | (lock: &ioc->taskmgmt_lock, flags); |
3849 | mutex_unlock(lock: &ioc-> |
3850 | sas_device_info_mutex); |
3851 | return; |
3852 | } |
3853 | spin_unlock_irqrestore(lock: &ioc->taskmgmt_lock, |
3854 | flags); |
3855 | } |
3856 | |
3857 | if (retval && (retval != -ENODEV)) { |
3858 | if (retry_count < 10) { |
3859 | retry_count++; |
3860 | goto retry_page; |
3861 | } else { |
3862 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
3863 | "%s: Config page retry exceeded retry " |
3864 | "count deleting device 0x%llx\n" , |
3865 | ioc->name, __func__, |
3866 | sas_info->sas_address)); |
3867 | } |
3868 | } |
3869 | |
3870 | /* delete device */ |
3871 | vtarget = mptsas_find_vtarget(ioc, |
3872 | channel: sas_info->fw.channel, id: sas_info->fw.id); |
3873 | |
3874 | if (vtarget) |
3875 | vtarget->deleted = 1; |
3876 | |
3877 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
3878 | sas_address: sas_info->sas_address); |
3879 | |
3880 | mptsas_del_end_device(ioc, phy_info); |
3881 | goto redo_device_scan; |
3882 | } else |
3883 | mptsas_volume_delete(ioc, id: sas_info->fw.id); |
3884 | } |
3885 | mutex_unlock(lock: &ioc->sas_device_info_mutex); |
3886 | |
3887 | /* expanders */ |
3888 | mutex_lock(&ioc->sas_topology_mutex); |
3889 | redo_expander_scan: |
3890 | list_for_each_entry(port_info, &ioc->sas_topology, list) { |
3891 | |
3892 | if (!(port_info->phy_info[0].identify.device_info & |
3893 | MPI_SAS_DEVICE_INFO_SMP_TARGET)) |
3894 | continue; |
3895 | found_expander = 0; |
3896 | handle = 0xFFFF; |
3897 | while (!mptsas_sas_expander_pg0(ioc, port_info: &buffer, |
3898 | form: (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << |
3899 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), form_specific: handle) && |
3900 | !found_expander) { |
3901 | |
3902 | handle = buffer.phy_info[0].handle; |
3903 | if (buffer.phy_info[0].identify.sas_address == |
3904 | port_info->phy_info[0].identify.sas_address) { |
3905 | found_expander = 1; |
3906 | } |
3907 | kfree(objp: buffer.phy_info); |
3908 | } |
3909 | |
3910 | if (!found_expander) { |
3911 | mptsas_expander_delete(ioc, port_info, force: 0); |
3912 | goto redo_expander_scan; |
3913 | } |
3914 | } |
3915 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
3916 | } |
3917 | |
3918 | /** |
3919 | * mptsas_probe_expanders - adding expanders |
3920 | * @ioc: Pointer to MPT_ADAPTER structure |
3921 | * |
3922 | **/ |
3923 | static void |
3924 | mptsas_probe_expanders(MPT_ADAPTER *ioc) |
3925 | { |
3926 | struct mptsas_portinfo buffer, *port_info; |
3927 | u32 handle; |
3928 | int i; |
3929 | |
3930 | handle = 0xFFFF; |
3931 | while (!mptsas_sas_expander_pg0(ioc, port_info: &buffer, |
3932 | form: (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << |
3933 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), form_specific: handle)) { |
3934 | |
3935 | handle = buffer.phy_info[0].handle; |
3936 | port_info = mptsas_find_portinfo_by_sas_address(ioc, |
3937 | sas_address: buffer.phy_info[0].identify.sas_address); |
3938 | |
3939 | if (port_info) { |
3940 | /* refreshing handles */ |
3941 | for (i = 0; i < buffer.num_phys; i++) { |
3942 | port_info->phy_info[i].handle = handle; |
3943 | port_info->phy_info[i].identify.handle_parent = |
3944 | buffer.phy_info[0].identify.handle_parent; |
3945 | } |
3946 | mptsas_expander_refresh(ioc, port_info); |
3947 | kfree(objp: buffer.phy_info); |
3948 | continue; |
3949 | } |
3950 | |
3951 | port_info = kzalloc(size: sizeof(struct mptsas_portinfo), GFP_KERNEL); |
3952 | if (!port_info) { |
3953 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
3954 | "%s: exit at line=%d\n" , ioc->name, |
3955 | __func__, __LINE__)); |
3956 | return; |
3957 | } |
3958 | port_info->num_phys = buffer.num_phys; |
3959 | port_info->phy_info = buffer.phy_info; |
3960 | for (i = 0; i < port_info->num_phys; i++) |
3961 | port_info->phy_info[i].portinfo = port_info; |
3962 | mutex_lock(&ioc->sas_topology_mutex); |
3963 | list_add_tail(new: &port_info->list, head: &ioc->sas_topology); |
3964 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
3965 | printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, " |
3966 | "sas_addr (0x%llx)\n" , ioc->name, port_info->num_phys, |
3967 | (unsigned long long)buffer.phy_info[0].identify.sas_address); |
3968 | mptsas_expander_refresh(ioc, port_info); |
3969 | } |
3970 | } |
3971 | |
3972 | static void |
3973 | mptsas_probe_devices(MPT_ADAPTER *ioc) |
3974 | { |
3975 | u16 handle; |
3976 | struct mptsas_devinfo sas_device; |
3977 | struct mptsas_phyinfo *phy_info; |
3978 | |
3979 | handle = 0xFFFF; |
3980 | while (!(mptsas_sas_device_pg0(ioc, device_info: &sas_device, |
3981 | MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, form_specific: handle))) { |
3982 | |
3983 | handle = sas_device.handle; |
3984 | |
3985 | if ((sas_device.device_info & |
3986 | (MPI_SAS_DEVICE_INFO_SSP_TARGET | |
3987 | MPI_SAS_DEVICE_INFO_STP_TARGET | |
3988 | MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) |
3989 | continue; |
3990 | |
3991 | /* If there is no FW B_T mapping for this device then continue |
3992 | * */ |
3993 | if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) |
3994 | || !(sas_device.flags & |
3995 | MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) |
3996 | continue; |
3997 | |
3998 | phy_info = mptsas_refreshing_device_handles(ioc, sas_device: &sas_device); |
3999 | if (!phy_info) |
4000 | continue; |
4001 | |
4002 | if (mptsas_get_rphy(phy_info)) |
4003 | continue; |
4004 | |
4005 | mptsas_add_end_device(ioc, phy_info); |
4006 | } |
4007 | } |
4008 | |
4009 | /** |
4010 | * mptsas_scan_sas_topology - scans new SAS topology |
4011 | * (part of probe or rescan) |
4012 | * @ioc: Pointer to MPT_ADAPTER structure |
4013 | * |
4014 | **/ |
4015 | static void |
4016 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) |
4017 | { |
4018 | struct scsi_device *sdev; |
4019 | int i; |
4020 | |
4021 | mptsas_probe_hba_phys(ioc); |
4022 | mptsas_probe_expanders(ioc); |
4023 | mptsas_probe_devices(ioc); |
4024 | |
4025 | /* |
4026 | Reporting RAID volumes. |
4027 | */ |
4028 | if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 || |
4029 | !ioc->raid_data.pIocPg2->NumActiveVolumes) |
4030 | return; |
4031 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { |
4032 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, |
4033 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); |
4034 | if (sdev) { |
4035 | scsi_device_put(sdev); |
4036 | continue; |
4037 | } |
4038 | printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " |
4039 | "id %d\n" , ioc->name, MPTSAS_RAID_CHANNEL, |
4040 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID); |
4041 | scsi_add_device(host: ioc->sh, MPTSAS_RAID_CHANNEL, |
4042 | target: ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, lun: 0); |
4043 | } |
4044 | } |
4045 | |
4046 | |
4047 | static void |
4048 | mptsas_handle_queue_full_event(struct fw_event_work *fw_event) |
4049 | { |
4050 | MPT_ADAPTER *ioc; |
4051 | EventDataQueueFull_t *qfull_data; |
4052 | struct mptsas_device_info *sas_info; |
4053 | struct scsi_device *sdev; |
4054 | int depth; |
4055 | int id = -1; |
4056 | int channel = -1; |
4057 | int fw_id, fw_channel; |
4058 | u16 current_depth; |
4059 | |
4060 | |
4061 | ioc = fw_event->ioc; |
4062 | qfull_data = (EventDataQueueFull_t *)fw_event->event_data; |
4063 | fw_id = qfull_data->TargetID; |
4064 | fw_channel = qfull_data->Bus; |
4065 | current_depth = le16_to_cpu(qfull_data->CurrentDepth); |
4066 | |
4067 | /* if hidden raid component, look for the volume id */ |
4068 | mutex_lock(&ioc->sas_device_info_mutex); |
4069 | if (mptscsih_is_phys_disk(ioc, channel: fw_channel, id: fw_id)) { |
4070 | list_for_each_entry(sas_info, &ioc->sas_device_info_list, |
4071 | list) { |
4072 | if (sas_info->is_cached || |
4073 | sas_info->is_logical_volume) |
4074 | continue; |
4075 | if (sas_info->is_hidden_raid_component && |
4076 | (sas_info->fw.channel == fw_channel && |
4077 | sas_info->fw.id == fw_id)) { |
4078 | id = sas_info->volume_id; |
4079 | channel = MPTSAS_RAID_CHANNEL; |
4080 | goto out; |
4081 | } |
4082 | } |
4083 | } else { |
4084 | list_for_each_entry(sas_info, &ioc->sas_device_info_list, |
4085 | list) { |
4086 | if (sas_info->is_cached || |
4087 | sas_info->is_hidden_raid_component || |
4088 | sas_info->is_logical_volume) |
4089 | continue; |
4090 | if (sas_info->fw.channel == fw_channel && |
4091 | sas_info->fw.id == fw_id) { |
4092 | id = sas_info->os.id; |
4093 | channel = sas_info->os.channel; |
4094 | goto out; |
4095 | } |
4096 | } |
4097 | |
4098 | } |
4099 | |
4100 | out: |
4101 | mutex_unlock(lock: &ioc->sas_device_info_mutex); |
4102 | |
4103 | if (id != -1) { |
4104 | shost_for_each_device(sdev, ioc->sh) { |
4105 | if (sdev->id == id && sdev->channel == channel) { |
4106 | if (current_depth > sdev->queue_depth) { |
4107 | sdev_printk(KERN_INFO, sdev, |
4108 | "strange observation, the queue " |
4109 | "depth is (%d) meanwhile fw queue " |
4110 | "depth (%d)\n" , sdev->queue_depth, |
4111 | current_depth); |
4112 | continue; |
4113 | } |
4114 | depth = scsi_track_queue_full(sdev, |
4115 | sdev->queue_depth - 1); |
4116 | if (depth > 0) |
4117 | sdev_printk(KERN_INFO, sdev, |
4118 | "Queue depth reduced to (%d)\n" , |
4119 | depth); |
4120 | else if (depth < 0) |
4121 | sdev_printk(KERN_INFO, sdev, |
4122 | "Tagged Command Queueing is being " |
4123 | "disabled\n" ); |
4124 | else if (depth == 0) |
4125 | sdev_printk(KERN_DEBUG, sdev, |
4126 | "Queue depth not changed yet\n" ); |
4127 | } |
4128 | } |
4129 | } |
4130 | |
4131 | mptsas_free_fw_event(ioc, fw_event); |
4132 | } |
4133 | |
4134 | |
4135 | static struct mptsas_phyinfo * |
4136 | mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) |
4137 | { |
4138 | struct mptsas_portinfo *port_info; |
4139 | struct mptsas_phyinfo *phy_info = NULL; |
4140 | int i; |
4141 | |
4142 | mutex_lock(&ioc->sas_topology_mutex); |
4143 | list_for_each_entry(port_info, &ioc->sas_topology, list) { |
4144 | for (i = 0; i < port_info->num_phys; i++) { |
4145 | if (!mptsas_is_end_device( |
4146 | attached: &port_info->phy_info[i].attached)) |
4147 | continue; |
4148 | if (port_info->phy_info[i].attached.sas_address |
4149 | != sas_address) |
4150 | continue; |
4151 | phy_info = &port_info->phy_info[i]; |
4152 | break; |
4153 | } |
4154 | } |
4155 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
4156 | return phy_info; |
4157 | } |
4158 | |
4159 | /** |
4160 | * mptsas_find_phyinfo_by_phys_disk_num - find phyinfo for the |
4161 | * specified @phys_disk_num |
4162 | * @ioc: Pointer to MPT_ADAPTER structure |
4163 | * @phys_disk_num: (hot plug) physical disk number (for RAID support) |
4164 | * @channel: channel number |
4165 | * @id: Logical Target ID |
4166 | * |
4167 | **/ |
4168 | static struct mptsas_phyinfo * |
4169 | mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, |
4170 | u8 channel, u8 id) |
4171 | { |
4172 | struct mptsas_phyinfo *phy_info = NULL; |
4173 | struct mptsas_portinfo *port_info; |
4174 | RaidPhysDiskPage1_t *phys_disk = NULL; |
4175 | int num_paths; |
4176 | u64 sas_address = 0; |
4177 | int i; |
4178 | |
4179 | phy_info = NULL; |
4180 | if (!ioc->raid_data.pIocPg3) |
4181 | return NULL; |
4182 | /* dual port support */ |
4183 | num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num); |
4184 | if (!num_paths) |
4185 | goto out; |
4186 | phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) + |
4187 | (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL); |
4188 | if (!phys_disk) |
4189 | goto out; |
4190 | mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk); |
4191 | for (i = 0; i < num_paths; i++) { |
4192 | if ((phys_disk->Path[i].Flags & 1) != 0) |
4193 | /* entry no longer valid */ |
4194 | continue; |
4195 | if ((id == phys_disk->Path[i].PhysDiskID) && |
4196 | (channel == phys_disk->Path[i].PhysDiskBus)) { |
4197 | memcpy(&sas_address, &phys_disk->Path[i].WWID, |
4198 | sizeof(u64)); |
4199 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
4200 | sas_address); |
4201 | goto out; |
4202 | } |
4203 | } |
4204 | |
4205 | out: |
4206 | kfree(objp: phys_disk); |
4207 | if (phy_info) |
4208 | return phy_info; |
4209 | |
4210 | /* |
4211 | * Extra code to handle RAID0 case, where the sas_address is not updated |
4212 | * in phys_disk_page_1 when hotswapped |
4213 | */ |
4214 | mutex_lock(&ioc->sas_topology_mutex); |
4215 | list_for_each_entry(port_info, &ioc->sas_topology, list) { |
4216 | for (i = 0; i < port_info->num_phys && !phy_info; i++) { |
4217 | if (!mptsas_is_end_device( |
4218 | attached: &port_info->phy_info[i].attached)) |
4219 | continue; |
4220 | if (port_info->phy_info[i].attached.phys_disk_num == ~0) |
4221 | continue; |
4222 | if ((port_info->phy_info[i].attached.phys_disk_num == |
4223 | phys_disk_num) && |
4224 | (port_info->phy_info[i].attached.id == id) && |
4225 | (port_info->phy_info[i].attached.channel == |
4226 | channel)) |
4227 | phy_info = &port_info->phy_info[i]; |
4228 | } |
4229 | } |
4230 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
4231 | return phy_info; |
4232 | } |
4233 | |
4234 | static void |
4235 | mptsas_reprobe_lun(struct scsi_device *sdev, void *data) |
4236 | { |
4237 | int rc; |
4238 | |
4239 | sdev->no_uld_attach = data ? 1 : 0; |
4240 | rc = scsi_device_reprobe(sdev); |
4241 | } |
4242 | |
4243 | static void |
4244 | mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) |
4245 | { |
4246 | starget_for_each_device(starget, uld_attach ? (void *)1 : NULL, |
4247 | fn: mptsas_reprobe_lun); |
4248 | } |
4249 | |
4250 | static void |
4251 | mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) |
4252 | { |
4253 | CONFIGPARMS cfg; |
4254 | ConfigPageHeader_t hdr; |
4255 | dma_addr_t dma_handle; |
4256 | pRaidVolumePage0_t buffer = NULL; |
4257 | RaidPhysDiskPage0_t phys_disk; |
4258 | int i; |
4259 | struct mptsas_phyinfo *phy_info; |
4260 | struct mptsas_devinfo sas_device; |
4261 | |
4262 | memset(&cfg, 0 , sizeof(CONFIGPARMS)); |
4263 | memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); |
4264 | hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME; |
4265 | cfg.pageAddr = (channel << 8) + id; |
4266 | cfg.cfghdr.hdr = &hdr; |
4267 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; |
4268 | cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT; |
4269 | |
4270 | if (mpt_config(ioc, cfg: &cfg) != 0) |
4271 | goto out; |
4272 | |
4273 | if (!hdr.PageLength) |
4274 | goto out; |
4275 | |
4276 | buffer = dma_alloc_coherent(dev: &ioc->pcidev->dev, size: hdr.PageLength * 4, |
4277 | dma_handle: &dma_handle, GFP_KERNEL); |
4278 | |
4279 | if (!buffer) |
4280 | goto out; |
4281 | |
4282 | cfg.physAddr = dma_handle; |
4283 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; |
4284 | |
4285 | if (mpt_config(ioc, cfg: &cfg) != 0) |
4286 | goto out; |
4287 | |
4288 | if (!(buffer->VolumeStatus.Flags & |
4289 | MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE)) |
4290 | goto out; |
4291 | |
4292 | if (!buffer->NumPhysDisks) |
4293 | goto out; |
4294 | |
4295 | for (i = 0; i < buffer->NumPhysDisks; i++) { |
4296 | |
4297 | if (mpt_raid_phys_disk_pg0(ioc, |
4298 | phys_disk_num: buffer->PhysDisk[i].PhysDiskNum, phys_disk: &phys_disk) != 0) |
4299 | continue; |
4300 | |
4301 | if (mptsas_sas_device_pg0(ioc, device_info: &sas_device, |
4302 | form: (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
4303 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
4304 | form_specific: (phys_disk.PhysDiskBus << 8) + |
4305 | phys_disk.PhysDiskID)) |
4306 | continue; |
4307 | |
4308 | /* If there is no FW B_T mapping for this device then continue |
4309 | * */ |
4310 | if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) |
4311 | || !(sas_device.flags & |
4312 | MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) |
4313 | continue; |
4314 | |
4315 | |
4316 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
4317 | sas_address: sas_device.sas_address); |
4318 | mptsas_add_end_device(ioc, phy_info); |
4319 | } |
4320 | |
4321 | out: |
4322 | if (buffer) |
4323 | dma_free_coherent(dev: &ioc->pcidev->dev, size: hdr.PageLength * 4, |
4324 | cpu_addr: buffer, dma_handle); |
4325 | } |
4326 | /* |
4327 | * Work queue thread to handle SAS hotplug events |
4328 | */ |
4329 | static void |
4330 | mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, |
4331 | struct mptsas_hotplug_event *hot_plug_info) |
4332 | { |
4333 | struct mptsas_phyinfo *phy_info; |
4334 | struct scsi_target * starget; |
4335 | struct mptsas_devinfo sas_device; |
4336 | VirtTarget *vtarget; |
4337 | int i; |
4338 | struct mptsas_portinfo *port_info; |
4339 | |
4340 | switch (hot_plug_info->event_type) { |
4341 | |
4342 | case MPTSAS_ADD_PHYSDISK: |
4343 | |
4344 | if (!ioc->raid_data.pIocPg2) |
4345 | break; |
4346 | |
4347 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { |
4348 | if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == |
4349 | hot_plug_info->id) { |
4350 | printk(MYIOC_s_WARN_FMT "firmware bug: unable " |
4351 | "to add hidden disk - target_id matches " |
4352 | "volume_id\n" , ioc->name); |
4353 | mptsas_free_fw_event(ioc, fw_event); |
4354 | return; |
4355 | } |
4356 | } |
4357 | mpt_findImVolumes(ioc); |
4358 | fallthrough; |
4359 | |
4360 | case MPTSAS_ADD_DEVICE: |
4361 | memset(&sas_device, 0, sizeof(struct mptsas_devinfo)); |
4362 | mptsas_sas_device_pg0(ioc, device_info: &sas_device, |
4363 | form: (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
4364 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
4365 | form_specific: (hot_plug_info->channel << 8) + |
4366 | hot_plug_info->id); |
4367 | |
4368 | /* If there is no FW B_T mapping for this device then break |
4369 | * */ |
4370 | if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) |
4371 | || !(sas_device.flags & |
4372 | MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) |
4373 | break; |
4374 | |
4375 | if (!sas_device.handle) |
4376 | return; |
4377 | |
4378 | phy_info = mptsas_refreshing_device_handles(ioc, sas_device: &sas_device); |
4379 | /* Device hot plug */ |
4380 | if (!phy_info) { |
4381 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
4382 | "%s %d HOT PLUG: " |
4383 | "parent handle of device %x\n" , ioc->name, |
4384 | __func__, __LINE__, sas_device.handle_parent)); |
4385 | port_info = mptsas_find_portinfo_by_handle(ioc, |
4386 | handle: sas_device.handle_parent); |
4387 | |
4388 | if (port_info == ioc->hba_port_info) |
4389 | mptsas_probe_hba_phys(ioc); |
4390 | else if (port_info) |
4391 | mptsas_expander_refresh(ioc, port_info); |
4392 | else { |
4393 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4394 | "%s %d port info is NULL\n" , |
4395 | ioc->name, __func__, __LINE__)); |
4396 | break; |
4397 | } |
4398 | phy_info = mptsas_refreshing_device_handles |
4399 | (ioc, sas_device: &sas_device); |
4400 | } |
4401 | |
4402 | if (!phy_info) { |
4403 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4404 | "%s %d phy info is NULL\n" , |
4405 | ioc->name, __func__, __LINE__)); |
4406 | break; |
4407 | } |
4408 | |
4409 | if (mptsas_get_rphy(phy_info)) |
4410 | break; |
4411 | |
4412 | mptsas_add_end_device(ioc, phy_info); |
4413 | break; |
4414 | |
4415 | case MPTSAS_DEL_DEVICE: |
4416 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
4417 | sas_address: hot_plug_info->sas_address); |
4418 | mptsas_del_end_device(ioc, phy_info); |
4419 | break; |
4420 | |
4421 | case MPTSAS_DEL_PHYSDISK: |
4422 | |
4423 | mpt_findImVolumes(ioc); |
4424 | |
4425 | phy_info = mptsas_find_phyinfo_by_phys_disk_num( |
4426 | ioc, phys_disk_num: hot_plug_info->phys_disk_num, |
4427 | channel: hot_plug_info->channel, |
4428 | id: hot_plug_info->id); |
4429 | mptsas_del_end_device(ioc, phy_info); |
4430 | break; |
4431 | |
4432 | case MPTSAS_ADD_PHYSDISK_REPROBE: |
4433 | |
4434 | if (mptsas_sas_device_pg0(ioc, device_info: &sas_device, |
4435 | form: (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
4436 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
4437 | form_specific: (hot_plug_info->channel << 8) + hot_plug_info->id)) { |
4438 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4439 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
4440 | __func__, hot_plug_info->id, __LINE__)); |
4441 | break; |
4442 | } |
4443 | |
4444 | /* If there is no FW B_T mapping for this device then break |
4445 | * */ |
4446 | if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) |
4447 | || !(sas_device.flags & |
4448 | MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) |
4449 | break; |
4450 | |
4451 | phy_info = mptsas_find_phyinfo_by_sas_address( |
4452 | ioc, sas_address: sas_device.sas_address); |
4453 | |
4454 | if (!phy_info) { |
4455 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4456 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
4457 | __func__, hot_plug_info->id, __LINE__)); |
4458 | break; |
4459 | } |
4460 | |
4461 | starget = mptsas_get_starget(phy_info); |
4462 | if (!starget) { |
4463 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4464 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
4465 | __func__, hot_plug_info->id, __LINE__)); |
4466 | break; |
4467 | } |
4468 | |
4469 | vtarget = starget->hostdata; |
4470 | if (!vtarget) { |
4471 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4472 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
4473 | __func__, hot_plug_info->id, __LINE__)); |
4474 | break; |
4475 | } |
4476 | |
4477 | mpt_findImVolumes(ioc); |
4478 | |
4479 | starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: " |
4480 | "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n" , |
4481 | ioc->name, hot_plug_info->channel, hot_plug_info->id, |
4482 | hot_plug_info->phys_disk_num, (unsigned long long) |
4483 | sas_device.sas_address); |
4484 | |
4485 | vtarget->id = hot_plug_info->phys_disk_num; |
4486 | vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; |
4487 | phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num; |
4488 | mptsas_reprobe_target(starget, uld_attach: 1); |
4489 | break; |
4490 | |
4491 | case MPTSAS_DEL_PHYSDISK_REPROBE: |
4492 | |
4493 | if (mptsas_sas_device_pg0(ioc, device_info: &sas_device, |
4494 | form: (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
4495 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
4496 | form_specific: (hot_plug_info->channel << 8) + hot_plug_info->id)) { |
4497 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4498 | "%s: fw_id=%d exit at line=%d\n" , |
4499 | ioc->name, __func__, |
4500 | hot_plug_info->id, __LINE__)); |
4501 | break; |
4502 | } |
4503 | |
4504 | /* If there is no FW B_T mapping for this device then break |
4505 | * */ |
4506 | if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) |
4507 | || !(sas_device.flags & |
4508 | MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) |
4509 | break; |
4510 | |
4511 | phy_info = mptsas_find_phyinfo_by_sas_address(ioc, |
4512 | sas_address: sas_device.sas_address); |
4513 | if (!phy_info) { |
4514 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4515 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
4516 | __func__, hot_plug_info->id, __LINE__)); |
4517 | break; |
4518 | } |
4519 | |
4520 | starget = mptsas_get_starget(phy_info); |
4521 | if (!starget) { |
4522 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4523 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
4524 | __func__, hot_plug_info->id, __LINE__)); |
4525 | break; |
4526 | } |
4527 | |
4528 | vtarget = starget->hostdata; |
4529 | if (!vtarget) { |
4530 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4531 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
4532 | __func__, hot_plug_info->id, __LINE__)); |
4533 | break; |
4534 | } |
4535 | |
4536 | if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) { |
4537 | dfailprintk(ioc, printk(MYIOC_s_ERR_FMT |
4538 | "%s: fw_id=%d exit at line=%d\n" , ioc->name, |
4539 | __func__, hot_plug_info->id, __LINE__)); |
4540 | break; |
4541 | } |
4542 | |
4543 | mpt_findImVolumes(ioc); |
4544 | |
4545 | starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:" |
4546 | " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n" , |
4547 | ioc->name, hot_plug_info->channel, hot_plug_info->id, |
4548 | hot_plug_info->phys_disk_num, (unsigned long long) |
4549 | sas_device.sas_address); |
4550 | |
4551 | vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; |
4552 | vtarget->id = hot_plug_info->id; |
4553 | phy_info->attached.phys_disk_num = ~0; |
4554 | mptsas_reprobe_target(starget, uld_attach: 0); |
4555 | mptsas_add_device_component_by_fw(ioc, |
4556 | channel: hot_plug_info->channel, id: hot_plug_info->id); |
4557 | break; |
4558 | |
4559 | case MPTSAS_ADD_RAID: |
4560 | |
4561 | mpt_findImVolumes(ioc); |
4562 | printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, " |
4563 | "id %d\n" , ioc->name, MPTSAS_RAID_CHANNEL, |
4564 | hot_plug_info->id); |
4565 | scsi_add_device(host: ioc->sh, MPTSAS_RAID_CHANNEL, |
4566 | target: hot_plug_info->id, lun: 0); |
4567 | break; |
4568 | |
4569 | case MPTSAS_DEL_RAID: |
4570 | |
4571 | mpt_findImVolumes(ioc); |
4572 | printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " |
4573 | "id %d\n" , ioc->name, MPTSAS_RAID_CHANNEL, |
4574 | hot_plug_info->id); |
4575 | scsi_remove_device(hot_plug_info->sdev); |
4576 | scsi_device_put(hot_plug_info->sdev); |
4577 | break; |
4578 | |
4579 | case MPTSAS_ADD_INACTIVE_VOLUME: |
4580 | |
4581 | mpt_findImVolumes(ioc); |
4582 | mptsas_adding_inactive_raid_components(ioc, |
4583 | channel: hot_plug_info->channel, id: hot_plug_info->id); |
4584 | break; |
4585 | |
4586 | default: |
4587 | break; |
4588 | } |
4589 | |
4590 | mptsas_free_fw_event(ioc, fw_event); |
4591 | } |
4592 | |
4593 | static void |
4594 | mptsas_send_sas_event(struct fw_event_work *fw_event) |
4595 | { |
4596 | MPT_ADAPTER *ioc; |
4597 | struct mptsas_hotplug_event hot_plug_info; |
4598 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; |
4599 | u32 device_info; |
4600 | u64 sas_address; |
4601 | |
4602 | ioc = fw_event->ioc; |
4603 | sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) |
4604 | fw_event->event_data; |
4605 | device_info = le32_to_cpu(sas_event_data->DeviceInfo); |
4606 | |
4607 | if ((device_info & |
4608 | (MPI_SAS_DEVICE_INFO_SSP_TARGET | |
4609 | MPI_SAS_DEVICE_INFO_STP_TARGET | |
4610 | MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) { |
4611 | mptsas_free_fw_event(ioc, fw_event); |
4612 | return; |
4613 | } |
4614 | |
4615 | if (sas_event_data->ReasonCode == |
4616 | MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) { |
4617 | mptbase_sas_persist_operation(ioc, |
4618 | MPI_SAS_OP_CLEAR_NOT_PRESENT); |
4619 | mptsas_free_fw_event(ioc, fw_event); |
4620 | return; |
4621 | } |
4622 | |
4623 | switch (sas_event_data->ReasonCode) { |
4624 | case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: |
4625 | case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: |
4626 | memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); |
4627 | hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle); |
4628 | hot_plug_info.channel = sas_event_data->Bus; |
4629 | hot_plug_info.id = sas_event_data->TargetID; |
4630 | hot_plug_info.phy_id = sas_event_data->PhyNum; |
4631 | memcpy(&sas_address, &sas_event_data->SASAddress, |
4632 | sizeof(u64)); |
4633 | hot_plug_info.sas_address = le64_to_cpu(sas_address); |
4634 | hot_plug_info.device_info = device_info; |
4635 | if (sas_event_data->ReasonCode & |
4636 | MPI_EVENT_SAS_DEV_STAT_RC_ADDED) |
4637 | hot_plug_info.event_type = MPTSAS_ADD_DEVICE; |
4638 | else |
4639 | hot_plug_info.event_type = MPTSAS_DEL_DEVICE; |
4640 | mptsas_hotplug_work(ioc, fw_event, hot_plug_info: &hot_plug_info); |
4641 | break; |
4642 | |
4643 | case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: |
4644 | mptbase_sas_persist_operation(ioc, |
4645 | MPI_SAS_OP_CLEAR_NOT_PRESENT); |
4646 | mptsas_free_fw_event(ioc, fw_event); |
4647 | break; |
4648 | |
4649 | case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: |
4650 | /* TODO */ |
4651 | case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: |
4652 | /* TODO */ |
4653 | default: |
4654 | mptsas_free_fw_event(ioc, fw_event); |
4655 | break; |
4656 | } |
4657 | } |
4658 | |
4659 | static void |
4660 | mptsas_send_raid_event(struct fw_event_work *fw_event) |
4661 | { |
4662 | MPT_ADAPTER *ioc; |
4663 | EVENT_DATA_RAID *raid_event_data; |
4664 | struct mptsas_hotplug_event hot_plug_info; |
4665 | int status; |
4666 | int state; |
4667 | struct scsi_device *sdev = NULL; |
4668 | VirtDevice *vdevice = NULL; |
4669 | RaidPhysDiskPage0_t phys_disk; |
4670 | |
4671 | ioc = fw_event->ioc; |
4672 | raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data; |
4673 | status = le32_to_cpu(raid_event_data->SettingsStatus); |
4674 | state = (status >> 8) & 0xff; |
4675 | |
4676 | memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); |
4677 | hot_plug_info.id = raid_event_data->VolumeID; |
4678 | hot_plug_info.channel = raid_event_data->VolumeBus; |
4679 | hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum; |
4680 | |
4681 | if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED || |
4682 | raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED || |
4683 | raid_event_data->ReasonCode == |
4684 | MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) { |
4685 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, |
4686 | hot_plug_info.id, 0); |
4687 | hot_plug_info.sdev = sdev; |
4688 | if (sdev) |
4689 | vdevice = sdev->hostdata; |
4690 | } |
4691 | |
4692 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " |
4693 | "ReasonCode=%02x\n" , ioc->name, __func__, |
4694 | raid_event_data->ReasonCode)); |
4695 | |
4696 | switch (raid_event_data->ReasonCode) { |
4697 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: |
4698 | hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE; |
4699 | break; |
4700 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: |
4701 | hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE; |
4702 | break; |
4703 | case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: |
4704 | switch (state) { |
4705 | case MPI_PD_STATE_ONLINE: |
4706 | case MPI_PD_STATE_NOT_COMPATIBLE: |
4707 | mpt_raid_phys_disk_pg0(ioc, |
4708 | phys_disk_num: raid_event_data->PhysDiskNum, phys_disk: &phys_disk); |
4709 | hot_plug_info.id = phys_disk.PhysDiskID; |
4710 | hot_plug_info.channel = phys_disk.PhysDiskBus; |
4711 | hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; |
4712 | break; |
4713 | case MPI_PD_STATE_FAILED: |
4714 | case MPI_PD_STATE_MISSING: |
4715 | case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: |
4716 | case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: |
4717 | case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: |
4718 | hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; |
4719 | break; |
4720 | default: |
4721 | break; |
4722 | } |
4723 | break; |
4724 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: |
4725 | if (!sdev) |
4726 | break; |
4727 | vdevice->vtarget->deleted = 1; /* block IO */ |
4728 | hot_plug_info.event_type = MPTSAS_DEL_RAID; |
4729 | break; |
4730 | case MPI_EVENT_RAID_RC_VOLUME_CREATED: |
4731 | if (sdev) { |
4732 | scsi_device_put(sdev); |
4733 | break; |
4734 | } |
4735 | hot_plug_info.event_type = MPTSAS_ADD_RAID; |
4736 | break; |
4737 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: |
4738 | if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) { |
4739 | if (!sdev) |
4740 | break; |
4741 | vdevice->vtarget->deleted = 1; /* block IO */ |
4742 | hot_plug_info.event_type = MPTSAS_DEL_RAID; |
4743 | break; |
4744 | } |
4745 | switch (state) { |
4746 | case MPI_RAIDVOL0_STATUS_STATE_FAILED: |
4747 | case MPI_RAIDVOL0_STATUS_STATE_MISSING: |
4748 | if (!sdev) |
4749 | break; |
4750 | vdevice->vtarget->deleted = 1; /* block IO */ |
4751 | hot_plug_info.event_type = MPTSAS_DEL_RAID; |
4752 | break; |
4753 | case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: |
4754 | case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: |
4755 | if (sdev) { |
4756 | scsi_device_put(sdev); |
4757 | break; |
4758 | } |
4759 | hot_plug_info.event_type = MPTSAS_ADD_RAID; |
4760 | break; |
4761 | default: |
4762 | break; |
4763 | } |
4764 | break; |
4765 | default: |
4766 | break; |
4767 | } |
4768 | |
4769 | if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT) |
4770 | mptsas_hotplug_work(ioc, fw_event, hot_plug_info: &hot_plug_info); |
4771 | else |
4772 | mptsas_free_fw_event(ioc, fw_event); |
4773 | } |
4774 | |
4775 | /** |
4776 | * mptsas_issue_tm - send mptsas internal tm request |
4777 | * @ioc: Pointer to MPT_ADAPTER structure |
4778 | * @type: Task Management type |
4779 | * @channel: channel number for task management |
4780 | * @id: Logical Target ID for reset (if appropriate) |
4781 | * @lun: Logical unit for reset (if appropriate) |
4782 | * @task_context: Context for the task to be aborted |
4783 | * @timeout: timeout for task management control |
4784 | * @issue_reset: set to 1 on return if reset is needed, else 0 |
4785 | * |
4786 | * Return: 0 on success or -1 on failure. |
4787 | * |
4788 | */ |
4789 | static int |
4790 | mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, |
4791 | int task_context, ulong timeout, u8 *issue_reset) |
4792 | { |
4793 | MPT_FRAME_HDR *mf; |
4794 | SCSITaskMgmt_t *pScsiTm; |
4795 | int retval; |
4796 | unsigned long timeleft; |
4797 | |
4798 | *issue_reset = 0; |
4799 | mf = mpt_get_msg_frame(cb_idx: mptsasDeviceResetCtx, ioc); |
4800 | if (mf == NULL) { |
4801 | retval = -1; /* return failure */ |
4802 | dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no " |
4803 | "msg frames!!\n" , ioc->name)); |
4804 | goto out; |
4805 | } |
4806 | |
4807 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, " |
4808 | "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, " |
4809 | "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n" , ioc->name, mf, |
4810 | type, timeout, channel, id, (unsigned long long)lun, |
4811 | task_context)); |
4812 | |
4813 | pScsiTm = (SCSITaskMgmt_t *) mf; |
4814 | memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); |
4815 | pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; |
4816 | pScsiTm->TaskType = type; |
4817 | pScsiTm->MsgFlags = 0; |
4818 | pScsiTm->TargetID = id; |
4819 | pScsiTm->Bus = channel; |
4820 | pScsiTm->ChainOffset = 0; |
4821 | pScsiTm->Reserved = 0; |
4822 | pScsiTm->Reserved1 = 0; |
4823 | pScsiTm->TaskMsgContext = task_context; |
4824 | int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); |
4825 | |
4826 | INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) |
4827 | CLEAR_MGMT_STATUS(ioc->internal_cmds.status) |
4828 | retval = 0; |
4829 | mpt_put_msg_frame_hi_pri(cb_idx: mptsasDeviceResetCtx, ioc, mf); |
4830 | |
4831 | /* Now wait for the command to complete */ |
4832 | timeleft = wait_for_completion_timeout(x: &ioc->taskmgmt_cmds.done, |
4833 | timeout: timeout*HZ); |
4834 | if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { |
4835 | retval = -1; /* return failure */ |
4836 | dtmprintk(ioc, printk(MYIOC_s_ERR_FMT |
4837 | "TaskMgmt request: TIMED OUT!(mr=%p)\n" , ioc->name, mf)); |
4838 | mpt_free_msg_frame(ioc, mf); |
4839 | if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) |
4840 | goto out; |
4841 | *issue_reset = 1; |
4842 | goto out; |
4843 | } |
4844 | |
4845 | if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { |
4846 | retval = -1; /* return failure */ |
4847 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
4848 | "TaskMgmt request: failed with no reply\n" , ioc->name)); |
4849 | goto out; |
4850 | } |
4851 | |
4852 | out: |
4853 | CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) |
4854 | return retval; |
4855 | } |
4856 | |
4857 | /** |
4858 | * mptsas_broadcast_primitive_work - Handle broadcast primitives |
4859 | * @fw_event: work queue payload containing info describing the event |
4860 | * |
4861 | * This will be handled in workqueue context. |
4862 | */ |
4863 | static void |
4864 | mptsas_broadcast_primitive_work(struct fw_event_work *fw_event) |
4865 | { |
4866 | MPT_ADAPTER *ioc = fw_event->ioc; |
4867 | MPT_FRAME_HDR *mf; |
4868 | VirtDevice *vdevice; |
4869 | int ii; |
4870 | struct scsi_cmnd *sc; |
4871 | SCSITaskMgmtReply_t *pScsiTmReply; |
4872 | u8 issue_reset; |
4873 | int task_context; |
4874 | u8 channel, id; |
4875 | int lun; |
4876 | u32 termination_count; |
4877 | u32 query_count; |
4878 | |
4879 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
4880 | "%s - enter\n" , ioc->name, __func__)); |
4881 | |
4882 | mutex_lock(&ioc->taskmgmt_cmds.mutex); |
4883 | if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { |
4884 | mutex_unlock(lock: &ioc->taskmgmt_cmds.mutex); |
4885 | mptsas_requeue_fw_event(ioc, fw_event, delay: 1000); |
4886 | return; |
4887 | } |
4888 | |
4889 | issue_reset = 0; |
4890 | termination_count = 0; |
4891 | query_count = 0; |
4892 | mpt_findImVolumes(ioc); |
4893 | pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; |
4894 | |
4895 | for (ii = 0; ii < ioc->req_depth; ii++) { |
4896 | if (ioc->fw_events_off) |
4897 | goto out; |
4898 | sc = mptscsih_get_scsi_lookup(ioc, i: ii); |
4899 | if (!sc) |
4900 | continue; |
4901 | mf = MPT_INDEX_2_MFPTR(ioc, ii); |
4902 | if (!mf) |
4903 | continue; |
4904 | task_context = mf->u.frame.hwhdr.msgctxu.MsgContext; |
4905 | vdevice = sc->device->hostdata; |
4906 | if (!vdevice || !vdevice->vtarget) |
4907 | continue; |
4908 | if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) |
4909 | continue; /* skip hidden raid components */ |
4910 | if (vdevice->vtarget->raidVolume) |
4911 | continue; /* skip hidden raid components */ |
4912 | channel = vdevice->vtarget->channel; |
4913 | id = vdevice->vtarget->id; |
4914 | lun = vdevice->lun; |
4915 | if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK, |
4916 | channel, id, lun: (u64)lun, task_context, timeout: 30, issue_reset: &issue_reset)) |
4917 | goto out; |
4918 | query_count++; |
4919 | termination_count += |
4920 | le32_to_cpu(pScsiTmReply->TerminationCount); |
4921 | if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) && |
4922 | (pScsiTmReply->ResponseCode == |
4923 | MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED || |
4924 | pScsiTmReply->ResponseCode == |
4925 | MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) |
4926 | continue; |
4927 | if (mptsas_issue_tm(ioc, |
4928 | MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, |
4929 | channel, id, lun: (u64)lun, task_context: 0, timeout: 30, issue_reset: &issue_reset)) |
4930 | goto out; |
4931 | termination_count += |
4932 | le32_to_cpu(pScsiTmReply->TerminationCount); |
4933 | } |
4934 | |
4935 | out: |
4936 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
4937 | "%s - exit, query_count = %d termination_count = %d\n" , |
4938 | ioc->name, __func__, query_count, termination_count)); |
4939 | |
4940 | ioc->broadcast_aen_busy = 0; |
4941 | mpt_clear_taskmgmt_in_progress_flag(ioc); |
4942 | mutex_unlock(lock: &ioc->taskmgmt_cmds.mutex); |
4943 | |
4944 | if (issue_reset) { |
4945 | printk(MYIOC_s_WARN_FMT |
4946 | "Issuing Reset from %s!! doorbell=0x%08x\n" , |
4947 | ioc->name, __func__, mpt_GetIocState(ioc, 0)); |
4948 | mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); |
4949 | } |
4950 | mptsas_free_fw_event(ioc, fw_event); |
4951 | } |
4952 | |
4953 | /* |
4954 | * mptsas_send_ir2_event - handle exposing hidden disk when |
4955 | * an inactive raid volume is added |
4956 | * |
4957 | * @ioc: Pointer to MPT_ADAPTER structure |
4958 | * @ir2_data |
4959 | * |
4960 | */ |
4961 | static void |
4962 | mptsas_send_ir2_event(struct fw_event_work *fw_event) |
4963 | { |
4964 | MPT_ADAPTER *ioc; |
4965 | struct mptsas_hotplug_event hot_plug_info; |
4966 | MPI_EVENT_DATA_IR2 *ir2_data; |
4967 | u8 reasonCode; |
4968 | RaidPhysDiskPage0_t phys_disk; |
4969 | |
4970 | ioc = fw_event->ioc; |
4971 | ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data; |
4972 | reasonCode = ir2_data->ReasonCode; |
4973 | |
4974 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: " |
4975 | "ReasonCode=%02x\n" , ioc->name, __func__, reasonCode)); |
4976 | |
4977 | memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event)); |
4978 | hot_plug_info.id = ir2_data->TargetID; |
4979 | hot_plug_info.channel = ir2_data->Bus; |
4980 | switch (reasonCode) { |
4981 | case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED: |
4982 | hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME; |
4983 | break; |
4984 | case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED: |
4985 | hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; |
4986 | hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK; |
4987 | break; |
4988 | case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED: |
4989 | hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum; |
4990 | mpt_raid_phys_disk_pg0(ioc, |
4991 | phys_disk_num: ir2_data->PhysDiskNum, phys_disk: &phys_disk); |
4992 | hot_plug_info.id = phys_disk.PhysDiskID; |
4993 | hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK; |
4994 | break; |
4995 | default: |
4996 | mptsas_free_fw_event(ioc, fw_event); |
4997 | return; |
4998 | } |
4999 | mptsas_hotplug_work(ioc, fw_event, hot_plug_info: &hot_plug_info); |
5000 | } |
5001 | |
5002 | static int |
5003 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) |
5004 | { |
5005 | u32 event = le32_to_cpu(reply->Event); |
5006 | int event_data_sz; |
5007 | struct fw_event_work *fw_event; |
5008 | unsigned long delay; |
5009 | |
5010 | if (ioc->bus_type != SAS) |
5011 | return 0; |
5012 | |
5013 | /* events turned off due to host reset or driver unloading */ |
5014 | if (ioc->fw_events_off) |
5015 | return 0; |
5016 | |
5017 | delay = msecs_to_jiffies(m: 1); |
5018 | switch (event) { |
5019 | case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: |
5020 | { |
5021 | EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data = |
5022 | (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data; |
5023 | if (broadcast_event_data->Primitive != |
5024 | MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) |
5025 | return 0; |
5026 | if (ioc->broadcast_aen_busy) |
5027 | return 0; |
5028 | ioc->broadcast_aen_busy = 1; |
5029 | break; |
5030 | } |
5031 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
5032 | { |
5033 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = |
5034 | (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; |
5035 | u16 ioc_stat; |
5036 | ioc_stat = le16_to_cpu(reply->IOCStatus); |
5037 | |
5038 | if (sas_event_data->ReasonCode == |
5039 | MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { |
5040 | mptsas_target_reset_queue(ioc, sas_event_data); |
5041 | return 0; |
5042 | } |
5043 | if (sas_event_data->ReasonCode == |
5044 | MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && |
5045 | ioc->device_missing_delay && |
5046 | (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) { |
5047 | VirtTarget *vtarget = NULL; |
5048 | u8 id, channel; |
5049 | |
5050 | id = sas_event_data->TargetID; |
5051 | channel = sas_event_data->Bus; |
5052 | |
5053 | vtarget = mptsas_find_vtarget(ioc, channel, id); |
5054 | if (vtarget) { |
5055 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
5056 | "LogInfo (0x%x) available for " |
5057 | "INTERNAL_DEVICE_RESET" |
5058 | "fw_id %d fw_channel %d\n" , ioc->name, |
5059 | le32_to_cpu(reply->IOCLogInfo), |
5060 | id, channel)); |
5061 | if (vtarget->raidVolume) { |
5062 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
5063 | "Skipping Raid Volume for inDMD\n" , |
5064 | ioc->name)); |
5065 | } else { |
5066 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
5067 | "Setting device flag inDMD\n" , |
5068 | ioc->name)); |
5069 | vtarget->inDMD = 1; |
5070 | } |
5071 | |
5072 | } |
5073 | |
5074 | } |
5075 | |
5076 | break; |
5077 | } |
5078 | case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: |
5079 | { |
5080 | MpiEventDataSasExpanderStatusChange_t *expander_data = |
5081 | (MpiEventDataSasExpanderStatusChange_t *)reply->Data; |
5082 | |
5083 | if (ioc->old_sas_discovery_protocal) |
5084 | return 0; |
5085 | |
5086 | if (expander_data->ReasonCode == |
5087 | MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING && |
5088 | ioc->device_missing_delay) |
5089 | delay = HZ * ioc->device_missing_delay; |
5090 | break; |
5091 | } |
5092 | case MPI_EVENT_SAS_DISCOVERY: |
5093 | { |
5094 | u32 discovery_status; |
5095 | EventDataSasDiscovery_t *discovery_data = |
5096 | (EventDataSasDiscovery_t *)reply->Data; |
5097 | |
5098 | discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus); |
5099 | ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0; |
5100 | if (ioc->old_sas_discovery_protocal && !discovery_status) |
5101 | mptsas_queue_rescan(ioc); |
5102 | return 0; |
5103 | } |
5104 | case MPI_EVENT_INTEGRATED_RAID: |
5105 | case MPI_EVENT_PERSISTENT_TABLE_FULL: |
5106 | case MPI_EVENT_IR2: |
5107 | case MPI_EVENT_SAS_PHY_LINK_STATUS: |
5108 | case MPI_EVENT_QUEUE_FULL: |
5109 | break; |
5110 | default: |
5111 | return 0; |
5112 | } |
5113 | |
5114 | event_data_sz = ((reply->MsgLength * 4) - |
5115 | offsetof(EventNotificationReply_t, Data)); |
5116 | fw_event = kzalloc(size: sizeof(*fw_event) + event_data_sz, GFP_ATOMIC); |
5117 | if (!fw_event) { |
5118 | printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n" , ioc->name, |
5119 | __func__, __LINE__); |
5120 | return 0; |
5121 | } |
5122 | memcpy(fw_event->event_data, reply->Data, event_data_sz); |
5123 | fw_event->event = event; |
5124 | fw_event->ioc = ioc; |
5125 | mptsas_add_fw_event(ioc, fw_event, delay); |
5126 | return 0; |
5127 | } |
5128 | |
5129 | /* Delete a volume when no longer listed in ioc pg2 |
5130 | */ |
5131 | static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id) |
5132 | { |
5133 | struct scsi_device *sdev; |
5134 | int i; |
5135 | |
5136 | sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0); |
5137 | if (!sdev) |
5138 | return; |
5139 | if (!ioc->raid_data.pIocPg2) |
5140 | goto out; |
5141 | if (!ioc->raid_data.pIocPg2->NumActiveVolumes) |
5142 | goto out; |
5143 | for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) |
5144 | if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) |
5145 | goto release_sdev; |
5146 | out: |
5147 | printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, " |
5148 | "id %d\n" , ioc->name, MPTSAS_RAID_CHANNEL, id); |
5149 | scsi_remove_device(sdev); |
5150 | release_sdev: |
5151 | scsi_device_put(sdev); |
5152 | } |
5153 | |
5154 | static int |
5155 | mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
5156 | { |
5157 | struct Scsi_Host *sh; |
5158 | MPT_SCSI_HOST *hd; |
5159 | MPT_ADAPTER *ioc; |
5160 | unsigned long flags; |
5161 | int ii; |
5162 | int numSGE = 0; |
5163 | int scale; |
5164 | int ioc_cap; |
5165 | int error=0; |
5166 | int r; |
5167 | |
5168 | r = mpt_attach(pdev,id); |
5169 | if (r) |
5170 | return r; |
5171 | |
5172 | ioc = pci_get_drvdata(pdev); |
5173 | mptsas_fw_event_off(ioc); |
5174 | ioc->DoneCtx = mptsasDoneCtx; |
5175 | ioc->TaskCtx = mptsasTaskCtx; |
5176 | ioc->InternalCtx = mptsasInternalCtx; |
5177 | ioc->schedule_target_reset = &mptsas_schedule_target_reset; |
5178 | ioc->schedule_dead_ioc_flush_running_cmds = |
5179 | &mptscsih_flush_running_cmds; |
5180 | /* Added sanity check on readiness of the MPT adapter. |
5181 | */ |
5182 | if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { |
5183 | printk(MYIOC_s_WARN_FMT |
5184 | "Skipping because it's not operational!\n" , |
5185 | ioc->name); |
5186 | error = -ENODEV; |
5187 | goto out_mptsas_probe; |
5188 | } |
5189 | |
5190 | if (!ioc->active) { |
5191 | printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n" , |
5192 | ioc->name); |
5193 | error = -ENODEV; |
5194 | goto out_mptsas_probe; |
5195 | } |
5196 | |
5197 | /* Sanity check - ensure at least 1 port is INITIATOR capable |
5198 | */ |
5199 | ioc_cap = 0; |
5200 | for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) { |
5201 | if (ioc->pfacts[ii].ProtocolFlags & |
5202 | MPI_PORTFACTS_PROTOCOL_INITIATOR) |
5203 | ioc_cap++; |
5204 | } |
5205 | |
5206 | if (!ioc_cap) { |
5207 | printk(MYIOC_s_WARN_FMT |
5208 | "Skipping ioc=%p because SCSI Initiator mode " |
5209 | "is NOT enabled!\n" , ioc->name, ioc); |
5210 | return 0; |
5211 | } |
5212 | |
5213 | sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST)); |
5214 | if (!sh) { |
5215 | printk(MYIOC_s_WARN_FMT |
5216 | "Unable to register controller with SCSI subsystem\n" , |
5217 | ioc->name); |
5218 | error = -1; |
5219 | goto out_mptsas_probe; |
5220 | } |
5221 | |
5222 | spin_lock_irqsave(&ioc->FreeQlock, flags); |
5223 | |
5224 | /* Attach the SCSI Host to the IOC structure |
5225 | */ |
5226 | ioc->sh = sh; |
5227 | |
5228 | sh->io_port = 0; |
5229 | sh->n_io_port = 0; |
5230 | sh->irq = 0; |
5231 | |
5232 | /* set 16 byte cdb's */ |
5233 | sh->max_cmd_len = 16; |
5234 | sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue); |
5235 | sh->max_id = -1; |
5236 | sh->max_lun = max_lun; |
5237 | sh->transportt = mptsas_transport_template; |
5238 | |
5239 | /* Required entry. |
5240 | */ |
5241 | sh->unique_id = ioc->id; |
5242 | |
5243 | INIT_LIST_HEAD(list: &ioc->sas_topology); |
5244 | mutex_init(&ioc->sas_topology_mutex); |
5245 | mutex_init(&ioc->sas_discovery_mutex); |
5246 | mutex_init(&ioc->sas_mgmt.mutex); |
5247 | init_completion(x: &ioc->sas_mgmt.done); |
5248 | |
5249 | /* Verify that we won't exceed the maximum |
5250 | * number of chain buffers |
5251 | * We can optimize: ZZ = req_sz/sizeof(SGE) |
5252 | * For 32bit SGE's: |
5253 | * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ |
5254 | * + (req_sz - 64)/sizeof(SGE) |
5255 | * A slightly different algorithm is required for |
5256 | * 64bit SGEs. |
5257 | */ |
5258 | scale = ioc->req_sz/ioc->SGE_size; |
5259 | if (ioc->sg_addr_size == sizeof(u64)) { |
5260 | numSGE = (scale - 1) * |
5261 | (ioc->facts.MaxChainDepth-1) + scale + |
5262 | (ioc->req_sz - 60) / ioc->SGE_size; |
5263 | } else { |
5264 | numSGE = 1 + (scale - 1) * |
5265 | (ioc->facts.MaxChainDepth-1) + scale + |
5266 | (ioc->req_sz - 64) / ioc->SGE_size; |
5267 | } |
5268 | |
5269 | if (numSGE < sh->sg_tablesize) { |
5270 | /* Reset this value */ |
5271 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
5272 | "Resetting sg_tablesize to %d from %d\n" , |
5273 | ioc->name, numSGE, sh->sg_tablesize)); |
5274 | sh->sg_tablesize = numSGE; |
5275 | } |
5276 | |
5277 | if (mpt_loadtime_max_sectors) { |
5278 | if (mpt_loadtime_max_sectors < 64 || |
5279 | mpt_loadtime_max_sectors > 8192) { |
5280 | printk(MYIOC_s_INFO_FMT "Invalid value passed for" |
5281 | "mpt_loadtime_max_sectors %d." |
5282 | "Range from 64 to 8192\n" , ioc->name, |
5283 | mpt_loadtime_max_sectors); |
5284 | } |
5285 | mpt_loadtime_max_sectors &= 0xFFFFFFFE; |
5286 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT |
5287 | "Resetting max sector to %d from %d\n" , |
5288 | ioc->name, mpt_loadtime_max_sectors, sh->max_sectors)); |
5289 | sh->max_sectors = mpt_loadtime_max_sectors; |
5290 | } |
5291 | |
5292 | hd = shost_priv(shost: sh); |
5293 | hd->ioc = ioc; |
5294 | |
5295 | /* SCSI needs scsi_cmnd lookup table! |
5296 | * (with size equal to req_depth*PtrSz!) |
5297 | */ |
5298 | ioc->ScsiLookup = kcalloc(n: ioc->req_depth, size: sizeof(void *), GFP_ATOMIC); |
5299 | if (!ioc->ScsiLookup) { |
5300 | error = -ENOMEM; |
5301 | spin_unlock_irqrestore(lock: &ioc->FreeQlock, flags); |
5302 | goto out_mptsas_probe; |
5303 | } |
5304 | spin_lock_init(&ioc->scsi_lookup_lock); |
5305 | |
5306 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n" , |
5307 | ioc->name, ioc->ScsiLookup)); |
5308 | |
5309 | ioc->sas_data.ptClear = mpt_pt_clear; |
5310 | |
5311 | hd->last_queue_full = 0; |
5312 | INIT_LIST_HEAD(list: &hd->target_reset_list); |
5313 | INIT_LIST_HEAD(list: &ioc->sas_device_info_list); |
5314 | mutex_init(&ioc->sas_device_info_mutex); |
5315 | |
5316 | spin_unlock_irqrestore(lock: &ioc->FreeQlock, flags); |
5317 | |
5318 | if (ioc->sas_data.ptClear==1) { |
5319 | mptbase_sas_persist_operation( |
5320 | ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT); |
5321 | } |
5322 | |
5323 | error = scsi_add_host(host: sh, dev: &ioc->pcidev->dev); |
5324 | if (error) { |
5325 | dprintk(ioc, printk(MYIOC_s_ERR_FMT |
5326 | "scsi_add_host failed\n" , ioc->name)); |
5327 | goto out_mptsas_probe; |
5328 | } |
5329 | |
5330 | /* older firmware doesn't support expander events */ |
5331 | if ((ioc->facts.HeaderVersion >> 8) < 0xE) |
5332 | ioc->old_sas_discovery_protocal = 1; |
5333 | mptsas_scan_sas_topology(ioc); |
5334 | mptsas_fw_event_on(ioc); |
5335 | return 0; |
5336 | |
5337 | out_mptsas_probe: |
5338 | |
5339 | mptscsih_remove(pdev); |
5340 | return error; |
5341 | } |
5342 | |
5343 | static void |
5344 | mptsas_shutdown(struct pci_dev *pdev) |
5345 | { |
5346 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
5347 | |
5348 | mptsas_fw_event_off(ioc); |
5349 | mptsas_cleanup_fw_event_q(ioc); |
5350 | } |
5351 | |
5352 | static void mptsas_remove(struct pci_dev *pdev) |
5353 | { |
5354 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
5355 | struct mptsas_portinfo *p, *n; |
5356 | int i; |
5357 | |
5358 | if (!ioc->sh) { |
5359 | printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n" , ioc->name); |
5360 | mpt_detach(pdev); |
5361 | return; |
5362 | } |
5363 | |
5364 | mptsas_shutdown(pdev); |
5365 | |
5366 | mptsas_del_device_components(ioc); |
5367 | |
5368 | ioc->sas_discovery_ignore_events = 1; |
5369 | sas_remove_host(ioc->sh); |
5370 | |
5371 | mutex_lock(&ioc->sas_topology_mutex); |
5372 | list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { |
5373 | list_del(entry: &p->list); |
5374 | for (i = 0 ; i < p->num_phys ; i++) |
5375 | mptsas_port_delete(ioc, port_details: p->phy_info[i].port_details); |
5376 | |
5377 | kfree(objp: p->phy_info); |
5378 | kfree(objp: p); |
5379 | } |
5380 | mutex_unlock(lock: &ioc->sas_topology_mutex); |
5381 | ioc->hba_port_info = NULL; |
5382 | mptscsih_remove(pdev); |
5383 | } |
5384 | |
5385 | static struct pci_device_id mptsas_pci_table[] = { |
5386 | { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064, |
5387 | PCI_ANY_ID, PCI_ANY_ID }, |
5388 | { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068, |
5389 | PCI_ANY_ID, PCI_ANY_ID }, |
5390 | { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E, |
5391 | PCI_ANY_ID, PCI_ANY_ID }, |
5392 | { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E, |
5393 | PCI_ANY_ID, PCI_ANY_ID }, |
5394 | { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078, |
5395 | PCI_ANY_ID, PCI_ANY_ID }, |
5396 | { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068_820XELP, |
5397 | PCI_ANY_ID, PCI_ANY_ID }, |
5398 | {0} /* Terminating entry */ |
5399 | }; |
5400 | MODULE_DEVICE_TABLE(pci, mptsas_pci_table); |
5401 | |
5402 | |
5403 | static struct pci_driver mptsas_driver = { |
5404 | .name = "mptsas" , |
5405 | .id_table = mptsas_pci_table, |
5406 | .probe = mptsas_probe, |
5407 | .remove = mptsas_remove, |
5408 | .shutdown = mptsas_shutdown, |
5409 | #ifdef CONFIG_PM |
5410 | .suspend = mptscsih_suspend, |
5411 | .resume = mptscsih_resume, |
5412 | #endif |
5413 | }; |
5414 | |
5415 | static int __init |
5416 | mptsas_init(void) |
5417 | { |
5418 | int error; |
5419 | |
5420 | show_mptmod_ver(my_NAME, my_VERSION); |
5421 | |
5422 | mptsas_transport_template = |
5423 | sas_attach_transport(&mptsas_transport_functions); |
5424 | if (!mptsas_transport_template) |
5425 | return -ENODEV; |
5426 | |
5427 | mptsasDoneCtx = mpt_register(cbfunc: mptscsih_io_done, dclass: MPTSAS_DRIVER, |
5428 | func_name: "mptscsih_io_done" ); |
5429 | mptsasTaskCtx = mpt_register(cbfunc: mptscsih_taskmgmt_complete, dclass: MPTSAS_DRIVER, |
5430 | func_name: "mptscsih_taskmgmt_complete" ); |
5431 | mptsasInternalCtx = |
5432 | mpt_register(cbfunc: mptscsih_scandv_complete, dclass: MPTSAS_DRIVER, |
5433 | func_name: "mptscsih_scandv_complete" ); |
5434 | mptsasMgmtCtx = mpt_register(cbfunc: mptsas_mgmt_done, dclass: MPTSAS_DRIVER, |
5435 | func_name: "mptsas_mgmt_done" ); |
5436 | mptsasDeviceResetCtx = |
5437 | mpt_register(cbfunc: mptsas_taskmgmt_complete, dclass: MPTSAS_DRIVER, |
5438 | func_name: "mptsas_taskmgmt_complete" ); |
5439 | |
5440 | mpt_event_register(cb_idx: mptsasDoneCtx, ev_cbfunc: mptsas_event_process); |
5441 | mpt_reset_register(cb_idx: mptsasDoneCtx, reset_func: mptsas_ioc_reset); |
5442 | |
5443 | error = pci_register_driver(&mptsas_driver); |
5444 | if (error) |
5445 | sas_release_transport(mptsas_transport_template); |
5446 | |
5447 | return error; |
5448 | } |
5449 | |
5450 | static void __exit |
5451 | mptsas_exit(void) |
5452 | { |
5453 | pci_unregister_driver(dev: &mptsas_driver); |
5454 | sas_release_transport(mptsas_transport_template); |
5455 | |
5456 | mpt_reset_deregister(cb_idx: mptsasDoneCtx); |
5457 | mpt_event_deregister(cb_idx: mptsasDoneCtx); |
5458 | |
5459 | mpt_deregister(cb_idx: mptsasMgmtCtx); |
5460 | mpt_deregister(cb_idx: mptsasInternalCtx); |
5461 | mpt_deregister(cb_idx: mptsasTaskCtx); |
5462 | mpt_deregister(cb_idx: mptsasDoneCtx); |
5463 | mpt_deregister(cb_idx: mptsasDeviceResetCtx); |
5464 | } |
5465 | |
5466 | module_init(mptsas_init); |
5467 | module_exit(mptsas_exit); |
5468 | |