blob: f6308ad35b19774d64fcdd008466ac458a185f61 [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02008 */
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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090048#include <linux/slab.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020049#include <linux/init.h>
50#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080051#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020052#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060053#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020054
Eric Moore547f9a22006-06-27 14:42:12 -060055#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020056#include <scsi/scsi_cmnd.h>
57#include <scsi/scsi_device.h>
58#include <scsi/scsi_host.h>
59#include <scsi/scsi_transport_sas.h>
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +053060#include <scsi/scsi_transport.h>
Eric Moore547f9a22006-06-27 14:42:12 -060061#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020062
63#include "mptbase.h"
64#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053065#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020066
67
68#define my_NAME "Fusion MPT SAS Host driver"
69#define my_VERSION MPT_LINUX_VERSION_COMMON
70#define MYNAM "mptsas"
71
James Bottomleye8bf3942006-07-11 17:49:34 -040072/*
73 * Reserved channel for integrated raid
74 */
75#define MPTSAS_RAID_CHANNEL 1
76
Kashyap, Desai4b976502009-08-05 12:52:03 +053077#define SAS_CONFIG_PAGE_TIMEOUT 30
Christoph Hellwig0c33b272005-09-09 16:27:19 +020078MODULE_AUTHOR(MODULEAUTHOR);
79MODULE_DESCRIPTION(my_NAME);
80MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070081MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020082
Christoph Hellwig0c33b272005-09-09 16:27:19 +020083static int mpt_pt_clear;
84module_param(mpt_pt_clear, int, 0);
85MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060086 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020087 "(default=MPTSCSIH_PT_CLEAR=0)");
88
Eric Moore793955f2007-01-29 09:42:20 -070089/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
90#define MPTSAS_MAX_LUN (16895)
91static int max_lun = MPTSAS_MAX_LUN;
92module_param(max_lun, int, 0);
93MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
94
kashyap.desai@lsi.com3850b142011-08-04 16:41:55 +053095static int mpt_loadtime_max_sectors = 8192;
96module_param(mpt_loadtime_max_sectors, int, 0);
97MODULE_PARM_DESC(mpt_loadtime_max_sectors,
98 " Maximum sector define for Host Bus Adaptor.Range 64 to 8192 default=8192");
99
Prakash, Sathyaf606f572007-08-14 16:12:53 +0530100static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
101static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
102static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
103static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530104static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200105
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530106static void mptsas_firmware_event_work(struct work_struct *work);
107static void mptsas_send_sas_event(struct fw_event_work *fw_event);
108static void mptsas_send_raid_event(struct fw_event_work *fw_event);
109static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
110static void mptsas_parse_device_info(struct sas_identify *identify,
111 struct mptsas_devinfo *device_info);
112static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
113 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
114static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
115 (MPT_ADAPTER *ioc, u64 sas_address);
116static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
117 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
118static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
119 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
120static int mptsas_add_end_device(MPT_ADAPTER *ioc,
121 struct mptsas_phyinfo *phy_info);
122static void mptsas_del_end_device(MPT_ADAPTER *ioc,
123 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530124static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
125static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
126 (MPT_ADAPTER *ioc, u64 sas_address);
127static void mptsas_expander_delete(MPT_ADAPTER *ioc,
128 struct mptsas_portinfo *port_info, u8 force);
129static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530130static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
131static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530132static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
Kashyap, Desai57e98512009-05-29 16:55:09 +0530133static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530134static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Kashyap, Desaib68bf092010-06-17 14:40:56 +0530135void mptsas_schedule_target_reset(void *ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200136
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530137static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
138 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200139{
Eric Moore29dd3602007-09-14 18:46:51 -0600140 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)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200159}
160
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530161static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200162{
163 __le64 sas_address;
164
165 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
166
Eric Moore29dd3602007-09-14 18:46:51 -0600167 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)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200185}
186
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530187static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200188{
Eric Moore29dd3602007-09-14 18:46:51 -0600189 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));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200202}
203
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530204static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200205{
206 __le64 sas_address;
207
208 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
209
Eric Moore29dd3602007-09-14 18:46:51 -0600210 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));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200236}
237
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530238static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200239{
Eric Moore29dd3602007-09-14 18:46:51 -0600240 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)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200257}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200258
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530259/* inhibit sas firmware event handling */
260static void
261mptsas_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(&ioc->fw_event_lock, flags);
269
270}
271
272/* enable sas firmware event handling */
273static void
274mptsas_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(&ioc->fw_event_lock, flags);
281}
282
283/* queue a sas firmware event */
284static void
285mptsas_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(&fw_event->list, &ioc->fw_event_list);
292 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
kashyap.desai@lsi.coma38ae372011-08-04 16:42:46 +0530293 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)"
294 "on cpuid %d\n", ioc->name, __func__,
295 fw_event, smp_processor_id()));
296 queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q,
297 &fw_event->work, delay);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530298 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
299}
300
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530301/* requeue a sas firmware event */
302static void
303mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
304 unsigned long delay)
305{
306 unsigned long flags;
307 spin_lock_irqsave(&ioc->fw_event_lock, flags);
308 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
kashyap.desai@lsi.coma38ae372011-08-04 16:42:46 +0530309 "(fw_event=0x%p)on cpuid %d\n", ioc->name, __func__,
310 fw_event, smp_processor_id()));
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530311 fw_event->retries++;
kashyap.desai@lsi.coma38ae372011-08-04 16:42:46 +0530312 queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q,
313 &fw_event->work, msecs_to_jiffies(delay));
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530314 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
315}
316
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300317/* free memory associated to a sas firmware event */
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530318static void
319mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
320{
321 unsigned long flags;
322
323 spin_lock_irqsave(&ioc->fw_event_lock, flags);
324 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
325 ioc->name, __func__, fw_event));
326 list_del(&fw_event->list);
327 kfree(fw_event);
328 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
329}
330
331/* walk the firmware event queue, and either stop or wait for
332 * outstanding events to complete */
333static void
334mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
335{
336 struct fw_event_work *fw_event, *next;
337 struct mptsas_target_reset_event *target_reset_list, *n;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530338 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
339
340 /* flush the target_reset_list */
341 if (!list_empty(&hd->target_reset_list)) {
342 list_for_each_entry_safe(target_reset_list, n,
343 &hd->target_reset_list, list) {
344 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
345 "%s: removing target reset for id=%d\n",
346 ioc->name, __func__,
347 target_reset_list->sas_event_data.TargetID));
348 list_del(&target_reset_list->list);
349 kfree(target_reset_list);
350 }
351 }
352
353 if (list_empty(&ioc->fw_event_list) ||
354 !ioc->fw_event_q || in_interrupt())
355 return;
356
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530357 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
358 if (cancel_delayed_work(&fw_event->work))
359 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530360 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530361}
362
363
Christoph Hellwige3094442006-02-16 13:25:36 +0100364static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
365{
366 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
367 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
368}
369
370static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
371{
372 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
373 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
374}
375
Moore, Erice6b2d762006-03-14 09:14:24 -0700376/*
377 * mptsas_find_portinfo_by_handle
378 *
379 * This function should be called with the sas_topology_mutex already held
380 */
381static struct mptsas_portinfo *
382mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
383{
384 struct mptsas_portinfo *port_info, *rc=NULL;
385 int i;
386
387 list_for_each_entry(port_info, &ioc->sas_topology, list)
388 for (i = 0; i < port_info->num_phys; i++)
389 if (port_info->phy_info[i].identify.handle == handle) {
390 rc = port_info;
391 goto out;
392 }
393 out:
394 return rc;
395}
396
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530397/**
398 * mptsas_find_portinfo_by_sas_address -
399 * @ioc: Pointer to MPT_ADAPTER structure
400 * @handle:
401 *
402 * This function should be called with the sas_topology_mutex already held
403 *
404 **/
405static struct mptsas_portinfo *
406mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
407{
408 struct mptsas_portinfo *port_info, *rc = NULL;
409 int i;
410
411 if (sas_address >= ioc->hba_port_sas_addr &&
412 sas_address < (ioc->hba_port_sas_addr +
413 ioc->hba_port_num_phy))
414 return ioc->hba_port_info;
415
416 mutex_lock(&ioc->sas_topology_mutex);
417 list_for_each_entry(port_info, &ioc->sas_topology, list)
418 for (i = 0; i < port_info->num_phys; i++)
419 if (port_info->phy_info[i].identify.sas_address ==
420 sas_address) {
421 rc = port_info;
422 goto out;
423 }
424 out:
425 mutex_unlock(&ioc->sas_topology_mutex);
426 return rc;
427}
428
Moore, Ericbd23e942006-04-17 12:43:04 -0600429/*
430 * Returns true if there is a scsi end device
431 */
432static inline int
433mptsas_is_end_device(struct mptsas_devinfo * attached)
434{
Eric Moore547f9a22006-06-27 14:42:12 -0600435 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600436 (attached->device_info &
437 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
438 ((attached->device_info &
439 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
440 (attached->device_info &
441 MPI_SAS_DEVICE_INFO_STP_TARGET) |
442 (attached->device_info &
443 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
444 return 1;
445 else
446 return 0;
447}
448
Eric Moore547f9a22006-06-27 14:42:12 -0600449/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600450static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530451mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600452{
453 struct mptsas_portinfo *port_info;
454 struct mptsas_phyinfo *phy_info;
455 u8 i;
456
457 if (!port_details)
458 return;
459
460 port_info = port_details->port_info;
461 phy_info = port_info->phy_info;
462
Eric Moore29dd3602007-09-14 18:46:51 -0600463 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700464 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700465 port_details->num_phys, (unsigned long long)
466 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600467
468 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
469 if(phy_info->port_details != port_details)
470 continue;
471 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530472 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600473 phy_info->port_details = NULL;
474 }
475 kfree(port_details);
476}
477
478static inline struct sas_rphy *
479mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
480{
481 if (phy_info->port_details)
482 return phy_info->port_details->rphy;
483 else
484 return NULL;
485}
486
487static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530488mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600489{
490 if (phy_info->port_details) {
491 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600492 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
493 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600494 }
495
Eric Moore547f9a22006-06-27 14:42:12 -0600496 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600497 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
498 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600499 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
500 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600501 }
Eric Moore547f9a22006-06-27 14:42:12 -0600502}
503
504static inline struct sas_port *
505mptsas_get_port(struct mptsas_phyinfo *phy_info)
506{
507 if (phy_info->port_details)
508 return phy_info->port_details->port;
509 else
510 return NULL;
511}
512
513static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530514mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600515{
516 if (phy_info->port_details)
517 phy_info->port_details->port = port;
518
Eric Moore547f9a22006-06-27 14:42:12 -0600519 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600520 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
521 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600522 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
523 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600524 }
Eric Moore547f9a22006-06-27 14:42:12 -0600525}
526
527static inline struct scsi_target *
528mptsas_get_starget(struct mptsas_phyinfo *phy_info)
529{
530 if (phy_info->port_details)
531 return phy_info->port_details->starget;
532 else
533 return NULL;
534}
535
536static inline void
537mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
538starget)
539{
540 if (phy_info->port_details)
541 phy_info->port_details->starget = starget;
542}
543
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530544/**
545 * mptsas_add_device_component -
546 * @ioc: Pointer to MPT_ADAPTER structure
547 * @channel: fw mapped id's
548 * @id:
549 * @sas_address:
550 * @device_info:
551 *
552 **/
553static void
554mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
555 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
556{
557 struct mptsas_device_info *sas_info, *next;
558 struct scsi_device *sdev;
559 struct scsi_target *starget;
560 struct sas_rphy *rphy;
561
562 /*
563 * Delete all matching devices out of the list
564 */
565 mutex_lock(&ioc->sas_device_info_mutex);
566 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
567 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530568 if (!sas_info->is_logical_volume &&
569 (sas_info->sas_address == sas_address ||
570 (sas_info->fw.channel == channel &&
571 sas_info->fw.id == id))) {
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530572 list_del(&sas_info->list);
573 kfree(sas_info);
574 }
575 }
576
577 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
578 if (!sas_info)
579 goto out;
580
581 /*
582 * Set Firmware mapping
583 */
584 sas_info->fw.id = id;
585 sas_info->fw.channel = channel;
586
587 sas_info->sas_address = sas_address;
588 sas_info->device_info = device_info;
589 sas_info->slot = slot;
590 sas_info->enclosure_logical_id = enclosure_logical_id;
591 INIT_LIST_HEAD(&sas_info->list);
592 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
593
594 /*
595 * Set OS mapping
596 */
597 shost_for_each_device(sdev, ioc->sh) {
598 starget = scsi_target(sdev);
599 rphy = dev_to_rphy(starget->dev.parent);
600 if (rphy->identify.sas_address == sas_address) {
601 sas_info->os.id = starget->id;
602 sas_info->os.channel = starget->channel;
603 }
604 }
605
606 out:
607 mutex_unlock(&ioc->sas_device_info_mutex);
608 return;
609}
610
611/**
612 * mptsas_add_device_component_by_fw -
613 * @ioc: Pointer to MPT_ADAPTER structure
614 * @channel: fw mapped id's
615 * @id:
616 *
617 **/
618static void
619mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
620{
621 struct mptsas_devinfo sas_device;
622 struct mptsas_enclosure enclosure_info;
623 int rc;
624
625 rc = mptsas_sas_device_pg0(ioc, &sas_device,
626 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
627 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
628 (channel << 8) + id);
629 if (rc)
630 return;
631
632 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
633 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
634 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
635 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
636 sas_device.handle_enclosure);
637
638 mptsas_add_device_component(ioc, sas_device.channel,
639 sas_device.id, sas_device.sas_address, sas_device.device_info,
640 sas_device.slot, enclosure_info.enclosure_logical_id);
641}
642
643/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000644 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530645 * @ioc: Pointer to MPT_ADAPTER structure
646 * @channel: fw mapped id's
647 * @id:
648 *
649 **/
650static void
651mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
652 struct scsi_target *starget)
653{
654 CONFIGPARMS cfg;
655 ConfigPageHeader_t hdr;
656 dma_addr_t dma_handle;
657 pRaidVolumePage0_t buffer = NULL;
658 int i;
659 RaidPhysDiskPage0_t phys_disk;
660 struct mptsas_device_info *sas_info, *next;
661
662 memset(&cfg, 0 , sizeof(CONFIGPARMS));
663 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
664 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
665 /* assumption that all volumes on channel = 0 */
666 cfg.pageAddr = starget->id;
667 cfg.cfghdr.hdr = &hdr;
668 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +0530669 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530670
671 if (mpt_config(ioc, &cfg) != 0)
672 goto out;
673
674 if (!hdr.PageLength)
675 goto out;
676
677 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
678 &dma_handle);
679
680 if (!buffer)
681 goto out;
682
683 cfg.physAddr = dma_handle;
684 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
685
686 if (mpt_config(ioc, &cfg) != 0)
687 goto out;
688
689 if (!buffer->NumPhysDisks)
690 goto out;
691
692 /*
693 * Adding entry for hidden components
694 */
695 for (i = 0; i < buffer->NumPhysDisks; i++) {
696
697 if (mpt_raid_phys_disk_pg0(ioc,
698 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
699 continue;
700
701 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
702 phys_disk.PhysDiskID);
703
Kashyap, Desai57e98512009-05-29 16:55:09 +0530704 mutex_lock(&ioc->sas_device_info_mutex);
705 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
706 list) {
707 if (!sas_info->is_logical_volume &&
708 (sas_info->fw.channel == phys_disk.PhysDiskBus &&
709 sas_info->fw.id == phys_disk.PhysDiskID)) {
710 sas_info->is_hidden_raid_component = 1;
711 sas_info->volume_id = starget->id;
712 }
713 }
714 mutex_unlock(&ioc->sas_device_info_mutex);
715
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530716 }
717
718 /*
719 * Delete all matching devices out of the list
720 */
721 mutex_lock(&ioc->sas_device_info_mutex);
722 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
723 list) {
724 if (sas_info->is_logical_volume && sas_info->fw.id ==
725 starget->id) {
726 list_del(&sas_info->list);
727 kfree(sas_info);
728 }
729 }
730
731 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
732 if (sas_info) {
733 sas_info->fw.id = starget->id;
734 sas_info->os.id = starget->id;
735 sas_info->os.channel = starget->channel;
736 sas_info->is_logical_volume = 1;
737 INIT_LIST_HEAD(&sas_info->list);
738 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
739 }
740 mutex_unlock(&ioc->sas_device_info_mutex);
741
742 out:
743 if (buffer)
744 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
745 dma_handle);
746}
747
748/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530749 * mptsas_add_device_component_starget -
750 * @ioc: Pointer to MPT_ADAPTER structure
751 * @starget:
752 *
753 **/
754static void
755mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
756 struct scsi_target *starget)
757{
758 VirtTarget *vtarget;
759 struct sas_rphy *rphy;
760 struct mptsas_phyinfo *phy_info = NULL;
761 struct mptsas_enclosure enclosure_info;
762
763 rphy = dev_to_rphy(starget->dev.parent);
764 vtarget = starget->hostdata;
765 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
766 rphy->identify.sas_address);
767 if (!phy_info)
768 return;
769
770 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
771 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
772 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
773 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
774 phy_info->attached.handle_enclosure);
775
776 mptsas_add_device_component(ioc, phy_info->attached.channel,
777 phy_info->attached.id, phy_info->attached.sas_address,
778 phy_info->attached.device_info,
779 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
780}
781
782/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000783 * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached
Kashyap, Desai57e98512009-05-29 16:55:09 +0530784 * @ioc: Pointer to MPT_ADAPTER structure
785 * @channel: os mapped id's
786 * @id:
787 *
788 **/
789static void
790mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
791{
792 struct mptsas_device_info *sas_info, *next;
793
794 /*
795 * Set is_cached flag
796 */
797 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
798 list) {
799 if (sas_info->os.channel == channel && sas_info->os.id == id)
800 sas_info->is_cached = 1;
801 }
802}
803
804/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530805 * mptsas_del_device_components - Cleaning the list
806 * @ioc: Pointer to MPT_ADAPTER structure
807 *
808 **/
809static void
810mptsas_del_device_components(MPT_ADAPTER *ioc)
811{
812 struct mptsas_device_info *sas_info, *next;
813
814 mutex_lock(&ioc->sas_device_info_mutex);
815 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
816 list) {
817 list_del(&sas_info->list);
818 kfree(sas_info);
819 }
820 mutex_unlock(&ioc->sas_device_info_mutex);
821}
822
Eric Moore547f9a22006-06-27 14:42:12 -0600823
824/*
825 * mptsas_setup_wide_ports
826 *
827 * Updates for new and existing narrow/wide port configuration
828 * in the sas_topology
829 */
Eric Moore376ac832006-06-29 17:36:26 -0600830static void
Eric Moore547f9a22006-06-27 14:42:12 -0600831mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
832{
833 struct mptsas_portinfo_details * port_details;
834 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
835 u64 sas_address;
836 int i, j;
837
838 mutex_lock(&ioc->sas_topology_mutex);
839
840 phy_info = port_info->phy_info;
841 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
842 if (phy_info->attached.handle)
843 continue;
844 port_details = phy_info->port_details;
845 if (!port_details)
846 continue;
847 if (port_details->num_phys < 2)
848 continue;
849 /*
850 * Removing a phy from a port, letting the last
851 * phy be removed by firmware events.
852 */
Eric Moore29dd3602007-09-14 18:46:51 -0600853 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
854 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700855 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600856 port_details->num_phys--;
857 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
858 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai9e390892009-09-02 11:43:36 +0530859 if (phy_info->phy) {
860 devtprintk(ioc, dev_printk(KERN_DEBUG,
861 &phy_info->phy->dev, MYIOC_s_FMT
862 "delete phy %d, phy-obj (0x%p)\n", ioc->name,
863 phy_info->phy_id, phy_info->phy));
864 sas_port_delete_phy(port_details->port, phy_info->phy);
865 }
Eric Moore547f9a22006-06-27 14:42:12 -0600866 phy_info->port_details = NULL;
867 }
868
869 /*
870 * Populate and refresh the tree
871 */
872 phy_info = port_info->phy_info;
873 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
874 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600875 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
876 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600877 if (!sas_address)
878 continue;
879 port_details = phy_info->port_details;
880 /*
881 * Forming a port
882 */
883 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530884 port_details = kzalloc(sizeof(struct
885 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600886 if (!port_details)
887 goto out;
888 port_details->num_phys = 1;
889 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600890 if (phy_info->phy_id < 64 )
891 port_details->phy_bitmask |=
892 (1 << phy_info->phy_id);
893 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600894 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700895 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600896 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600897 phy_info->port_details = port_details;
898 }
899
900 if (i == port_info->num_phys - 1)
901 continue;
902 phy_info_cmp = &port_info->phy_info[i + 1];
903 for (j = i + 1 ; j < port_info->num_phys ; j++,
904 phy_info_cmp++) {
905 if (!phy_info_cmp->attached.sas_address)
906 continue;
907 if (sas_address != phy_info_cmp->attached.sas_address)
908 continue;
909 if (phy_info_cmp->port_details == port_details )
910 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600911 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700912 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600913 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700914 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600915 if (phy_info_cmp->port_details) {
916 port_details->rphy =
917 mptsas_get_rphy(phy_info_cmp);
918 port_details->port =
919 mptsas_get_port(phy_info_cmp);
920 port_details->starget =
921 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600922 port_details->num_phys =
923 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600924 if (!phy_info_cmp->port_details->num_phys)
925 kfree(phy_info_cmp->port_details);
926 } else
927 phy_info_cmp->sas_port_add_phy=1;
928 /*
929 * Adding a phy to a port
930 */
931 phy_info_cmp->port_details = port_details;
932 if (phy_info_cmp->phy_id < 64 )
933 port_details->phy_bitmask |=
934 (1 << phy_info_cmp->phy_id);
935 port_details->num_phys++;
936 }
937 }
938
939 out:
940
Eric Moore547f9a22006-06-27 14:42:12 -0600941 for (i = 0; i < port_info->num_phys; i++) {
942 port_details = port_info->phy_info[i].port_details;
943 if (!port_details)
944 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600945 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700946 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700947 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700948 port_details, i, port_details->num_phys,
949 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600950 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
951 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600952 }
Eric Moore29dd3602007-09-14 18:46:51 -0600953 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600954 mutex_unlock(&ioc->sas_topology_mutex);
955}
956
Eric Mooredf9e0622007-01-29 09:46:21 -0700957/**
958 * csmisas_find_vtarget
959 *
960 * @ioc
961 * @volume_id
962 * @volume_bus
963 *
964 **/
965static VirtTarget *
966mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600967{
Eric Mooredf9e0622007-01-29 09:46:21 -0700968 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600969 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700970 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600971
Eric Mooredf9e0622007-01-29 09:46:21 -0700972 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530973 vdevice = sdev->hostdata;
974 if ((vdevice == NULL) ||
975 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700976 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530977 if ((vdevice->vtarget->tflags &
978 MPT_TARGET_FLAGS_RAID_COMPONENT ||
979 vdevice->vtarget->raidVolume))
980 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600981 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530982 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600983 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600984 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700985 return vtarget;
986}
987
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530988static void
989mptsas_queue_device_delete(MPT_ADAPTER *ioc,
990 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
991{
992 struct fw_event_work *fw_event;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530993
Joe Lawrence32696192014-06-25 17:06:42 -0400994 fw_event = kzalloc(sizeof(*fw_event) +
995 sizeof(MpiEventDataSasDeviceStatusChange_t),
996 GFP_ATOMIC);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530997 if (!fw_event) {
998 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
999 ioc->name, __func__, __LINE__);
1000 return;
1001 }
1002 memcpy(fw_event->event_data, sas_event_data,
1003 sizeof(MpiEventDataSasDeviceStatusChange_t));
1004 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
1005 fw_event->ioc = ioc;
1006 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1007}
1008
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301009static void
1010mptsas_queue_rescan(MPT_ADAPTER *ioc)
1011{
1012 struct fw_event_work *fw_event;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301013
Joe Lawrence32696192014-06-25 17:06:42 -04001014 fw_event = kzalloc(sizeof(*fw_event), GFP_ATOMIC);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301015 if (!fw_event) {
1016 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1017 ioc->name, __func__, __LINE__);
1018 return;
1019 }
1020 fw_event->event = -1;
1021 fw_event->ioc = ioc;
1022 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1023}
1024
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301025
Eric Mooredf9e0622007-01-29 09:46:21 -07001026/**
1027 * mptsas_target_reset
1028 *
1029 * Issues TARGET_RESET to end device using handshaking method
1030 *
1031 * @ioc
1032 * @channel
1033 * @id
1034 *
1035 * Returns (1) success
1036 * (0) failure
1037 *
1038 **/
1039static int
1040mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1041{
1042 MPT_FRAME_HDR *mf;
1043 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301044 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1045 return 0;
1046
Eric Mooredf9e0622007-01-29 09:46:21 -07001047
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301048 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1049 if (mf == NULL) {
1050 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301051 "%s, no msg frames @%d!!\n", ioc->name,
1052 __func__, __LINE__));
1053 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001054 }
1055
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301056 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1057 ioc->name, mf));
1058
Eric Mooredf9e0622007-01-29 09:46:21 -07001059 /* Format the Request
1060 */
1061 pScsiTm = (SCSITaskMgmt_t *) mf;
1062 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1063 pScsiTm->TargetID = id;
1064 pScsiTm->Bus = channel;
1065 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1066 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1067 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1068
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301069 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001070
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301071 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1072 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1073 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1074
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301075 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001076
1077 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301078
1079 out_fail:
1080
1081 mpt_clear_taskmgmt_in_progress_flag(ioc);
1082 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001083}
1084
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301085static void
1086mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
1087{
1088 scsi_device_set_state(sdev, SDEV_BLOCK);
1089}
1090
1091static void
1092mptsas_block_io_starget(struct scsi_target *starget)
1093{
1094 if (starget)
1095 starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
1096}
1097
Eric Mooredf9e0622007-01-29 09:46:21 -07001098/**
1099 * mptsas_target_reset_queue
1100 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001101 * Receive request for TARGET_RESET after receiving an firmware
Eric Mooredf9e0622007-01-29 09:46:21 -07001102 * event NOT_RESPONDING_EVENT, then put command in link list
1103 * and queue if task_queue already in use.
1104 *
1105 * @ioc
1106 * @sas_event_data
1107 *
1108 **/
1109static void
1110mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1111 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1112{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001113 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001114 VirtTarget *vtarget = NULL;
1115 struct mptsas_target_reset_event *target_reset_list;
1116 u8 id, channel;
1117
1118 id = sas_event_data->TargetID;
1119 channel = sas_event_data->Bus;
1120
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301121 vtarget = mptsas_find_vtarget(ioc, channel, id);
1122 if (vtarget) {
1123 mptsas_block_io_starget(vtarget->starget);
1124 vtarget->deleted = 1; /* block IO */
1125 }
Eric Mooredf9e0622007-01-29 09:46:21 -07001126
Kashyap, Desai2f187862009-05-29 16:52:37 +05301127 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001128 GFP_ATOMIC);
1129 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301130 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1131 "%s, failed to allocate mem @%d..!!\n",
1132 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001133 return;
1134 }
1135
1136 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1137 sizeof(*sas_event_data));
1138 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1139
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301140 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001141
1142 if (mptsas_target_reset(ioc, channel, id)) {
1143 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001144 }
1145}
1146
1147/**
Kashyap, Desaib68bf092010-06-17 14:40:56 +05301148 * mptsas_schedule_target_reset- send pending target reset
1149 * @iocp: per adapter object
1150 *
1151 * This function will delete scheduled target reset from the list and
1152 * try to send next target reset. This will be called from completion
Uwe Kleine-Königb5950762010-11-01 15:38:34 -04001153 * context of any Task management command.
Kashyap, Desaib68bf092010-06-17 14:40:56 +05301154 */
1155
1156void
1157mptsas_schedule_target_reset(void *iocp)
1158{
1159 MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp);
1160 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1161 struct list_head *head = &hd->target_reset_list;
1162 struct mptsas_target_reset_event *target_reset_list;
1163 u8 id, channel;
1164 /*
1165 * issue target reset to next device in the queue
1166 */
1167
1168 head = &hd->target_reset_list;
1169 if (list_empty(head))
1170 return;
1171
1172 target_reset_list = list_entry(head->next,
1173 struct mptsas_target_reset_event, list);
1174
1175 id = target_reset_list->sas_event_data.TargetID;
1176 channel = target_reset_list->sas_event_data.Bus;
1177 target_reset_list->time_count = jiffies;
1178
1179 if (mptsas_target_reset(ioc, channel, id))
1180 target_reset_list->target_reset_issued = 1;
1181 return;
1182}
1183
1184
1185/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001186 * mptsas_taskmgmt_complete - complete SAS task management function
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301187 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001188 *
James Bottomleyfc847ab2009-06-09 23:01:01 +00001189 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1190 * queue to finish off removing device from upper layers. then send next
1191 * TARGET_RESET in the queue.
Eric Mooredf9e0622007-01-29 09:46:21 -07001192 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301193static int
1194mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001195{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001196 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001197 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001198 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301199 struct mptsas_target_reset_event *target_reset_list;
1200 SCSITaskMgmtReply_t *pScsiTmReply;
1201
1202 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1203 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1204
1205 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
Joe Lawrence9f213162014-06-25 17:06:54 -04001206 if (!pScsiTmReply)
1207 return 0;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301208
Joe Lawrence9f213162014-06-25 17:06:54 -04001209 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1210 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1211 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1212 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1213 "term_cmnds = %d\n", ioc->name,
1214 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1215 pScsiTmReply->TaskType,
1216 le16_to_cpu(pScsiTmReply->IOCStatus),
1217 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1218 pScsiTmReply->ResponseCode,
1219 le32_to_cpu(pScsiTmReply->TerminationCount)));
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301220
Joe Lawrence9f213162014-06-25 17:06:54 -04001221 if (pScsiTmReply->ResponseCode)
1222 mptscsih_taskmgmt_response_code(ioc,
1223 pScsiTmReply->ResponseCode);
1224
1225 if (pScsiTmReply->TaskType ==
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301226 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
Joe Lawrence9f213162014-06-25 17:06:54 -04001227 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301228 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1229 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1230 memcpy(ioc->taskmgmt_cmds.reply, mr,
1231 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1232 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1233 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1234 complete(&ioc->taskmgmt_cmds.done);
1235 return 1;
1236 }
1237 return 0;
1238 }
1239
1240 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001241
1242 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301243 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001244
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301245 target_reset_list = list_entry(head->next,
1246 struct mptsas_target_reset_event, list);
1247
1248 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1249 "TaskMgmt: completed (%d seconds)\n",
1250 ioc->name, jiffies_to_msecs(jiffies -
1251 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001252
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301253 id = pScsiTmReply->TargetID;
1254 channel = pScsiTmReply->Bus;
1255 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001256
1257 /*
1258 * retry target reset
1259 */
1260 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301261 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001262 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301263 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001264 }
1265
1266 /*
1267 * enable work queue to remove device from upper layers
1268 */
1269 list_del(&target_reset_list->list);
Kei Tokunaga3e84beb2010-04-07 19:17:24 +09001270 if (!ioc->fw_events_off)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301271 mptsas_queue_device_delete(ioc,
1272 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301273
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301274
Kashyap, Desaib68bf092010-06-17 14:40:56 +05301275 ioc->schedule_target_reset(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001276
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301277 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001278}
1279
1280/**
1281 * mptscsih_ioc_reset
1282 *
1283 * @ioc
1284 * @reset_phase
1285 *
1286 **/
1287static int
1288mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1289{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001290 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001291 int rc;
1292
1293 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301294 if ((ioc->bus_type != SAS) || (!rc))
1295 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001296
Eric Mooree7eae9f2007-09-29 10:15:59 -06001297 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001298 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001299 goto out;
1300
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301301 switch (reset_phase) {
1302 case MPT_IOC_SETUP_RESET:
1303 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1304 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1305 mptsas_fw_event_off(ioc);
1306 break;
1307 case MPT_IOC_PRE_RESET:
1308 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1309 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1310 break;
1311 case MPT_IOC_POST_RESET:
1312 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1313 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1314 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1315 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1316 complete(&ioc->sas_mgmt.done);
1317 }
1318 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301319 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301320 break;
1321 default:
1322 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001323 }
1324
1325 out:
1326 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001327}
1328
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301329
1330/**
1331 * enum device_state -
1332 * @DEVICE_RETRY: need to retry the TUR
1333 * @DEVICE_ERROR: TUR return error, don't add device
1334 * @DEVICE_READY: device can be added
1335 *
1336 */
1337enum device_state{
1338 DEVICE_RETRY,
1339 DEVICE_ERROR,
1340 DEVICE_READY,
1341};
1342
Christoph Hellwige3094442006-02-16 13:25:36 +01001343static int
Moore, Eric52435432006-03-14 09:14:15 -07001344mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001345 u32 form, u32 form_specific)
1346{
1347 ConfigExtendedPageHeader_t hdr;
1348 CONFIGPARMS cfg;
1349 SasEnclosurePage0_t *buffer;
1350 dma_addr_t dma_handle;
1351 int error;
1352 __le64 le_identifier;
1353
1354 memset(&hdr, 0, sizeof(hdr));
1355 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1356 hdr.PageNumber = 0;
1357 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1358 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1359
1360 cfg.cfghdr.ehdr = &hdr;
1361 cfg.physAddr = -1;
1362 cfg.pageAddr = form + form_specific;
1363 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1364 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301365 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwige3094442006-02-16 13:25:36 +01001366
1367 error = mpt_config(ioc, &cfg);
1368 if (error)
1369 goto out;
1370 if (!hdr.ExtPageLength) {
1371 error = -ENXIO;
1372 goto out;
1373 }
1374
1375 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1376 &dma_handle);
1377 if (!buffer) {
1378 error = -ENOMEM;
1379 goto out;
1380 }
1381
1382 cfg.physAddr = dma_handle;
1383 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1384
1385 error = mpt_config(ioc, &cfg);
1386 if (error)
1387 goto out_free_consistent;
1388
1389 /* save config data */
1390 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1391 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1392 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1393 enclosure->flags = le16_to_cpu(buffer->Flags);
1394 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1395 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1396 enclosure->start_id = buffer->StartTargetID;
1397 enclosure->start_channel = buffer->StartBus;
1398 enclosure->sep_id = buffer->SEPTargetID;
1399 enclosure->sep_channel = buffer->SEPBus;
1400
1401 out_free_consistent:
1402 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1403 buffer, dma_handle);
1404 out:
1405 return error;
1406}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001407
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301408/**
1409 * mptsas_add_end_device - report a new end device to sas transport layer
1410 * @ioc: Pointer to MPT_ADAPTER structure
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001411 * @phy_info: describes attached device
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301412 *
1413 * return (0) success (1) failure
1414 *
1415 **/
1416static int
1417mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1418{
1419 struct sas_rphy *rphy;
1420 struct sas_port *port;
1421 struct sas_identify identify;
1422 char *ds = NULL;
1423 u8 fw_id;
1424
1425 if (!phy_info) {
1426 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1427 "%s: exit at line=%d\n", ioc->name,
1428 __func__, __LINE__));
1429 return 1;
1430 }
1431
1432 fw_id = phy_info->attached.id;
1433
1434 if (mptsas_get_rphy(phy_info)) {
1435 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1436 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1437 __func__, fw_id, __LINE__));
1438 return 2;
1439 }
1440
1441 port = mptsas_get_port(phy_info);
1442 if (!port) {
1443 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1444 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1445 __func__, fw_id, __LINE__));
1446 return 3;
1447 }
1448
1449 if (phy_info->attached.device_info &
1450 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1451 ds = "ssp";
1452 if (phy_info->attached.device_info &
1453 MPI_SAS_DEVICE_INFO_STP_TARGET)
1454 ds = "stp";
1455 if (phy_info->attached.device_info &
1456 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1457 ds = "sata";
1458
1459 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1460 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1461 phy_info->attached.channel, phy_info->attached.id,
1462 phy_info->attached.phy_id, (unsigned long long)
1463 phy_info->attached.sas_address);
1464
1465 mptsas_parse_device_info(&identify, &phy_info->attached);
1466 rphy = sas_end_device_alloc(port);
1467 if (!rphy) {
1468 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1469 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1470 __func__, fw_id, __LINE__));
1471 return 5; /* non-fatal: an rphy can be added later */
1472 }
1473
1474 rphy->identify = identify;
1475 if (sas_rphy_add(rphy)) {
1476 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1477 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1478 __func__, fw_id, __LINE__));
1479 sas_rphy_free(rphy);
1480 return 6;
1481 }
1482 mptsas_set_rphy(ioc, phy_info, rphy);
1483 return 0;
1484}
1485
1486/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001487 * mptsas_del_end_device - report a deleted end device to sas transport layer
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301488 * @ioc: Pointer to MPT_ADAPTER structure
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001489 * @phy_info: describes attached device
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301490 *
1491 **/
1492static void
1493mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1494{
1495 struct sas_rphy *rphy;
1496 struct sas_port *port;
1497 struct mptsas_portinfo *port_info;
1498 struct mptsas_phyinfo *phy_info_parent;
1499 int i;
1500 char *ds = NULL;
1501 u8 fw_id;
1502 u64 sas_address;
1503
1504 if (!phy_info)
1505 return;
1506
1507 fw_id = phy_info->attached.id;
1508 sas_address = phy_info->attached.sas_address;
1509
1510 if (!phy_info->port_details) {
1511 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1512 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1513 __func__, fw_id, __LINE__));
1514 return;
1515 }
1516 rphy = mptsas_get_rphy(phy_info);
1517 if (!rphy) {
1518 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1519 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1520 __func__, fw_id, __LINE__));
1521 return;
1522 }
1523
1524 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1525 || phy_info->attached.device_info
1526 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1527 || phy_info->attached.device_info
1528 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1529 ds = "initiator";
1530 if (phy_info->attached.device_info &
1531 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1532 ds = "ssp";
1533 if (phy_info->attached.device_info &
1534 MPI_SAS_DEVICE_INFO_STP_TARGET)
1535 ds = "stp";
1536 if (phy_info->attached.device_info &
1537 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1538 ds = "sata";
1539
1540 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1541 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1542 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1543 phy_info->attached.id, phy_info->attached.phy_id,
1544 (unsigned long long) sas_address);
1545
1546 port = mptsas_get_port(phy_info);
1547 if (!port) {
1548 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1549 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1550 __func__, fw_id, __LINE__));
1551 return;
1552 }
1553 port_info = phy_info->portinfo;
1554 phy_info_parent = port_info->phy_info;
1555 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1556 if (!phy_info_parent->phy)
1557 continue;
1558 if (phy_info_parent->attached.sas_address !=
1559 sas_address)
1560 continue;
1561 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1562 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1563 ioc->name, phy_info_parent->phy_id,
1564 phy_info_parent->phy);
1565 sas_port_delete_phy(port, phy_info_parent->phy);
1566 }
1567
1568 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1569 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1570 port->port_identifier, (unsigned long long)sas_address);
1571 sas_port_delete(port);
1572 mptsas_set_port(ioc, phy_info, NULL);
1573 mptsas_port_delete(ioc, phy_info->port_details);
1574}
1575
Joe Lawrence5767d252014-06-25 17:05:49 -04001576static struct mptsas_phyinfo *
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301577mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1578 struct mptsas_devinfo *sas_device)
1579{
1580 struct mptsas_phyinfo *phy_info;
1581 struct mptsas_portinfo *port_info;
1582 int i;
1583
1584 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1585 sas_device->sas_address);
1586 if (!phy_info)
1587 goto out;
1588 port_info = phy_info->portinfo;
1589 if (!port_info)
1590 goto out;
1591 mutex_lock(&ioc->sas_topology_mutex);
1592 for (i = 0; i < port_info->num_phys; i++) {
1593 if (port_info->phy_info[i].attached.sas_address !=
1594 sas_device->sas_address)
1595 continue;
1596 port_info->phy_info[i].attached.channel = sas_device->channel;
1597 port_info->phy_info[i].attached.id = sas_device->id;
1598 port_info->phy_info[i].attached.sas_address =
1599 sas_device->sas_address;
1600 port_info->phy_info[i].attached.handle = sas_device->handle;
1601 port_info->phy_info[i].attached.handle_parent =
1602 sas_device->handle_parent;
1603 port_info->phy_info[i].attached.handle_enclosure =
1604 sas_device->handle_enclosure;
1605 }
1606 mutex_unlock(&ioc->sas_topology_mutex);
1607 out:
1608 return phy_info;
1609}
1610
1611/**
1612 * mptsas_firmware_event_work - work thread for processing fw events
1613 * @work: work queue payload containing info describing the event
1614 * Context: user
1615 *
1616 */
1617static void
1618mptsas_firmware_event_work(struct work_struct *work)
1619{
1620 struct fw_event_work *fw_event =
1621 container_of(work, struct fw_event_work, work.work);
1622 MPT_ADAPTER *ioc = fw_event->ioc;
1623
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301624 /* special rescan topology handling */
1625 if (fw_event->event == -1) {
1626 if (ioc->in_rescan) {
1627 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1628 "%s: rescan ignored as it is in progress\n",
1629 ioc->name, __func__));
1630 return;
1631 }
1632 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1633 "reset\n", ioc->name, __func__));
1634 ioc->in_rescan = 1;
1635 mptsas_not_responding_devices(ioc);
1636 mptsas_scan_sas_topology(ioc);
1637 ioc->in_rescan = 0;
1638 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai97660962009-09-02 11:46:33 +05301639 mptsas_fw_event_on(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301640 return;
1641 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301642
1643 /* events handling turned off during host reset */
1644 if (ioc->fw_events_off) {
1645 mptsas_free_fw_event(ioc, fw_event);
1646 return;
1647 }
1648
1649 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1650 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1651 (fw_event->event & 0xFF)));
1652
1653 switch (fw_event->event) {
1654 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1655 mptsas_send_sas_event(fw_event);
1656 break;
1657 case MPI_EVENT_INTEGRATED_RAID:
1658 mptsas_send_raid_event(fw_event);
1659 break;
1660 case MPI_EVENT_IR2:
1661 mptsas_send_ir2_event(fw_event);
1662 break;
1663 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1664 mptbase_sas_persist_operation(ioc,
1665 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1666 mptsas_free_fw_event(ioc, fw_event);
1667 break;
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05301668 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1669 mptsas_broadcast_primative_work(fw_event);
1670 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301671 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1672 mptsas_send_expander_event(fw_event);
1673 break;
1674 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1675 mptsas_send_link_status_event(fw_event);
1676 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301677 case MPI_EVENT_QUEUE_FULL:
1678 mptsas_handle_queue_full_event(fw_event);
1679 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301680 }
1681}
1682
1683
1684
James Bottomleyf013db32006-03-18 14:54:36 -06001685static int
1686mptsas_slave_configure(struct scsi_device *sdev)
1687{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301688 struct Scsi_Host *host = sdev->host;
1689 MPT_SCSI_HOST *hd = shost_priv(host);
1690 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301691 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001692
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301693 if (vdevice->vtarget->deleted) {
1694 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1695 vdevice->vtarget->deleted = 0;
1696 }
1697
1698 /*
1699 * RAID volumes placed beyond the last expected port.
1700 * Ignore sending sas mode pages in that case..
1701 */
1702 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1703 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001704 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301705 }
James Bottomleyf013db32006-03-18 14:54:36 -06001706
James Bottomleye8bf3942006-07-11 17:49:34 -04001707 sas_read_port_mode_page(sdev);
1708
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301709 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1710
James Bottomleye8bf3942006-07-11 17:49:34 -04001711 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001712 return mptscsih_slave_configure(sdev);
1713}
1714
Eric Moore547f9a22006-06-27 14:42:12 -06001715static int
1716mptsas_target_alloc(struct scsi_target *starget)
1717{
1718 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001719 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001720 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001721 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001722 struct sas_rphy *rphy;
1723 struct mptsas_portinfo *p;
1724 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001725 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001726
1727 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1728 if (!vtarget)
1729 return -ENOMEM;
1730
1731 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001732 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001733 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1734 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001735 channel = 0;
1736
Eric Moore793955f2007-01-29 09:42:20 -07001737 /*
1738 * RAID volumes placed beyond the last expected port.
1739 */
1740 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301741 if (!ioc->raid_data.pIocPg2) {
1742 kfree(vtarget);
1743 return -ENXIO;
1744 }
1745 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1746 if (id == ioc->raid_data.pIocPg2->
1747 RaidVolume[i].VolumeID) {
1748 channel = ioc->raid_data.pIocPg2->
1749 RaidVolume[i].VolumeBus;
1750 }
1751 }
1752 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001753 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001754 }
Eric Moore547f9a22006-06-27 14:42:12 -06001755
1756 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001757 mutex_lock(&ioc->sas_topology_mutex);
1758 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001759 for (i = 0; i < p->num_phys; i++) {
1760 if (p->phy_info[i].attached.sas_address !=
1761 rphy->identify.sas_address)
1762 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001763 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001764 channel = p->phy_info[i].attached.channel;
1765 mptsas_set_starget(&p->phy_info[i], starget);
1766
1767 /*
1768 * Exposing hidden raid components
1769 */
Eric Mooree80b0022007-09-14 18:49:03 -06001770 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1771 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001772 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001773 vtarget->tflags |=
1774 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001775 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001776 }
Eric Mooree80b0022007-09-14 18:49:03 -06001777 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001778 goto out;
1779 }
1780 }
Eric Mooree80b0022007-09-14 18:49:03 -06001781 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001782
1783 kfree(vtarget);
1784 return -ENXIO;
1785
1786 out:
Eric Moore793955f2007-01-29 09:42:20 -07001787 vtarget->id = id;
1788 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001789 starget->hostdata = vtarget;
1790 return 0;
1791}
1792
1793static void
1794mptsas_target_destroy(struct scsi_target *starget)
1795{
1796 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001797 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001798 struct sas_rphy *rphy;
1799 struct mptsas_portinfo *p;
1800 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301801 MPT_ADAPTER *ioc = hd->ioc;
1802 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001803
1804 if (!starget->hostdata)
1805 return;
1806
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301807 vtarget = starget->hostdata;
1808
Kashyap, Desai57e98512009-05-29 16:55:09 +05301809 mptsas_del_device_component_by_os(ioc, starget->channel,
1810 starget->id);
1811
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301812
James Bottomleye8bf3942006-07-11 17:49:34 -04001813 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001814 goto out;
1815
1816 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001817 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001818 for (i = 0; i < p->num_phys; i++) {
1819 if (p->phy_info[i].attached.sas_address !=
1820 rphy->identify.sas_address)
1821 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301822
1823 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1824 "delete device: fw_channel %d, fw_id %d, phy %d, "
1825 "sas_addr 0x%llx\n", ioc->name,
1826 p->phy_info[i].attached.channel,
1827 p->phy_info[i].attached.id,
1828 p->phy_info[i].attached.phy_id, (unsigned long long)
1829 p->phy_info[i].attached.sas_address);
1830
Eric Moore547f9a22006-06-27 14:42:12 -06001831 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001832 }
1833 }
1834
1835 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301836 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001837 kfree(starget->hostdata);
1838 starget->hostdata = NULL;
1839}
1840
1841
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001842static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001843mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001844{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001845 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001846 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001847 struct sas_rphy *rphy;
1848 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001849 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001850 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001851 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001852 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001853
Eric Moorea69de502007-09-14 18:48:19 -06001854 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1855 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001856 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001857 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001858 return -ENOMEM;
1859 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001860 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001861 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001862
James Bottomleye8bf3942006-07-11 17:49:34 -04001863 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001864 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001865
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001866 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001867 mutex_lock(&ioc->sas_topology_mutex);
1868 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001869 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001870 if (p->phy_info[i].attached.sas_address !=
1871 rphy->identify.sas_address)
1872 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001873 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001874 /*
1875 * Exposing hidden raid components
1876 */
Eric Mooree80b0022007-09-14 18:49:03 -06001877 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001878 p->phy_info[i].attached.channel,
1879 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001880 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001881 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001882 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001883 }
1884 }
Eric Mooree80b0022007-09-14 18:49:03 -06001885 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001886
Eric Moorea69de502007-09-14 18:48:19 -06001887 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001888 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001889
1890 out:
Eric Moorea69de502007-09-14 18:48:19 -06001891 vdevice->vtarget->num_luns++;
1892 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001893 return 0;
1894}
1895
Eric Moore547f9a22006-06-27 14:42:12 -06001896static int
Matthew Wilcoxa48ac9e2014-03-27 16:40:36 -04001897mptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001898{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301899 MPT_SCSI_HOST *hd;
1900 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001901 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001902
Eric Moorea69de502007-09-14 18:48:19 -06001903 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001904 SCpnt->result = DID_NO_CONNECT << 16;
Matthew Wilcoxa48ac9e2014-03-27 16:40:36 -04001905 SCpnt->scsi_done(SCpnt);
Eric Moore547f9a22006-06-27 14:42:12 -06001906 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001907 }
Eric Moore547f9a22006-06-27 14:42:12 -06001908
Matthew Wilcoxa48ac9e2014-03-27 16:40:36 -04001909 hd = shost_priv(shost);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301910 ioc = hd->ioc;
1911
1912 if (ioc->sas_discovery_quiesce_io)
1913 return SCSI_MLQUEUE_HOST_BUSY;
1914
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301915 if (ioc->debug_level & MPT_DEBUG_SCSI)
1916 scsi_print_command(SCpnt);
Eric Moore793955f2007-01-29 09:42:20 -07001917
Matthew Wilcoxa48ac9e2014-03-27 16:40:36 -04001918 return mptscsih_qcmd(SCpnt);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001919}
1920
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05301921/**
1922 * mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
1923 * if the device under question is currently in the
1924 * device removal delay.
1925 * @sc: scsi command that the midlayer is about to time out
1926 *
1927 **/
1928static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc)
1929{
1930 MPT_SCSI_HOST *hd;
1931 MPT_ADAPTER *ioc;
1932 VirtDevice *vdevice;
1933 enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
1934
1935 hd = shost_priv(sc->device->host);
1936 if (hd == NULL) {
1937 printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n",
1938 __func__, sc);
1939 goto done;
1940 }
1941
1942 ioc = hd->ioc;
1943 if (ioc->bus_type != SAS) {
1944 printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n",
1945 __func__, sc);
1946 goto done;
1947 }
1948
kashyap.desai@lsi.com98cbe372011-08-05 11:04:37 +05301949 /* In case if IOC is in reset from internal context.
1950 * Do not execute EEH for the same IOC. SML should to reset timer.
1951 */
1952 if (ioc->ioc_reset_in_progress) {
1953 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset,"
1954 "SML need to reset the timer (sc=%p)\n",
1955 ioc->name, __func__, sc));
1956 rc = BLK_EH_RESET_TIMER;
1957 }
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05301958 vdevice = sc->device->hostdata;
1959 if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD
1960 || vdevice->vtarget->deleted)) {
1961 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed "
1962 "or in device removal delay (sc=%p)\n",
1963 ioc->name, __func__, sc));
1964 rc = BLK_EH_RESET_TIMER;
1965 goto done;
1966 }
1967
1968done:
1969 return rc;
1970}
1971
Eric Moore547f9a22006-06-27 14:42:12 -06001972
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001973static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001974 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001975 .proc_name = "mptsas",
Al Virocac19702013-03-31 01:42:38 -04001976 .show_info = mptscsih_show_info,
Kashyap, Desai568da762010-03-18 19:23:50 +05301977 .name = "MPT SAS Host",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001978 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001979 .queuecommand = mptsas_qcmd,
1980 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001981 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001982 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001983 .target_destroy = mptsas_target_destroy,
1984 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001985 .change_queue_depth = mptscsih_change_queue_depth,
Christoph Hellwigb6a05c82017-01-30 13:18:58 +01001986 .eh_timed_out = mptsas_eh_timed_out,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001987 .eh_abort_handler = mptscsih_abort,
1988 .eh_device_reset_handler = mptscsih_dev_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001989 .eh_host_reset_handler = mptscsih_host_reset,
1990 .bios_param = mptscsih_bios_param,
Kashyap, Desai9d2e9d62009-08-05 12:48:44 +05301991 .can_queue = MPT_SAS_CAN_QUEUE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001992 .this_id = -1,
1993 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1994 .max_sectors = 8192,
1995 .cmd_per_lun = 7,
1996 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301997 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001998};
1999
Christoph Hellwigb5141122005-10-28 22:07:41 +02002000static int mptsas_get_linkerrors(struct sas_phy *phy)
2001{
2002 MPT_ADAPTER *ioc = phy_to_ioc(phy);
2003 ConfigExtendedPageHeader_t hdr;
2004 CONFIGPARMS cfg;
2005 SasPhyPage1_t *buffer;
2006 dma_addr_t dma_handle;
2007 int error;
2008
James Bottomleyf4ad7b52006-08-25 13:48:18 -05002009 /* FIXME: only have link errors on local phys */
2010 if (!scsi_is_sas_phy_local(phy))
2011 return -EINVAL;
2012
Christoph Hellwigb5141122005-10-28 22:07:41 +02002013 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
2014 hdr.ExtPageLength = 0;
2015 hdr.PageNumber = 1 /* page number 1*/;
2016 hdr.Reserved1 = 0;
2017 hdr.Reserved2 = 0;
2018 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2019 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2020
2021 cfg.cfghdr.ehdr = &hdr;
2022 cfg.physAddr = -1;
2023 cfg.pageAddr = phy->identify.phy_identifier;
2024 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2025 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302026 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwigb5141122005-10-28 22:07:41 +02002027
2028 error = mpt_config(ioc, &cfg);
2029 if (error)
2030 return error;
2031 if (!hdr.ExtPageLength)
2032 return -ENXIO;
2033
2034 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2035 &dma_handle);
2036 if (!buffer)
2037 return -ENOMEM;
2038
2039 cfg.physAddr = dma_handle;
2040 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2041
2042 error = mpt_config(ioc, &cfg);
2043 if (error)
2044 goto out_free_consistent;
2045
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302046 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02002047
2048 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
2049 phy->running_disparity_error_count =
2050 le32_to_cpu(buffer->RunningDisparityErrorCount);
2051 phy->loss_of_dword_sync_count =
2052 le32_to_cpu(buffer->LossDwordSynchCount);
2053 phy->phy_reset_problem_count =
2054 le32_to_cpu(buffer->PhyResetProblemCount);
2055
2056 out_free_consistent:
2057 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2058 buffer, dma_handle);
2059 return error;
2060}
2061
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002062static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2063 MPT_FRAME_HDR *reply)
2064{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302065 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002066 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302067 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002068 memcpy(ioc->sas_mgmt.reply, reply,
2069 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
2070 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302071
2072 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
2073 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
2074 complete(&ioc->sas_mgmt.done);
2075 return 1;
2076 }
2077 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002078}
2079
2080static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
2081{
2082 MPT_ADAPTER *ioc = phy_to_ioc(phy);
2083 SasIoUnitControlRequest_t *req;
2084 SasIoUnitControlReply_t *reply;
2085 MPT_FRAME_HDR *mf;
2086 MPIHeader_t *hdr;
2087 unsigned long timeleft;
2088 int error = -ERESTARTSYS;
2089
James Bottomleyf4ad7b52006-08-25 13:48:18 -05002090 /* FIXME: fusion doesn't allow non-local phy reset */
2091 if (!scsi_is_sas_phy_local(phy))
2092 return -EINVAL;
2093
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002094 /* not implemented for expanders */
2095 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2096 return -ENXIO;
2097
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002098 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002099 goto out;
2100
2101 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2102 if (!mf) {
2103 error = -ENOMEM;
2104 goto out_unlock;
2105 }
2106
2107 hdr = (MPIHeader_t *) mf;
2108 req = (SasIoUnitControlRequest_t *)mf;
2109 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2110 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2111 req->MsgContext = hdr->MsgContext;
2112 req->Operation = hard_reset ?
2113 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2114 req->PhyNum = phy->identify.phy_identifier;
2115
Kashyap, Desai2f187862009-05-29 16:52:37 +05302116 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002117 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2118
2119 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2120 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302121 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2122 error = -ETIME;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002123 mpt_free_msg_frame(ioc, mf);
Kashyap, Desai568da762010-03-18 19:23:50 +05302124 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2125 goto out_unlock;
2126 if (!timeleft)
2127 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002128 goto out_unlock;
2129 }
2130
2131 /* a reply frame is expected */
2132 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302133 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002134 error = -ENXIO;
2135 goto out_unlock;
2136 }
2137
2138 /* process the completed Reply Message Frame */
2139 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2140 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002141 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002142 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002143 error = -ENXIO;
2144 goto out_unlock;
2145 }
2146
2147 error = 0;
2148
2149 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302150 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002151 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002152 out:
2153 return error;
2154}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002155
Christoph Hellwige3094442006-02-16 13:25:36 +01002156static int
2157mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2158{
2159 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2160 int i, error;
2161 struct mptsas_portinfo *p;
2162 struct mptsas_enclosure enclosure_info;
2163 u64 enclosure_handle;
2164
2165 mutex_lock(&ioc->sas_topology_mutex);
2166 list_for_each_entry(p, &ioc->sas_topology, list) {
2167 for (i = 0; i < p->num_phys; i++) {
2168 if (p->phy_info[i].attached.sas_address ==
2169 rphy->identify.sas_address) {
2170 enclosure_handle = p->phy_info[i].
2171 attached.handle_enclosure;
2172 goto found_info;
2173 }
2174 }
2175 }
2176 mutex_unlock(&ioc->sas_topology_mutex);
2177 return -ENXIO;
2178
2179 found_info:
2180 mutex_unlock(&ioc->sas_topology_mutex);
2181 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002182 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002183 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2184 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2185 if (!error)
2186 *identifier = enclosure_info.enclosure_logical_id;
2187 return error;
2188}
2189
2190static int
2191mptsas_get_bay_identifier(struct sas_rphy *rphy)
2192{
2193 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2194 struct mptsas_portinfo *p;
2195 int i, rc;
2196
2197 mutex_lock(&ioc->sas_topology_mutex);
2198 list_for_each_entry(p, &ioc->sas_topology, list) {
2199 for (i = 0; i < p->num_phys; i++) {
2200 if (p->phy_info[i].attached.sas_address ==
2201 rphy->identify.sas_address) {
2202 rc = p->phy_info[i].attached.slot;
2203 goto out;
2204 }
2205 }
2206 }
2207 rc = -ENXIO;
2208 out:
2209 mutex_unlock(&ioc->sas_topology_mutex);
2210 return rc;
2211}
2212
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002213static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2214 struct request *req)
2215{
2216 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2217 MPT_FRAME_HDR *mf;
2218 SmpPassthroughRequest_t *smpreq;
2219 struct request *rsp = req->next_rq;
2220 int ret;
2221 int flagsLength;
2222 unsigned long timeleft;
2223 char *psge;
2224 dma_addr_t dma_addr_in = 0;
2225 dma_addr_t dma_addr_out = 0;
2226 u64 sas_address = 0;
2227
2228 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002229 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002230 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002231 return -EINVAL;
2232 }
2233
2234 /* do we need to support multiple segments? */
Kent Overstreet458b76e2013-09-24 16:26:05 -07002235 if (bio_multiple_segments(req->bio) ||
2236 bio_multiple_segments(rsp->bio)) {
2237 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n",
2238 ioc->name, __func__, blk_rq_bytes(req), blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002239 return -EINVAL;
2240 }
2241
2242 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2243 if (ret)
2244 goto out;
2245
2246 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2247 if (!mf) {
2248 ret = -ENOMEM;
2249 goto out_unlock;
2250 }
2251
2252 smpreq = (SmpPassthroughRequest_t *)mf;
2253 memset(smpreq, 0, sizeof(*smpreq));
2254
Tejun Heob0790412009-05-07 22:24:42 +09002255 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002256 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2257
2258 if (rphy)
2259 sas_address = rphy->identify.sas_address;
2260 else {
2261 struct mptsas_portinfo *port_info;
2262
2263 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302264 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002265 if (port_info && port_info->phy_info)
2266 sas_address =
2267 port_info->phy_info[0].phy->identify.sas_address;
2268 mutex_unlock(&ioc->sas_topology_mutex);
2269 }
2270
2271 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2272
2273 psge = (char *)
2274 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2275
2276 /* request */
2277 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2278 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302279 MPI_SGE_FLAGS_DIRECTION)
2280 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002281 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002282
2283 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002284 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
Alexey Khoroshilov13543792016-04-16 02:12:29 +03002285 if (pci_dma_mapping_error(ioc->pcidev, dma_addr_out))
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002286 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302287 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302288 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002289
2290 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302291 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2292 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2293 MPI_SGE_FLAGS_IOC_TO_HOST |
2294 MPI_SGE_FLAGS_END_OF_BUFFER;
2295
2296 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002297 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002298 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002299 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
Alexey Khoroshilov13543792016-04-16 02:12:29 +03002300 if (pci_dma_mapping_error(ioc->pcidev, dma_addr_in))
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002301 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302302 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002303
Kashyap, Desai2f187862009-05-29 16:52:37 +05302304 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002305 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2306
2307 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302308 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2309 ret = -ETIME;
2310 mpt_free_msg_frame(ioc, mf);
2311 mf = NULL;
2312 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2313 goto unmap;
2314 if (!timeleft)
2315 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002316 goto unmap;
2317 }
2318 mf = NULL;
2319
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302320 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002321 SmpPassthroughReply_t *smprep;
2322
2323 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
Christoph Hellwig82ed4db2017-01-27 09:46:29 +01002324 memcpy(scsi_req(req)->sense, smprep, sizeof(*smprep));
2325 scsi_req(req)->sense_len = sizeof(*smprep);
2326 scsi_req(req)->resid_len = 0;
2327 scsi_req(rsp)->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002328 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302329 printk(MYIOC_s_ERR_FMT
2330 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002331 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002332 ret = -ENXIO;
2333 }
2334unmap:
2335 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002336 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002337 PCI_DMA_BIDIRECTIONAL);
2338 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002339 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002340 PCI_DMA_BIDIRECTIONAL);
2341put_mf:
2342 if (mf)
2343 mpt_free_msg_frame(ioc, mf);
2344out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302345 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002346 mutex_unlock(&ioc->sas_mgmt.mutex);
2347out:
2348 return ret;
2349}
2350
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002351static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002352 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002353 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2354 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002355 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002356 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002357};
2358
2359static struct scsi_transport_template *mptsas_transport_template;
2360
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002361static int
2362mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2363{
2364 ConfigExtendedPageHeader_t hdr;
2365 CONFIGPARMS cfg;
2366 SasIOUnitPage0_t *buffer;
2367 dma_addr_t dma_handle;
2368 int error, i;
2369
2370 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2371 hdr.ExtPageLength = 0;
2372 hdr.PageNumber = 0;
2373 hdr.Reserved1 = 0;
2374 hdr.Reserved2 = 0;
2375 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2376 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2377
2378 cfg.cfghdr.ehdr = &hdr;
2379 cfg.physAddr = -1;
2380 cfg.pageAddr = 0;
2381 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2382 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302383 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002384
2385 error = mpt_config(ioc, &cfg);
2386 if (error)
2387 goto out;
2388 if (!hdr.ExtPageLength) {
2389 error = -ENXIO;
2390 goto out;
2391 }
2392
2393 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2394 &dma_handle);
2395 if (!buffer) {
2396 error = -ENOMEM;
2397 goto out;
2398 }
2399
2400 cfg.physAddr = dma_handle;
2401 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2402
2403 error = mpt_config(ioc, &cfg);
2404 if (error)
2405 goto out_free_consistent;
2406
2407 port_info->num_phys = buffer->NumPhys;
2408 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302409 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002410 if (!port_info->phy_info) {
2411 error = -ENOMEM;
2412 goto out_free_consistent;
2413 }
2414
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302415 ioc->nvdata_version_persistent =
2416 le16_to_cpu(buffer->NvdataVersionPersistent);
2417 ioc->nvdata_version_default =
2418 le16_to_cpu(buffer->NvdataVersionDefault);
2419
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002420 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302421 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002422 port_info->phy_info[i].phy_id = i;
2423 port_info->phy_info[i].port_id =
2424 buffer->PhyData[i].Port;
2425 port_info->phy_info[i].negotiated_link_rate =
2426 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002427 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002428 port_info->phy_info[i].handle =
2429 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002430 }
2431
2432 out_free_consistent:
2433 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2434 buffer, dma_handle);
2435 out:
2436 return error;
2437}
2438
2439static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302440mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2441{
2442 ConfigExtendedPageHeader_t hdr;
2443 CONFIGPARMS cfg;
2444 SasIOUnitPage1_t *buffer;
2445 dma_addr_t dma_handle;
2446 int error;
Kashyap, Desaiaca794d2010-06-17 14:39:25 +05302447 u8 device_missing_delay;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302448
2449 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2450 memset(&cfg, 0, sizeof(CONFIGPARMS));
2451
2452 cfg.cfghdr.ehdr = &hdr;
2453 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +05302454 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302455 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2456 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2457 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2458 cfg.cfghdr.ehdr->PageNumber = 1;
2459
2460 error = mpt_config(ioc, &cfg);
2461 if (error)
2462 goto out;
2463 if (!hdr.ExtPageLength) {
2464 error = -ENXIO;
2465 goto out;
2466 }
2467
2468 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2469 &dma_handle);
2470 if (!buffer) {
2471 error = -ENOMEM;
2472 goto out;
2473 }
2474
2475 cfg.physAddr = dma_handle;
2476 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2477
2478 error = mpt_config(ioc, &cfg);
2479 if (error)
2480 goto out_free_consistent;
2481
2482 ioc->io_missing_delay =
2483 le16_to_cpu(buffer->IODeviceMissingDelay);
Kashyap, Desaiaca794d2010-06-17 14:39:25 +05302484 device_missing_delay = buffer->ReportDeviceMissingDelay;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302485 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2486 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2487 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2488
2489 out_free_consistent:
2490 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2491 buffer, dma_handle);
2492 out:
2493 return error;
2494}
2495
2496static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002497mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2498 u32 form, u32 form_specific)
2499{
2500 ConfigExtendedPageHeader_t hdr;
2501 CONFIGPARMS cfg;
2502 SasPhyPage0_t *buffer;
2503 dma_addr_t dma_handle;
2504 int error;
2505
2506 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2507 hdr.ExtPageLength = 0;
2508 hdr.PageNumber = 0;
2509 hdr.Reserved1 = 0;
2510 hdr.Reserved2 = 0;
2511 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2512 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2513
2514 cfg.cfghdr.ehdr = &hdr;
2515 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302516 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002517
2518 /* Get Phy Pg 0 for each Phy. */
2519 cfg.physAddr = -1;
2520 cfg.pageAddr = form + form_specific;
2521 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2522
2523 error = mpt_config(ioc, &cfg);
2524 if (error)
2525 goto out;
2526
2527 if (!hdr.ExtPageLength) {
2528 error = -ENXIO;
2529 goto out;
2530 }
2531
2532 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2533 &dma_handle);
2534 if (!buffer) {
2535 error = -ENOMEM;
2536 goto out;
2537 }
2538
2539 cfg.physAddr = dma_handle;
2540 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2541
2542 error = mpt_config(ioc, &cfg);
2543 if (error)
2544 goto out_free_consistent;
2545
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302546 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002547
2548 phy_info->hw_link_rate = buffer->HwLinkRate;
2549 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2550 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2551 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2552
2553 out_free_consistent:
2554 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2555 buffer, dma_handle);
2556 out:
2557 return error;
2558}
2559
2560static int
2561mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2562 u32 form, u32 form_specific)
2563{
2564 ConfigExtendedPageHeader_t hdr;
2565 CONFIGPARMS cfg;
2566 SasDevicePage0_t *buffer;
2567 dma_addr_t dma_handle;
2568 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002569 int error=0;
2570
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002571 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2572 hdr.ExtPageLength = 0;
2573 hdr.PageNumber = 0;
2574 hdr.Reserved1 = 0;
2575 hdr.Reserved2 = 0;
2576 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2577 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2578
2579 cfg.cfghdr.ehdr = &hdr;
2580 cfg.pageAddr = form + form_specific;
2581 cfg.physAddr = -1;
2582 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2583 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302584 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002585
Moore, Ericdb9c9172006-03-14 09:14:18 -07002586 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002587 error = mpt_config(ioc, &cfg);
2588 if (error)
2589 goto out;
2590 if (!hdr.ExtPageLength) {
2591 error = -ENXIO;
2592 goto out;
2593 }
2594
2595 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2596 &dma_handle);
2597 if (!buffer) {
2598 error = -ENOMEM;
2599 goto out;
2600 }
2601
2602 cfg.physAddr = dma_handle;
2603 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2604
2605 error = mpt_config(ioc, &cfg);
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302606
2607 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2608 error = -ENODEV;
2609 goto out_free_consistent;
2610 }
2611
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002612 if (error)
2613 goto out_free_consistent;
2614
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302615 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002616
Kashyap, Desai2f187862009-05-29 16:52:37 +05302617 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002618 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002619 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002620 device_info->handle_enclosure =
2621 le16_to_cpu(buffer->EnclosureHandle);
2622 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002623 device_info->phy_id = buffer->PhyNum;
2624 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002625 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002626 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002627 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002628 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2629 device_info->sas_address = le64_to_cpu(sas_address);
2630 device_info->device_info =
2631 le32_to_cpu(buffer->DeviceInfo);
Kashyap, Desai51106ab2010-06-17 14:40:10 +05302632 device_info->flags = le16_to_cpu(buffer->Flags);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002633
2634 out_free_consistent:
2635 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2636 buffer, dma_handle);
2637 out:
2638 return error;
2639}
2640
2641static int
2642mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2643 u32 form, u32 form_specific)
2644{
2645 ConfigExtendedPageHeader_t hdr;
2646 CONFIGPARMS cfg;
2647 SasExpanderPage0_t *buffer;
2648 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002649 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302650 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002651
Kashyap, Desai2f187862009-05-29 16:52:37 +05302652 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002653 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2654 hdr.ExtPageLength = 0;
2655 hdr.PageNumber = 0;
2656 hdr.Reserved1 = 0;
2657 hdr.Reserved2 = 0;
2658 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2659 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2660
2661 cfg.cfghdr.ehdr = &hdr;
2662 cfg.physAddr = -1;
2663 cfg.pageAddr = form + form_specific;
2664 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2665 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302666 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002667
Moore, Ericdb9c9172006-03-14 09:14:18 -07002668 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002669 error = mpt_config(ioc, &cfg);
2670 if (error)
2671 goto out;
2672
2673 if (!hdr.ExtPageLength) {
2674 error = -ENXIO;
2675 goto out;
2676 }
2677
2678 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2679 &dma_handle);
2680 if (!buffer) {
2681 error = -ENOMEM;
2682 goto out;
2683 }
2684
2685 cfg.physAddr = dma_handle;
2686 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2687
2688 error = mpt_config(ioc, &cfg);
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302689 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002690 error = -ENODEV;
2691 goto out_free_consistent;
2692 }
2693
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302694 if (error)
2695 goto out_free_consistent;
2696
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002697 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302698 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002699 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302700 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002701 if (!port_info->phy_info) {
2702 error = -ENOMEM;
2703 goto out_free_consistent;
2704 }
2705
Kashyap, Desai2f187862009-05-29 16:52:37 +05302706 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002707 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002708 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002709 port_info->phy_info[i].handle =
2710 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302711 port_info->phy_info[i].identify.sas_address =
2712 le64_to_cpu(sas_address);
2713 port_info->phy_info[i].identify.handle_parent =
2714 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002715 }
Eric Moore547f9a22006-06-27 14:42:12 -06002716
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002717 out_free_consistent:
2718 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2719 buffer, dma_handle);
2720 out:
2721 return error;
2722}
2723
2724static int
2725mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2726 u32 form, u32 form_specific)
2727{
2728 ConfigExtendedPageHeader_t hdr;
2729 CONFIGPARMS cfg;
2730 SasExpanderPage1_t *buffer;
2731 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002732 int error=0;
2733
Kashyap, Desai2f187862009-05-29 16:52:37 +05302734 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002735 hdr.ExtPageLength = 0;
2736 hdr.PageNumber = 1;
2737 hdr.Reserved1 = 0;
2738 hdr.Reserved2 = 0;
2739 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2740 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2741
2742 cfg.cfghdr.ehdr = &hdr;
2743 cfg.physAddr = -1;
2744 cfg.pageAddr = form + form_specific;
2745 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2746 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302747 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002748
2749 error = mpt_config(ioc, &cfg);
2750 if (error)
2751 goto out;
2752
2753 if (!hdr.ExtPageLength) {
2754 error = -ENXIO;
2755 goto out;
2756 }
2757
2758 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2759 &dma_handle);
2760 if (!buffer) {
2761 error = -ENOMEM;
2762 goto out;
2763 }
2764
2765 cfg.physAddr = dma_handle;
2766 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2767
2768 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302769
2770 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2771 error = -ENODEV;
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302772 goto out_free_consistent;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302773 }
2774
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002775 if (error)
2776 goto out_free_consistent;
2777
2778
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302779 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002780
2781 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002782 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002783 phy_info->port_id = buffer->PhysicalPort;
2784 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2785 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2786 phy_info->hw_link_rate = buffer->HwLinkRate;
2787 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2788 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2789
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002790 out_free_consistent:
2791 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2792 buffer, dma_handle);
2793 out:
2794 return error;
2795}
2796
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302797struct rep_manu_request{
2798 u8 smp_frame_type;
2799 u8 function;
2800 u8 reserved;
2801 u8 request_length;
2802};
2803
2804struct rep_manu_reply{
2805 u8 smp_frame_type; /* 0x41 */
2806 u8 function; /* 0x01 */
2807 u8 function_result;
2808 u8 response_length;
2809 u16 expander_change_count;
2810 u8 reserved0[2];
2811 u8 sas_format:1;
2812 u8 reserved1:7;
2813 u8 reserved2[3];
2814 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2815 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2816 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2817 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2818 u16 component_id;
2819 u8 component_revision_id;
2820 u8 reserved3;
2821 u8 vendor_specific[8];
2822};
2823
2824/**
2825 * mptsas_exp_repmanufacture_info -
2826 * @ioc: per adapter object
2827 * @sas_address: expander sas address
2828 * @edev: the sas_expander_device object
2829 *
2830 * Fills in the sas_expander_device object when SMP port is created.
2831 *
2832 * Returns 0 for success, non-zero for failure.
2833 */
2834static int
2835mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2836 u64 sas_address, struct sas_expander_device *edev)
2837{
2838 MPT_FRAME_HDR *mf;
2839 SmpPassthroughRequest_t *smpreq;
2840 SmpPassthroughReply_t *smprep;
2841 struct rep_manu_reply *manufacture_reply;
2842 struct rep_manu_request *manufacture_request;
2843 int ret;
2844 int flagsLength;
2845 unsigned long timeleft;
2846 char *psge;
2847 unsigned long flags;
2848 void *data_out = NULL;
2849 dma_addr_t data_out_dma = 0;
2850 u32 sz;
2851
2852 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2853 if (ioc->ioc_reset_in_progress) {
2854 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2855 printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2856 __func__, ioc->name);
2857 return -EFAULT;
2858 }
2859 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2860
2861 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2862 if (ret)
2863 goto out;
2864
2865 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2866 if (!mf) {
2867 ret = -ENOMEM;
2868 goto out_unlock;
2869 }
2870
2871 smpreq = (SmpPassthroughRequest_t *)mf;
2872 memset(smpreq, 0, sizeof(*smpreq));
2873
2874 sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2875
2876 data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
2877 if (!data_out) {
2878 printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2879 __FILE__, __LINE__, __func__);
2880 ret = -ENOMEM;
2881 goto put_mf;
2882 }
2883
2884 manufacture_request = data_out;
2885 manufacture_request->smp_frame_type = 0x40;
2886 manufacture_request->function = 1;
2887 manufacture_request->reserved = 0;
2888 manufacture_request->request_length = 0;
2889
2890 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2891 smpreq->PhysicalPort = 0xFF;
2892 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2893 smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2894
2895 psge = (char *)
2896 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2897
2898 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2899 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2900 MPI_SGE_FLAGS_HOST_TO_IOC |
2901 MPI_SGE_FLAGS_END_OF_BUFFER;
2902 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2903 flagsLength |= sizeof(struct rep_manu_request);
2904
2905 ioc->add_sge(psge, flagsLength, data_out_dma);
2906 psge += ioc->SGE_size;
2907
2908 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2909 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2910 MPI_SGE_FLAGS_IOC_TO_HOST |
2911 MPI_SGE_FLAGS_END_OF_BUFFER;
2912 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2913 flagsLength |= sizeof(struct rep_manu_reply);
2914 ioc->add_sge(psge, flagsLength, data_out_dma +
2915 sizeof(struct rep_manu_request));
2916
2917 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2918 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2919
2920 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2921 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2922 ret = -ETIME;
2923 mpt_free_msg_frame(ioc, mf);
2924 mf = NULL;
2925 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2926 goto out_free;
2927 if (!timeleft)
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302928 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302929 goto out_free;
2930 }
2931
2932 mf = NULL;
2933
2934 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2935 u8 *tmp;
2936
2937 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2938 if (le16_to_cpu(smprep->ResponseDataLength) !=
2939 sizeof(struct rep_manu_reply))
2940 goto out_free;
2941
2942 manufacture_reply = data_out + sizeof(struct rep_manu_request);
2943 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2944 SAS_EXPANDER_VENDOR_ID_LEN);
2945 strncpy(edev->product_id, manufacture_reply->product_id,
2946 SAS_EXPANDER_PRODUCT_ID_LEN);
2947 strncpy(edev->product_rev, manufacture_reply->product_rev,
2948 SAS_EXPANDER_PRODUCT_REV_LEN);
2949 edev->level = manufacture_reply->sas_format;
2950 if (manufacture_reply->sas_format) {
2951 strncpy(edev->component_vendor_id,
2952 manufacture_reply->component_vendor_id,
2953 SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2954 tmp = (u8 *)&manufacture_reply->component_id;
2955 edev->component_id = tmp[0] << 8 | tmp[1];
2956 edev->component_revision_id =
2957 manufacture_reply->component_revision_id;
2958 }
2959 } else {
2960 printk(MYIOC_s_ERR_FMT
2961 "%s: smp passthru reply failed to be returned\n",
2962 ioc->name, __func__);
2963 ret = -ENXIO;
2964 }
2965out_free:
2966 if (data_out_dma)
2967 pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
2968put_mf:
2969 if (mf)
2970 mpt_free_msg_frame(ioc, mf);
2971out_unlock:
2972 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2973 mutex_unlock(&ioc->sas_mgmt.mutex);
2974out:
2975 return ret;
2976 }
2977
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002978static void
2979mptsas_parse_device_info(struct sas_identify *identify,
2980 struct mptsas_devinfo *device_info)
2981{
2982 u16 protocols;
2983
2984 identify->sas_address = device_info->sas_address;
2985 identify->phy_identifier = device_info->phy_id;
2986
2987 /*
2988 * Fill in Phy Initiator Port Protocol.
2989 * Bits 6:3, more than one bit can be set, fall through cases.
2990 */
2991 protocols = device_info->device_info & 0x78;
2992 identify->initiator_port_protocols = 0;
2993 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2994 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2995 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2996 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2997 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2998 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2999 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
3000 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
3001
3002 /*
3003 * Fill in Phy Target Port Protocol.
3004 * Bits 10:7, more than one bit can be set, fall through cases.
3005 */
3006 protocols = device_info->device_info & 0x780;
3007 identify->target_port_protocols = 0;
3008 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
3009 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
3010 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
3011 identify->target_port_protocols |= SAS_PROTOCOL_STP;
3012 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
3013 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
3014 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
3015 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
3016
3017 /*
3018 * Fill in Attached device type.
3019 */
3020 switch (device_info->device_info &
3021 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
3022 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
3023 identify->device_type = SAS_PHY_UNUSED;
3024 break;
3025 case MPI_SAS_DEVICE_INFO_END_DEVICE:
3026 identify->device_type = SAS_END_DEVICE;
3027 break;
3028 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
3029 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
3030 break;
3031 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
3032 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
3033 break;
3034 }
3035}
3036
3037static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003038 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003039{
Moore, Erice6b2d762006-03-14 09:14:24 -07003040 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003041 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06003042 struct sas_port *port;
3043 int error = 0;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303044 VirtTarget *vtarget;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003045
Eric Moore547f9a22006-06-27 14:42:12 -06003046 if (!dev) {
3047 error = -ENODEV;
3048 goto out;
3049 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003050
3051 if (!phy_info->phy) {
3052 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06003053 if (!phy) {
3054 error = -ENOMEM;
3055 goto out;
3056 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003057 } else
3058 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003059
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003060 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003061
3062 /*
3063 * Set Negotiated link rate.
3064 */
3065 switch (phy_info->negotiated_link_rate) {
3066 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003067 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003068 break;
3069 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003070 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003071 break;
3072 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003073 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003074 break;
3075 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003076 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003077 break;
Kashyap, Desaid75733d2011-02-10 11:50:39 +05303078 case MPI_SAS_IOUNIT0_RATE_6_0:
3079 phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
3080 break;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003081 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
3082 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
3083 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003084 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003085 break;
3086 }
3087
3088 /*
3089 * Set Max hardware link rate.
3090 */
3091 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3092 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003093 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003094 break;
3095 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003096 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003097 break;
3098 default:
3099 break;
3100 }
3101
3102 /*
3103 * Set Max programmed link rate.
3104 */
3105 switch (phy_info->programmed_link_rate &
3106 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3107 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003108 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003109 break;
3110 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003111 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003112 break;
3113 default:
3114 break;
3115 }
3116
3117 /*
3118 * Set Min hardware link rate.
3119 */
3120 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
3121 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003122 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003123 break;
3124 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003125 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003126 break;
3127 default:
3128 break;
3129 }
3130
3131 /*
3132 * Set Min programmed link rate.
3133 */
3134 switch (phy_info->programmed_link_rate &
3135 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
3136 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003137 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003138 break;
3139 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003140 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003141 break;
3142 default:
3143 break;
3144 }
3145
Moore, Erice6b2d762006-03-14 09:14:24 -07003146 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003147
Moore, Erice6b2d762006-03-14 09:14:24 -07003148 error = sas_phy_add(phy);
3149 if (error) {
3150 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06003151 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07003152 }
3153 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003154 }
3155
Eric Moore547f9a22006-06-27 14:42:12 -06003156 if (!phy_info->attached.handle ||
3157 !phy_info->port_details)
3158 goto out;
3159
3160 port = mptsas_get_port(phy_info);
3161 ioc = phy_to_ioc(phy_info->phy);
3162
3163 if (phy_info->sas_port_add_phy) {
3164
3165 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06003166 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06003167 if (!port) {
3168 error = -ENOMEM;
3169 goto out;
3170 }
3171 error = sas_port_add(port);
3172 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303173 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003174 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003175 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003176 goto out;
3177 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303178 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303179 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
3180 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
3181 ioc->name, port->port_identifier,
3182 (unsigned long long)phy_info->
3183 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06003184 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05303185 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3186 "sas_port_add_phy: phy_id=%d\n",
3187 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06003188 sas_port_add_phy(port, phy_info->phy);
3189 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303190 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3191 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
3192 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06003193 }
Eric Moore547f9a22006-06-27 14:42:12 -06003194 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003195
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003196 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05003197 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06003198 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003199
James Bottomley2686de22006-06-30 12:54:02 -05003200 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07003201 /*
3202 * Let the hotplug_work thread handle processing
3203 * the adding/removing of devices that occur
3204 * after start of day.
3205 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303206 if (mptsas_is_end_device(&phy_info->attached) &&
3207 phy_info->attached.handle_parent) {
3208 goto out;
3209 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003210
James Bottomleyf013db32006-03-18 14:54:36 -06003211 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05003212 if (scsi_is_host_device(parent)) {
3213 struct mptsas_portinfo *port_info;
3214 int i;
3215
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303216 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05003217
3218 for (i = 0; i < port_info->num_phys; i++)
3219 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003220 identify.sas_address) {
3221 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003222 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003223 }
James Bottomley2686de22006-06-30 12:54:02 -05003224
3225 } else if (scsi_is_sas_rphy(parent)) {
3226 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
3227 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003228 parent_rphy->identify.sas_address) {
3229 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003230 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003231 }
James Bottomley2686de22006-06-30 12:54:02 -05003232 }
3233
James Bottomleyf013db32006-03-18 14:54:36 -06003234 switch (identify.device_type) {
3235 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003236 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06003237 break;
3238 case SAS_EDGE_EXPANDER_DEVICE:
3239 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003240 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06003241 break;
3242 default:
3243 rphy = NULL;
3244 break;
3245 }
Eric Moore547f9a22006-06-27 14:42:12 -06003246 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303247 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003248 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003249 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003250 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003251 }
3252
Eric Moore547f9a22006-06-27 14:42:12 -06003253 rphy->identify = identify;
3254 error = sas_rphy_add(rphy);
3255 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303256 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003257 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003258 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003259 sas_rphy_free(rphy);
3260 goto out;
3261 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303262 mptsas_set_rphy(ioc, phy_info, rphy);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05303263 if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3264 identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3265 mptsas_exp_repmanufacture_info(ioc,
3266 identify.sas_address,
3267 rphy_to_expander_device(rphy));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003268 }
3269
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303270 /* If the device exists,verify it wasn't previously flagged
3271 as a missing device. If so, clear it */
3272 vtarget = mptsas_find_vtarget(ioc,
3273 phy_info->attached.channel,
3274 phy_info->attached.id);
3275 if (vtarget && vtarget->inDMD) {
3276 printk(KERN_INFO "Device returned, unsetting inDMD\n");
3277 vtarget->inDMD = 0;
3278 }
3279
Eric Moore547f9a22006-06-27 14:42:12 -06003280 out:
3281 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003282}
3283
3284static int
Moore, Erice6b2d762006-03-14 09:14:24 -07003285mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003286{
Moore, Erice6b2d762006-03-14 09:14:24 -07003287 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003288 int error = -ENOMEM, i;
3289
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303290 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07003291 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003292 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003293
Moore, Erice6b2d762006-03-14 09:14:24 -07003294 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003295 if (error)
3296 goto out_free_port_info;
3297
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303298 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003299 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303300 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07003301 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303302 ioc->hba_port_info = port_info = hba;
3303 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07003304 list_add_tail(&port_info->list, &ioc->sas_topology);
3305 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07003306 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003307 port_info->phy_info[i].negotiated_link_rate =
3308 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003309 port_info->phy_info[i].handle =
3310 hba->phy_info[i].handle;
3311 port_info->phy_info[i].port_id =
3312 hba->phy_info[i].port_id;
3313 }
Eric Moore547f9a22006-06-27 14:42:12 -06003314 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003315 kfree(hba);
3316 hba = NULL;
3317 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003318 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303319#if defined(CPQ_CIM)
3320 ioc->num_ports = port_info->num_phys;
3321#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003322 for (i = 0; i < port_info->num_phys; i++) {
3323 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3324 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3325 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303326 port_info->phy_info[i].identify.handle =
3327 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003328 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003329 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3330 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303331 port_info->phy_info[i].identify.handle);
3332 if (!ioc->hba_port_sas_addr)
3333 ioc->hba_port_sas_addr =
3334 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003335 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003336 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003337 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003338 mptsas_sas_device_pg0(ioc,
3339 &port_info->phy_info[i].attached,
3340 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3341 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3342 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003343 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003344
Eric Moore547f9a22006-06-27 14:42:12 -06003345 mptsas_setup_wide_ports(ioc, port_info);
3346
3347 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003348 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003349 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003350
3351 return 0;
3352
3353 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003354 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003355 out:
3356 return error;
3357}
3358
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303359static void
3360mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003361{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303362 struct mptsas_portinfo *parent;
3363 struct device *parent_dev;
3364 struct sas_rphy *rphy;
3365 int i;
3366 u64 sas_address; /* expander sas address */
3367 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003368
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303369 handle = port_info->phy_info[0].handle;
3370 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003371 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003372 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303373 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3374 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003375
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303376 mptsas_sas_device_pg0(ioc,
3377 &port_info->phy_info[i].identify,
3378 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3379 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3380 port_info->phy_info[i].identify.handle);
3381 port_info->phy_info[i].identify.phy_id =
3382 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003383
3384 if (port_info->phy_info[i].attached.handle) {
3385 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303386 &port_info->phy_info[i].attached,
3387 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3388 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3389 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003390 port_info->phy_info[i].attached.phy_id =
3391 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003392 }
Eric Moore547f9a22006-06-27 14:42:12 -06003393 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003394
Moore, Erice6b2d762006-03-14 09:14:24 -07003395 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303396 parent = mptsas_find_portinfo_by_handle(ioc,
3397 port_info->phy_info[0].identify.handle_parent);
3398 if (!parent) {
3399 mutex_unlock(&ioc->sas_topology_mutex);
3400 return;
3401 }
3402 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3403 i++) {
3404 if (parent->phy_info[i].attached.sas_address == sas_address) {
3405 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3406 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003407 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003408 }
3409 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303410
3411 mptsas_setup_wide_ports(ioc, port_info);
3412 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3413 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3414 ioc->sas_index, 0);
3415}
3416
3417static void
3418mptsas_expander_event_add(MPT_ADAPTER *ioc,
3419 MpiEventDataSasExpanderStatusChange_t *expander_data)
3420{
3421 struct mptsas_portinfo *port_info;
3422 int i;
3423 __le64 sas_address;
3424
3425 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3426 if (!port_info)
3427 BUG();
3428 port_info->num_phys = (expander_data->NumPhys) ?
3429 expander_data->NumPhys : 1;
3430 port_info->phy_info = kcalloc(port_info->num_phys,
3431 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3432 if (!port_info->phy_info)
3433 BUG();
3434 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3435 for (i = 0; i < port_info->num_phys; i++) {
3436 port_info->phy_info[i].portinfo = port_info;
3437 port_info->phy_info[i].handle =
3438 le16_to_cpu(expander_data->DevHandle);
3439 port_info->phy_info[i].identify.sas_address =
3440 le64_to_cpu(sas_address);
3441 port_info->phy_info[i].identify.handle_parent =
3442 le16_to_cpu(expander_data->ParentDevHandle);
3443 }
3444
3445 mutex_lock(&ioc->sas_topology_mutex);
3446 list_add_tail(&port_info->list, &ioc->sas_topology);
3447 mutex_unlock(&ioc->sas_topology_mutex);
3448
3449 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3450 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3451 (unsigned long long)sas_address);
3452
3453 mptsas_expander_refresh(ioc, port_info);
3454}
3455
3456/**
3457 * mptsas_delete_expander_siblings - remove siblings attached to expander
3458 * @ioc: Pointer to MPT_ADAPTER structure
3459 * @parent: the parent port_info object
3460 * @expander: the expander port_info object
3461 **/
3462static void
3463mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3464 *parent, struct mptsas_portinfo *expander)
3465{
3466 struct mptsas_phyinfo *phy_info;
3467 struct mptsas_portinfo *port_info;
3468 struct sas_rphy *rphy;
3469 int i;
3470
3471 phy_info = expander->phy_info;
3472 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3473 rphy = mptsas_get_rphy(phy_info);
3474 if (!rphy)
3475 continue;
3476 if (rphy->identify.device_type == SAS_END_DEVICE)
3477 mptsas_del_end_device(ioc, phy_info);
3478 }
3479
3480 phy_info = expander->phy_info;
3481 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3482 rphy = mptsas_get_rphy(phy_info);
3483 if (!rphy)
3484 continue;
3485 if (rphy->identify.device_type ==
3486 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3487 rphy->identify.device_type ==
3488 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3489 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3490 rphy->identify.sas_address);
3491 if (!port_info)
3492 continue;
3493 if (port_info == parent) /* backlink rphy */
3494 continue;
3495 /*
3496 Delete this expander even if the expdevpage is exists
3497 because the parent expander is already deleted
3498 */
3499 mptsas_expander_delete(ioc, port_info, 1);
3500 }
3501 }
3502}
3503
3504
3505/**
3506 * mptsas_expander_delete - remove this expander
3507 * @ioc: Pointer to MPT_ADAPTER structure
3508 * @port_info: expander port_info struct
3509 * @force: Flag to forcefully delete the expander
3510 *
3511 **/
3512
3513static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3514 struct mptsas_portinfo *port_info, u8 force)
3515{
3516
3517 struct mptsas_portinfo *parent;
3518 int i;
3519 u64 expander_sas_address;
3520 struct mptsas_phyinfo *phy_info;
3521 struct mptsas_portinfo buffer;
3522 struct mptsas_portinfo_details *port_details;
3523 struct sas_port *port;
3524
3525 if (!port_info)
3526 return;
3527
3528 /* see if expander is still there before deleting */
3529 mptsas_sas_expander_pg0(ioc, &buffer,
3530 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3531 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3532 port_info->phy_info[0].identify.handle);
3533
3534 if (buffer.num_phys) {
3535 kfree(buffer.phy_info);
3536 if (!force)
3537 return;
3538 }
3539
3540
3541 /*
3542 * Obtain the port_info instance to the parent port
3543 */
3544 port_details = NULL;
3545 expander_sas_address =
3546 port_info->phy_info[0].identify.sas_address;
3547 parent = mptsas_find_portinfo_by_handle(ioc,
3548 port_info->phy_info[0].identify.handle_parent);
3549 mptsas_delete_expander_siblings(ioc, parent, port_info);
3550 if (!parent)
3551 goto out;
3552
3553 /*
3554 * Delete rphys in the parent that point
3555 * to this expander.
3556 */
3557 phy_info = parent->phy_info;
3558 port = NULL;
3559 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3560 if (!phy_info->phy)
3561 continue;
3562 if (phy_info->attached.sas_address !=
3563 expander_sas_address)
3564 continue;
3565 if (!port) {
3566 port = mptsas_get_port(phy_info);
3567 port_details = phy_info->port_details;
3568 }
3569 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3570 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3571 phy_info->phy_id, phy_info->phy);
3572 sas_port_delete_phy(port, phy_info->phy);
3573 }
3574 if (port) {
3575 dev_printk(KERN_DEBUG, &port->dev,
3576 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3577 ioc->name, port->port_identifier,
3578 (unsigned long long)expander_sas_address);
3579 sas_port_delete(port);
3580 mptsas_port_delete(ioc, port_details);
3581 }
3582 out:
3583
3584 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3585 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3586 (unsigned long long)expander_sas_address);
3587
3588 /*
3589 * free link
3590 */
3591 list_del(&port_info->list);
3592 kfree(port_info->phy_info);
3593 kfree(port_info);
3594}
3595
3596
3597/**
3598 * mptsas_send_expander_event - expanders events
3599 * @ioc: Pointer to MPT_ADAPTER structure
3600 * @expander_data: event data
3601 *
3602 *
3603 * This function handles adding, removing, and refreshing
3604 * device handles within the expander objects.
3605 */
3606static void
3607mptsas_send_expander_event(struct fw_event_work *fw_event)
3608{
3609 MPT_ADAPTER *ioc;
3610 MpiEventDataSasExpanderStatusChange_t *expander_data;
3611 struct mptsas_portinfo *port_info;
3612 __le64 sas_address;
3613 int i;
3614
3615 ioc = fw_event->ioc;
3616 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3617 fw_event->event_data;
3618 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
Kashyap, Desaif44fd182009-09-02 11:44:19 +05303619 sas_address = le64_to_cpu(sas_address);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303620 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3621
3622 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3623 if (port_info) {
3624 for (i = 0; i < port_info->num_phys; i++) {
3625 port_info->phy_info[i].portinfo = port_info;
3626 port_info->phy_info[i].handle =
3627 le16_to_cpu(expander_data->DevHandle);
3628 port_info->phy_info[i].identify.sas_address =
3629 le64_to_cpu(sas_address);
3630 port_info->phy_info[i].identify.handle_parent =
3631 le16_to_cpu(expander_data->ParentDevHandle);
3632 }
3633 mptsas_expander_refresh(ioc, port_info);
3634 } else if (!port_info && expander_data->NumPhys)
3635 mptsas_expander_event_add(ioc, expander_data);
3636 } else if (expander_data->ReasonCode ==
3637 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3638 mptsas_expander_delete(ioc, port_info, 0);
3639
3640 mptsas_free_fw_event(ioc, fw_event);
3641}
3642
3643
3644/**
3645 * mptsas_expander_add -
3646 * @ioc: Pointer to MPT_ADAPTER structure
3647 * @handle:
3648 *
3649 */
Joe Lawrence5767d252014-06-25 17:05:49 -04003650static struct mptsas_portinfo *
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303651mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3652{
3653 struct mptsas_portinfo buffer, *port_info;
3654 int i;
3655
3656 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3657 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3658 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3659 return NULL;
3660
3661 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3662 if (!port_info) {
3663 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3664 "%s: exit at line=%d\n", ioc->name,
3665 __func__, __LINE__));
3666 return NULL;
3667 }
3668 port_info->num_phys = buffer.num_phys;
3669 port_info->phy_info = buffer.phy_info;
3670 for (i = 0; i < port_info->num_phys; i++)
3671 port_info->phy_info[i].portinfo = port_info;
3672 mutex_lock(&ioc->sas_topology_mutex);
3673 list_add_tail(&port_info->list, &ioc->sas_topology);
3674 mutex_unlock(&ioc->sas_topology_mutex);
3675 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3676 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3677 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3678 mptsas_expander_refresh(ioc, port_info);
3679 return port_info;
3680}
3681
3682static void
3683mptsas_send_link_status_event(struct fw_event_work *fw_event)
3684{
3685 MPT_ADAPTER *ioc;
3686 MpiEventDataSasPhyLinkStatus_t *link_data;
3687 struct mptsas_portinfo *port_info;
3688 struct mptsas_phyinfo *phy_info = NULL;
3689 __le64 sas_address;
3690 u8 phy_num;
3691 u8 link_rate;
3692
3693 ioc = fw_event->ioc;
3694 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3695
3696 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3697 sas_address = le64_to_cpu(sas_address);
3698 link_rate = link_data->LinkRates >> 4;
3699 phy_num = link_data->PhyNum;
3700
3701 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3702 if (port_info) {
3703 phy_info = &port_info->phy_info[phy_num];
3704 if (phy_info)
3705 phy_info->negotiated_link_rate = link_rate;
3706 }
3707
3708 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
Kashyap, Desaid75733d2011-02-10 11:50:39 +05303709 link_rate == MPI_SAS_IOUNIT0_RATE_3_0 ||
3710 link_rate == MPI_SAS_IOUNIT0_RATE_6_0) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303711
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303712 if (!port_info) {
3713 if (ioc->old_sas_discovery_protocal) {
3714 port_info = mptsas_expander_add(ioc,
3715 le16_to_cpu(link_data->DevHandle));
3716 if (port_info)
3717 goto out;
3718 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303719 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303720 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303721
3722 if (port_info == ioc->hba_port_info)
3723 mptsas_probe_hba_phys(ioc);
3724 else
3725 mptsas_expander_refresh(ioc, port_info);
3726 } else if (phy_info && phy_info->phy) {
3727 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3728 phy_info->phy->negotiated_linkrate =
3729 SAS_PHY_DISABLED;
3730 else if (link_rate ==
3731 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3732 phy_info->phy->negotiated_linkrate =
3733 SAS_LINK_RATE_FAILED;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303734 else {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303735 phy_info->phy->negotiated_linkrate =
3736 SAS_LINK_RATE_UNKNOWN;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303737 if (ioc->device_missing_delay &&
3738 mptsas_is_end_device(&phy_info->attached)) {
3739 struct scsi_device *sdev;
3740 VirtDevice *vdevice;
3741 u8 channel, id;
3742 id = phy_info->attached.id;
3743 channel = phy_info->attached.channel;
3744 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3745 "Link down for fw_id %d:fw_channel %d\n",
3746 ioc->name, phy_info->attached.id,
3747 phy_info->attached.channel));
3748
3749 shost_for_each_device(sdev, ioc->sh) {
3750 vdevice = sdev->hostdata;
3751 if ((vdevice == NULL) ||
3752 (vdevice->vtarget == NULL))
3753 continue;
3754 if ((vdevice->vtarget->tflags &
3755 MPT_TARGET_FLAGS_RAID_COMPONENT ||
3756 vdevice->vtarget->raidVolume))
3757 continue;
3758 if (vdevice->vtarget->id == id &&
3759 vdevice->vtarget->channel ==
3760 channel)
3761 devtprintk(ioc,
3762 printk(MYIOC_s_DEBUG_FMT
3763 "SDEV OUTSTANDING CMDS"
3764 "%d\n", ioc->name,
Christoph Hellwig71e75c92014-04-11 19:07:01 +02003765 atomic_read(&sdev->device_busy)));
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303766 }
3767
3768 }
3769 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303770 }
3771 out:
3772 mptsas_free_fw_event(ioc, fw_event);
3773}
3774
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303775static void
3776mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3777{
3778 struct mptsas_portinfo buffer, *port_info;
3779 struct mptsas_device_info *sas_info;
3780 struct mptsas_devinfo sas_device;
3781 u32 handle;
3782 VirtTarget *vtarget = NULL;
3783 struct mptsas_phyinfo *phy_info;
3784 u8 found_expander;
3785 int retval, retry_count;
3786 unsigned long flags;
3787
3788 mpt_findImVolumes(ioc);
3789
3790 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3791 if (ioc->ioc_reset_in_progress) {
3792 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3793 "%s: exiting due to a parallel reset \n", ioc->name,
3794 __func__));
3795 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3796 return;
3797 }
3798 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3799
3800 /* devices, logical volumes */
3801 mutex_lock(&ioc->sas_device_info_mutex);
3802 redo_device_scan:
3803 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303804 if (sas_info->is_cached)
3805 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303806 if (!sas_info->is_logical_volume) {
3807 sas_device.handle = 0;
3808 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303809retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303810 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303811 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3812 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3813 (sas_info->fw.channel << 8) +
3814 sas_info->fw.id);
3815
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303816 if (sas_device.handle)
3817 continue;
3818 if (retval == -EBUSY) {
3819 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3820 if (ioc->ioc_reset_in_progress) {
3821 dfailprintk(ioc,
3822 printk(MYIOC_s_DEBUG_FMT
3823 "%s: exiting due to reset\n",
3824 ioc->name, __func__));
3825 spin_unlock_irqrestore
3826 (&ioc->taskmgmt_lock, flags);
3827 mutex_unlock(&ioc->
3828 sas_device_info_mutex);
3829 return;
3830 }
3831 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3832 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303833 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303834
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303835 if (retval && (retval != -ENODEV)) {
3836 if (retry_count < 10) {
3837 retry_count++;
3838 goto retry_page;
3839 } else {
3840 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3841 "%s: Config page retry exceeded retry "
3842 "count deleting device 0x%llx\n",
3843 ioc->name, __func__,
3844 sas_info->sas_address));
3845 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303846 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303847
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303848 /* delete device */
3849 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303850 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303851
3852 if (vtarget)
3853 vtarget->deleted = 1;
3854
3855 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3856 sas_info->sas_address);
3857
Joe Lawrence9f213162014-06-25 17:06:54 -04003858 mptsas_del_end_device(ioc, phy_info);
3859 goto redo_device_scan;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303860 } else
3861 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303862 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003863 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303864
3865 /* expanders */
3866 mutex_lock(&ioc->sas_topology_mutex);
3867 redo_expander_scan:
3868 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3869
Joe Lawrence9f213162014-06-25 17:06:54 -04003870 if (!(port_info->phy_info[0].identify.device_info &
3871 MPI_SAS_DEVICE_INFO_SMP_TARGET))
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303872 continue;
3873 found_expander = 0;
3874 handle = 0xFFFF;
3875 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3876 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3877 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3878 !found_expander) {
3879
3880 handle = buffer.phy_info[0].handle;
3881 if (buffer.phy_info[0].identify.sas_address ==
3882 port_info->phy_info[0].identify.sas_address) {
3883 found_expander = 1;
3884 }
3885 kfree(buffer.phy_info);
3886 }
3887
3888 if (!found_expander) {
3889 mptsas_expander_delete(ioc, port_info, 0);
3890 goto redo_expander_scan;
3891 }
3892 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003893 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303894}
3895
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303896/**
3897 * mptsas_probe_expanders - adding expanders
3898 * @ioc: Pointer to MPT_ADAPTER structure
3899 *
3900 **/
3901static void
3902mptsas_probe_expanders(MPT_ADAPTER *ioc)
3903{
3904 struct mptsas_portinfo buffer, *port_info;
3905 u32 handle;
3906 int i;
3907
3908 handle = 0xFFFF;
3909 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3910 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3911 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3912
3913 handle = buffer.phy_info[0].handle;
3914 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3915 buffer.phy_info[0].identify.sas_address);
3916
3917 if (port_info) {
3918 /* refreshing handles */
3919 for (i = 0; i < buffer.num_phys; i++) {
3920 port_info->phy_info[i].handle = handle;
3921 port_info->phy_info[i].identify.handle_parent =
3922 buffer.phy_info[0].identify.handle_parent;
3923 }
3924 mptsas_expander_refresh(ioc, port_info);
3925 kfree(buffer.phy_info);
3926 continue;
3927 }
3928
3929 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3930 if (!port_info) {
3931 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3932 "%s: exit at line=%d\n", ioc->name,
3933 __func__, __LINE__));
3934 return;
3935 }
3936 port_info->num_phys = buffer.num_phys;
3937 port_info->phy_info = buffer.phy_info;
3938 for (i = 0; i < port_info->num_phys; i++)
3939 port_info->phy_info[i].portinfo = port_info;
3940 mutex_lock(&ioc->sas_topology_mutex);
3941 list_add_tail(&port_info->list, &ioc->sas_topology);
3942 mutex_unlock(&ioc->sas_topology_mutex);
3943 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3944 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3945 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3946 mptsas_expander_refresh(ioc, port_info);
3947 }
3948}
3949
3950static void
3951mptsas_probe_devices(MPT_ADAPTER *ioc)
3952{
3953 u16 handle;
3954 struct mptsas_devinfo sas_device;
3955 struct mptsas_phyinfo *phy_info;
3956
3957 handle = 0xFFFF;
3958 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3959 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3960
3961 handle = sas_device.handle;
3962
3963 if ((sas_device.device_info &
3964 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3965 MPI_SAS_DEVICE_INFO_STP_TARGET |
3966 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3967 continue;
3968
Kashyap, Desai51106ab2010-06-17 14:40:10 +05303969 /* If there is no FW B_T mapping for this device then continue
3970 * */
3971 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
3972 || !(sas_device.flags &
3973 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
3974 continue;
3975
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303976 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3977 if (!phy_info)
3978 continue;
3979
3980 if (mptsas_get_rphy(phy_info))
3981 continue;
3982
3983 mptsas_add_end_device(ioc, phy_info);
3984 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003985}
3986
Kashyap, Desai2f187862009-05-29 16:52:37 +05303987/**
3988 * mptsas_scan_sas_topology -
3989 * @ioc: Pointer to MPT_ADAPTER structure
3990 * @sas_address:
3991 *
3992 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003993static void
3994mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3995{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303996 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003997 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003998
Moore, Erice6b2d762006-03-14 09:14:24 -07003999 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304000 mptsas_probe_expanders(ioc);
4001 mptsas_probe_devices(ioc);
4002
Moore, Ericf44e5462006-03-14 09:14:21 -07004003 /*
4004 Reporting RAID volumes.
4005 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304006 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
4007 !ioc->raid_data.pIocPg2->NumActiveVolumes)
4008 return;
Eric Moore793955f2007-01-29 09:42:20 -07004009 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304010 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4011 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
4012 if (sdev) {
4013 scsi_device_put(sdev);
4014 continue;
4015 }
4016 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4017 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4018 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04004019 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07004020 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
4021 }
Moore, Erice6b2d762006-03-14 09:14:24 -07004022}
4023
Kashyap, Desai57e98512009-05-29 16:55:09 +05304024
4025static void
4026mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
4027{
4028 MPT_ADAPTER *ioc;
4029 EventDataQueueFull_t *qfull_data;
4030 struct mptsas_device_info *sas_info;
4031 struct scsi_device *sdev;
4032 int depth;
4033 int id = -1;
4034 int channel = -1;
4035 int fw_id, fw_channel;
4036 u16 current_depth;
4037
4038
4039 ioc = fw_event->ioc;
4040 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
4041 fw_id = qfull_data->TargetID;
4042 fw_channel = qfull_data->Bus;
4043 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
4044
4045 /* if hidden raid component, look for the volume id */
4046 mutex_lock(&ioc->sas_device_info_mutex);
4047 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
4048 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
4049 list) {
4050 if (sas_info->is_cached ||
4051 sas_info->is_logical_volume)
4052 continue;
4053 if (sas_info->is_hidden_raid_component &&
4054 (sas_info->fw.channel == fw_channel &&
4055 sas_info->fw.id == fw_id)) {
4056 id = sas_info->volume_id;
4057 channel = MPTSAS_RAID_CHANNEL;
4058 goto out;
4059 }
4060 }
4061 } else {
4062 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
4063 list) {
4064 if (sas_info->is_cached ||
4065 sas_info->is_hidden_raid_component ||
4066 sas_info->is_logical_volume)
4067 continue;
4068 if (sas_info->fw.channel == fw_channel &&
4069 sas_info->fw.id == fw_id) {
4070 id = sas_info->os.id;
4071 channel = sas_info->os.channel;
4072 goto out;
4073 }
4074 }
4075
4076 }
4077
4078 out:
4079 mutex_unlock(&ioc->sas_device_info_mutex);
4080
4081 if (id != -1) {
4082 shost_for_each_device(sdev, ioc->sh) {
4083 if (sdev->id == id && sdev->channel == channel) {
4084 if (current_depth > sdev->queue_depth) {
4085 sdev_printk(KERN_INFO, sdev,
4086 "strange observation, the queue "
4087 "depth is (%d) meanwhile fw queue "
4088 "depth (%d)\n", sdev->queue_depth,
4089 current_depth);
4090 continue;
4091 }
4092 depth = scsi_track_queue_full(sdev,
Tomas Henzl2865c072015-06-03 17:37:02 +02004093 sdev->queue_depth - 1);
Kashyap, Desai57e98512009-05-29 16:55:09 +05304094 if (depth > 0)
4095 sdev_printk(KERN_INFO, sdev,
4096 "Queue depth reduced to (%d)\n",
4097 depth);
4098 else if (depth < 0)
4099 sdev_printk(KERN_INFO, sdev,
4100 "Tagged Command Queueing is being "
4101 "disabled\n");
4102 else if (depth == 0)
Tomas Henzl2865c072015-06-03 17:37:02 +02004103 sdev_printk(KERN_DEBUG, sdev,
Kashyap, Desai57e98512009-05-29 16:55:09 +05304104 "Queue depth not changed yet\n");
4105 }
4106 }
4107 }
4108
4109 mptsas_free_fw_event(ioc, fw_event);
4110}
4111
4112
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004113static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06004114mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004115{
4116 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004117 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06004118 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004119
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004120 mutex_lock(&ioc->sas_topology_mutex);
4121 list_for_each_entry(port_info, &ioc->sas_topology, list) {
4122 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06004123 if (!mptsas_is_end_device(
4124 &port_info->phy_info[i].attached))
4125 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004126 if (port_info->phy_info[i].attached.sas_address
4127 != sas_address)
4128 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06004129 phy_info = &port_info->phy_info[i];
4130 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004131 }
4132 }
4133 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004134 return phy_info;
4135}
4136
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304137/**
4138 * mptsas_find_phyinfo_by_phys_disk_num -
4139 * @ioc: Pointer to MPT_ADAPTER structure
4140 * @phys_disk_num:
4141 * @channel:
4142 * @id:
4143 *
4144 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07004145static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304146mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
4147 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07004148{
Eric Mooreb506ade2007-01-29 09:45:37 -07004149 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304150 struct mptsas_portinfo *port_info;
4151 RaidPhysDiskPage1_t *phys_disk = NULL;
4152 int num_paths;
4153 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07004154 int i;
4155
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304156 phy_info = NULL;
4157 if (!ioc->raid_data.pIocPg3)
4158 return NULL;
4159 /* dual port support */
4160 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4161 if (!num_paths)
4162 goto out;
4163 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4164 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4165 if (!phys_disk)
4166 goto out;
4167 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4168 for (i = 0; i < num_paths; i++) {
4169 if ((phys_disk->Path[i].Flags & 1) != 0)
4170 /* entry no longer valid */
4171 continue;
4172 if ((id == phys_disk->Path[i].PhysDiskID) &&
4173 (channel == phys_disk->Path[i].PhysDiskBus)) {
4174 memcpy(&sas_address, &phys_disk->Path[i].WWID,
4175 sizeof(u64));
4176 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4177 sas_address);
4178 goto out;
4179 }
4180 }
4181
4182 out:
4183 kfree(phys_disk);
4184 if (phy_info)
4185 return phy_info;
4186
4187 /*
4188 * Extra code to handle RAID0 case, where the sas_address is not updated
4189 * in phys_disk_page_1 when hotswapped
4190 */
Eric Mooreb506ade2007-01-29 09:45:37 -07004191 mutex_lock(&ioc->sas_topology_mutex);
4192 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304193 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004194 if (!mptsas_is_end_device(
4195 &port_info->phy_info[i].attached))
4196 continue;
4197 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4198 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304199 if ((port_info->phy_info[i].attached.phys_disk_num ==
4200 phys_disk_num) &&
4201 (port_info->phy_info[i].attached.id == id) &&
4202 (port_info->phy_info[i].attached.channel ==
4203 channel))
4204 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06004205 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004206 }
4207 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004208 return phy_info;
4209}
4210
4211static void
Moore, Ericf44e5462006-03-14 09:14:21 -07004212mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4213{
Eric Mooref99be432007-01-04 20:46:54 -07004214 int rc;
4215
Moore, Ericf44e5462006-03-14 09:14:21 -07004216 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07004217 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07004218}
4219
4220static void
4221mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4222{
4223 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4224 mptsas_reprobe_lun);
4225}
4226
Eric Mooreb506ade2007-01-29 09:45:37 -07004227static void
4228mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4229{
4230 CONFIGPARMS cfg;
4231 ConfigPageHeader_t hdr;
4232 dma_addr_t dma_handle;
4233 pRaidVolumePage0_t buffer = NULL;
4234 RaidPhysDiskPage0_t phys_disk;
4235 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304236 struct mptsas_phyinfo *phy_info;
4237 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07004238
4239 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4240 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4241 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4242 cfg.pageAddr = (channel << 8) + id;
4243 cfg.cfghdr.hdr = &hdr;
4244 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai568da762010-03-18 19:23:50 +05304245 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Eric Mooreb506ade2007-01-29 09:45:37 -07004246
4247 if (mpt_config(ioc, &cfg) != 0)
4248 goto out;
4249
4250 if (!hdr.PageLength)
4251 goto out;
4252
4253 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4254 &dma_handle);
4255
4256 if (!buffer)
4257 goto out;
4258
4259 cfg.physAddr = dma_handle;
4260 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4261
4262 if (mpt_config(ioc, &cfg) != 0)
4263 goto out;
4264
4265 if (!(buffer->VolumeStatus.Flags &
4266 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4267 goto out;
4268
4269 if (!buffer->NumPhysDisks)
4270 goto out;
4271
4272 for (i = 0; i < buffer->NumPhysDisks; i++) {
4273
4274 if (mpt_raid_phys_disk_pg0(ioc,
4275 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4276 continue;
4277
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304278 if (mptsas_sas_device_pg0(ioc, &sas_device,
4279 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4280 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4281 (phys_disk.PhysDiskBus << 8) +
4282 phys_disk.PhysDiskID))
4283 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004284
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304285 /* If there is no FW B_T mapping for this device then continue
4286 * */
4287 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4288 || !(sas_device.flags &
4289 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4290 continue;
4291
4292
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304293 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4294 sas_device.sas_address);
4295 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07004296 }
4297
4298 out:
4299 if (buffer)
4300 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4301 dma_handle);
4302}
Moore, Erice6b2d762006-03-14 09:14:24 -07004303/*
4304 * Work queue thread to handle SAS hotplug events
4305 */
Moore, Ericf44e5462006-03-14 09:14:21 -07004306static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304307mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
4308 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004309{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004310 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004311 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004312 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07004313 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304314 int i;
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304315 struct mptsas_portinfo *port_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004316
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304317 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004318
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304319 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07004320
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304321 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07004322 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07004323
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304324 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4325 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4326 hot_plug_info->id) {
4327 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4328 "to add hidden disk - target_id matchs "
4329 "volume_id\n", ioc->name);
4330 mptsas_free_fw_event(ioc, fw_event);
4331 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07004332 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004333 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304334 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004335
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004336 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304337 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4338 mptsas_sas_device_pg0(ioc, &sas_device,
4339 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4340 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4341 (hot_plug_info->channel << 8) +
4342 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004343
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304344 /* If there is no FW B_T mapping for this device then break
4345 * */
4346 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4347 || !(sas_device.flags &
4348 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4349 break;
4350
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304351 if (!sas_device.handle)
4352 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06004353
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304354 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304355 /* Only For SATA Device ADD */
4356 if (!phy_info && (sas_device.device_info &
4357 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) {
4358 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4359 "%s %d SATA HOT PLUG: "
4360 "parent handle of device %x\n", ioc->name,
4361 __func__, __LINE__, sas_device.handle_parent));
4362 port_info = mptsas_find_portinfo_by_handle(ioc,
4363 sas_device.handle_parent);
4364
4365 if (port_info == ioc->hba_port_info)
4366 mptsas_probe_hba_phys(ioc);
4367 else if (port_info)
4368 mptsas_expander_refresh(ioc, port_info);
4369 else {
4370 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4371 "%s %d port info is NULL\n",
4372 ioc->name, __func__, __LINE__));
4373 break;
4374 }
4375 phy_info = mptsas_refreshing_device_handles
4376 (ioc, &sas_device);
4377 }
4378
4379 if (!phy_info) {
4380 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4381 "%s %d phy info is NULL\n",
4382 ioc->name, __func__, __LINE__));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304383 break;
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304384 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304385
4386 if (mptsas_get_rphy(phy_info))
4387 break;
4388
4389 mptsas_add_end_device(ioc, phy_info);
4390 break;
4391
4392 case MPTSAS_DEL_DEVICE:
4393 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4394 hot_plug_info->sas_address);
4395 mptsas_del_end_device(ioc, phy_info);
4396 break;
4397
4398 case MPTSAS_DEL_PHYSDISK:
4399
4400 mpt_findImVolumes(ioc);
4401
4402 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304403 ioc, hot_plug_info->phys_disk_num,
4404 hot_plug_info->channel,
4405 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304406 mptsas_del_end_device(ioc, phy_info);
4407 break;
4408
4409 case MPTSAS_ADD_PHYSDISK_REPROBE:
4410
Christoph Hellwige3094442006-02-16 13:25:36 +01004411 if (mptsas_sas_device_pg0(ioc, &sas_device,
4412 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004413 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304414 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4415 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4416 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4417 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004418 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004419 }
4420
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304421 /* If there is no FW B_T mapping for this device then break
4422 * */
4423 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4424 || !(sas_device.flags &
4425 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4426 break;
4427
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304428 phy_info = mptsas_find_phyinfo_by_sas_address(
4429 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004430
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304431 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304432 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304433 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4434 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004435 break;
4436 }
4437
4438 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304439 if (!starget) {
4440 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4441 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4442 __func__, hot_plug_info->id, __LINE__));
4443 break;
4444 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004445
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304446 vtarget = starget->hostdata;
4447 if (!vtarget) {
4448 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4449 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4450 __func__, hot_plug_info->id, __LINE__));
4451 break;
4452 }
Eric Moore547f9a22006-06-27 14:42:12 -06004453
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304454 mpt_findImVolumes(ioc);
4455
4456 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4457 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4458 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4459 hot_plug_info->phys_disk_num, (unsigned long long)
4460 sas_device.sas_address);
4461
4462 vtarget->id = hot_plug_info->phys_disk_num;
4463 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4464 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4465 mptsas_reprobe_target(starget, 1);
4466 break;
4467
4468 case MPTSAS_DEL_PHYSDISK_REPROBE:
4469
4470 if (mptsas_sas_device_pg0(ioc, &sas_device,
4471 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4472 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4473 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304474 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304475 "%s: fw_id=%d exit at line=%d\n",
4476 ioc->name, __func__,
4477 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004478 break;
4479 }
4480
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304481 /* If there is no FW B_T mapping for this device then break
4482 * */
4483 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4484 || !(sas_device.flags &
4485 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4486 break;
4487
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304488 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4489 sas_device.sas_address);
4490 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304491 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304492 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4493 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004494 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004495 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004496
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304497 starget = mptsas_get_starget(phy_info);
4498 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304499 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304500 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4501 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004502 break;
4503 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004504
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304505 vtarget = starget->hostdata;
4506 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304507 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304508 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4509 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004510 break;
4511 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304512
4513 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
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 mpt_findImVolumes(ioc);
4521
4522 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4523 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4524 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4525 hot_plug_info->phys_disk_num, (unsigned long long)
4526 sas_device.sas_address);
4527
4528 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4529 vtarget->id = hot_plug_info->id;
4530 phy_info->attached.phys_disk_num = ~0;
4531 mptsas_reprobe_target(starget, 0);
4532 mptsas_add_device_component_by_fw(ioc,
4533 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004534 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304535
Moore, Ericc73787ee2006-01-26 16:20:06 -07004536 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304537
Moore, Ericc73787ee2006-01-26 16:20:06 -07004538 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304539 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4540 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4541 hot_plug_info->id);
4542 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4543 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004544 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304545
Moore, Ericc73787ee2006-01-26 16:20:06 -07004546 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304547
Moore, Ericc73787ee2006-01-26 16:20:06 -07004548 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304549 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4550 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4551 hot_plug_info->id);
4552 scsi_remove_device(hot_plug_info->sdev);
4553 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004554 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304555
Eric Mooreb506ade2007-01-29 09:45:37 -07004556 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304557
4558 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004559 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304560 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004561 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304562
Moore, Ericbd23e942006-04-17 12:43:04 -06004563 default:
4564 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004565 }
4566
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304567 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004568}
4569
4570static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304571mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004572{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304573 MPT_ADAPTER *ioc;
4574 struct mptsas_hotplug_event hot_plug_info;
4575 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4576 u32 device_info;
4577 u64 sas_address;
4578
4579 ioc = fw_event->ioc;
4580 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4581 fw_event->event_data;
4582 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004583
4584 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304585 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4586 MPI_SAS_DEVICE_INFO_STP_TARGET |
4587 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4588 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004589 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304590 }
4591
4592 if (sas_event_data->ReasonCode ==
4593 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4594 mptbase_sas_persist_operation(ioc,
4595 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4596 mptsas_free_fw_event(ioc, fw_event);
4597 return;
4598 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004599
Moore, Eric4b766472006-03-14 09:14:12 -07004600 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004601 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004602 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304603 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4604 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4605 hot_plug_info.channel = sas_event_data->Bus;
4606 hot_plug_info.id = sas_event_data->TargetID;
4607 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004608 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304609 sizeof(u64));
4610 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4611 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004612 if (sas_event_data->ReasonCode &
4613 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304614 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004615 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304616 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4617 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004618 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304619
Moore, Eric4b766472006-03-14 09:14:12 -07004620 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304621 mptbase_sas_persist_operation(ioc,
4622 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4623 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004624 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304625
Moore, Eric4b766472006-03-14 09:14:12 -07004626 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304627 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004628 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304629 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004630 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304631 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004632 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004633 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004634}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304635
Moore, Ericc73787ee2006-01-26 16:20:06 -07004636static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304637mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004638{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304639 MPT_ADAPTER *ioc;
4640 EVENT_DATA_RAID *raid_event_data;
4641 struct mptsas_hotplug_event hot_plug_info;
4642 int status;
4643 int state;
4644 struct scsi_device *sdev = NULL;
4645 VirtDevice *vdevice = NULL;
4646 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004647
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304648 ioc = fw_event->ioc;
4649 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4650 status = le32_to_cpu(raid_event_data->SettingsStatus);
4651 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004652
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304653 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4654 hot_plug_info.id = raid_event_data->VolumeID;
4655 hot_plug_info.channel = raid_event_data->VolumeBus;
4656 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4657
4658 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4659 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4660 raid_event_data->ReasonCode ==
4661 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4662 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4663 hot_plug_info.id, 0);
4664 hot_plug_info.sdev = sdev;
4665 if (sdev)
4666 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004667 }
4668
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304669 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4670 "ReasonCode=%02x\n", ioc->name, __func__,
4671 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004672
4673 switch (raid_event_data->ReasonCode) {
4674 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304675 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004676 break;
4677 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304678 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004679 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004680 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4681 switch (state) {
4682 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004683 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304684 mpt_raid_phys_disk_pg0(ioc,
4685 raid_event_data->PhysDiskNum, &phys_disk);
4686 hot_plug_info.id = phys_disk.PhysDiskID;
4687 hot_plug_info.channel = phys_disk.PhysDiskBus;
4688 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004689 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304690 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004691 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004692 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4693 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4694 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304695 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004696 break;
4697 default:
4698 break;
4699 }
4700 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004701 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304702 if (!sdev)
4703 break;
4704 vdevice->vtarget->deleted = 1; /* block IO */
4705 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004706 break;
4707 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304708 if (sdev) {
4709 scsi_device_put(sdev);
4710 break;
4711 }
4712 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004713 break;
4714 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304715 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4716 if (!sdev)
4717 break;
4718 vdevice->vtarget->deleted = 1; /* block IO */
4719 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4720 break;
4721 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004722 switch (state) {
4723 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4724 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304725 if (!sdev)
4726 break;
4727 vdevice->vtarget->deleted = 1; /* block IO */
4728 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004729 break;
4730 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4731 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304732 if (sdev) {
4733 scsi_device_put(sdev);
4734 break;
4735 }
4736 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004737 break;
4738 default:
4739 break;
4740 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004741 break;
4742 default:
4743 break;
4744 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304745
4746 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4747 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4748 else
4749 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004750}
4751
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304752/**
4753 * mptsas_issue_tm - send mptsas internal tm request
4754 * @ioc: Pointer to MPT_ADAPTER structure
4755 * @type: Task Management type
4756 * @channel: channel number for task management
4757 * @id: Logical Target ID for reset (if appropriate)
4758 * @lun: Logical unit for reset (if appropriate)
4759 * @task_context: Context for the task to be aborted
4760 * @timeout: timeout for task management control
4761 *
4762 * return 0 on success and -1 on failure:
4763 *
4764 */
4765static int
4766mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4767 int task_context, ulong timeout, u8 *issue_reset)
4768{
4769 MPT_FRAME_HDR *mf;
4770 SCSITaskMgmt_t *pScsiTm;
4771 int retval;
4772 unsigned long timeleft;
4773
4774 *issue_reset = 0;
4775 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4776 if (mf == NULL) {
4777 retval = -1; /* return failure */
4778 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4779 "msg frames!!\n", ioc->name));
4780 goto out;
4781 }
4782
4783 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4784 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4785 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4786 type, timeout, channel, id, (unsigned long long)lun,
4787 task_context));
4788
4789 pScsiTm = (SCSITaskMgmt_t *) mf;
4790 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4791 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4792 pScsiTm->TaskType = type;
4793 pScsiTm->MsgFlags = 0;
4794 pScsiTm->TargetID = id;
4795 pScsiTm->Bus = channel;
4796 pScsiTm->ChainOffset = 0;
4797 pScsiTm->Reserved = 0;
4798 pScsiTm->Reserved1 = 0;
4799 pScsiTm->TaskMsgContext = task_context;
4800 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4801
4802 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4803 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4804 retval = 0;
4805 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4806
4807 /* Now wait for the command to complete */
4808 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4809 timeout*HZ);
4810 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4811 retval = -1; /* return failure */
4812 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4813 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4814 mpt_free_msg_frame(ioc, mf);
4815 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4816 goto out;
4817 *issue_reset = 1;
4818 goto out;
4819 }
4820
4821 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4822 retval = -1; /* return failure */
4823 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4824 "TaskMgmt request: failed with no reply\n", ioc->name));
4825 goto out;
4826 }
4827
4828 out:
4829 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4830 return retval;
4831}
4832
4833/**
4834 * mptsas_broadcast_primative_work - Handle broadcast primitives
4835 * @work: work queue payload containing info describing the event
4836 *
4837 * this will be handled in workqueue context.
4838 */
4839static void
4840mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4841{
4842 MPT_ADAPTER *ioc = fw_event->ioc;
4843 MPT_FRAME_HDR *mf;
4844 VirtDevice *vdevice;
4845 int ii;
4846 struct scsi_cmnd *sc;
4847 SCSITaskMgmtReply_t *pScsiTmReply;
4848 u8 issue_reset;
4849 int task_context;
4850 u8 channel, id;
4851 int lun;
4852 u32 termination_count;
4853 u32 query_count;
4854
4855 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4856 "%s - enter\n", ioc->name, __func__));
4857
4858 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4859 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4860 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4861 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4862 return;
4863 }
4864
4865 issue_reset = 0;
4866 termination_count = 0;
4867 query_count = 0;
4868 mpt_findImVolumes(ioc);
4869 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4870
4871 for (ii = 0; ii < ioc->req_depth; ii++) {
4872 if (ioc->fw_events_off)
4873 goto out;
4874 sc = mptscsih_get_scsi_lookup(ioc, ii);
4875 if (!sc)
4876 continue;
4877 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4878 if (!mf)
4879 continue;
4880 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4881 vdevice = sc->device->hostdata;
4882 if (!vdevice || !vdevice->vtarget)
4883 continue;
4884 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4885 continue; /* skip hidden raid components */
4886 if (vdevice->vtarget->raidVolume)
4887 continue; /* skip hidden raid components */
4888 channel = vdevice->vtarget->channel;
4889 id = vdevice->vtarget->id;
4890 lun = vdevice->lun;
4891 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4892 channel, id, (u64)lun, task_context, 30, &issue_reset))
4893 goto out;
4894 query_count++;
4895 termination_count +=
4896 le32_to_cpu(pScsiTmReply->TerminationCount);
4897 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4898 (pScsiTmReply->ResponseCode ==
4899 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4900 pScsiTmReply->ResponseCode ==
4901 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4902 continue;
4903 if (mptsas_issue_tm(ioc,
4904 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4905 channel, id, (u64)lun, 0, 30, &issue_reset))
4906 goto out;
4907 termination_count +=
4908 le32_to_cpu(pScsiTmReply->TerminationCount);
4909 }
4910
4911 out:
4912 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4913 "%s - exit, query_count = %d termination_count = %d\n",
4914 ioc->name, __func__, query_count, termination_count));
4915
4916 ioc->broadcast_aen_busy = 0;
4917 mpt_clear_taskmgmt_in_progress_flag(ioc);
4918 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4919
4920 if (issue_reset) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09004921 printk(MYIOC_s_WARN_FMT
4922 "Issuing Reset from %s!! doorbell=0x%08x\n",
4923 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05304924 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304925 }
4926 mptsas_free_fw_event(ioc, fw_event);
4927}
4928
Eric Mooreb506ade2007-01-29 09:45:37 -07004929/*
4930 * mptsas_send_ir2_event - handle exposing hidden disk when
4931 * an inactive raid volume is added
4932 *
4933 * @ioc: Pointer to MPT_ADAPTER structure
4934 * @ir2_data
4935 *
4936 */
4937static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304938mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004939{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304940 MPT_ADAPTER *ioc;
4941 struct mptsas_hotplug_event hot_plug_info;
4942 MPI_EVENT_DATA_IR2 *ir2_data;
4943 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304944 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004945
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304946 ioc = fw_event->ioc;
4947 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4948 reasonCode = ir2_data->ReasonCode;
4949
4950 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4951 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4952
4953 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4954 hot_plug_info.id = ir2_data->TargetID;
4955 hot_plug_info.channel = ir2_data->Bus;
4956 switch (reasonCode) {
4957 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4958 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4959 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304960 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4961 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4962 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4963 break;
4964 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4965 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4966 mpt_raid_phys_disk_pg0(ioc,
4967 ir2_data->PhysDiskNum, &phys_disk);
4968 hot_plug_info.id = phys_disk.PhysDiskID;
4969 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4970 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304971 default:
4972 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004973 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304974 }
4975 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4976}
Moore, Erice6b2d762006-03-14 09:14:24 -07004977
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004978static int
4979mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4980{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304981 u32 event = le32_to_cpu(reply->Event);
Joe Lawrence32696192014-06-25 17:06:42 -04004982 int event_data_sz;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304983 struct fw_event_work *fw_event;
4984 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004985
Kashyap, Desaiffb7fef2010-03-18 19:20:38 +05304986 if (ioc->bus_type != SAS)
4987 return 0;
4988
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304989 /* events turned off due to host reset or driver unloading */
4990 if (ioc->fw_events_off)
4991 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004992
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304993 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004994 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304995 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4996 {
4997 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4998 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4999 if (broadcast_event_data->Primitive !=
5000 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
5001 return 0;
5002 if (ioc->broadcast_aen_busy)
5003 return 0;
5004 ioc->broadcast_aen_busy = 1;
5005 break;
5006 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005007 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305008 {
5009 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
5010 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305011 u16 ioc_stat;
5012 ioc_stat = le16_to_cpu(reply->IOCStatus);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305013
5014 if (sas_event_data->ReasonCode ==
5015 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
5016 mptsas_target_reset_queue(ioc, sas_event_data);
5017 return 0;
5018 }
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305019 if (sas_event_data->ReasonCode ==
5020 MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
5021 ioc->device_missing_delay &&
5022 (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) {
5023 VirtTarget *vtarget = NULL;
5024 u8 id, channel;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305025
5026 id = sas_event_data->TargetID;
5027 channel = sas_event_data->Bus;
5028
5029 vtarget = mptsas_find_vtarget(ioc, channel, id);
5030 if (vtarget) {
5031 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5032 "LogInfo (0x%x) available for "
5033 "INTERNAL_DEVICE_RESET"
5034 "fw_id %d fw_channel %d\n", ioc->name,
Borislav Petkov72ef0e52011-05-02 16:49:38 +02005035 le32_to_cpu(reply->IOCLogInfo),
5036 id, channel));
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305037 if (vtarget->raidVolume) {
5038 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5039 "Skipping Raid Volume for inDMD\n",
5040 ioc->name));
5041 } else {
5042 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5043 "Setting device flag inDMD\n",
5044 ioc->name));
5045 vtarget->inDMD = 1;
5046 }
5047
5048 }
5049
5050 }
5051
Moore, Ericc73787ee2006-01-26 16:20:06 -07005052 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305053 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305054 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
5055 {
5056 MpiEventDataSasExpanderStatusChange_t *expander_data =
5057 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
5058
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305059 if (ioc->old_sas_discovery_protocal)
5060 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305061
5062 if (expander_data->ReasonCode ==
5063 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
5064 ioc->device_missing_delay)
5065 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07005066 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305067 }
5068 case MPI_EVENT_SAS_DISCOVERY:
5069 {
5070 u32 discovery_status;
5071 EventDataSasDiscovery_t *discovery_data =
5072 (EventDataSasDiscovery_t *)reply->Data;
5073
5074 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
5075 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305076 if (ioc->old_sas_discovery_protocal && !discovery_status)
5077 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305078 return 0;
5079 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305080 case MPI_EVENT_INTEGRATED_RAID:
5081 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07005082 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305083 case MPI_EVENT_SAS_PHY_LINK_STATUS:
5084 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07005085 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005086 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305087 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005088 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07005089
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305090 event_data_sz = ((reply->MsgLength * 4) -
5091 offsetof(EventNotificationReply_t, Data));
Joe Lawrence32696192014-06-25 17:06:42 -04005092 fw_event = kzalloc(sizeof(*fw_event) + event_data_sz, GFP_ATOMIC);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305093 if (!fw_event) {
5094 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
5095 __func__, __LINE__);
5096 return 0;
5097 }
5098 memcpy(fw_event->event_data, reply->Data, event_data_sz);
5099 fw_event->event = event;
5100 fw_event->ioc = ioc;
5101 mptsas_add_fw_event(ioc, fw_event, delay);
5102 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005103}
5104
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305105/* Delete a volume when no longer listed in ioc pg2
5106 */
5107static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
5108{
5109 struct scsi_device *sdev;
5110 int i;
5111
5112 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
5113 if (!sdev)
5114 return;
5115 if (!ioc->raid_data.pIocPg2)
5116 goto out;
5117 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
5118 goto out;
5119 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
5120 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
5121 goto release_sdev;
5122 out:
5123 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
5124 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
5125 scsi_remove_device(sdev);
5126 release_sdev:
5127 scsi_device_put(sdev);
5128}
5129
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005130static int
5131mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
5132{
5133 struct Scsi_Host *sh;
5134 MPT_SCSI_HOST *hd;
5135 MPT_ADAPTER *ioc;
5136 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01005137 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005138 int numSGE = 0;
5139 int scale;
5140 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005141 int error=0;
5142 int r;
5143
5144 r = mpt_attach(pdev,id);
5145 if (r)
5146 return r;
5147
5148 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305149 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005150 ioc->DoneCtx = mptsasDoneCtx;
5151 ioc->TaskCtx = mptsasTaskCtx;
5152 ioc->InternalCtx = mptsasInternalCtx;
Kashyap, Desaib68bf092010-06-17 14:40:56 +05305153 ioc->schedule_target_reset = &mptsas_schedule_target_reset;
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +05305154 ioc->schedule_dead_ioc_flush_running_cmds =
5155 &mptscsih_flush_running_cmds;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005156 /* Added sanity check on readiness of the MPT adapter.
5157 */
5158 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
5159 printk(MYIOC_s_WARN_FMT
5160 "Skipping because it's not operational!\n",
5161 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005162 error = -ENODEV;
5163 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005164 }
5165
5166 if (!ioc->active) {
5167 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
5168 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005169 error = -ENODEV;
5170 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005171 }
5172
5173 /* Sanity check - ensure at least 1 port is INITIATOR capable
5174 */
5175 ioc_cap = 0;
5176 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
5177 if (ioc->pfacts[ii].ProtocolFlags &
5178 MPI_PORTFACTS_PROTOCOL_INITIATOR)
5179 ioc_cap++;
5180 }
5181
5182 if (!ioc_cap) {
5183 printk(MYIOC_s_WARN_FMT
5184 "Skipping ioc=%p because SCSI Initiator mode "
5185 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005186 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005187 }
5188
5189 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
5190 if (!sh) {
5191 printk(MYIOC_s_WARN_FMT
5192 "Unable to register controller with SCSI subsystem\n",
5193 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005194 error = -1;
5195 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005196 }
5197
5198 spin_lock_irqsave(&ioc->FreeQlock, flags);
5199
5200 /* Attach the SCSI Host to the IOC structure
5201 */
5202 ioc->sh = sh;
5203
5204 sh->io_port = 0;
5205 sh->n_io_port = 0;
5206 sh->irq = 0;
5207
5208 /* set 16 byte cdb's */
5209 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05305210 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
5211 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07005212 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005213 sh->transportt = mptsas_transport_template;
5214
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005215 /* Required entry.
5216 */
5217 sh->unique_id = ioc->id;
5218
5219 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005220 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07005221 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01005222 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005223 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005224
5225 /* Verify that we won't exceed the maximum
5226 * number of chain buffers
5227 * We can optimize: ZZ = req_sz/sizeof(SGE)
5228 * For 32bit SGE's:
5229 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
5230 * + (req_sz - 64)/sizeof(SGE)
5231 * A slightly different algorithm is required for
5232 * 64bit SGEs.
5233 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305234 scale = ioc->req_sz/ioc->SGE_size;
5235 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005236 numSGE = (scale - 1) *
5237 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305238 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005239 } else {
5240 numSGE = 1 + (scale - 1) *
5241 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305242 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005243 }
5244
5245 if (numSGE < sh->sg_tablesize) {
5246 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305247 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005248 "Resetting sg_tablesize to %d from %d\n",
5249 ioc->name, numSGE, sh->sg_tablesize));
5250 sh->sg_tablesize = numSGE;
5251 }
5252
kashyap.desai@lsi.com3850b142011-08-04 16:41:55 +05305253 if (mpt_loadtime_max_sectors) {
5254 if (mpt_loadtime_max_sectors < 64 ||
5255 mpt_loadtime_max_sectors > 8192) {
5256 printk(MYIOC_s_INFO_FMT "Invalid value passed for"
5257 "mpt_loadtime_max_sectors %d."
5258 "Range from 64 to 8192\n", ioc->name,
5259 mpt_loadtime_max_sectors);
5260 }
5261 mpt_loadtime_max_sectors &= 0xFFFFFFFE;
5262 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5263 "Resetting max sector to %d from %d\n",
5264 ioc->name, mpt_loadtime_max_sectors, sh->max_sectors));
5265 sh->max_sectors = mpt_loadtime_max_sectors;
5266 }
5267
Eric Mooree7eae9f2007-09-29 10:15:59 -06005268 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005269 hd->ioc = ioc;
5270
5271 /* SCSI needs scsi_cmnd lookup table!
5272 * (with size equal to req_depth*PtrSz!)
5273 */
Eric Mooree8206382007-09-29 10:16:53 -06005274 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5275 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005276 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06005277 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005278 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005279 }
Eric Mooree8206382007-09-29 10:16:53 -06005280 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005281
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305282 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06005283 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005284
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005285 ioc->sas_data.ptClear = mpt_pt_clear;
5286
Eric Mooredf9e0622007-01-29 09:46:21 -07005287 hd->last_queue_full = 0;
5288 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305289 INIT_LIST_HEAD(&ioc->sas_device_info_list);
5290 mutex_init(&ioc->sas_device_info_mutex);
5291
Eric Mooredf9e0622007-01-29 09:46:21 -07005292 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5293
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005294 if (ioc->sas_data.ptClear==1) {
5295 mptbase_sas_persist_operation(
5296 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5297 }
5298
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005299 error = scsi_add_host(sh, &ioc->pcidev->dev);
5300 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06005301 dprintk(ioc, printk(MYIOC_s_ERR_FMT
5302 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005303 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005304 }
5305
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305306 /* older firmware doesn't support expander events */
5307 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5308 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005309 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305310 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005311 return 0;
5312
Eric Moore547f9a22006-06-27 14:42:12 -06005313 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005314
5315 mptscsih_remove(pdev);
5316 return error;
5317}
5318
Joe Lawrence5767d252014-06-25 17:05:49 -04005319static void
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305320mptsas_shutdown(struct pci_dev *pdev)
5321{
5322 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5323
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305324 mptsas_fw_event_off(ioc);
5325 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305326}
5327
Greg Kroah-Hartman47b1ea72012-12-21 15:04:26 -08005328static void mptsas_remove(struct pci_dev *pdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005329{
5330 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5331 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06005332 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005333
Kashyap, Desai48959f12010-03-18 19:18:30 +05305334 if (!ioc->sh) {
5335 printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
5336 mpt_detach(pdev);
5337 return;
5338 }
5339
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305340 mptsas_shutdown(pdev);
5341
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305342 mptsas_del_device_components(ioc);
5343
Eric Mooreb506ade2007-01-29 09:45:37 -07005344 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005345 sas_remove_host(ioc->sh);
5346
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005347 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005348 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5349 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06005350 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305351 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305352
Eric Moore547f9a22006-06-27 14:42:12 -06005353 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005354 kfree(p);
5355 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005356 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305357 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005358 mptscsih_remove(pdev);
5359}
5360
5361static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06005362 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005363 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005364 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005365 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005366 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005367 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005368 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005369 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005370 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005371 PCI_ANY_ID, PCI_ANY_ID },
Chandrakala Chavva85d37222011-11-18 14:13:42 -08005372 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068_820XELP,
5373 PCI_ANY_ID, PCI_ANY_ID },
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005374 {0} /* Terminating entry */
5375};
5376MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5377
5378
5379static struct pci_driver mptsas_driver = {
5380 .name = "mptsas",
5381 .id_table = mptsas_pci_table,
5382 .probe = mptsas_probe,
Greg Kroah-Hartman47b1ea72012-12-21 15:04:26 -08005383 .remove = mptsas_remove,
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305384 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005385#ifdef CONFIG_PM
5386 .suspend = mptscsih_suspend,
5387 .resume = mptscsih_resume,
5388#endif
5389};
5390
5391static int __init
5392mptsas_init(void)
5393{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305394 int error;
5395
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005396 show_mptmod_ver(my_NAME, my_VERSION);
5397
5398 mptsas_transport_template =
5399 sas_attach_transport(&mptsas_transport_functions);
5400 if (!mptsas_transport_template)
5401 return -ENODEV;
5402
Kashyap, Desai213aaca2010-07-26 18:57:36 +05305403 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER,
5404 "mptscsih_io_done");
5405 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER,
5406 "mptscsih_taskmgmt_complete");
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005407 mptsasInternalCtx =
Kashyap, Desai213aaca2010-07-26 18:57:36 +05305408 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER,
5409 "mptscsih_scandv_complete");
5410 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER,
5411 "mptsas_mgmt_done");
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305412 mptsasDeviceResetCtx =
Kashyap, Desai213aaca2010-07-26 18:57:36 +05305413 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER,
5414 "mptsas_taskmgmt_complete");
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005415
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305416 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5417 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005418
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305419 error = pci_register_driver(&mptsas_driver);
5420 if (error)
5421 sas_release_transport(mptsas_transport_template);
5422
5423 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005424}
5425
5426static void __exit
5427mptsas_exit(void)
5428{
5429 pci_unregister_driver(&mptsas_driver);
5430 sas_release_transport(mptsas_transport_template);
5431
5432 mpt_reset_deregister(mptsasDoneCtx);
5433 mpt_event_deregister(mptsasDoneCtx);
5434
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005435 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005436 mpt_deregister(mptsasInternalCtx);
5437 mpt_deregister(mptsasTaskCtx);
5438 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305439 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005440}
5441
5442module_init(mptsas_init);
5443module_exit(mptsas_exit);