blob: d21924ba4b1aff87b96cc3ee81c5eec628cb1582 [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);
293 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
294 ioc->name, __func__, fw_event));
295 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
296 delay);
297 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
298}
299
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530300/* requeue a sas firmware event */
301static void
302mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
303 unsigned long delay)
304{
305 unsigned long flags;
306 spin_lock_irqsave(&ioc->fw_event_lock, flags);
307 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
308 "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
309 fw_event->retries++;
310 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
311 msecs_to_jiffies(delay));
312 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
313}
314
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300315/* free memory associated to a sas firmware event */
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530316static void
317mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
318{
319 unsigned long flags;
320
321 spin_lock_irqsave(&ioc->fw_event_lock, flags);
322 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
323 ioc->name, __func__, fw_event));
324 list_del(&fw_event->list);
325 kfree(fw_event);
326 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
327}
328
329/* walk the firmware event queue, and either stop or wait for
330 * outstanding events to complete */
331static void
332mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
333{
334 struct fw_event_work *fw_event, *next;
335 struct mptsas_target_reset_event *target_reset_list, *n;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530336 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
337
338 /* flush the target_reset_list */
339 if (!list_empty(&hd->target_reset_list)) {
340 list_for_each_entry_safe(target_reset_list, n,
341 &hd->target_reset_list, list) {
342 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
343 "%s: removing target reset for id=%d\n",
344 ioc->name, __func__,
345 target_reset_list->sas_event_data.TargetID));
346 list_del(&target_reset_list->list);
347 kfree(target_reset_list);
348 }
349 }
350
351 if (list_empty(&ioc->fw_event_list) ||
352 !ioc->fw_event_q || in_interrupt())
353 return;
354
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530355 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
356 if (cancel_delayed_work(&fw_event->work))
357 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530358 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530359}
360
361
Christoph Hellwige3094442006-02-16 13:25:36 +0100362static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
363{
364 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
365 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
366}
367
368static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
369{
370 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
371 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
372}
373
Moore, Erice6b2d762006-03-14 09:14:24 -0700374/*
375 * mptsas_find_portinfo_by_handle
376 *
377 * This function should be called with the sas_topology_mutex already held
378 */
379static struct mptsas_portinfo *
380mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
381{
382 struct mptsas_portinfo *port_info, *rc=NULL;
383 int i;
384
385 list_for_each_entry(port_info, &ioc->sas_topology, list)
386 for (i = 0; i < port_info->num_phys; i++)
387 if (port_info->phy_info[i].identify.handle == handle) {
388 rc = port_info;
389 goto out;
390 }
391 out:
392 return rc;
393}
394
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530395/**
396 * mptsas_find_portinfo_by_sas_address -
397 * @ioc: Pointer to MPT_ADAPTER structure
398 * @handle:
399 *
400 * This function should be called with the sas_topology_mutex already held
401 *
402 **/
403static struct mptsas_portinfo *
404mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
405{
406 struct mptsas_portinfo *port_info, *rc = NULL;
407 int i;
408
409 if (sas_address >= ioc->hba_port_sas_addr &&
410 sas_address < (ioc->hba_port_sas_addr +
411 ioc->hba_port_num_phy))
412 return ioc->hba_port_info;
413
414 mutex_lock(&ioc->sas_topology_mutex);
415 list_for_each_entry(port_info, &ioc->sas_topology, list)
416 for (i = 0; i < port_info->num_phys; i++)
417 if (port_info->phy_info[i].identify.sas_address ==
418 sas_address) {
419 rc = port_info;
420 goto out;
421 }
422 out:
423 mutex_unlock(&ioc->sas_topology_mutex);
424 return rc;
425}
426
Moore, Ericbd23e942006-04-17 12:43:04 -0600427/*
428 * Returns true if there is a scsi end device
429 */
430static inline int
431mptsas_is_end_device(struct mptsas_devinfo * attached)
432{
Eric Moore547f9a22006-06-27 14:42:12 -0600433 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600434 (attached->device_info &
435 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
436 ((attached->device_info &
437 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
438 (attached->device_info &
439 MPI_SAS_DEVICE_INFO_STP_TARGET) |
440 (attached->device_info &
441 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
442 return 1;
443 else
444 return 0;
445}
446
Eric Moore547f9a22006-06-27 14:42:12 -0600447/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600448static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530449mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600450{
451 struct mptsas_portinfo *port_info;
452 struct mptsas_phyinfo *phy_info;
453 u8 i;
454
455 if (!port_details)
456 return;
457
458 port_info = port_details->port_info;
459 phy_info = port_info->phy_info;
460
Eric Moore29dd3602007-09-14 18:46:51 -0600461 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700462 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700463 port_details->num_phys, (unsigned long long)
464 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600465
466 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
467 if(phy_info->port_details != port_details)
468 continue;
469 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530470 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600471 phy_info->port_details = NULL;
472 }
473 kfree(port_details);
474}
475
476static inline struct sas_rphy *
477mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
478{
479 if (phy_info->port_details)
480 return phy_info->port_details->rphy;
481 else
482 return NULL;
483}
484
485static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530486mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600487{
488 if (phy_info->port_details) {
489 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600490 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
491 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600492 }
493
Eric Moore547f9a22006-06-27 14:42:12 -0600494 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600495 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
496 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600497 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
498 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600499 }
Eric Moore547f9a22006-06-27 14:42:12 -0600500}
501
502static inline struct sas_port *
503mptsas_get_port(struct mptsas_phyinfo *phy_info)
504{
505 if (phy_info->port_details)
506 return phy_info->port_details->port;
507 else
508 return NULL;
509}
510
511static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530512mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600513{
514 if (phy_info->port_details)
515 phy_info->port_details->port = port;
516
Eric Moore547f9a22006-06-27 14:42:12 -0600517 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600518 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
519 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600520 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
521 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600522 }
Eric Moore547f9a22006-06-27 14:42:12 -0600523}
524
525static inline struct scsi_target *
526mptsas_get_starget(struct mptsas_phyinfo *phy_info)
527{
528 if (phy_info->port_details)
529 return phy_info->port_details->starget;
530 else
531 return NULL;
532}
533
534static inline void
535mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
536starget)
537{
538 if (phy_info->port_details)
539 phy_info->port_details->starget = starget;
540}
541
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530542/**
543 * mptsas_add_device_component -
544 * @ioc: Pointer to MPT_ADAPTER structure
545 * @channel: fw mapped id's
546 * @id:
547 * @sas_address:
548 * @device_info:
549 *
550 **/
551static void
552mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
553 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
554{
555 struct mptsas_device_info *sas_info, *next;
556 struct scsi_device *sdev;
557 struct scsi_target *starget;
558 struct sas_rphy *rphy;
559
560 /*
561 * Delete all matching devices out of the list
562 */
563 mutex_lock(&ioc->sas_device_info_mutex);
564 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
565 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530566 if (!sas_info->is_logical_volume &&
567 (sas_info->sas_address == sas_address ||
568 (sas_info->fw.channel == channel &&
569 sas_info->fw.id == id))) {
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530570 list_del(&sas_info->list);
571 kfree(sas_info);
572 }
573 }
574
575 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
576 if (!sas_info)
577 goto out;
578
579 /*
580 * Set Firmware mapping
581 */
582 sas_info->fw.id = id;
583 sas_info->fw.channel = channel;
584
585 sas_info->sas_address = sas_address;
586 sas_info->device_info = device_info;
587 sas_info->slot = slot;
588 sas_info->enclosure_logical_id = enclosure_logical_id;
589 INIT_LIST_HEAD(&sas_info->list);
590 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
591
592 /*
593 * Set OS mapping
594 */
595 shost_for_each_device(sdev, ioc->sh) {
596 starget = scsi_target(sdev);
597 rphy = dev_to_rphy(starget->dev.parent);
598 if (rphy->identify.sas_address == sas_address) {
599 sas_info->os.id = starget->id;
600 sas_info->os.channel = starget->channel;
601 }
602 }
603
604 out:
605 mutex_unlock(&ioc->sas_device_info_mutex);
606 return;
607}
608
609/**
610 * mptsas_add_device_component_by_fw -
611 * @ioc: Pointer to MPT_ADAPTER structure
612 * @channel: fw mapped id's
613 * @id:
614 *
615 **/
616static void
617mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
618{
619 struct mptsas_devinfo sas_device;
620 struct mptsas_enclosure enclosure_info;
621 int rc;
622
623 rc = mptsas_sas_device_pg0(ioc, &sas_device,
624 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
625 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
626 (channel << 8) + id);
627 if (rc)
628 return;
629
630 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
631 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
632 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
633 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
634 sas_device.handle_enclosure);
635
636 mptsas_add_device_component(ioc, sas_device.channel,
637 sas_device.id, sas_device.sas_address, sas_device.device_info,
638 sas_device.slot, enclosure_info.enclosure_logical_id);
639}
640
641/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000642 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530643 * @ioc: Pointer to MPT_ADAPTER structure
644 * @channel: fw mapped id's
645 * @id:
646 *
647 **/
648static void
649mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
650 struct scsi_target *starget)
651{
652 CONFIGPARMS cfg;
653 ConfigPageHeader_t hdr;
654 dma_addr_t dma_handle;
655 pRaidVolumePage0_t buffer = NULL;
656 int i;
657 RaidPhysDiskPage0_t phys_disk;
658 struct mptsas_device_info *sas_info, *next;
659
660 memset(&cfg, 0 , sizeof(CONFIGPARMS));
661 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
662 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
663 /* assumption that all volumes on channel = 0 */
664 cfg.pageAddr = starget->id;
665 cfg.cfghdr.hdr = &hdr;
666 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +0530667 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530668
669 if (mpt_config(ioc, &cfg) != 0)
670 goto out;
671
672 if (!hdr.PageLength)
673 goto out;
674
675 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
676 &dma_handle);
677
678 if (!buffer)
679 goto out;
680
681 cfg.physAddr = dma_handle;
682 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
683
684 if (mpt_config(ioc, &cfg) != 0)
685 goto out;
686
687 if (!buffer->NumPhysDisks)
688 goto out;
689
690 /*
691 * Adding entry for hidden components
692 */
693 for (i = 0; i < buffer->NumPhysDisks; i++) {
694
695 if (mpt_raid_phys_disk_pg0(ioc,
696 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
697 continue;
698
699 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
700 phys_disk.PhysDiskID);
701
Kashyap, Desai57e98512009-05-29 16:55:09 +0530702 mutex_lock(&ioc->sas_device_info_mutex);
703 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
704 list) {
705 if (!sas_info->is_logical_volume &&
706 (sas_info->fw.channel == phys_disk.PhysDiskBus &&
707 sas_info->fw.id == phys_disk.PhysDiskID)) {
708 sas_info->is_hidden_raid_component = 1;
709 sas_info->volume_id = starget->id;
710 }
711 }
712 mutex_unlock(&ioc->sas_device_info_mutex);
713
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530714 }
715
716 /*
717 * Delete all matching devices out of the list
718 */
719 mutex_lock(&ioc->sas_device_info_mutex);
720 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
721 list) {
722 if (sas_info->is_logical_volume && sas_info->fw.id ==
723 starget->id) {
724 list_del(&sas_info->list);
725 kfree(sas_info);
726 }
727 }
728
729 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
730 if (sas_info) {
731 sas_info->fw.id = starget->id;
732 sas_info->os.id = starget->id;
733 sas_info->os.channel = starget->channel;
734 sas_info->is_logical_volume = 1;
735 INIT_LIST_HEAD(&sas_info->list);
736 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
737 }
738 mutex_unlock(&ioc->sas_device_info_mutex);
739
740 out:
741 if (buffer)
742 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
743 dma_handle);
744}
745
746/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530747 * mptsas_add_device_component_starget -
748 * @ioc: Pointer to MPT_ADAPTER structure
749 * @starget:
750 *
751 **/
752static void
753mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
754 struct scsi_target *starget)
755{
756 VirtTarget *vtarget;
757 struct sas_rphy *rphy;
758 struct mptsas_phyinfo *phy_info = NULL;
759 struct mptsas_enclosure enclosure_info;
760
761 rphy = dev_to_rphy(starget->dev.parent);
762 vtarget = starget->hostdata;
763 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
764 rphy->identify.sas_address);
765 if (!phy_info)
766 return;
767
768 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
769 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
770 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
771 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
772 phy_info->attached.handle_enclosure);
773
774 mptsas_add_device_component(ioc, phy_info->attached.channel,
775 phy_info->attached.id, phy_info->attached.sas_address,
776 phy_info->attached.device_info,
777 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
778}
779
780/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000781 * 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 +0530782 * @ioc: Pointer to MPT_ADAPTER structure
783 * @channel: os mapped id's
784 * @id:
785 *
786 **/
787static void
788mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
789{
790 struct mptsas_device_info *sas_info, *next;
791
792 /*
793 * Set is_cached flag
794 */
795 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
796 list) {
797 if (sas_info->os.channel == channel && sas_info->os.id == id)
798 sas_info->is_cached = 1;
799 }
800}
801
802/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530803 * mptsas_del_device_components - Cleaning the list
804 * @ioc: Pointer to MPT_ADAPTER structure
805 *
806 **/
807static void
808mptsas_del_device_components(MPT_ADAPTER *ioc)
809{
810 struct mptsas_device_info *sas_info, *next;
811
812 mutex_lock(&ioc->sas_device_info_mutex);
813 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
814 list) {
815 list_del(&sas_info->list);
816 kfree(sas_info);
817 }
818 mutex_unlock(&ioc->sas_device_info_mutex);
819}
820
Eric Moore547f9a22006-06-27 14:42:12 -0600821
822/*
823 * mptsas_setup_wide_ports
824 *
825 * Updates for new and existing narrow/wide port configuration
826 * in the sas_topology
827 */
Eric Moore376ac832006-06-29 17:36:26 -0600828static void
Eric Moore547f9a22006-06-27 14:42:12 -0600829mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
830{
831 struct mptsas_portinfo_details * port_details;
832 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
833 u64 sas_address;
834 int i, j;
835
836 mutex_lock(&ioc->sas_topology_mutex);
837
838 phy_info = port_info->phy_info;
839 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
840 if (phy_info->attached.handle)
841 continue;
842 port_details = phy_info->port_details;
843 if (!port_details)
844 continue;
845 if (port_details->num_phys < 2)
846 continue;
847 /*
848 * Removing a phy from a port, letting the last
849 * phy be removed by firmware events.
850 */
Eric Moore29dd3602007-09-14 18:46:51 -0600851 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
852 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700853 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600854 port_details->num_phys--;
855 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
856 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai9e390892009-09-02 11:43:36 +0530857 if (phy_info->phy) {
858 devtprintk(ioc, dev_printk(KERN_DEBUG,
859 &phy_info->phy->dev, MYIOC_s_FMT
860 "delete phy %d, phy-obj (0x%p)\n", ioc->name,
861 phy_info->phy_id, phy_info->phy));
862 sas_port_delete_phy(port_details->port, phy_info->phy);
863 }
Eric Moore547f9a22006-06-27 14:42:12 -0600864 phy_info->port_details = NULL;
865 }
866
867 /*
868 * Populate and refresh the tree
869 */
870 phy_info = port_info->phy_info;
871 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
872 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600873 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
874 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600875 if (!sas_address)
876 continue;
877 port_details = phy_info->port_details;
878 /*
879 * Forming a port
880 */
881 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530882 port_details = kzalloc(sizeof(struct
883 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600884 if (!port_details)
885 goto out;
886 port_details->num_phys = 1;
887 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600888 if (phy_info->phy_id < 64 )
889 port_details->phy_bitmask |=
890 (1 << phy_info->phy_id);
891 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600892 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700893 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600894 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600895 phy_info->port_details = port_details;
896 }
897
898 if (i == port_info->num_phys - 1)
899 continue;
900 phy_info_cmp = &port_info->phy_info[i + 1];
901 for (j = i + 1 ; j < port_info->num_phys ; j++,
902 phy_info_cmp++) {
903 if (!phy_info_cmp->attached.sas_address)
904 continue;
905 if (sas_address != phy_info_cmp->attached.sas_address)
906 continue;
907 if (phy_info_cmp->port_details == port_details )
908 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600909 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700910 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600911 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700912 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600913 if (phy_info_cmp->port_details) {
914 port_details->rphy =
915 mptsas_get_rphy(phy_info_cmp);
916 port_details->port =
917 mptsas_get_port(phy_info_cmp);
918 port_details->starget =
919 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600920 port_details->num_phys =
921 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600922 if (!phy_info_cmp->port_details->num_phys)
923 kfree(phy_info_cmp->port_details);
924 } else
925 phy_info_cmp->sas_port_add_phy=1;
926 /*
927 * Adding a phy to a port
928 */
929 phy_info_cmp->port_details = port_details;
930 if (phy_info_cmp->phy_id < 64 )
931 port_details->phy_bitmask |=
932 (1 << phy_info_cmp->phy_id);
933 port_details->num_phys++;
934 }
935 }
936
937 out:
938
Eric Moore547f9a22006-06-27 14:42:12 -0600939 for (i = 0; i < port_info->num_phys; i++) {
940 port_details = port_info->phy_info[i].port_details;
941 if (!port_details)
942 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600943 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700944 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700945 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700946 port_details, i, port_details->num_phys,
947 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600948 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
949 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600950 }
Eric Moore29dd3602007-09-14 18:46:51 -0600951 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600952 mutex_unlock(&ioc->sas_topology_mutex);
953}
954
Eric Mooredf9e0622007-01-29 09:46:21 -0700955/**
956 * csmisas_find_vtarget
957 *
958 * @ioc
959 * @volume_id
960 * @volume_bus
961 *
962 **/
963static VirtTarget *
964mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600965{
Eric Mooredf9e0622007-01-29 09:46:21 -0700966 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600967 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700968 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600969
Eric Mooredf9e0622007-01-29 09:46:21 -0700970 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530971 vdevice = sdev->hostdata;
972 if ((vdevice == NULL) ||
973 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700974 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530975 if ((vdevice->vtarget->tflags &
976 MPT_TARGET_FLAGS_RAID_COMPONENT ||
977 vdevice->vtarget->raidVolume))
978 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600979 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530980 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600981 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600982 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700983 return vtarget;
984}
985
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530986static void
987mptsas_queue_device_delete(MPT_ADAPTER *ioc,
988 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
989{
990 struct fw_event_work *fw_event;
991 int sz;
992
993 sz = offsetof(struct fw_event_work, event_data) +
994 sizeof(MpiEventDataSasDeviceStatusChange_t);
995 fw_event = kzalloc(sz, GFP_ATOMIC);
996 if (!fw_event) {
997 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
998 ioc->name, __func__, __LINE__);
999 return;
1000 }
1001 memcpy(fw_event->event_data, sas_event_data,
1002 sizeof(MpiEventDataSasDeviceStatusChange_t));
1003 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
1004 fw_event->ioc = ioc;
1005 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1006}
1007
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301008static void
1009mptsas_queue_rescan(MPT_ADAPTER *ioc)
1010{
1011 struct fw_event_work *fw_event;
1012 int sz;
1013
1014 sz = offsetof(struct fw_event_work, event_data);
1015 fw_event = kzalloc(sz, GFP_ATOMIC);
1016 if (!fw_event) {
1017 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1018 ioc->name, __func__, __LINE__);
1019 return;
1020 }
1021 fw_event->event = -1;
1022 fw_event->ioc = ioc;
1023 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1024}
1025
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301026
Eric Mooredf9e0622007-01-29 09:46:21 -07001027/**
1028 * mptsas_target_reset
1029 *
1030 * Issues TARGET_RESET to end device using handshaking method
1031 *
1032 * @ioc
1033 * @channel
1034 * @id
1035 *
1036 * Returns (1) success
1037 * (0) failure
1038 *
1039 **/
1040static int
1041mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1042{
1043 MPT_FRAME_HDR *mf;
1044 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301045 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1046 return 0;
1047
Eric Mooredf9e0622007-01-29 09:46:21 -07001048
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301049 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1050 if (mf == NULL) {
1051 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301052 "%s, no msg frames @%d!!\n", ioc->name,
1053 __func__, __LINE__));
1054 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001055 }
1056
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301057 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1058 ioc->name, mf));
1059
Eric Mooredf9e0622007-01-29 09:46:21 -07001060 /* Format the Request
1061 */
1062 pScsiTm = (SCSITaskMgmt_t *) mf;
1063 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1064 pScsiTm->TargetID = id;
1065 pScsiTm->Bus = channel;
1066 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1067 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1068 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1069
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301070 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001071
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301072 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1073 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1074 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1075
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301076 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001077
1078 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301079
1080 out_fail:
1081
1082 mpt_clear_taskmgmt_in_progress_flag(ioc);
1083 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001084}
1085
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301086static void
1087mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
1088{
1089 scsi_device_set_state(sdev, SDEV_BLOCK);
1090}
1091
1092static void
1093mptsas_block_io_starget(struct scsi_target *starget)
1094{
1095 if (starget)
1096 starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
1097}
1098
Eric Mooredf9e0622007-01-29 09:46:21 -07001099/**
1100 * mptsas_target_reset_queue
1101 *
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001102 * Receive request for TARGET_RESET after receiving an firmware
Eric Mooredf9e0622007-01-29 09:46:21 -07001103 * event NOT_RESPONDING_EVENT, then put command in link list
1104 * and queue if task_queue already in use.
1105 *
1106 * @ioc
1107 * @sas_event_data
1108 *
1109 **/
1110static void
1111mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1112 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1113{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001114 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001115 VirtTarget *vtarget = NULL;
1116 struct mptsas_target_reset_event *target_reset_list;
1117 u8 id, channel;
1118
1119 id = sas_event_data->TargetID;
1120 channel = sas_event_data->Bus;
1121
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301122 vtarget = mptsas_find_vtarget(ioc, channel, id);
1123 if (vtarget) {
1124 mptsas_block_io_starget(vtarget->starget);
1125 vtarget->deleted = 1; /* block IO */
1126 }
Eric Mooredf9e0622007-01-29 09:46:21 -07001127
Kashyap, Desai2f187862009-05-29 16:52:37 +05301128 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001129 GFP_ATOMIC);
1130 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301131 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1132 "%s, failed to allocate mem @%d..!!\n",
1133 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001134 return;
1135 }
1136
1137 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1138 sizeof(*sas_event_data));
1139 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1140
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301141 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001142
1143 if (mptsas_target_reset(ioc, channel, id)) {
1144 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001145 }
1146}
1147
1148/**
Kashyap, Desaib68bf092010-06-17 14:40:56 +05301149 * mptsas_schedule_target_reset- send pending target reset
1150 * @iocp: per adapter object
1151 *
1152 * This function will delete scheduled target reset from the list and
1153 * try to send next target reset. This will be called from completion
Uwe Kleine-Königb5950762010-11-01 15:38:34 -04001154 * context of any Task management command.
Kashyap, Desaib68bf092010-06-17 14:40:56 +05301155 */
1156
1157void
1158mptsas_schedule_target_reset(void *iocp)
1159{
1160 MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp);
1161 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1162 struct list_head *head = &hd->target_reset_list;
1163 struct mptsas_target_reset_event *target_reset_list;
1164 u8 id, channel;
1165 /*
1166 * issue target reset to next device in the queue
1167 */
1168
1169 head = &hd->target_reset_list;
1170 if (list_empty(head))
1171 return;
1172
1173 target_reset_list = list_entry(head->next,
1174 struct mptsas_target_reset_event, list);
1175
1176 id = target_reset_list->sas_event_data.TargetID;
1177 channel = target_reset_list->sas_event_data.Bus;
1178 target_reset_list->time_count = jiffies;
1179
1180 if (mptsas_target_reset(ioc, channel, id))
1181 target_reset_list->target_reset_issued = 1;
1182 return;
1183}
1184
1185
1186/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001187 * mptsas_taskmgmt_complete - complete SAS task management function
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301188 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001189 *
James Bottomleyfc847ab2009-06-09 23:01:01 +00001190 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1191 * queue to finish off removing device from upper layers. then send next
1192 * TARGET_RESET in the queue.
Eric Mooredf9e0622007-01-29 09:46:21 -07001193 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301194static int
1195mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001196{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001197 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001198 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001199 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301200 struct mptsas_target_reset_event *target_reset_list;
1201 SCSITaskMgmtReply_t *pScsiTmReply;
1202
1203 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1204 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1205
1206 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1207 if (pScsiTmReply) {
1208 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1209 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1210 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1211 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1212 "term_cmnds = %d\n", ioc->name,
1213 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1214 pScsiTmReply->TaskType,
1215 le16_to_cpu(pScsiTmReply->IOCStatus),
1216 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1217 pScsiTmReply->ResponseCode,
1218 le32_to_cpu(pScsiTmReply->TerminationCount)));
1219
1220 if (pScsiTmReply->ResponseCode)
1221 mptscsih_taskmgmt_response_code(ioc,
1222 pScsiTmReply->ResponseCode);
1223 }
1224
1225 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1226 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1227 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1228 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
1576struct mptsas_phyinfo *
1577mptsas_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
Jeff Garzikf2812332010-11-16 02:10:29 -05001897mptsas_qcmd_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f49a2006-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 Hellwig9a28f49a2006-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;
1905 done(SCpnt);
1906 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001907 }
Eric Moore547f9a22006-06-27 14:42:12 -06001908
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301909 hd = shost_priv(SCpnt->device->host);
1910 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
Eric Moore547f9a22006-06-27 14:42:12 -06001918 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001919}
1920
Jeff Garzikf2812332010-11-16 02:10:29 -05001921static DEF_SCSI_QCMD(mptsas_qcmd)
1922
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05301923/**
1924 * mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
1925 * if the device under question is currently in the
1926 * device removal delay.
1927 * @sc: scsi command that the midlayer is about to time out
1928 *
1929 **/
1930static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc)
1931{
1932 MPT_SCSI_HOST *hd;
1933 MPT_ADAPTER *ioc;
1934 VirtDevice *vdevice;
1935 enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
1936
1937 hd = shost_priv(sc->device->host);
1938 if (hd == NULL) {
1939 printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n",
1940 __func__, sc);
1941 goto done;
1942 }
1943
1944 ioc = hd->ioc;
1945 if (ioc->bus_type != SAS) {
1946 printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n",
1947 __func__, sc);
1948 goto done;
1949 }
1950
1951 vdevice = sc->device->hostdata;
1952 if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD
1953 || vdevice->vtarget->deleted)) {
1954 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed "
1955 "or in device removal delay (sc=%p)\n",
1956 ioc->name, __func__, sc));
1957 rc = BLK_EH_RESET_TIMER;
1958 goto done;
1959 }
1960
1961done:
1962 return rc;
1963}
1964
Eric Moore547f9a22006-06-27 14:42:12 -06001965
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001966static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001967 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001968 .proc_name = "mptsas",
1969 .proc_info = mptscsih_proc_info,
Kashyap, Desai568da762010-03-18 19:23:50 +05301970 .name = "MPT SAS Host",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001971 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001972 .queuecommand = mptsas_qcmd,
1973 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001974 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001975 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001976 .target_destroy = mptsas_target_destroy,
1977 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001978 .change_queue_depth = mptscsih_change_queue_depth,
1979 .eh_abort_handler = mptscsih_abort,
1980 .eh_device_reset_handler = mptscsih_dev_reset,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001981 .eh_host_reset_handler = mptscsih_host_reset,
1982 .bios_param = mptscsih_bios_param,
Kashyap, Desai9d2e9d62009-08-05 12:48:44 +05301983 .can_queue = MPT_SAS_CAN_QUEUE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001984 .this_id = -1,
1985 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1986 .max_sectors = 8192,
1987 .cmd_per_lun = 7,
1988 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301989 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001990};
1991
Christoph Hellwigb5141122005-10-28 22:07:41 +02001992static int mptsas_get_linkerrors(struct sas_phy *phy)
1993{
1994 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1995 ConfigExtendedPageHeader_t hdr;
1996 CONFIGPARMS cfg;
1997 SasPhyPage1_t *buffer;
1998 dma_addr_t dma_handle;
1999 int error;
2000
James Bottomleyf4ad7b52006-08-25 13:48:18 -05002001 /* FIXME: only have link errors on local phys */
2002 if (!scsi_is_sas_phy_local(phy))
2003 return -EINVAL;
2004
Christoph Hellwigb5141122005-10-28 22:07:41 +02002005 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
2006 hdr.ExtPageLength = 0;
2007 hdr.PageNumber = 1 /* page number 1*/;
2008 hdr.Reserved1 = 0;
2009 hdr.Reserved2 = 0;
2010 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2011 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2012
2013 cfg.cfghdr.ehdr = &hdr;
2014 cfg.physAddr = -1;
2015 cfg.pageAddr = phy->identify.phy_identifier;
2016 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2017 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302018 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwigb5141122005-10-28 22:07:41 +02002019
2020 error = mpt_config(ioc, &cfg);
2021 if (error)
2022 return error;
2023 if (!hdr.ExtPageLength)
2024 return -ENXIO;
2025
2026 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2027 &dma_handle);
2028 if (!buffer)
2029 return -ENOMEM;
2030
2031 cfg.physAddr = dma_handle;
2032 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2033
2034 error = mpt_config(ioc, &cfg);
2035 if (error)
2036 goto out_free_consistent;
2037
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302038 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02002039
2040 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
2041 phy->running_disparity_error_count =
2042 le32_to_cpu(buffer->RunningDisparityErrorCount);
2043 phy->loss_of_dword_sync_count =
2044 le32_to_cpu(buffer->LossDwordSynchCount);
2045 phy->phy_reset_problem_count =
2046 le32_to_cpu(buffer->PhyResetProblemCount);
2047
2048 out_free_consistent:
2049 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2050 buffer, dma_handle);
2051 return error;
2052}
2053
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002054static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2055 MPT_FRAME_HDR *reply)
2056{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302057 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002058 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302059 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002060 memcpy(ioc->sas_mgmt.reply, reply,
2061 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
2062 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302063
2064 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
2065 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
2066 complete(&ioc->sas_mgmt.done);
2067 return 1;
2068 }
2069 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002070}
2071
2072static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
2073{
2074 MPT_ADAPTER *ioc = phy_to_ioc(phy);
2075 SasIoUnitControlRequest_t *req;
2076 SasIoUnitControlReply_t *reply;
2077 MPT_FRAME_HDR *mf;
2078 MPIHeader_t *hdr;
2079 unsigned long timeleft;
2080 int error = -ERESTARTSYS;
2081
James Bottomleyf4ad7b52006-08-25 13:48:18 -05002082 /* FIXME: fusion doesn't allow non-local phy reset */
2083 if (!scsi_is_sas_phy_local(phy))
2084 return -EINVAL;
2085
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002086 /* not implemented for expanders */
2087 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2088 return -ENXIO;
2089
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002090 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002091 goto out;
2092
2093 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2094 if (!mf) {
2095 error = -ENOMEM;
2096 goto out_unlock;
2097 }
2098
2099 hdr = (MPIHeader_t *) mf;
2100 req = (SasIoUnitControlRequest_t *)mf;
2101 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2102 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2103 req->MsgContext = hdr->MsgContext;
2104 req->Operation = hard_reset ?
2105 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2106 req->PhyNum = phy->identify.phy_identifier;
2107
Kashyap, Desai2f187862009-05-29 16:52:37 +05302108 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002109 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2110
2111 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2112 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302113 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2114 error = -ETIME;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002115 mpt_free_msg_frame(ioc, mf);
Kashyap, Desai568da762010-03-18 19:23:50 +05302116 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2117 goto out_unlock;
2118 if (!timeleft)
2119 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002120 goto out_unlock;
2121 }
2122
2123 /* a reply frame is expected */
2124 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302125 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002126 error = -ENXIO;
2127 goto out_unlock;
2128 }
2129
2130 /* process the completed Reply Message Frame */
2131 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2132 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002133 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002134 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002135 error = -ENXIO;
2136 goto out_unlock;
2137 }
2138
2139 error = 0;
2140
2141 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302142 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002143 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002144 out:
2145 return error;
2146}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002147
Christoph Hellwige3094442006-02-16 13:25:36 +01002148static int
2149mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2150{
2151 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2152 int i, error;
2153 struct mptsas_portinfo *p;
2154 struct mptsas_enclosure enclosure_info;
2155 u64 enclosure_handle;
2156
2157 mutex_lock(&ioc->sas_topology_mutex);
2158 list_for_each_entry(p, &ioc->sas_topology, list) {
2159 for (i = 0; i < p->num_phys; i++) {
2160 if (p->phy_info[i].attached.sas_address ==
2161 rphy->identify.sas_address) {
2162 enclosure_handle = p->phy_info[i].
2163 attached.handle_enclosure;
2164 goto found_info;
2165 }
2166 }
2167 }
2168 mutex_unlock(&ioc->sas_topology_mutex);
2169 return -ENXIO;
2170
2171 found_info:
2172 mutex_unlock(&ioc->sas_topology_mutex);
2173 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002174 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002175 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2176 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2177 if (!error)
2178 *identifier = enclosure_info.enclosure_logical_id;
2179 return error;
2180}
2181
2182static int
2183mptsas_get_bay_identifier(struct sas_rphy *rphy)
2184{
2185 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2186 struct mptsas_portinfo *p;
2187 int i, rc;
2188
2189 mutex_lock(&ioc->sas_topology_mutex);
2190 list_for_each_entry(p, &ioc->sas_topology, list) {
2191 for (i = 0; i < p->num_phys; i++) {
2192 if (p->phy_info[i].attached.sas_address ==
2193 rphy->identify.sas_address) {
2194 rc = p->phy_info[i].attached.slot;
2195 goto out;
2196 }
2197 }
2198 }
2199 rc = -ENXIO;
2200 out:
2201 mutex_unlock(&ioc->sas_topology_mutex);
2202 return rc;
2203}
2204
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002205static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2206 struct request *req)
2207{
2208 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2209 MPT_FRAME_HDR *mf;
2210 SmpPassthroughRequest_t *smpreq;
2211 struct request *rsp = req->next_rq;
2212 int ret;
2213 int flagsLength;
2214 unsigned long timeleft;
2215 char *psge;
2216 dma_addr_t dma_addr_in = 0;
2217 dma_addr_t dma_addr_out = 0;
2218 u64 sas_address = 0;
2219
2220 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002221 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002222 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002223 return -EINVAL;
2224 }
2225
2226 /* do we need to support multiple segments? */
2227 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002228 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Tejun Heob0790412009-05-07 22:24:42 +09002229 ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
2230 rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002231 return -EINVAL;
2232 }
2233
2234 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2235 if (ret)
2236 goto out;
2237
2238 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2239 if (!mf) {
2240 ret = -ENOMEM;
2241 goto out_unlock;
2242 }
2243
2244 smpreq = (SmpPassthroughRequest_t *)mf;
2245 memset(smpreq, 0, sizeof(*smpreq));
2246
Tejun Heob0790412009-05-07 22:24:42 +09002247 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002248 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2249
2250 if (rphy)
2251 sas_address = rphy->identify.sas_address;
2252 else {
2253 struct mptsas_portinfo *port_info;
2254
2255 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302256 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002257 if (port_info && port_info->phy_info)
2258 sas_address =
2259 port_info->phy_info[0].phy->identify.sas_address;
2260 mutex_unlock(&ioc->sas_topology_mutex);
2261 }
2262
2263 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2264
2265 psge = (char *)
2266 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2267
2268 /* request */
2269 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2270 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302271 MPI_SGE_FLAGS_DIRECTION)
2272 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002273 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002274
2275 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002276 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002277 if (!dma_addr_out)
2278 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302279 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302280 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002281
2282 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302283 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2284 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2285 MPI_SGE_FLAGS_IOC_TO_HOST |
2286 MPI_SGE_FLAGS_END_OF_BUFFER;
2287
2288 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002289 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002290 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002291 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002292 if (!dma_addr_in)
2293 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302294 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002295
Kashyap, Desai2f187862009-05-29 16:52:37 +05302296 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002297 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2298
2299 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302300 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2301 ret = -ETIME;
2302 mpt_free_msg_frame(ioc, mf);
2303 mf = NULL;
2304 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2305 goto unmap;
2306 if (!timeleft)
2307 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002308 goto unmap;
2309 }
2310 mf = NULL;
2311
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302312 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002313 SmpPassthroughReply_t *smprep;
2314
2315 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2316 memcpy(req->sense, smprep, sizeof(*smprep));
2317 req->sense_len = sizeof(*smprep);
Tejun Heo5f49f632009-05-19 18:33:05 +09002318 req->resid_len = 0;
2319 rsp->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002320 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302321 printk(MYIOC_s_ERR_FMT
2322 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002323 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002324 ret = -ENXIO;
2325 }
2326unmap:
2327 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002328 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002329 PCI_DMA_BIDIRECTIONAL);
2330 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002331 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002332 PCI_DMA_BIDIRECTIONAL);
2333put_mf:
2334 if (mf)
2335 mpt_free_msg_frame(ioc, mf);
2336out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302337 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002338 mutex_unlock(&ioc->sas_mgmt.mutex);
2339out:
2340 return ret;
2341}
2342
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002343static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002344 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002345 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2346 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002347 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002348 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002349};
2350
2351static struct scsi_transport_template *mptsas_transport_template;
2352
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002353static int
2354mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2355{
2356 ConfigExtendedPageHeader_t hdr;
2357 CONFIGPARMS cfg;
2358 SasIOUnitPage0_t *buffer;
2359 dma_addr_t dma_handle;
2360 int error, i;
2361
2362 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2363 hdr.ExtPageLength = 0;
2364 hdr.PageNumber = 0;
2365 hdr.Reserved1 = 0;
2366 hdr.Reserved2 = 0;
2367 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2368 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2369
2370 cfg.cfghdr.ehdr = &hdr;
2371 cfg.physAddr = -1;
2372 cfg.pageAddr = 0;
2373 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2374 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302375 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002376
2377 error = mpt_config(ioc, &cfg);
2378 if (error)
2379 goto out;
2380 if (!hdr.ExtPageLength) {
2381 error = -ENXIO;
2382 goto out;
2383 }
2384
2385 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2386 &dma_handle);
2387 if (!buffer) {
2388 error = -ENOMEM;
2389 goto out;
2390 }
2391
2392 cfg.physAddr = dma_handle;
2393 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2394
2395 error = mpt_config(ioc, &cfg);
2396 if (error)
2397 goto out_free_consistent;
2398
2399 port_info->num_phys = buffer->NumPhys;
2400 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302401 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002402 if (!port_info->phy_info) {
2403 error = -ENOMEM;
2404 goto out_free_consistent;
2405 }
2406
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302407 ioc->nvdata_version_persistent =
2408 le16_to_cpu(buffer->NvdataVersionPersistent);
2409 ioc->nvdata_version_default =
2410 le16_to_cpu(buffer->NvdataVersionDefault);
2411
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002412 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302413 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002414 port_info->phy_info[i].phy_id = i;
2415 port_info->phy_info[i].port_id =
2416 buffer->PhyData[i].Port;
2417 port_info->phy_info[i].negotiated_link_rate =
2418 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002419 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002420 port_info->phy_info[i].handle =
2421 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002422 }
2423
2424 out_free_consistent:
2425 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2426 buffer, dma_handle);
2427 out:
2428 return error;
2429}
2430
2431static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302432mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2433{
2434 ConfigExtendedPageHeader_t hdr;
2435 CONFIGPARMS cfg;
2436 SasIOUnitPage1_t *buffer;
2437 dma_addr_t dma_handle;
2438 int error;
Kashyap, Desaiaca794d2010-06-17 14:39:25 +05302439 u8 device_missing_delay;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302440
2441 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2442 memset(&cfg, 0, sizeof(CONFIGPARMS));
2443
2444 cfg.cfghdr.ehdr = &hdr;
2445 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +05302446 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302447 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2448 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2449 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2450 cfg.cfghdr.ehdr->PageNumber = 1;
2451
2452 error = mpt_config(ioc, &cfg);
2453 if (error)
2454 goto out;
2455 if (!hdr.ExtPageLength) {
2456 error = -ENXIO;
2457 goto out;
2458 }
2459
2460 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2461 &dma_handle);
2462 if (!buffer) {
2463 error = -ENOMEM;
2464 goto out;
2465 }
2466
2467 cfg.physAddr = dma_handle;
2468 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2469
2470 error = mpt_config(ioc, &cfg);
2471 if (error)
2472 goto out_free_consistent;
2473
2474 ioc->io_missing_delay =
2475 le16_to_cpu(buffer->IODeviceMissingDelay);
Kashyap, Desaiaca794d2010-06-17 14:39:25 +05302476 device_missing_delay = buffer->ReportDeviceMissingDelay;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302477 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2478 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2479 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2480
2481 out_free_consistent:
2482 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2483 buffer, dma_handle);
2484 out:
2485 return error;
2486}
2487
2488static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002489mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2490 u32 form, u32 form_specific)
2491{
2492 ConfigExtendedPageHeader_t hdr;
2493 CONFIGPARMS cfg;
2494 SasPhyPage0_t *buffer;
2495 dma_addr_t dma_handle;
2496 int error;
2497
2498 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2499 hdr.ExtPageLength = 0;
2500 hdr.PageNumber = 0;
2501 hdr.Reserved1 = 0;
2502 hdr.Reserved2 = 0;
2503 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2504 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2505
2506 cfg.cfghdr.ehdr = &hdr;
2507 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302508 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002509
2510 /* Get Phy Pg 0 for each Phy. */
2511 cfg.physAddr = -1;
2512 cfg.pageAddr = form + form_specific;
2513 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2514
2515 error = mpt_config(ioc, &cfg);
2516 if (error)
2517 goto out;
2518
2519 if (!hdr.ExtPageLength) {
2520 error = -ENXIO;
2521 goto out;
2522 }
2523
2524 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2525 &dma_handle);
2526 if (!buffer) {
2527 error = -ENOMEM;
2528 goto out;
2529 }
2530
2531 cfg.physAddr = dma_handle;
2532 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2533
2534 error = mpt_config(ioc, &cfg);
2535 if (error)
2536 goto out_free_consistent;
2537
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302538 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002539
2540 phy_info->hw_link_rate = buffer->HwLinkRate;
2541 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2542 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2543 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2544
2545 out_free_consistent:
2546 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2547 buffer, dma_handle);
2548 out:
2549 return error;
2550}
2551
2552static int
2553mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2554 u32 form, u32 form_specific)
2555{
2556 ConfigExtendedPageHeader_t hdr;
2557 CONFIGPARMS cfg;
2558 SasDevicePage0_t *buffer;
2559 dma_addr_t dma_handle;
2560 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002561 int error=0;
2562
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002563 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2564 hdr.ExtPageLength = 0;
2565 hdr.PageNumber = 0;
2566 hdr.Reserved1 = 0;
2567 hdr.Reserved2 = 0;
2568 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2569 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2570
2571 cfg.cfghdr.ehdr = &hdr;
2572 cfg.pageAddr = form + form_specific;
2573 cfg.physAddr = -1;
2574 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2575 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302576 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002577
Moore, Ericdb9c9172006-03-14 09:14:18 -07002578 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002579 error = mpt_config(ioc, &cfg);
2580 if (error)
2581 goto out;
2582 if (!hdr.ExtPageLength) {
2583 error = -ENXIO;
2584 goto out;
2585 }
2586
2587 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2588 &dma_handle);
2589 if (!buffer) {
2590 error = -ENOMEM;
2591 goto out;
2592 }
2593
2594 cfg.physAddr = dma_handle;
2595 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2596
2597 error = mpt_config(ioc, &cfg);
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302598
2599 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2600 error = -ENODEV;
2601 goto out_free_consistent;
2602 }
2603
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002604 if (error)
2605 goto out_free_consistent;
2606
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302607 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002608
Kashyap, Desai2f187862009-05-29 16:52:37 +05302609 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002610 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002611 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002612 device_info->handle_enclosure =
2613 le16_to_cpu(buffer->EnclosureHandle);
2614 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002615 device_info->phy_id = buffer->PhyNum;
2616 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002617 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002618 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002619 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002620 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2621 device_info->sas_address = le64_to_cpu(sas_address);
2622 device_info->device_info =
2623 le32_to_cpu(buffer->DeviceInfo);
Kashyap, Desai51106ab2010-06-17 14:40:10 +05302624 device_info->flags = le16_to_cpu(buffer->Flags);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002625
2626 out_free_consistent:
2627 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2628 buffer, dma_handle);
2629 out:
2630 return error;
2631}
2632
2633static int
2634mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2635 u32 form, u32 form_specific)
2636{
2637 ConfigExtendedPageHeader_t hdr;
2638 CONFIGPARMS cfg;
2639 SasExpanderPage0_t *buffer;
2640 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002641 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302642 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002643
Kashyap, Desai2f187862009-05-29 16:52:37 +05302644 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002645 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2646 hdr.ExtPageLength = 0;
2647 hdr.PageNumber = 0;
2648 hdr.Reserved1 = 0;
2649 hdr.Reserved2 = 0;
2650 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2651 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2652
2653 cfg.cfghdr.ehdr = &hdr;
2654 cfg.physAddr = -1;
2655 cfg.pageAddr = form + form_specific;
2656 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2657 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302658 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002659
Moore, Ericdb9c9172006-03-14 09:14:18 -07002660 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002661 error = mpt_config(ioc, &cfg);
2662 if (error)
2663 goto out;
2664
2665 if (!hdr.ExtPageLength) {
2666 error = -ENXIO;
2667 goto out;
2668 }
2669
2670 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2671 &dma_handle);
2672 if (!buffer) {
2673 error = -ENOMEM;
2674 goto out;
2675 }
2676
2677 cfg.physAddr = dma_handle;
2678 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2679
2680 error = mpt_config(ioc, &cfg);
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302681 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002682 error = -ENODEV;
2683 goto out_free_consistent;
2684 }
2685
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302686 if (error)
2687 goto out_free_consistent;
2688
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002689 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302690 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002691 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302692 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002693 if (!port_info->phy_info) {
2694 error = -ENOMEM;
2695 goto out_free_consistent;
2696 }
2697
Kashyap, Desai2f187862009-05-29 16:52:37 +05302698 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002699 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002700 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002701 port_info->phy_info[i].handle =
2702 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302703 port_info->phy_info[i].identify.sas_address =
2704 le64_to_cpu(sas_address);
2705 port_info->phy_info[i].identify.handle_parent =
2706 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002707 }
Eric Moore547f9a22006-06-27 14:42:12 -06002708
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002709 out_free_consistent:
2710 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2711 buffer, dma_handle);
2712 out:
2713 return error;
2714}
2715
2716static int
2717mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2718 u32 form, u32 form_specific)
2719{
2720 ConfigExtendedPageHeader_t hdr;
2721 CONFIGPARMS cfg;
2722 SasExpanderPage1_t *buffer;
2723 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002724 int error=0;
2725
Kashyap, Desai2f187862009-05-29 16:52:37 +05302726 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002727 hdr.ExtPageLength = 0;
2728 hdr.PageNumber = 1;
2729 hdr.Reserved1 = 0;
2730 hdr.Reserved2 = 0;
2731 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2732 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2733
2734 cfg.cfghdr.ehdr = &hdr;
2735 cfg.physAddr = -1;
2736 cfg.pageAddr = form + form_specific;
2737 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2738 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302739 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002740
2741 error = mpt_config(ioc, &cfg);
2742 if (error)
2743 goto out;
2744
2745 if (!hdr.ExtPageLength) {
2746 error = -ENXIO;
2747 goto out;
2748 }
2749
2750 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2751 &dma_handle);
2752 if (!buffer) {
2753 error = -ENOMEM;
2754 goto out;
2755 }
2756
2757 cfg.physAddr = dma_handle;
2758 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2759
2760 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302761
2762 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2763 error = -ENODEV;
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302764 goto out_free_consistent;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302765 }
2766
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002767 if (error)
2768 goto out_free_consistent;
2769
2770
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302771 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002772
2773 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002774 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002775 phy_info->port_id = buffer->PhysicalPort;
2776 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2777 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2778 phy_info->hw_link_rate = buffer->HwLinkRate;
2779 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2780 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2781
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002782 out_free_consistent:
2783 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2784 buffer, dma_handle);
2785 out:
2786 return error;
2787}
2788
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302789struct rep_manu_request{
2790 u8 smp_frame_type;
2791 u8 function;
2792 u8 reserved;
2793 u8 request_length;
2794};
2795
2796struct rep_manu_reply{
2797 u8 smp_frame_type; /* 0x41 */
2798 u8 function; /* 0x01 */
2799 u8 function_result;
2800 u8 response_length;
2801 u16 expander_change_count;
2802 u8 reserved0[2];
2803 u8 sas_format:1;
2804 u8 reserved1:7;
2805 u8 reserved2[3];
2806 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2807 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2808 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2809 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2810 u16 component_id;
2811 u8 component_revision_id;
2812 u8 reserved3;
2813 u8 vendor_specific[8];
2814};
2815
2816/**
2817 * mptsas_exp_repmanufacture_info -
2818 * @ioc: per adapter object
2819 * @sas_address: expander sas address
2820 * @edev: the sas_expander_device object
2821 *
2822 * Fills in the sas_expander_device object when SMP port is created.
2823 *
2824 * Returns 0 for success, non-zero for failure.
2825 */
2826static int
2827mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2828 u64 sas_address, struct sas_expander_device *edev)
2829{
2830 MPT_FRAME_HDR *mf;
2831 SmpPassthroughRequest_t *smpreq;
2832 SmpPassthroughReply_t *smprep;
2833 struct rep_manu_reply *manufacture_reply;
2834 struct rep_manu_request *manufacture_request;
2835 int ret;
2836 int flagsLength;
2837 unsigned long timeleft;
2838 char *psge;
2839 unsigned long flags;
2840 void *data_out = NULL;
2841 dma_addr_t data_out_dma = 0;
2842 u32 sz;
2843
2844 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2845 if (ioc->ioc_reset_in_progress) {
2846 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2847 printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2848 __func__, ioc->name);
2849 return -EFAULT;
2850 }
2851 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2852
2853 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2854 if (ret)
2855 goto out;
2856
2857 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2858 if (!mf) {
2859 ret = -ENOMEM;
2860 goto out_unlock;
2861 }
2862
2863 smpreq = (SmpPassthroughRequest_t *)mf;
2864 memset(smpreq, 0, sizeof(*smpreq));
2865
2866 sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2867
2868 data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
2869 if (!data_out) {
2870 printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2871 __FILE__, __LINE__, __func__);
2872 ret = -ENOMEM;
2873 goto put_mf;
2874 }
2875
2876 manufacture_request = data_out;
2877 manufacture_request->smp_frame_type = 0x40;
2878 manufacture_request->function = 1;
2879 manufacture_request->reserved = 0;
2880 manufacture_request->request_length = 0;
2881
2882 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2883 smpreq->PhysicalPort = 0xFF;
2884 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2885 smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2886
2887 psge = (char *)
2888 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2889
2890 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2891 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2892 MPI_SGE_FLAGS_HOST_TO_IOC |
2893 MPI_SGE_FLAGS_END_OF_BUFFER;
2894 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2895 flagsLength |= sizeof(struct rep_manu_request);
2896
2897 ioc->add_sge(psge, flagsLength, data_out_dma);
2898 psge += ioc->SGE_size;
2899
2900 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2901 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2902 MPI_SGE_FLAGS_IOC_TO_HOST |
2903 MPI_SGE_FLAGS_END_OF_BUFFER;
2904 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2905 flagsLength |= sizeof(struct rep_manu_reply);
2906 ioc->add_sge(psge, flagsLength, data_out_dma +
2907 sizeof(struct rep_manu_request));
2908
2909 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2910 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2911
2912 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2913 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2914 ret = -ETIME;
2915 mpt_free_msg_frame(ioc, mf);
2916 mf = NULL;
2917 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2918 goto out_free;
2919 if (!timeleft)
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302920 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302921 goto out_free;
2922 }
2923
2924 mf = NULL;
2925
2926 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2927 u8 *tmp;
2928
2929 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2930 if (le16_to_cpu(smprep->ResponseDataLength) !=
2931 sizeof(struct rep_manu_reply))
2932 goto out_free;
2933
2934 manufacture_reply = data_out + sizeof(struct rep_manu_request);
2935 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2936 SAS_EXPANDER_VENDOR_ID_LEN);
2937 strncpy(edev->product_id, manufacture_reply->product_id,
2938 SAS_EXPANDER_PRODUCT_ID_LEN);
2939 strncpy(edev->product_rev, manufacture_reply->product_rev,
2940 SAS_EXPANDER_PRODUCT_REV_LEN);
2941 edev->level = manufacture_reply->sas_format;
2942 if (manufacture_reply->sas_format) {
2943 strncpy(edev->component_vendor_id,
2944 manufacture_reply->component_vendor_id,
2945 SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2946 tmp = (u8 *)&manufacture_reply->component_id;
2947 edev->component_id = tmp[0] << 8 | tmp[1];
2948 edev->component_revision_id =
2949 manufacture_reply->component_revision_id;
2950 }
2951 } else {
2952 printk(MYIOC_s_ERR_FMT
2953 "%s: smp passthru reply failed to be returned\n",
2954 ioc->name, __func__);
2955 ret = -ENXIO;
2956 }
2957out_free:
2958 if (data_out_dma)
2959 pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
2960put_mf:
2961 if (mf)
2962 mpt_free_msg_frame(ioc, mf);
2963out_unlock:
2964 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2965 mutex_unlock(&ioc->sas_mgmt.mutex);
2966out:
2967 return ret;
2968 }
2969
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002970static void
2971mptsas_parse_device_info(struct sas_identify *identify,
2972 struct mptsas_devinfo *device_info)
2973{
2974 u16 protocols;
2975
2976 identify->sas_address = device_info->sas_address;
2977 identify->phy_identifier = device_info->phy_id;
2978
2979 /*
2980 * Fill in Phy Initiator Port Protocol.
2981 * Bits 6:3, more than one bit can be set, fall through cases.
2982 */
2983 protocols = device_info->device_info & 0x78;
2984 identify->initiator_port_protocols = 0;
2985 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2986 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2987 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2988 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2989 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2990 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2991 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2992 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2993
2994 /*
2995 * Fill in Phy Target Port Protocol.
2996 * Bits 10:7, more than one bit can be set, fall through cases.
2997 */
2998 protocols = device_info->device_info & 0x780;
2999 identify->target_port_protocols = 0;
3000 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
3001 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
3002 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
3003 identify->target_port_protocols |= SAS_PROTOCOL_STP;
3004 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
3005 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
3006 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
3007 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
3008
3009 /*
3010 * Fill in Attached device type.
3011 */
3012 switch (device_info->device_info &
3013 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
3014 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
3015 identify->device_type = SAS_PHY_UNUSED;
3016 break;
3017 case MPI_SAS_DEVICE_INFO_END_DEVICE:
3018 identify->device_type = SAS_END_DEVICE;
3019 break;
3020 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
3021 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
3022 break;
3023 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
3024 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
3025 break;
3026 }
3027}
3028
3029static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003030 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003031{
Moore, Erice6b2d762006-03-14 09:14:24 -07003032 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003033 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06003034 struct sas_port *port;
3035 int error = 0;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303036 VirtTarget *vtarget;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003037
Eric Moore547f9a22006-06-27 14:42:12 -06003038 if (!dev) {
3039 error = -ENODEV;
3040 goto out;
3041 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003042
3043 if (!phy_info->phy) {
3044 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06003045 if (!phy) {
3046 error = -ENOMEM;
3047 goto out;
3048 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003049 } else
3050 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003051
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003052 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003053
3054 /*
3055 * Set Negotiated link rate.
3056 */
3057 switch (phy_info->negotiated_link_rate) {
3058 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003059 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003060 break;
3061 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003062 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003063 break;
3064 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003065 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003066 break;
3067 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003068 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003069 break;
Kashyap, Desaid75733d2011-02-10 11:50:39 +05303070 case MPI_SAS_IOUNIT0_RATE_6_0:
3071 phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
3072 break;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003073 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
3074 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
3075 default:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003076 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003077 break;
3078 }
3079
3080 /*
3081 * Set Max hardware link rate.
3082 */
3083 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3084 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003085 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003086 break;
3087 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003088 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003089 break;
3090 default:
3091 break;
3092 }
3093
3094 /*
3095 * Set Max programmed link rate.
3096 */
3097 switch (phy_info->programmed_link_rate &
3098 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3099 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003100 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003101 break;
3102 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003103 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003104 break;
3105 default:
3106 break;
3107 }
3108
3109 /*
3110 * Set Min hardware link rate.
3111 */
3112 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
3113 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003114 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003115 break;
3116 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003117 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003118 break;
3119 default:
3120 break;
3121 }
3122
3123 /*
3124 * Set Min programmed link rate.
3125 */
3126 switch (phy_info->programmed_link_rate &
3127 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
3128 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003129 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003130 break;
3131 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003132 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003133 break;
3134 default:
3135 break;
3136 }
3137
Moore, Erice6b2d762006-03-14 09:14:24 -07003138 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003139
Moore, Erice6b2d762006-03-14 09:14:24 -07003140 error = sas_phy_add(phy);
3141 if (error) {
3142 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06003143 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07003144 }
3145 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003146 }
3147
Eric Moore547f9a22006-06-27 14:42:12 -06003148 if (!phy_info->attached.handle ||
3149 !phy_info->port_details)
3150 goto out;
3151
3152 port = mptsas_get_port(phy_info);
3153 ioc = phy_to_ioc(phy_info->phy);
3154
3155 if (phy_info->sas_port_add_phy) {
3156
3157 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06003158 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06003159 if (!port) {
3160 error = -ENOMEM;
3161 goto out;
3162 }
3163 error = sas_port_add(port);
3164 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303165 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003166 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003167 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003168 goto out;
3169 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303170 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303171 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
3172 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
3173 ioc->name, port->port_identifier,
3174 (unsigned long long)phy_info->
3175 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06003176 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05303177 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3178 "sas_port_add_phy: phy_id=%d\n",
3179 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06003180 sas_port_add_phy(port, phy_info->phy);
3181 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303182 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3183 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
3184 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06003185 }
Eric Moore547f9a22006-06-27 14:42:12 -06003186 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003187
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003188 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05003189 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06003190 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003191
James Bottomley2686de22006-06-30 12:54:02 -05003192 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07003193 /*
3194 * Let the hotplug_work thread handle processing
3195 * the adding/removing of devices that occur
3196 * after start of day.
3197 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303198 if (mptsas_is_end_device(&phy_info->attached) &&
3199 phy_info->attached.handle_parent) {
3200 goto out;
3201 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003202
James Bottomleyf013db32006-03-18 14:54:36 -06003203 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05003204 if (scsi_is_host_device(parent)) {
3205 struct mptsas_portinfo *port_info;
3206 int i;
3207
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303208 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05003209
3210 for (i = 0; i < port_info->num_phys; i++)
3211 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003212 identify.sas_address) {
3213 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003214 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003215 }
James Bottomley2686de22006-06-30 12:54:02 -05003216
3217 } else if (scsi_is_sas_rphy(parent)) {
3218 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
3219 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003220 parent_rphy->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
James Bottomleyf013db32006-03-18 14:54:36 -06003226 switch (identify.device_type) {
3227 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003228 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06003229 break;
3230 case SAS_EDGE_EXPANDER_DEVICE:
3231 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003232 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06003233 break;
3234 default:
3235 rphy = NULL;
3236 break;
3237 }
Eric Moore547f9a22006-06-27 14:42:12 -06003238 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303239 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003240 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003241 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003242 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003243 }
3244
Eric Moore547f9a22006-06-27 14:42:12 -06003245 rphy->identify = identify;
3246 error = sas_rphy_add(rphy);
3247 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303248 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003249 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003250 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003251 sas_rphy_free(rphy);
3252 goto out;
3253 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303254 mptsas_set_rphy(ioc, phy_info, rphy);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05303255 if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3256 identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3257 mptsas_exp_repmanufacture_info(ioc,
3258 identify.sas_address,
3259 rphy_to_expander_device(rphy));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003260 }
3261
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303262 /* If the device exists,verify it wasn't previously flagged
3263 as a missing device. If so, clear it */
3264 vtarget = mptsas_find_vtarget(ioc,
3265 phy_info->attached.channel,
3266 phy_info->attached.id);
3267 if (vtarget && vtarget->inDMD) {
3268 printk(KERN_INFO "Device returned, unsetting inDMD\n");
3269 vtarget->inDMD = 0;
3270 }
3271
Eric Moore547f9a22006-06-27 14:42:12 -06003272 out:
3273 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003274}
3275
3276static int
Moore, Erice6b2d762006-03-14 09:14:24 -07003277mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003278{
Moore, Erice6b2d762006-03-14 09:14:24 -07003279 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003280 int error = -ENOMEM, i;
3281
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303282 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07003283 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003284 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003285
Moore, Erice6b2d762006-03-14 09:14:24 -07003286 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003287 if (error)
3288 goto out_free_port_info;
3289
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303290 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003291 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303292 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07003293 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303294 ioc->hba_port_info = port_info = hba;
3295 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07003296 list_add_tail(&port_info->list, &ioc->sas_topology);
3297 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07003298 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003299 port_info->phy_info[i].negotiated_link_rate =
3300 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003301 port_info->phy_info[i].handle =
3302 hba->phy_info[i].handle;
3303 port_info->phy_info[i].port_id =
3304 hba->phy_info[i].port_id;
3305 }
Eric Moore547f9a22006-06-27 14:42:12 -06003306 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003307 kfree(hba);
3308 hba = NULL;
3309 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003310 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303311#if defined(CPQ_CIM)
3312 ioc->num_ports = port_info->num_phys;
3313#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003314 for (i = 0; i < port_info->num_phys; i++) {
3315 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3316 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3317 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303318 port_info->phy_info[i].identify.handle =
3319 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003320 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003321 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3322 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303323 port_info->phy_info[i].identify.handle);
3324 if (!ioc->hba_port_sas_addr)
3325 ioc->hba_port_sas_addr =
3326 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003327 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003328 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003329 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003330 mptsas_sas_device_pg0(ioc,
3331 &port_info->phy_info[i].attached,
3332 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3333 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3334 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003335 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003336
Eric Moore547f9a22006-06-27 14:42:12 -06003337 mptsas_setup_wide_ports(ioc, port_info);
3338
3339 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003340 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003341 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003342
3343 return 0;
3344
3345 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003346 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003347 out:
3348 return error;
3349}
3350
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303351static void
3352mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003353{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303354 struct mptsas_portinfo *parent;
3355 struct device *parent_dev;
3356 struct sas_rphy *rphy;
3357 int i;
3358 u64 sas_address; /* expander sas address */
3359 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003360
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303361 handle = port_info->phy_info[0].handle;
3362 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003363 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003364 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303365 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3366 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003367
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303368 mptsas_sas_device_pg0(ioc,
3369 &port_info->phy_info[i].identify,
3370 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3371 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3372 port_info->phy_info[i].identify.handle);
3373 port_info->phy_info[i].identify.phy_id =
3374 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003375
3376 if (port_info->phy_info[i].attached.handle) {
3377 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303378 &port_info->phy_info[i].attached,
3379 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3380 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3381 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003382 port_info->phy_info[i].attached.phy_id =
3383 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003384 }
Eric Moore547f9a22006-06-27 14:42:12 -06003385 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003386
Moore, Erice6b2d762006-03-14 09:14:24 -07003387 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303388 parent = mptsas_find_portinfo_by_handle(ioc,
3389 port_info->phy_info[0].identify.handle_parent);
3390 if (!parent) {
3391 mutex_unlock(&ioc->sas_topology_mutex);
3392 return;
3393 }
3394 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3395 i++) {
3396 if (parent->phy_info[i].attached.sas_address == sas_address) {
3397 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3398 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003399 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003400 }
3401 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303402
3403 mptsas_setup_wide_ports(ioc, port_info);
3404 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3405 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3406 ioc->sas_index, 0);
3407}
3408
3409static void
3410mptsas_expander_event_add(MPT_ADAPTER *ioc,
3411 MpiEventDataSasExpanderStatusChange_t *expander_data)
3412{
3413 struct mptsas_portinfo *port_info;
3414 int i;
3415 __le64 sas_address;
3416
3417 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3418 if (!port_info)
3419 BUG();
3420 port_info->num_phys = (expander_data->NumPhys) ?
3421 expander_data->NumPhys : 1;
3422 port_info->phy_info = kcalloc(port_info->num_phys,
3423 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3424 if (!port_info->phy_info)
3425 BUG();
3426 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3427 for (i = 0; i < port_info->num_phys; i++) {
3428 port_info->phy_info[i].portinfo = port_info;
3429 port_info->phy_info[i].handle =
3430 le16_to_cpu(expander_data->DevHandle);
3431 port_info->phy_info[i].identify.sas_address =
3432 le64_to_cpu(sas_address);
3433 port_info->phy_info[i].identify.handle_parent =
3434 le16_to_cpu(expander_data->ParentDevHandle);
3435 }
3436
3437 mutex_lock(&ioc->sas_topology_mutex);
3438 list_add_tail(&port_info->list, &ioc->sas_topology);
3439 mutex_unlock(&ioc->sas_topology_mutex);
3440
3441 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3442 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3443 (unsigned long long)sas_address);
3444
3445 mptsas_expander_refresh(ioc, port_info);
3446}
3447
3448/**
3449 * mptsas_delete_expander_siblings - remove siblings attached to expander
3450 * @ioc: Pointer to MPT_ADAPTER structure
3451 * @parent: the parent port_info object
3452 * @expander: the expander port_info object
3453 **/
3454static void
3455mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3456 *parent, struct mptsas_portinfo *expander)
3457{
3458 struct mptsas_phyinfo *phy_info;
3459 struct mptsas_portinfo *port_info;
3460 struct sas_rphy *rphy;
3461 int i;
3462
3463 phy_info = expander->phy_info;
3464 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3465 rphy = mptsas_get_rphy(phy_info);
3466 if (!rphy)
3467 continue;
3468 if (rphy->identify.device_type == SAS_END_DEVICE)
3469 mptsas_del_end_device(ioc, phy_info);
3470 }
3471
3472 phy_info = expander->phy_info;
3473 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3474 rphy = mptsas_get_rphy(phy_info);
3475 if (!rphy)
3476 continue;
3477 if (rphy->identify.device_type ==
3478 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3479 rphy->identify.device_type ==
3480 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3481 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3482 rphy->identify.sas_address);
3483 if (!port_info)
3484 continue;
3485 if (port_info == parent) /* backlink rphy */
3486 continue;
3487 /*
3488 Delete this expander even if the expdevpage is exists
3489 because the parent expander is already deleted
3490 */
3491 mptsas_expander_delete(ioc, port_info, 1);
3492 }
3493 }
3494}
3495
3496
3497/**
3498 * mptsas_expander_delete - remove this expander
3499 * @ioc: Pointer to MPT_ADAPTER structure
3500 * @port_info: expander port_info struct
3501 * @force: Flag to forcefully delete the expander
3502 *
3503 **/
3504
3505static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3506 struct mptsas_portinfo *port_info, u8 force)
3507{
3508
3509 struct mptsas_portinfo *parent;
3510 int i;
3511 u64 expander_sas_address;
3512 struct mptsas_phyinfo *phy_info;
3513 struct mptsas_portinfo buffer;
3514 struct mptsas_portinfo_details *port_details;
3515 struct sas_port *port;
3516
3517 if (!port_info)
3518 return;
3519
3520 /* see if expander is still there before deleting */
3521 mptsas_sas_expander_pg0(ioc, &buffer,
3522 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3523 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3524 port_info->phy_info[0].identify.handle);
3525
3526 if (buffer.num_phys) {
3527 kfree(buffer.phy_info);
3528 if (!force)
3529 return;
3530 }
3531
3532
3533 /*
3534 * Obtain the port_info instance to the parent port
3535 */
3536 port_details = NULL;
3537 expander_sas_address =
3538 port_info->phy_info[0].identify.sas_address;
3539 parent = mptsas_find_portinfo_by_handle(ioc,
3540 port_info->phy_info[0].identify.handle_parent);
3541 mptsas_delete_expander_siblings(ioc, parent, port_info);
3542 if (!parent)
3543 goto out;
3544
3545 /*
3546 * Delete rphys in the parent that point
3547 * to this expander.
3548 */
3549 phy_info = parent->phy_info;
3550 port = NULL;
3551 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3552 if (!phy_info->phy)
3553 continue;
3554 if (phy_info->attached.sas_address !=
3555 expander_sas_address)
3556 continue;
3557 if (!port) {
3558 port = mptsas_get_port(phy_info);
3559 port_details = phy_info->port_details;
3560 }
3561 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3562 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3563 phy_info->phy_id, phy_info->phy);
3564 sas_port_delete_phy(port, phy_info->phy);
3565 }
3566 if (port) {
3567 dev_printk(KERN_DEBUG, &port->dev,
3568 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3569 ioc->name, port->port_identifier,
3570 (unsigned long long)expander_sas_address);
3571 sas_port_delete(port);
3572 mptsas_port_delete(ioc, port_details);
3573 }
3574 out:
3575
3576 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3577 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3578 (unsigned long long)expander_sas_address);
3579
3580 /*
3581 * free link
3582 */
3583 list_del(&port_info->list);
3584 kfree(port_info->phy_info);
3585 kfree(port_info);
3586}
3587
3588
3589/**
3590 * mptsas_send_expander_event - expanders events
3591 * @ioc: Pointer to MPT_ADAPTER structure
3592 * @expander_data: event data
3593 *
3594 *
3595 * This function handles adding, removing, and refreshing
3596 * device handles within the expander objects.
3597 */
3598static void
3599mptsas_send_expander_event(struct fw_event_work *fw_event)
3600{
3601 MPT_ADAPTER *ioc;
3602 MpiEventDataSasExpanderStatusChange_t *expander_data;
3603 struct mptsas_portinfo *port_info;
3604 __le64 sas_address;
3605 int i;
3606
3607 ioc = fw_event->ioc;
3608 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3609 fw_event->event_data;
3610 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
Kashyap, Desaif44fd182009-09-02 11:44:19 +05303611 sas_address = le64_to_cpu(sas_address);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303612 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3613
3614 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3615 if (port_info) {
3616 for (i = 0; i < port_info->num_phys; i++) {
3617 port_info->phy_info[i].portinfo = port_info;
3618 port_info->phy_info[i].handle =
3619 le16_to_cpu(expander_data->DevHandle);
3620 port_info->phy_info[i].identify.sas_address =
3621 le64_to_cpu(sas_address);
3622 port_info->phy_info[i].identify.handle_parent =
3623 le16_to_cpu(expander_data->ParentDevHandle);
3624 }
3625 mptsas_expander_refresh(ioc, port_info);
3626 } else if (!port_info && expander_data->NumPhys)
3627 mptsas_expander_event_add(ioc, expander_data);
3628 } else if (expander_data->ReasonCode ==
3629 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3630 mptsas_expander_delete(ioc, port_info, 0);
3631
3632 mptsas_free_fw_event(ioc, fw_event);
3633}
3634
3635
3636/**
3637 * mptsas_expander_add -
3638 * @ioc: Pointer to MPT_ADAPTER structure
3639 * @handle:
3640 *
3641 */
3642struct mptsas_portinfo *
3643mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3644{
3645 struct mptsas_portinfo buffer, *port_info;
3646 int i;
3647
3648 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3649 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3650 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3651 return NULL;
3652
3653 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3654 if (!port_info) {
3655 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3656 "%s: exit at line=%d\n", ioc->name,
3657 __func__, __LINE__));
3658 return NULL;
3659 }
3660 port_info->num_phys = buffer.num_phys;
3661 port_info->phy_info = buffer.phy_info;
3662 for (i = 0; i < port_info->num_phys; i++)
3663 port_info->phy_info[i].portinfo = port_info;
3664 mutex_lock(&ioc->sas_topology_mutex);
3665 list_add_tail(&port_info->list, &ioc->sas_topology);
3666 mutex_unlock(&ioc->sas_topology_mutex);
3667 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3668 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3669 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3670 mptsas_expander_refresh(ioc, port_info);
3671 return port_info;
3672}
3673
3674static void
3675mptsas_send_link_status_event(struct fw_event_work *fw_event)
3676{
3677 MPT_ADAPTER *ioc;
3678 MpiEventDataSasPhyLinkStatus_t *link_data;
3679 struct mptsas_portinfo *port_info;
3680 struct mptsas_phyinfo *phy_info = NULL;
3681 __le64 sas_address;
3682 u8 phy_num;
3683 u8 link_rate;
3684
3685 ioc = fw_event->ioc;
3686 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3687
3688 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3689 sas_address = le64_to_cpu(sas_address);
3690 link_rate = link_data->LinkRates >> 4;
3691 phy_num = link_data->PhyNum;
3692
3693 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3694 if (port_info) {
3695 phy_info = &port_info->phy_info[phy_num];
3696 if (phy_info)
3697 phy_info->negotiated_link_rate = link_rate;
3698 }
3699
3700 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
Kashyap, Desaid75733d2011-02-10 11:50:39 +05303701 link_rate == MPI_SAS_IOUNIT0_RATE_3_0 ||
3702 link_rate == MPI_SAS_IOUNIT0_RATE_6_0) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303703
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303704 if (!port_info) {
3705 if (ioc->old_sas_discovery_protocal) {
3706 port_info = mptsas_expander_add(ioc,
3707 le16_to_cpu(link_data->DevHandle));
3708 if (port_info)
3709 goto out;
3710 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303711 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303712 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303713
3714 if (port_info == ioc->hba_port_info)
3715 mptsas_probe_hba_phys(ioc);
3716 else
3717 mptsas_expander_refresh(ioc, port_info);
3718 } else if (phy_info && phy_info->phy) {
3719 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3720 phy_info->phy->negotiated_linkrate =
3721 SAS_PHY_DISABLED;
3722 else if (link_rate ==
3723 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3724 phy_info->phy->negotiated_linkrate =
3725 SAS_LINK_RATE_FAILED;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303726 else {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303727 phy_info->phy->negotiated_linkrate =
3728 SAS_LINK_RATE_UNKNOWN;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303729 if (ioc->device_missing_delay &&
3730 mptsas_is_end_device(&phy_info->attached)) {
3731 struct scsi_device *sdev;
3732 VirtDevice *vdevice;
3733 u8 channel, id;
3734 id = phy_info->attached.id;
3735 channel = phy_info->attached.channel;
3736 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3737 "Link down for fw_id %d:fw_channel %d\n",
3738 ioc->name, phy_info->attached.id,
3739 phy_info->attached.channel));
3740
3741 shost_for_each_device(sdev, ioc->sh) {
3742 vdevice = sdev->hostdata;
3743 if ((vdevice == NULL) ||
3744 (vdevice->vtarget == NULL))
3745 continue;
3746 if ((vdevice->vtarget->tflags &
3747 MPT_TARGET_FLAGS_RAID_COMPONENT ||
3748 vdevice->vtarget->raidVolume))
3749 continue;
3750 if (vdevice->vtarget->id == id &&
3751 vdevice->vtarget->channel ==
3752 channel)
3753 devtprintk(ioc,
3754 printk(MYIOC_s_DEBUG_FMT
3755 "SDEV OUTSTANDING CMDS"
3756 "%d\n", ioc->name,
3757 sdev->device_busy));
3758 }
3759
3760 }
3761 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303762 }
3763 out:
3764 mptsas_free_fw_event(ioc, fw_event);
3765}
3766
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303767static void
3768mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3769{
3770 struct mptsas_portinfo buffer, *port_info;
3771 struct mptsas_device_info *sas_info;
3772 struct mptsas_devinfo sas_device;
3773 u32 handle;
3774 VirtTarget *vtarget = NULL;
3775 struct mptsas_phyinfo *phy_info;
3776 u8 found_expander;
3777 int retval, retry_count;
3778 unsigned long flags;
3779
3780 mpt_findImVolumes(ioc);
3781
3782 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3783 if (ioc->ioc_reset_in_progress) {
3784 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3785 "%s: exiting due to a parallel reset \n", ioc->name,
3786 __func__));
3787 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3788 return;
3789 }
3790 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3791
3792 /* devices, logical volumes */
3793 mutex_lock(&ioc->sas_device_info_mutex);
3794 redo_device_scan:
3795 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303796 if (sas_info->is_cached)
3797 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303798 if (!sas_info->is_logical_volume) {
3799 sas_device.handle = 0;
3800 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303801retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303802 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303803 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3804 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3805 (sas_info->fw.channel << 8) +
3806 sas_info->fw.id);
3807
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303808 if (sas_device.handle)
3809 continue;
3810 if (retval == -EBUSY) {
3811 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3812 if (ioc->ioc_reset_in_progress) {
3813 dfailprintk(ioc,
3814 printk(MYIOC_s_DEBUG_FMT
3815 "%s: exiting due to reset\n",
3816 ioc->name, __func__));
3817 spin_unlock_irqrestore
3818 (&ioc->taskmgmt_lock, flags);
3819 mutex_unlock(&ioc->
3820 sas_device_info_mutex);
3821 return;
3822 }
3823 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3824 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303825 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303826
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303827 if (retval && (retval != -ENODEV)) {
3828 if (retry_count < 10) {
3829 retry_count++;
3830 goto retry_page;
3831 } else {
3832 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3833 "%s: Config page retry exceeded retry "
3834 "count deleting device 0x%llx\n",
3835 ioc->name, __func__,
3836 sas_info->sas_address));
3837 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303838 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303839
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303840 /* delete device */
3841 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303842 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303843
3844 if (vtarget)
3845 vtarget->deleted = 1;
3846
3847 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3848 sas_info->sas_address);
3849
3850 if (phy_info) {
3851 mptsas_del_end_device(ioc, phy_info);
3852 goto redo_device_scan;
3853 }
3854 } else
3855 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303856 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003857 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303858
3859 /* expanders */
3860 mutex_lock(&ioc->sas_topology_mutex);
3861 redo_expander_scan:
3862 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3863
3864 if (port_info->phy_info &&
3865 (!(port_info->phy_info[0].identify.device_info &
3866 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3867 continue;
3868 found_expander = 0;
3869 handle = 0xFFFF;
3870 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3871 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3872 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3873 !found_expander) {
3874
3875 handle = buffer.phy_info[0].handle;
3876 if (buffer.phy_info[0].identify.sas_address ==
3877 port_info->phy_info[0].identify.sas_address) {
3878 found_expander = 1;
3879 }
3880 kfree(buffer.phy_info);
3881 }
3882
3883 if (!found_expander) {
3884 mptsas_expander_delete(ioc, port_info, 0);
3885 goto redo_expander_scan;
3886 }
3887 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003888 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303889}
3890
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303891/**
3892 * mptsas_probe_expanders - adding expanders
3893 * @ioc: Pointer to MPT_ADAPTER structure
3894 *
3895 **/
3896static void
3897mptsas_probe_expanders(MPT_ADAPTER *ioc)
3898{
3899 struct mptsas_portinfo buffer, *port_info;
3900 u32 handle;
3901 int i;
3902
3903 handle = 0xFFFF;
3904 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3905 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3906 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3907
3908 handle = buffer.phy_info[0].handle;
3909 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3910 buffer.phy_info[0].identify.sas_address);
3911
3912 if (port_info) {
3913 /* refreshing handles */
3914 for (i = 0; i < buffer.num_phys; i++) {
3915 port_info->phy_info[i].handle = handle;
3916 port_info->phy_info[i].identify.handle_parent =
3917 buffer.phy_info[0].identify.handle_parent;
3918 }
3919 mptsas_expander_refresh(ioc, port_info);
3920 kfree(buffer.phy_info);
3921 continue;
3922 }
3923
3924 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3925 if (!port_info) {
3926 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3927 "%s: exit at line=%d\n", ioc->name,
3928 __func__, __LINE__));
3929 return;
3930 }
3931 port_info->num_phys = buffer.num_phys;
3932 port_info->phy_info = buffer.phy_info;
3933 for (i = 0; i < port_info->num_phys; i++)
3934 port_info->phy_info[i].portinfo = port_info;
3935 mutex_lock(&ioc->sas_topology_mutex);
3936 list_add_tail(&port_info->list, &ioc->sas_topology);
3937 mutex_unlock(&ioc->sas_topology_mutex);
3938 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3939 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3940 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3941 mptsas_expander_refresh(ioc, port_info);
3942 }
3943}
3944
3945static void
3946mptsas_probe_devices(MPT_ADAPTER *ioc)
3947{
3948 u16 handle;
3949 struct mptsas_devinfo sas_device;
3950 struct mptsas_phyinfo *phy_info;
3951
3952 handle = 0xFFFF;
3953 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3954 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3955
3956 handle = sas_device.handle;
3957
3958 if ((sas_device.device_info &
3959 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3960 MPI_SAS_DEVICE_INFO_STP_TARGET |
3961 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3962 continue;
3963
Kashyap, Desai51106ab2010-06-17 14:40:10 +05303964 /* If there is no FW B_T mapping for this device then continue
3965 * */
3966 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
3967 || !(sas_device.flags &
3968 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
3969 continue;
3970
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303971 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3972 if (!phy_info)
3973 continue;
3974
3975 if (mptsas_get_rphy(phy_info))
3976 continue;
3977
3978 mptsas_add_end_device(ioc, phy_info);
3979 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003980}
3981
Kashyap, Desai2f187862009-05-29 16:52:37 +05303982/**
3983 * mptsas_scan_sas_topology -
3984 * @ioc: Pointer to MPT_ADAPTER structure
3985 * @sas_address:
3986 *
3987 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003988static void
3989mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3990{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303991 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003992 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003993
Moore, Erice6b2d762006-03-14 09:14:24 -07003994 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303995 mptsas_probe_expanders(ioc);
3996 mptsas_probe_devices(ioc);
3997
Moore, Ericf44e5462006-03-14 09:14:21 -07003998 /*
3999 Reporting RAID volumes.
4000 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304001 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
4002 !ioc->raid_data.pIocPg2->NumActiveVolumes)
4003 return;
Eric Moore793955f2007-01-29 09:42:20 -07004004 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304005 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4006 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
4007 if (sdev) {
4008 scsi_device_put(sdev);
4009 continue;
4010 }
4011 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4012 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4013 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04004014 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07004015 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
4016 }
Moore, Erice6b2d762006-03-14 09:14:24 -07004017}
4018
Kashyap, Desai57e98512009-05-29 16:55:09 +05304019
4020static void
4021mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
4022{
4023 MPT_ADAPTER *ioc;
4024 EventDataQueueFull_t *qfull_data;
4025 struct mptsas_device_info *sas_info;
4026 struct scsi_device *sdev;
4027 int depth;
4028 int id = -1;
4029 int channel = -1;
4030 int fw_id, fw_channel;
4031 u16 current_depth;
4032
4033
4034 ioc = fw_event->ioc;
4035 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
4036 fw_id = qfull_data->TargetID;
4037 fw_channel = qfull_data->Bus;
4038 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
4039
4040 /* if hidden raid component, look for the volume id */
4041 mutex_lock(&ioc->sas_device_info_mutex);
4042 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
4043 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
4044 list) {
4045 if (sas_info->is_cached ||
4046 sas_info->is_logical_volume)
4047 continue;
4048 if (sas_info->is_hidden_raid_component &&
4049 (sas_info->fw.channel == fw_channel &&
4050 sas_info->fw.id == fw_id)) {
4051 id = sas_info->volume_id;
4052 channel = MPTSAS_RAID_CHANNEL;
4053 goto out;
4054 }
4055 }
4056 } else {
4057 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
4058 list) {
4059 if (sas_info->is_cached ||
4060 sas_info->is_hidden_raid_component ||
4061 sas_info->is_logical_volume)
4062 continue;
4063 if (sas_info->fw.channel == fw_channel &&
4064 sas_info->fw.id == fw_id) {
4065 id = sas_info->os.id;
4066 channel = sas_info->os.channel;
4067 goto out;
4068 }
4069 }
4070
4071 }
4072
4073 out:
4074 mutex_unlock(&ioc->sas_device_info_mutex);
4075
4076 if (id != -1) {
4077 shost_for_each_device(sdev, ioc->sh) {
4078 if (sdev->id == id && sdev->channel == channel) {
4079 if (current_depth > sdev->queue_depth) {
4080 sdev_printk(KERN_INFO, sdev,
4081 "strange observation, the queue "
4082 "depth is (%d) meanwhile fw queue "
4083 "depth (%d)\n", sdev->queue_depth,
4084 current_depth);
4085 continue;
4086 }
4087 depth = scsi_track_queue_full(sdev,
4088 current_depth - 1);
4089 if (depth > 0)
4090 sdev_printk(KERN_INFO, sdev,
4091 "Queue depth reduced to (%d)\n",
4092 depth);
4093 else if (depth < 0)
4094 sdev_printk(KERN_INFO, sdev,
4095 "Tagged Command Queueing is being "
4096 "disabled\n");
4097 else if (depth == 0)
4098 sdev_printk(KERN_INFO, sdev,
4099 "Queue depth not changed yet\n");
4100 }
4101 }
4102 }
4103
4104 mptsas_free_fw_event(ioc, fw_event);
4105}
4106
4107
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004108static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06004109mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004110{
4111 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004112 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06004113 int i;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004114
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004115 mutex_lock(&ioc->sas_topology_mutex);
4116 list_for_each_entry(port_info, &ioc->sas_topology, list) {
4117 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06004118 if (!mptsas_is_end_device(
4119 &port_info->phy_info[i].attached))
4120 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004121 if (port_info->phy_info[i].attached.sas_address
4122 != sas_address)
4123 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06004124 phy_info = &port_info->phy_info[i];
4125 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004126 }
4127 }
4128 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004129 return phy_info;
4130}
4131
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304132/**
4133 * mptsas_find_phyinfo_by_phys_disk_num -
4134 * @ioc: Pointer to MPT_ADAPTER structure
4135 * @phys_disk_num:
4136 * @channel:
4137 * @id:
4138 *
4139 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07004140static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304141mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
4142 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07004143{
Eric Mooreb506ade2007-01-29 09:45:37 -07004144 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304145 struct mptsas_portinfo *port_info;
4146 RaidPhysDiskPage1_t *phys_disk = NULL;
4147 int num_paths;
4148 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07004149 int i;
4150
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304151 phy_info = NULL;
4152 if (!ioc->raid_data.pIocPg3)
4153 return NULL;
4154 /* dual port support */
4155 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4156 if (!num_paths)
4157 goto out;
4158 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4159 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4160 if (!phys_disk)
4161 goto out;
4162 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4163 for (i = 0; i < num_paths; i++) {
4164 if ((phys_disk->Path[i].Flags & 1) != 0)
4165 /* entry no longer valid */
4166 continue;
4167 if ((id == phys_disk->Path[i].PhysDiskID) &&
4168 (channel == phys_disk->Path[i].PhysDiskBus)) {
4169 memcpy(&sas_address, &phys_disk->Path[i].WWID,
4170 sizeof(u64));
4171 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4172 sas_address);
4173 goto out;
4174 }
4175 }
4176
4177 out:
4178 kfree(phys_disk);
4179 if (phy_info)
4180 return phy_info;
4181
4182 /*
4183 * Extra code to handle RAID0 case, where the sas_address is not updated
4184 * in phys_disk_page_1 when hotswapped
4185 */
Eric Mooreb506ade2007-01-29 09:45:37 -07004186 mutex_lock(&ioc->sas_topology_mutex);
4187 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304188 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004189 if (!mptsas_is_end_device(
4190 &port_info->phy_info[i].attached))
4191 continue;
4192 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4193 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304194 if ((port_info->phy_info[i].attached.phys_disk_num ==
4195 phys_disk_num) &&
4196 (port_info->phy_info[i].attached.id == id) &&
4197 (port_info->phy_info[i].attached.channel ==
4198 channel))
4199 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06004200 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004201 }
4202 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004203 return phy_info;
4204}
4205
4206static void
Moore, Ericf44e5462006-03-14 09:14:21 -07004207mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4208{
Eric Mooref99be432007-01-04 20:46:54 -07004209 int rc;
4210
Moore, Ericf44e5462006-03-14 09:14:21 -07004211 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07004212 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07004213}
4214
4215static void
4216mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4217{
4218 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4219 mptsas_reprobe_lun);
4220}
4221
Eric Mooreb506ade2007-01-29 09:45:37 -07004222static void
4223mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4224{
4225 CONFIGPARMS cfg;
4226 ConfigPageHeader_t hdr;
4227 dma_addr_t dma_handle;
4228 pRaidVolumePage0_t buffer = NULL;
4229 RaidPhysDiskPage0_t phys_disk;
4230 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304231 struct mptsas_phyinfo *phy_info;
4232 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07004233
4234 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4235 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4236 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4237 cfg.pageAddr = (channel << 8) + id;
4238 cfg.cfghdr.hdr = &hdr;
4239 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai568da762010-03-18 19:23:50 +05304240 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Eric Mooreb506ade2007-01-29 09:45:37 -07004241
4242 if (mpt_config(ioc, &cfg) != 0)
4243 goto out;
4244
4245 if (!hdr.PageLength)
4246 goto out;
4247
4248 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4249 &dma_handle);
4250
4251 if (!buffer)
4252 goto out;
4253
4254 cfg.physAddr = dma_handle;
4255 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4256
4257 if (mpt_config(ioc, &cfg) != 0)
4258 goto out;
4259
4260 if (!(buffer->VolumeStatus.Flags &
4261 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4262 goto out;
4263
4264 if (!buffer->NumPhysDisks)
4265 goto out;
4266
4267 for (i = 0; i < buffer->NumPhysDisks; i++) {
4268
4269 if (mpt_raid_phys_disk_pg0(ioc,
4270 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4271 continue;
4272
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304273 if (mptsas_sas_device_pg0(ioc, &sas_device,
4274 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4275 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4276 (phys_disk.PhysDiskBus << 8) +
4277 phys_disk.PhysDiskID))
4278 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004279
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304280 /* If there is no FW B_T mapping for this device then continue
4281 * */
4282 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4283 || !(sas_device.flags &
4284 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4285 continue;
4286
4287
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304288 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4289 sas_device.sas_address);
4290 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07004291 }
4292
4293 out:
4294 if (buffer)
4295 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4296 dma_handle);
4297}
Moore, Erice6b2d762006-03-14 09:14:24 -07004298/*
4299 * Work queue thread to handle SAS hotplug events
4300 */
Moore, Ericf44e5462006-03-14 09:14:21 -07004301static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304302mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
4303 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004304{
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004305 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004306 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004307 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07004308 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304309 int i;
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304310 struct mptsas_portinfo *port_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004311
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304312 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004313
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304314 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07004315
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304316 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07004317 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07004318
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304319 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4320 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4321 hot_plug_info->id) {
4322 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4323 "to add hidden disk - target_id matchs "
4324 "volume_id\n", ioc->name);
4325 mptsas_free_fw_event(ioc, fw_event);
4326 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07004327 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004328 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304329 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004330
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004331 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304332 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4333 mptsas_sas_device_pg0(ioc, &sas_device,
4334 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4335 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4336 (hot_plug_info->channel << 8) +
4337 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004338
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304339 /* If there is no FW B_T mapping for this device then break
4340 * */
4341 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4342 || !(sas_device.flags &
4343 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4344 break;
4345
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304346 if (!sas_device.handle)
4347 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06004348
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304349 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304350 /* Only For SATA Device ADD */
4351 if (!phy_info && (sas_device.device_info &
4352 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) {
4353 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4354 "%s %d SATA HOT PLUG: "
4355 "parent handle of device %x\n", ioc->name,
4356 __func__, __LINE__, sas_device.handle_parent));
4357 port_info = mptsas_find_portinfo_by_handle(ioc,
4358 sas_device.handle_parent);
4359
4360 if (port_info == ioc->hba_port_info)
4361 mptsas_probe_hba_phys(ioc);
4362 else if (port_info)
4363 mptsas_expander_refresh(ioc, port_info);
4364 else {
4365 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4366 "%s %d port info is NULL\n",
4367 ioc->name, __func__, __LINE__));
4368 break;
4369 }
4370 phy_info = mptsas_refreshing_device_handles
4371 (ioc, &sas_device);
4372 }
4373
4374 if (!phy_info) {
4375 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4376 "%s %d phy info is NULL\n",
4377 ioc->name, __func__, __LINE__));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304378 break;
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304379 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304380
4381 if (mptsas_get_rphy(phy_info))
4382 break;
4383
4384 mptsas_add_end_device(ioc, phy_info);
4385 break;
4386
4387 case MPTSAS_DEL_DEVICE:
4388 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4389 hot_plug_info->sas_address);
4390 mptsas_del_end_device(ioc, phy_info);
4391 break;
4392
4393 case MPTSAS_DEL_PHYSDISK:
4394
4395 mpt_findImVolumes(ioc);
4396
4397 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304398 ioc, hot_plug_info->phys_disk_num,
4399 hot_plug_info->channel,
4400 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304401 mptsas_del_end_device(ioc, phy_info);
4402 break;
4403
4404 case MPTSAS_ADD_PHYSDISK_REPROBE:
4405
Christoph Hellwige3094442006-02-16 13:25:36 +01004406 if (mptsas_sas_device_pg0(ioc, &sas_device,
4407 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004408 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304409 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4410 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4411 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4412 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004413 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004414 }
4415
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304416 /* If there is no FW B_T mapping for this device then break
4417 * */
4418 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4419 || !(sas_device.flags &
4420 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4421 break;
4422
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304423 phy_info = mptsas_find_phyinfo_by_sas_address(
4424 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004425
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304426 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304427 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304428 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4429 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004430 break;
4431 }
4432
4433 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304434 if (!starget) {
4435 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4436 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4437 __func__, hot_plug_info->id, __LINE__));
4438 break;
4439 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004440
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304441 vtarget = starget->hostdata;
4442 if (!vtarget) {
4443 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4444 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4445 __func__, hot_plug_info->id, __LINE__));
4446 break;
4447 }
Eric Moore547f9a22006-06-27 14:42:12 -06004448
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304449 mpt_findImVolumes(ioc);
4450
4451 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4452 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4453 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4454 hot_plug_info->phys_disk_num, (unsigned long long)
4455 sas_device.sas_address);
4456
4457 vtarget->id = hot_plug_info->phys_disk_num;
4458 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4459 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4460 mptsas_reprobe_target(starget, 1);
4461 break;
4462
4463 case MPTSAS_DEL_PHYSDISK_REPROBE:
4464
4465 if (mptsas_sas_device_pg0(ioc, &sas_device,
4466 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4467 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4468 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304469 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304470 "%s: fw_id=%d exit at line=%d\n",
4471 ioc->name, __func__,
4472 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004473 break;
4474 }
4475
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304476 /* If there is no FW B_T mapping for this device then break
4477 * */
4478 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4479 || !(sas_device.flags &
4480 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4481 break;
4482
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304483 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4484 sas_device.sas_address);
4485 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304486 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304487 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4488 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004489 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004490 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004491
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304492 starget = mptsas_get_starget(phy_info);
4493 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304494 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304495 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4496 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004497 break;
4498 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004499
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304500 vtarget = starget->hostdata;
4501 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304502 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304503 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4504 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004505 break;
4506 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304507
4508 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4509 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4510 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4511 __func__, hot_plug_info->id, __LINE__));
4512 break;
4513 }
4514
4515 mpt_findImVolumes(ioc);
4516
4517 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4518 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4519 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4520 hot_plug_info->phys_disk_num, (unsigned long long)
4521 sas_device.sas_address);
4522
4523 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4524 vtarget->id = hot_plug_info->id;
4525 phy_info->attached.phys_disk_num = ~0;
4526 mptsas_reprobe_target(starget, 0);
4527 mptsas_add_device_component_by_fw(ioc,
4528 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004529 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304530
Moore, Ericc73787ee2006-01-26 16:20:06 -07004531 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304532
Moore, Ericc73787ee2006-01-26 16:20:06 -07004533 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304534 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4535 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4536 hot_plug_info->id);
4537 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4538 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004539 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304540
Moore, Ericc73787ee2006-01-26 16:20:06 -07004541 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304542
Moore, Ericc73787ee2006-01-26 16:20:06 -07004543 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304544 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4545 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4546 hot_plug_info->id);
4547 scsi_remove_device(hot_plug_info->sdev);
4548 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004549 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304550
Eric Mooreb506ade2007-01-29 09:45:37 -07004551 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304552
4553 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004554 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304555 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004556 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304557
Moore, Ericbd23e942006-04-17 12:43:04 -06004558 default:
4559 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004560 }
4561
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304562 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004563}
4564
4565static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304566mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004567{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304568 MPT_ADAPTER *ioc;
4569 struct mptsas_hotplug_event hot_plug_info;
4570 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4571 u32 device_info;
4572 u64 sas_address;
4573
4574 ioc = fw_event->ioc;
4575 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4576 fw_event->event_data;
4577 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004578
4579 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304580 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4581 MPI_SAS_DEVICE_INFO_STP_TARGET |
4582 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4583 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004584 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304585 }
4586
4587 if (sas_event_data->ReasonCode ==
4588 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4589 mptbase_sas_persist_operation(ioc,
4590 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4591 mptsas_free_fw_event(ioc, fw_event);
4592 return;
4593 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004594
Moore, Eric4b766472006-03-14 09:14:12 -07004595 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004596 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004597 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304598 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4599 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4600 hot_plug_info.channel = sas_event_data->Bus;
4601 hot_plug_info.id = sas_event_data->TargetID;
4602 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004603 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304604 sizeof(u64));
4605 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4606 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004607 if (sas_event_data->ReasonCode &
4608 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304609 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004610 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304611 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4612 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004613 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304614
Moore, Eric4b766472006-03-14 09:14:12 -07004615 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304616 mptbase_sas_persist_operation(ioc,
4617 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4618 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004619 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304620
Moore, Eric4b766472006-03-14 09:14:12 -07004621 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304622 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004623 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304624 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004625 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304626 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004627 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004628 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004629}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304630
Moore, Ericc73787ee2006-01-26 16:20:06 -07004631static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304632mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004633{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304634 MPT_ADAPTER *ioc;
4635 EVENT_DATA_RAID *raid_event_data;
4636 struct mptsas_hotplug_event hot_plug_info;
4637 int status;
4638 int state;
4639 struct scsi_device *sdev = NULL;
4640 VirtDevice *vdevice = NULL;
4641 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004642
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304643 ioc = fw_event->ioc;
4644 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4645 status = le32_to_cpu(raid_event_data->SettingsStatus);
4646 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004647
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304648 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4649 hot_plug_info.id = raid_event_data->VolumeID;
4650 hot_plug_info.channel = raid_event_data->VolumeBus;
4651 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4652
4653 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4654 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4655 raid_event_data->ReasonCode ==
4656 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4657 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4658 hot_plug_info.id, 0);
4659 hot_plug_info.sdev = sdev;
4660 if (sdev)
4661 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004662 }
4663
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304664 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4665 "ReasonCode=%02x\n", ioc->name, __func__,
4666 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004667
4668 switch (raid_event_data->ReasonCode) {
4669 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304670 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004671 break;
4672 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304673 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004674 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004675 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4676 switch (state) {
4677 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004678 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304679 mpt_raid_phys_disk_pg0(ioc,
4680 raid_event_data->PhysDiskNum, &phys_disk);
4681 hot_plug_info.id = phys_disk.PhysDiskID;
4682 hot_plug_info.channel = phys_disk.PhysDiskBus;
4683 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004684 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304685 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004686 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004687 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4688 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4689 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304690 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004691 break;
4692 default:
4693 break;
4694 }
4695 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004696 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304697 if (!sdev)
4698 break;
4699 vdevice->vtarget->deleted = 1; /* block IO */
4700 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004701 break;
4702 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304703 if (sdev) {
4704 scsi_device_put(sdev);
4705 break;
4706 }
4707 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004708 break;
4709 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304710 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4711 if (!sdev)
4712 break;
4713 vdevice->vtarget->deleted = 1; /* block IO */
4714 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4715 break;
4716 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004717 switch (state) {
4718 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4719 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304720 if (!sdev)
4721 break;
4722 vdevice->vtarget->deleted = 1; /* block IO */
4723 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004724 break;
4725 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4726 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304727 if (sdev) {
4728 scsi_device_put(sdev);
4729 break;
4730 }
4731 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004732 break;
4733 default:
4734 break;
4735 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004736 break;
4737 default:
4738 break;
4739 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304740
4741 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4742 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4743 else
4744 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004745}
4746
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304747/**
4748 * mptsas_issue_tm - send mptsas internal tm request
4749 * @ioc: Pointer to MPT_ADAPTER structure
4750 * @type: Task Management type
4751 * @channel: channel number for task management
4752 * @id: Logical Target ID for reset (if appropriate)
4753 * @lun: Logical unit for reset (if appropriate)
4754 * @task_context: Context for the task to be aborted
4755 * @timeout: timeout for task management control
4756 *
4757 * return 0 on success and -1 on failure:
4758 *
4759 */
4760static int
4761mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4762 int task_context, ulong timeout, u8 *issue_reset)
4763{
4764 MPT_FRAME_HDR *mf;
4765 SCSITaskMgmt_t *pScsiTm;
4766 int retval;
4767 unsigned long timeleft;
4768
4769 *issue_reset = 0;
4770 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4771 if (mf == NULL) {
4772 retval = -1; /* return failure */
4773 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4774 "msg frames!!\n", ioc->name));
4775 goto out;
4776 }
4777
4778 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4779 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4780 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4781 type, timeout, channel, id, (unsigned long long)lun,
4782 task_context));
4783
4784 pScsiTm = (SCSITaskMgmt_t *) mf;
4785 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4786 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4787 pScsiTm->TaskType = type;
4788 pScsiTm->MsgFlags = 0;
4789 pScsiTm->TargetID = id;
4790 pScsiTm->Bus = channel;
4791 pScsiTm->ChainOffset = 0;
4792 pScsiTm->Reserved = 0;
4793 pScsiTm->Reserved1 = 0;
4794 pScsiTm->TaskMsgContext = task_context;
4795 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4796
4797 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4798 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4799 retval = 0;
4800 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4801
4802 /* Now wait for the command to complete */
4803 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4804 timeout*HZ);
4805 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4806 retval = -1; /* return failure */
4807 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4808 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4809 mpt_free_msg_frame(ioc, mf);
4810 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4811 goto out;
4812 *issue_reset = 1;
4813 goto out;
4814 }
4815
4816 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4817 retval = -1; /* return failure */
4818 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4819 "TaskMgmt request: failed with no reply\n", ioc->name));
4820 goto out;
4821 }
4822
4823 out:
4824 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4825 return retval;
4826}
4827
4828/**
4829 * mptsas_broadcast_primative_work - Handle broadcast primitives
4830 * @work: work queue payload containing info describing the event
4831 *
4832 * this will be handled in workqueue context.
4833 */
4834static void
4835mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4836{
4837 MPT_ADAPTER *ioc = fw_event->ioc;
4838 MPT_FRAME_HDR *mf;
4839 VirtDevice *vdevice;
4840 int ii;
4841 struct scsi_cmnd *sc;
4842 SCSITaskMgmtReply_t *pScsiTmReply;
4843 u8 issue_reset;
4844 int task_context;
4845 u8 channel, id;
4846 int lun;
4847 u32 termination_count;
4848 u32 query_count;
4849
4850 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4851 "%s - enter\n", ioc->name, __func__));
4852
4853 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4854 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4855 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4856 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4857 return;
4858 }
4859
4860 issue_reset = 0;
4861 termination_count = 0;
4862 query_count = 0;
4863 mpt_findImVolumes(ioc);
4864 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4865
4866 for (ii = 0; ii < ioc->req_depth; ii++) {
4867 if (ioc->fw_events_off)
4868 goto out;
4869 sc = mptscsih_get_scsi_lookup(ioc, ii);
4870 if (!sc)
4871 continue;
4872 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4873 if (!mf)
4874 continue;
4875 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4876 vdevice = sc->device->hostdata;
4877 if (!vdevice || !vdevice->vtarget)
4878 continue;
4879 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4880 continue; /* skip hidden raid components */
4881 if (vdevice->vtarget->raidVolume)
4882 continue; /* skip hidden raid components */
4883 channel = vdevice->vtarget->channel;
4884 id = vdevice->vtarget->id;
4885 lun = vdevice->lun;
4886 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4887 channel, id, (u64)lun, task_context, 30, &issue_reset))
4888 goto out;
4889 query_count++;
4890 termination_count +=
4891 le32_to_cpu(pScsiTmReply->TerminationCount);
4892 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4893 (pScsiTmReply->ResponseCode ==
4894 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4895 pScsiTmReply->ResponseCode ==
4896 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4897 continue;
4898 if (mptsas_issue_tm(ioc,
4899 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4900 channel, id, (u64)lun, 0, 30, &issue_reset))
4901 goto out;
4902 termination_count +=
4903 le32_to_cpu(pScsiTmReply->TerminationCount);
4904 }
4905
4906 out:
4907 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4908 "%s - exit, query_count = %d termination_count = %d\n",
4909 ioc->name, __func__, query_count, termination_count));
4910
4911 ioc->broadcast_aen_busy = 0;
4912 mpt_clear_taskmgmt_in_progress_flag(ioc);
4913 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4914
4915 if (issue_reset) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09004916 printk(MYIOC_s_WARN_FMT
4917 "Issuing Reset from %s!! doorbell=0x%08x\n",
4918 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05304919 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304920 }
4921 mptsas_free_fw_event(ioc, fw_event);
4922}
4923
Eric Mooreb506ade2007-01-29 09:45:37 -07004924/*
4925 * mptsas_send_ir2_event - handle exposing hidden disk when
4926 * an inactive raid volume is added
4927 *
4928 * @ioc: Pointer to MPT_ADAPTER structure
4929 * @ir2_data
4930 *
4931 */
4932static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304933mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004934{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304935 MPT_ADAPTER *ioc;
4936 struct mptsas_hotplug_event hot_plug_info;
4937 MPI_EVENT_DATA_IR2 *ir2_data;
4938 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304939 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004940
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304941 ioc = fw_event->ioc;
4942 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4943 reasonCode = ir2_data->ReasonCode;
4944
4945 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4946 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4947
4948 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4949 hot_plug_info.id = ir2_data->TargetID;
4950 hot_plug_info.channel = ir2_data->Bus;
4951 switch (reasonCode) {
4952 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4953 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4954 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304955 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4956 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4957 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4958 break;
4959 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4960 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4961 mpt_raid_phys_disk_pg0(ioc,
4962 ir2_data->PhysDiskNum, &phys_disk);
4963 hot_plug_info.id = phys_disk.PhysDiskID;
4964 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4965 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304966 default:
4967 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004968 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304969 }
4970 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4971}
Moore, Erice6b2d762006-03-14 09:14:24 -07004972
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004973static int
4974mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4975{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304976 u32 event = le32_to_cpu(reply->Event);
4977 int sz, event_data_sz;
4978 struct fw_event_work *fw_event;
4979 unsigned long delay;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004980
Kashyap, Desaiffb7fef2010-03-18 19:20:38 +05304981 if (ioc->bus_type != SAS)
4982 return 0;
4983
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304984 /* events turned off due to host reset or driver unloading */
4985 if (ioc->fw_events_off)
4986 return 0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004987
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304988 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004989 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304990 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4991 {
4992 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4993 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4994 if (broadcast_event_data->Primitive !=
4995 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4996 return 0;
4997 if (ioc->broadcast_aen_busy)
4998 return 0;
4999 ioc->broadcast_aen_busy = 1;
5000 break;
5001 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005002 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305003 {
5004 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
5005 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305006 u16 ioc_stat;
5007 ioc_stat = le16_to_cpu(reply->IOCStatus);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305008
5009 if (sas_event_data->ReasonCode ==
5010 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
5011 mptsas_target_reset_queue(ioc, sas_event_data);
5012 return 0;
5013 }
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305014 if (sas_event_data->ReasonCode ==
5015 MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
5016 ioc->device_missing_delay &&
5017 (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) {
5018 VirtTarget *vtarget = NULL;
5019 u8 id, channel;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305020
5021 id = sas_event_data->TargetID;
5022 channel = sas_event_data->Bus;
5023
5024 vtarget = mptsas_find_vtarget(ioc, channel, id);
5025 if (vtarget) {
5026 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5027 "LogInfo (0x%x) available for "
5028 "INTERNAL_DEVICE_RESET"
5029 "fw_id %d fw_channel %d\n", ioc->name,
Borislav Petkov72ef0e52011-05-02 16:49:38 +02005030 le32_to_cpu(reply->IOCLogInfo),
5031 id, channel));
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305032 if (vtarget->raidVolume) {
5033 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5034 "Skipping Raid Volume for inDMD\n",
5035 ioc->name));
5036 } else {
5037 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5038 "Setting device flag inDMD\n",
5039 ioc->name));
5040 vtarget->inDMD = 1;
5041 }
5042
5043 }
5044
5045 }
5046
Moore, Ericc73787ee2006-01-26 16:20:06 -07005047 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305048 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305049 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
5050 {
5051 MpiEventDataSasExpanderStatusChange_t *expander_data =
5052 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
5053
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305054 if (ioc->old_sas_discovery_protocal)
5055 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305056
5057 if (expander_data->ReasonCode ==
5058 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
5059 ioc->device_missing_delay)
5060 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07005061 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305062 }
5063 case MPI_EVENT_SAS_DISCOVERY:
5064 {
5065 u32 discovery_status;
5066 EventDataSasDiscovery_t *discovery_data =
5067 (EventDataSasDiscovery_t *)reply->Data;
5068
5069 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
5070 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305071 if (ioc->old_sas_discovery_protocal && !discovery_status)
5072 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305073 return 0;
5074 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305075 case MPI_EVENT_INTEGRATED_RAID:
5076 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07005077 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305078 case MPI_EVENT_SAS_PHY_LINK_STATUS:
5079 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07005080 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005081 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305082 return 0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005083 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07005084
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305085 event_data_sz = ((reply->MsgLength * 4) -
5086 offsetof(EventNotificationReply_t, Data));
5087 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
5088 fw_event = kzalloc(sz, GFP_ATOMIC);
5089 if (!fw_event) {
5090 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
5091 __func__, __LINE__);
5092 return 0;
5093 }
5094 memcpy(fw_event->event_data, reply->Data, event_data_sz);
5095 fw_event->event = event;
5096 fw_event->ioc = ioc;
5097 mptsas_add_fw_event(ioc, fw_event, delay);
5098 return 0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005099}
5100
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305101/* Delete a volume when no longer listed in ioc pg2
5102 */
5103static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
5104{
5105 struct scsi_device *sdev;
5106 int i;
5107
5108 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
5109 if (!sdev)
5110 return;
5111 if (!ioc->raid_data.pIocPg2)
5112 goto out;
5113 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
5114 goto out;
5115 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
5116 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
5117 goto release_sdev;
5118 out:
5119 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
5120 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
5121 scsi_remove_device(sdev);
5122 release_sdev:
5123 scsi_device_put(sdev);
5124}
5125
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005126static int
5127mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
5128{
5129 struct Scsi_Host *sh;
5130 MPT_SCSI_HOST *hd;
5131 MPT_ADAPTER *ioc;
5132 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01005133 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005134 int numSGE = 0;
5135 int scale;
5136 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005137 int error=0;
5138 int r;
5139
5140 r = mpt_attach(pdev,id);
5141 if (r)
5142 return r;
5143
5144 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305145 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005146 ioc->DoneCtx = mptsasDoneCtx;
5147 ioc->TaskCtx = mptsasTaskCtx;
5148 ioc->InternalCtx = mptsasInternalCtx;
Kashyap, Desaib68bf092010-06-17 14:40:56 +05305149 ioc->schedule_target_reset = &mptsas_schedule_target_reset;
kashyap.desai@lsi.come62cca12011-08-04 16:42:15 +05305150 ioc->schedule_dead_ioc_flush_running_cmds =
5151 &mptscsih_flush_running_cmds;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005152 /* Added sanity check on readiness of the MPT adapter.
5153 */
5154 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
5155 printk(MYIOC_s_WARN_FMT
5156 "Skipping because it's not operational!\n",
5157 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005158 error = -ENODEV;
5159 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005160 }
5161
5162 if (!ioc->active) {
5163 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
5164 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005165 error = -ENODEV;
5166 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005167 }
5168
5169 /* Sanity check - ensure at least 1 port is INITIATOR capable
5170 */
5171 ioc_cap = 0;
5172 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
5173 if (ioc->pfacts[ii].ProtocolFlags &
5174 MPI_PORTFACTS_PROTOCOL_INITIATOR)
5175 ioc_cap++;
5176 }
5177
5178 if (!ioc_cap) {
5179 printk(MYIOC_s_WARN_FMT
5180 "Skipping ioc=%p because SCSI Initiator mode "
5181 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005182 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005183 }
5184
5185 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
5186 if (!sh) {
5187 printk(MYIOC_s_WARN_FMT
5188 "Unable to register controller with SCSI subsystem\n",
5189 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005190 error = -1;
5191 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005192 }
5193
5194 spin_lock_irqsave(&ioc->FreeQlock, flags);
5195
5196 /* Attach the SCSI Host to the IOC structure
5197 */
5198 ioc->sh = sh;
5199
5200 sh->io_port = 0;
5201 sh->n_io_port = 0;
5202 sh->irq = 0;
5203
5204 /* set 16 byte cdb's */
5205 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05305206 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
5207 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07005208 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005209 sh->transportt = mptsas_transport_template;
5210
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005211 /* Required entry.
5212 */
5213 sh->unique_id = ioc->id;
5214
5215 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005216 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07005217 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01005218 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005219 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005220
5221 /* Verify that we won't exceed the maximum
5222 * number of chain buffers
5223 * We can optimize: ZZ = req_sz/sizeof(SGE)
5224 * For 32bit SGE's:
5225 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
5226 * + (req_sz - 64)/sizeof(SGE)
5227 * A slightly different algorithm is required for
5228 * 64bit SGEs.
5229 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305230 scale = ioc->req_sz/ioc->SGE_size;
5231 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005232 numSGE = (scale - 1) *
5233 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305234 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005235 } else {
5236 numSGE = 1 + (scale - 1) *
5237 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305238 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005239 }
5240
5241 if (numSGE < sh->sg_tablesize) {
5242 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305243 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005244 "Resetting sg_tablesize to %d from %d\n",
5245 ioc->name, numSGE, sh->sg_tablesize));
5246 sh->sg_tablesize = numSGE;
5247 }
5248
kashyap.desai@lsi.com3850b142011-08-04 16:41:55 +05305249 if (mpt_loadtime_max_sectors) {
5250 if (mpt_loadtime_max_sectors < 64 ||
5251 mpt_loadtime_max_sectors > 8192) {
5252 printk(MYIOC_s_INFO_FMT "Invalid value passed for"
5253 "mpt_loadtime_max_sectors %d."
5254 "Range from 64 to 8192\n", ioc->name,
5255 mpt_loadtime_max_sectors);
5256 }
5257 mpt_loadtime_max_sectors &= 0xFFFFFFFE;
5258 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5259 "Resetting max sector to %d from %d\n",
5260 ioc->name, mpt_loadtime_max_sectors, sh->max_sectors));
5261 sh->max_sectors = mpt_loadtime_max_sectors;
5262 }
5263
Eric Mooree7eae9f2007-09-29 10:15:59 -06005264 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005265 hd->ioc = ioc;
5266
5267 /* SCSI needs scsi_cmnd lookup table!
5268 * (with size equal to req_depth*PtrSz!)
5269 */
Eric Mooree8206382007-09-29 10:16:53 -06005270 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5271 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005272 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06005273 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005274 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005275 }
Eric Mooree8206382007-09-29 10:16:53 -06005276 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005277
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305278 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06005279 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005280
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005281 ioc->sas_data.ptClear = mpt_pt_clear;
5282
Eric Mooredf9e0622007-01-29 09:46:21 -07005283 hd->last_queue_full = 0;
5284 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305285 INIT_LIST_HEAD(&ioc->sas_device_info_list);
5286 mutex_init(&ioc->sas_device_info_mutex);
5287
Eric Mooredf9e0622007-01-29 09:46:21 -07005288 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5289
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005290 if (ioc->sas_data.ptClear==1) {
5291 mptbase_sas_persist_operation(
5292 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5293 }
5294
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005295 error = scsi_add_host(sh, &ioc->pcidev->dev);
5296 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06005297 dprintk(ioc, printk(MYIOC_s_ERR_FMT
5298 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005299 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005300 }
5301
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305302 /* older firmware doesn't support expander events */
5303 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5304 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005305 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305306 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005307 return 0;
5308
Eric Moore547f9a22006-06-27 14:42:12 -06005309 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005310
5311 mptscsih_remove(pdev);
5312 return error;
5313}
5314
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305315void
5316mptsas_shutdown(struct pci_dev *pdev)
5317{
5318 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5319
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305320 mptsas_fw_event_off(ioc);
5321 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305322}
5323
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005324static void __devexit mptsas_remove(struct pci_dev *pdev)
5325{
5326 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5327 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06005328 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005329
Kashyap, Desai48959f12010-03-18 19:18:30 +05305330 if (!ioc->sh) {
5331 printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
5332 mpt_detach(pdev);
5333 return;
5334 }
5335
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305336 mptsas_shutdown(pdev);
5337
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305338 mptsas_del_device_components(ioc);
5339
Eric Mooreb506ade2007-01-29 09:45:37 -07005340 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005341 sas_remove_host(ioc->sh);
5342
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005343 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005344 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5345 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06005346 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305347 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305348
Eric Moore547f9a22006-06-27 14:42:12 -06005349 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005350 kfree(p);
5351 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005352 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305353 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005354 mptscsih_remove(pdev);
5355}
5356
5357static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06005358 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005359 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005360 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005361 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005362 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
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_SAS1068E,
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_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005367 PCI_ANY_ID, PCI_ANY_ID },
5368 {0} /* Terminating entry */
5369};
5370MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5371
5372
5373static struct pci_driver mptsas_driver = {
5374 .name = "mptsas",
5375 .id_table = mptsas_pci_table,
5376 .probe = mptsas_probe,
5377 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305378 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005379#ifdef CONFIG_PM
5380 .suspend = mptscsih_suspend,
5381 .resume = mptscsih_resume,
5382#endif
5383};
5384
5385static int __init
5386mptsas_init(void)
5387{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305388 int error;
5389
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005390 show_mptmod_ver(my_NAME, my_VERSION);
5391
5392 mptsas_transport_template =
5393 sas_attach_transport(&mptsas_transport_functions);
5394 if (!mptsas_transport_template)
5395 return -ENODEV;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305396 mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005397
Kashyap, Desai213aaca2010-07-26 18:57:36 +05305398 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER,
5399 "mptscsih_io_done");
5400 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER,
5401 "mptscsih_taskmgmt_complete");
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005402 mptsasInternalCtx =
Kashyap, Desai213aaca2010-07-26 18:57:36 +05305403 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER,
5404 "mptscsih_scandv_complete");
5405 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER,
5406 "mptsas_mgmt_done");
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305407 mptsasDeviceResetCtx =
Kashyap, Desai213aaca2010-07-26 18:57:36 +05305408 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER,
5409 "mptsas_taskmgmt_complete");
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005410
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305411 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5412 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005413
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305414 error = pci_register_driver(&mptsas_driver);
5415 if (error)
5416 sas_release_transport(mptsas_transport_template);
5417
5418 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005419}
5420
5421static void __exit
5422mptsas_exit(void)
5423{
5424 pci_unregister_driver(&mptsas_driver);
5425 sas_release_transport(mptsas_transport_template);
5426
5427 mpt_reset_deregister(mptsasDoneCtx);
5428 mpt_event_deregister(mptsasDoneCtx);
5429
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005430 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005431 mpt_deregister(mptsasInternalCtx);
5432 mpt_deregister(mptsasTaskCtx);
5433 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305434 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005435}
5436
5437module_init(mptsas_init);
5438module_exit(mptsas_exit);