blob: 10a12d846e85cc9ac800ab393d73f7f0f25b8fbc [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>
48#include <linux/init.h>
49#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080050#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020051#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060052#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020053
Eric Moore547f9a22006-06-27 14:42:12 -060054#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020055#include <scsi/scsi_cmnd.h>
56#include <scsi/scsi_device.h>
57#include <scsi/scsi_host.h>
58#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060059#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020060
61#include "mptbase.h"
62#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053063#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020064
65
66#define my_NAME "Fusion MPT SAS Host driver"
67#define my_VERSION MPT_LINUX_VERSION_COMMON
68#define MYNAM "mptsas"
69
James Bottomleye8bf3942006-07-11 17:49:34 -040070/*
71 * Reserved channel for integrated raid
72 */
73#define MPTSAS_RAID_CHANNEL 1
74
Christoph Hellwig0c33b272005-09-09 16:27:19 +020075MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020079
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080static int mpt_pt_clear;
81module_param(mpt_pt_clear, int, 0);
82MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060083 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020084 "(default=MPTSCSIH_PT_CLEAR=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
87#define MPTSAS_MAX_LUN (16895)
88static int max_lun = MPTSAS_MAX_LUN;
89module_param(max_lun, int, 0);
90MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
91
Prakash, Sathyaf606f572007-08-14 16:12:53 +053092static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
93static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
95static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053096static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020097
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +053098static void mptsas_firmware_event_work(struct work_struct *work);
99static void mptsas_send_sas_event(struct fw_event_work *fw_event);
100static void mptsas_send_raid_event(struct fw_event_work *fw_event);
101static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
102static void mptsas_parse_device_info(struct sas_identify *identify,
103 struct mptsas_devinfo *device_info);
104static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
105 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
106static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
107 (MPT_ADAPTER *ioc, u64 sas_address);
108static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
109 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
110static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
111 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
112static int mptsas_add_end_device(MPT_ADAPTER *ioc,
113 struct mptsas_phyinfo *phy_info);
114static void mptsas_del_end_device(MPT_ADAPTER *ioc,
115 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530116static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
117static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
118 (MPT_ADAPTER *ioc, u64 sas_address);
119static void mptsas_expander_delete(MPT_ADAPTER *ioc,
120 struct mptsas_portinfo *port_info, u8 force);
121static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530122static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
123static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
Kashyap, Desai57e98512009-05-29 16:55:09 +0530124static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530125static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200126
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530127static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
128 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200129{
Eric Moore29dd3602007-09-14 18:46:51 -0600130 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
131 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
132 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
133 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
134 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
135 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
136 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
137 ioc->name, phy_data->Port));
138 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
139 ioc->name, phy_data->PortFlags));
140 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
141 ioc->name, phy_data->PhyFlags));
142 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
143 ioc->name, phy_data->NegotiatedLinkRate));
144 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
145 "Controller PHY Device Info=0x%X\n", ioc->name,
146 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
147 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
148 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200149}
150
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530151static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200152{
153 __le64 sas_address;
154
155 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
156
Eric Moore29dd3602007-09-14 18:46:51 -0600157 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
158 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
159 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
160 "Attached Device Handle=0x%X\n", ioc->name,
161 le16_to_cpu(pg0->AttachedDevHandle)));
162 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
163 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
164 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
165 "Attached PHY Identifier=0x%X\n", ioc->name,
166 pg0->AttachedPhyIdentifier));
167 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
168 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
169 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
170 ioc->name, pg0->ProgrammedLinkRate));
171 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
172 ioc->name, pg0->ChangeCount));
173 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
174 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200175}
176
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530177static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200178{
Eric Moore29dd3602007-09-14 18:46:51 -0600179 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
180 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
181 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
182 ioc->name, pg1->InvalidDwordCount));
183 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
184 "Running Disparity Error Count=0x%x\n", ioc->name,
185 pg1->RunningDisparityErrorCount));
186 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
187 "Loss Dword Synch Count=0x%x\n", ioc->name,
188 pg1->LossDwordSynchCount));
189 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
190 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
191 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200192}
193
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530194static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200195{
196 __le64 sas_address;
197
198 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
199
Eric Moore29dd3602007-09-14 18:46:51 -0600200 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
201 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
202 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
203 ioc->name, le16_to_cpu(pg0->DevHandle)));
204 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
205 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
206 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
207 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
208 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
209 ioc->name, le16_to_cpu(pg0->Slot)));
210 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
211 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
212 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
213 ioc->name, pg0->TargetID));
214 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
215 ioc->name, pg0->Bus));
216 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
217 ioc->name, pg0->PhyNum));
218 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
219 ioc->name, le16_to_cpu(pg0->AccessStatus)));
220 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
221 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
222 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
223 ioc->name, le16_to_cpu(pg0->Flags)));
224 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
225 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200226}
227
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530228static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200229{
Eric Moore29dd3602007-09-14 18:46:51 -0600230 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
231 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
232 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
233 ioc->name, pg1->PhysicalPort));
234 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
235 ioc->name, pg1->PhyIdentifier));
236 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
237 ioc->name, pg1->NegotiatedLinkRate));
238 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
239 ioc->name, pg1->ProgrammedLinkRate));
240 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
241 ioc->name, pg1->HwLinkRate));
242 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
243 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
244 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
245 "Attached Device Handle=0x%X\n\n", ioc->name,
246 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200247}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200248
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530249/* inhibit sas firmware event handling */
250static void
251mptsas_fw_event_off(MPT_ADAPTER *ioc)
252{
253 unsigned long flags;
254
255 spin_lock_irqsave(&ioc->fw_event_lock, flags);
256 ioc->fw_events_off = 1;
257 ioc->sas_discovery_quiesce_io = 0;
258 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
259
260}
261
262/* enable sas firmware event handling */
263static void
264mptsas_fw_event_on(MPT_ADAPTER *ioc)
265{
266 unsigned long flags;
267
268 spin_lock_irqsave(&ioc->fw_event_lock, flags);
269 ioc->fw_events_off = 0;
270 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
271}
272
273/* queue a sas firmware event */
274static void
275mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
276 unsigned long delay)
277{
278 unsigned long flags;
279
280 spin_lock_irqsave(&ioc->fw_event_lock, flags);
281 list_add_tail(&fw_event->list, &ioc->fw_event_list);
282 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
283 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
284 ioc->name, __func__, fw_event));
285 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
286 delay);
287 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
288}
289
290/* free memory assoicated to a sas firmware event */
291static void
292mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
293{
294 unsigned long flags;
295
296 spin_lock_irqsave(&ioc->fw_event_lock, flags);
297 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
298 ioc->name, __func__, fw_event));
299 list_del(&fw_event->list);
300 kfree(fw_event);
301 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
302}
303
304/* walk the firmware event queue, and either stop or wait for
305 * outstanding events to complete */
306static void
307mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
308{
309 struct fw_event_work *fw_event, *next;
310 struct mptsas_target_reset_event *target_reset_list, *n;
311 u8 flush_q;
312 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
313
314 /* flush the target_reset_list */
315 if (!list_empty(&hd->target_reset_list)) {
316 list_for_each_entry_safe(target_reset_list, n,
317 &hd->target_reset_list, list) {
318 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
319 "%s: removing target reset for id=%d\n",
320 ioc->name, __func__,
321 target_reset_list->sas_event_data.TargetID));
322 list_del(&target_reset_list->list);
323 kfree(target_reset_list);
324 }
325 }
326
327 if (list_empty(&ioc->fw_event_list) ||
328 !ioc->fw_event_q || in_interrupt())
329 return;
330
331 flush_q = 0;
332 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
333 if (cancel_delayed_work(&fw_event->work))
334 mptsas_free_fw_event(ioc, fw_event);
335 else
336 flush_q = 1;
337 }
338 if (flush_q)
339 flush_workqueue(ioc->fw_event_q);
340}
341
342
Christoph Hellwige3094442006-02-16 13:25:36 +0100343static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
344{
345 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
346 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
347}
348
349static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
350{
351 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
352 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
353}
354
Moore, Erice6b2d762006-03-14 09:14:24 -0700355/*
356 * mptsas_find_portinfo_by_handle
357 *
358 * This function should be called with the sas_topology_mutex already held
359 */
360static struct mptsas_portinfo *
361mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
362{
363 struct mptsas_portinfo *port_info, *rc=NULL;
364 int i;
365
366 list_for_each_entry(port_info, &ioc->sas_topology, list)
367 for (i = 0; i < port_info->num_phys; i++)
368 if (port_info->phy_info[i].identify.handle == handle) {
369 rc = port_info;
370 goto out;
371 }
372 out:
373 return rc;
374}
375
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530376/**
377 * mptsas_find_portinfo_by_sas_address -
378 * @ioc: Pointer to MPT_ADAPTER structure
379 * @handle:
380 *
381 * This function should be called with the sas_topology_mutex already held
382 *
383 **/
384static struct mptsas_portinfo *
385mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
386{
387 struct mptsas_portinfo *port_info, *rc = NULL;
388 int i;
389
390 if (sas_address >= ioc->hba_port_sas_addr &&
391 sas_address < (ioc->hba_port_sas_addr +
392 ioc->hba_port_num_phy))
393 return ioc->hba_port_info;
394
395 mutex_lock(&ioc->sas_topology_mutex);
396 list_for_each_entry(port_info, &ioc->sas_topology, list)
397 for (i = 0; i < port_info->num_phys; i++)
398 if (port_info->phy_info[i].identify.sas_address ==
399 sas_address) {
400 rc = port_info;
401 goto out;
402 }
403 out:
404 mutex_unlock(&ioc->sas_topology_mutex);
405 return rc;
406}
407
Moore, Ericbd23e942006-04-17 12:43:04 -0600408/*
409 * Returns true if there is a scsi end device
410 */
411static inline int
412mptsas_is_end_device(struct mptsas_devinfo * attached)
413{
Eric Moore547f9a22006-06-27 14:42:12 -0600414 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600415 (attached->device_info &
416 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
417 ((attached->device_info &
418 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
419 (attached->device_info &
420 MPI_SAS_DEVICE_INFO_STP_TARGET) |
421 (attached->device_info &
422 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
423 return 1;
424 else
425 return 0;
426}
427
Eric Moore547f9a22006-06-27 14:42:12 -0600428/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600429static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530430mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600431{
432 struct mptsas_portinfo *port_info;
433 struct mptsas_phyinfo *phy_info;
434 u8 i;
435
436 if (!port_details)
437 return;
438
439 port_info = port_details->port_info;
440 phy_info = port_info->phy_info;
441
Eric Moore29dd3602007-09-14 18:46:51 -0600442 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700443 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700444 port_details->num_phys, (unsigned long long)
445 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600446
447 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
448 if(phy_info->port_details != port_details)
449 continue;
450 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530451 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600452 phy_info->port_details = NULL;
453 }
454 kfree(port_details);
455}
456
457static inline struct sas_rphy *
458mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
459{
460 if (phy_info->port_details)
461 return phy_info->port_details->rphy;
462 else
463 return NULL;
464}
465
466static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530467mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600468{
469 if (phy_info->port_details) {
470 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600471 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
472 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600473 }
474
Eric Moore547f9a22006-06-27 14:42:12 -0600475 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600476 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
477 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600478 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
479 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600480 }
Eric Moore547f9a22006-06-27 14:42:12 -0600481}
482
483static inline struct sas_port *
484mptsas_get_port(struct mptsas_phyinfo *phy_info)
485{
486 if (phy_info->port_details)
487 return phy_info->port_details->port;
488 else
489 return NULL;
490}
491
492static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530493mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600494{
495 if (phy_info->port_details)
496 phy_info->port_details->port = port;
497
Eric Moore547f9a22006-06-27 14:42:12 -0600498 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600499 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
500 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600501 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
502 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600503 }
Eric Moore547f9a22006-06-27 14:42:12 -0600504}
505
506static inline struct scsi_target *
507mptsas_get_starget(struct mptsas_phyinfo *phy_info)
508{
509 if (phy_info->port_details)
510 return phy_info->port_details->starget;
511 else
512 return NULL;
513}
514
515static inline void
516mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
517starget)
518{
519 if (phy_info->port_details)
520 phy_info->port_details->starget = starget;
521}
522
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530523/**
524 * mptsas_add_device_component -
525 * @ioc: Pointer to MPT_ADAPTER structure
526 * @channel: fw mapped id's
527 * @id:
528 * @sas_address:
529 * @device_info:
530 *
531 **/
532static void
533mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
534 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
535{
536 struct mptsas_device_info *sas_info, *next;
537 struct scsi_device *sdev;
538 struct scsi_target *starget;
539 struct sas_rphy *rphy;
540
541 /*
542 * Delete all matching devices out of the list
543 */
544 mutex_lock(&ioc->sas_device_info_mutex);
545 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
546 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530547 if (!sas_info->is_logical_volume &&
548 (sas_info->sas_address == sas_address ||
549 (sas_info->fw.channel == channel &&
550 sas_info->fw.id == id))) {
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530551 list_del(&sas_info->list);
552 kfree(sas_info);
553 }
554 }
555
556 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
557 if (!sas_info)
558 goto out;
559
560 /*
561 * Set Firmware mapping
562 */
563 sas_info->fw.id = id;
564 sas_info->fw.channel = channel;
565
566 sas_info->sas_address = sas_address;
567 sas_info->device_info = device_info;
568 sas_info->slot = slot;
569 sas_info->enclosure_logical_id = enclosure_logical_id;
570 INIT_LIST_HEAD(&sas_info->list);
571 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
572
573 /*
574 * Set OS mapping
575 */
576 shost_for_each_device(sdev, ioc->sh) {
577 starget = scsi_target(sdev);
578 rphy = dev_to_rphy(starget->dev.parent);
579 if (rphy->identify.sas_address == sas_address) {
580 sas_info->os.id = starget->id;
581 sas_info->os.channel = starget->channel;
582 }
583 }
584
585 out:
586 mutex_unlock(&ioc->sas_device_info_mutex);
587 return;
588}
589
590/**
591 * mptsas_add_device_component_by_fw -
592 * @ioc: Pointer to MPT_ADAPTER structure
593 * @channel: fw mapped id's
594 * @id:
595 *
596 **/
597static void
598mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
599{
600 struct mptsas_devinfo sas_device;
601 struct mptsas_enclosure enclosure_info;
602 int rc;
603
604 rc = mptsas_sas_device_pg0(ioc, &sas_device,
605 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
606 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
607 (channel << 8) + id);
608 if (rc)
609 return;
610
611 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
612 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
613 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
614 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
615 sas_device.handle_enclosure);
616
617 mptsas_add_device_component(ioc, sas_device.channel,
618 sas_device.id, sas_device.sas_address, sas_device.device_info,
619 sas_device.slot, enclosure_info.enclosure_logical_id);
620}
621
622/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530623 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding
624 * each individual device to list
625 * @ioc: Pointer to MPT_ADAPTER structure
626 * @channel: fw mapped id's
627 * @id:
628 *
629 **/
630static void
631mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
632 struct scsi_target *starget)
633{
634 CONFIGPARMS cfg;
635 ConfigPageHeader_t hdr;
636 dma_addr_t dma_handle;
637 pRaidVolumePage0_t buffer = NULL;
638 int i;
639 RaidPhysDiskPage0_t phys_disk;
640 struct mptsas_device_info *sas_info, *next;
641
642 memset(&cfg, 0 , sizeof(CONFIGPARMS));
643 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
644 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
645 /* assumption that all volumes on channel = 0 */
646 cfg.pageAddr = starget->id;
647 cfg.cfghdr.hdr = &hdr;
648 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
649 cfg.timeout = 10;
650
651 if (mpt_config(ioc, &cfg) != 0)
652 goto out;
653
654 if (!hdr.PageLength)
655 goto out;
656
657 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
658 &dma_handle);
659
660 if (!buffer)
661 goto out;
662
663 cfg.physAddr = dma_handle;
664 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
665
666 if (mpt_config(ioc, &cfg) != 0)
667 goto out;
668
669 if (!buffer->NumPhysDisks)
670 goto out;
671
672 /*
673 * Adding entry for hidden components
674 */
675 for (i = 0; i < buffer->NumPhysDisks; i++) {
676
677 if (mpt_raid_phys_disk_pg0(ioc,
678 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
679 continue;
680
681 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
682 phys_disk.PhysDiskID);
683
Kashyap, Desai57e98512009-05-29 16:55:09 +0530684 mutex_lock(&ioc->sas_device_info_mutex);
685 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
686 list) {
687 if (!sas_info->is_logical_volume &&
688 (sas_info->fw.channel == phys_disk.PhysDiskBus &&
689 sas_info->fw.id == phys_disk.PhysDiskID)) {
690 sas_info->is_hidden_raid_component = 1;
691 sas_info->volume_id = starget->id;
692 }
693 }
694 mutex_unlock(&ioc->sas_device_info_mutex);
695
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530696 }
697
698 /*
699 * Delete all matching devices out of the list
700 */
701 mutex_lock(&ioc->sas_device_info_mutex);
702 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
703 list) {
704 if (sas_info->is_logical_volume && sas_info->fw.id ==
705 starget->id) {
706 list_del(&sas_info->list);
707 kfree(sas_info);
708 }
709 }
710
711 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
712 if (sas_info) {
713 sas_info->fw.id = starget->id;
714 sas_info->os.id = starget->id;
715 sas_info->os.channel = starget->channel;
716 sas_info->is_logical_volume = 1;
717 INIT_LIST_HEAD(&sas_info->list);
718 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
719 }
720 mutex_unlock(&ioc->sas_device_info_mutex);
721
722 out:
723 if (buffer)
724 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
725 dma_handle);
726}
727
728/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530729 * mptsas_add_device_component_starget -
730 * @ioc: Pointer to MPT_ADAPTER structure
731 * @starget:
732 *
733 **/
734static void
735mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
736 struct scsi_target *starget)
737{
738 VirtTarget *vtarget;
739 struct sas_rphy *rphy;
740 struct mptsas_phyinfo *phy_info = NULL;
741 struct mptsas_enclosure enclosure_info;
742
743 rphy = dev_to_rphy(starget->dev.parent);
744 vtarget = starget->hostdata;
745 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
746 rphy->identify.sas_address);
747 if (!phy_info)
748 return;
749
750 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
751 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
752 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
753 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
754 phy_info->attached.handle_enclosure);
755
756 mptsas_add_device_component(ioc, phy_info->attached.channel,
757 phy_info->attached.id, phy_info->attached.sas_address,
758 phy_info->attached.device_info,
759 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
760}
761
762/**
Kashyap, Desai57e98512009-05-29 16:55:09 +0530763 * mptsas_del_device_component_by_os - Once a device has been removed, we
764 * mark the entry in the list as being cached
765 * @ioc: Pointer to MPT_ADAPTER structure
766 * @channel: os mapped id's
767 * @id:
768 *
769 **/
770static void
771mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
772{
773 struct mptsas_device_info *sas_info, *next;
774
775 /*
776 * Set is_cached flag
777 */
778 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
779 list) {
780 if (sas_info->os.channel == channel && sas_info->os.id == id)
781 sas_info->is_cached = 1;
782 }
783}
784
785/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530786 * mptsas_del_device_components - Cleaning the list
787 * @ioc: Pointer to MPT_ADAPTER structure
788 *
789 **/
790static void
791mptsas_del_device_components(MPT_ADAPTER *ioc)
792{
793 struct mptsas_device_info *sas_info, *next;
794
795 mutex_lock(&ioc->sas_device_info_mutex);
796 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
797 list) {
798 list_del(&sas_info->list);
799 kfree(sas_info);
800 }
801 mutex_unlock(&ioc->sas_device_info_mutex);
802}
803
Eric Moore547f9a22006-06-27 14:42:12 -0600804
805/*
806 * mptsas_setup_wide_ports
807 *
808 * Updates for new and existing narrow/wide port configuration
809 * in the sas_topology
810 */
Eric Moore376ac832006-06-29 17:36:26 -0600811static void
Eric Moore547f9a22006-06-27 14:42:12 -0600812mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
813{
814 struct mptsas_portinfo_details * port_details;
815 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
816 u64 sas_address;
817 int i, j;
818
819 mutex_lock(&ioc->sas_topology_mutex);
820
821 phy_info = port_info->phy_info;
822 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
823 if (phy_info->attached.handle)
824 continue;
825 port_details = phy_info->port_details;
826 if (!port_details)
827 continue;
828 if (port_details->num_phys < 2)
829 continue;
830 /*
831 * Removing a phy from a port, letting the last
832 * phy be removed by firmware events.
833 */
Eric Moore29dd3602007-09-14 18:46:51 -0600834 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
835 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700836 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600837 port_details->num_phys--;
838 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
839 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
840 sas_port_delete_phy(port_details->port, phy_info->phy);
841 phy_info->port_details = NULL;
842 }
843
844 /*
845 * Populate and refresh the tree
846 */
847 phy_info = port_info->phy_info;
848 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
849 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600850 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
851 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600852 if (!sas_address)
853 continue;
854 port_details = phy_info->port_details;
855 /*
856 * Forming a port
857 */
858 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530859 port_details = kzalloc(sizeof(struct
860 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600861 if (!port_details)
862 goto out;
863 port_details->num_phys = 1;
864 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600865 if (phy_info->phy_id < 64 )
866 port_details->phy_bitmask |=
867 (1 << phy_info->phy_id);
868 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600869 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700870 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600871 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600872 phy_info->port_details = port_details;
873 }
874
875 if (i == port_info->num_phys - 1)
876 continue;
877 phy_info_cmp = &port_info->phy_info[i + 1];
878 for (j = i + 1 ; j < port_info->num_phys ; j++,
879 phy_info_cmp++) {
880 if (!phy_info_cmp->attached.sas_address)
881 continue;
882 if (sas_address != phy_info_cmp->attached.sas_address)
883 continue;
884 if (phy_info_cmp->port_details == port_details )
885 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600886 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700887 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600888 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700889 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600890 if (phy_info_cmp->port_details) {
891 port_details->rphy =
892 mptsas_get_rphy(phy_info_cmp);
893 port_details->port =
894 mptsas_get_port(phy_info_cmp);
895 port_details->starget =
896 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600897 port_details->num_phys =
898 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600899 if (!phy_info_cmp->port_details->num_phys)
900 kfree(phy_info_cmp->port_details);
901 } else
902 phy_info_cmp->sas_port_add_phy=1;
903 /*
904 * Adding a phy to a port
905 */
906 phy_info_cmp->port_details = port_details;
907 if (phy_info_cmp->phy_id < 64 )
908 port_details->phy_bitmask |=
909 (1 << phy_info_cmp->phy_id);
910 port_details->num_phys++;
911 }
912 }
913
914 out:
915
Eric Moore547f9a22006-06-27 14:42:12 -0600916 for (i = 0; i < port_info->num_phys; i++) {
917 port_details = port_info->phy_info[i].port_details;
918 if (!port_details)
919 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600920 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700921 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700922 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700923 port_details, i, port_details->num_phys,
924 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600925 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
926 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600927 }
Eric Moore29dd3602007-09-14 18:46:51 -0600928 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600929 mutex_unlock(&ioc->sas_topology_mutex);
930}
931
Eric Mooredf9e0622007-01-29 09:46:21 -0700932/**
933 * csmisas_find_vtarget
934 *
935 * @ioc
936 * @volume_id
937 * @volume_bus
938 *
939 **/
940static VirtTarget *
941mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600942{
Eric Mooredf9e0622007-01-29 09:46:21 -0700943 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600944 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700945 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600946
Eric Mooredf9e0622007-01-29 09:46:21 -0700947 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530948 vdevice = sdev->hostdata;
949 if ((vdevice == NULL) ||
950 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700951 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530952 if ((vdevice->vtarget->tflags &
953 MPT_TARGET_FLAGS_RAID_COMPONENT ||
954 vdevice->vtarget->raidVolume))
955 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600956 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530957 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600958 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600959 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700960 return vtarget;
961}
962
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530963static void
964mptsas_queue_device_delete(MPT_ADAPTER *ioc,
965 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
966{
967 struct fw_event_work *fw_event;
968 int sz;
969
970 sz = offsetof(struct fw_event_work, event_data) +
971 sizeof(MpiEventDataSasDeviceStatusChange_t);
972 fw_event = kzalloc(sz, GFP_ATOMIC);
973 if (!fw_event) {
974 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
975 ioc->name, __func__, __LINE__);
976 return;
977 }
978 memcpy(fw_event->event_data, sas_event_data,
979 sizeof(MpiEventDataSasDeviceStatusChange_t));
980 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
981 fw_event->ioc = ioc;
982 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
983}
984
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530985static void
986mptsas_queue_rescan(MPT_ADAPTER *ioc)
987{
988 struct fw_event_work *fw_event;
989 int sz;
990
991 sz = offsetof(struct fw_event_work, event_data);
992 fw_event = kzalloc(sz, GFP_ATOMIC);
993 if (!fw_event) {
994 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
995 ioc->name, __func__, __LINE__);
996 return;
997 }
998 fw_event->event = -1;
999 fw_event->ioc = ioc;
1000 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1001}
1002
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301003
Eric Mooredf9e0622007-01-29 09:46:21 -07001004/**
1005 * mptsas_target_reset
1006 *
1007 * Issues TARGET_RESET to end device using handshaking method
1008 *
1009 * @ioc
1010 * @channel
1011 * @id
1012 *
1013 * Returns (1) success
1014 * (0) failure
1015 *
1016 **/
1017static int
1018mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1019{
1020 MPT_FRAME_HDR *mf;
1021 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301022 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1023 return 0;
1024
Eric Mooredf9e0622007-01-29 09:46:21 -07001025
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301026 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1027 if (mf == NULL) {
1028 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301029 "%s, no msg frames @%d!!\n", ioc->name,
1030 __func__, __LINE__));
1031 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001032 }
1033
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301034 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1035 ioc->name, mf));
1036
Eric Mooredf9e0622007-01-29 09:46:21 -07001037 /* Format the Request
1038 */
1039 pScsiTm = (SCSITaskMgmt_t *) mf;
1040 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1041 pScsiTm->TargetID = id;
1042 pScsiTm->Bus = channel;
1043 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1044 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1045 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1046
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301047 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001048
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301049 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1050 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1051 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1052
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301053 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001054
1055 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301056
1057 out_fail:
1058
1059 mpt_clear_taskmgmt_in_progress_flag(ioc);
1060 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001061}
1062
1063/**
1064 * mptsas_target_reset_queue
1065 *
1066 * Receive request for TARGET_RESET after recieving an firmware
1067 * event NOT_RESPONDING_EVENT, then put command in link list
1068 * and queue if task_queue already in use.
1069 *
1070 * @ioc
1071 * @sas_event_data
1072 *
1073 **/
1074static void
1075mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1076 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1077{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001078 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001079 VirtTarget *vtarget = NULL;
1080 struct mptsas_target_reset_event *target_reset_list;
1081 u8 id, channel;
1082
1083 id = sas_event_data->TargetID;
1084 channel = sas_event_data->Bus;
1085
1086 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
1087 return;
1088
1089 vtarget->deleted = 1; /* block IO */
1090
Kashyap, Desai2f187862009-05-29 16:52:37 +05301091 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001092 GFP_ATOMIC);
1093 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301094 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1095 "%s, failed to allocate mem @%d..!!\n",
1096 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001097 return;
1098 }
1099
1100 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1101 sizeof(*sas_event_data));
1102 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1103
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301104 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001105
1106 if (mptsas_target_reset(ioc, channel, id)) {
1107 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001108 }
1109}
1110
1111/**
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301112 * mptsas_taskmgmt_complete - Completion for TARGET_RESET after
1113 * NOT_RESPONDING_EVENT, enable work queue to finish off removing device
1114 * from upper layers. then send next TARGET_RESET in the queue.
1115 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001116 *
1117 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301118static int
1119mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001120{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001121 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001122 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001123 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301124 struct mptsas_target_reset_event *target_reset_list;
1125 SCSITaskMgmtReply_t *pScsiTmReply;
1126
1127 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1128 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1129
1130 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1131 if (pScsiTmReply) {
1132 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1133 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1134 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1135 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1136 "term_cmnds = %d\n", ioc->name,
1137 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1138 pScsiTmReply->TaskType,
1139 le16_to_cpu(pScsiTmReply->IOCStatus),
1140 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1141 pScsiTmReply->ResponseCode,
1142 le32_to_cpu(pScsiTmReply->TerminationCount)));
1143
1144 if (pScsiTmReply->ResponseCode)
1145 mptscsih_taskmgmt_response_code(ioc,
1146 pScsiTmReply->ResponseCode);
1147 }
1148
1149 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1150 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1151 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1152 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1153 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1154 memcpy(ioc->taskmgmt_cmds.reply, mr,
1155 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1156 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1157 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1158 complete(&ioc->taskmgmt_cmds.done);
1159 return 1;
1160 }
1161 return 0;
1162 }
1163
1164 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001165
1166 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301167 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001168
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301169 target_reset_list = list_entry(head->next,
1170 struct mptsas_target_reset_event, list);
1171
1172 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1173 "TaskMgmt: completed (%d seconds)\n",
1174 ioc->name, jiffies_to_msecs(jiffies -
1175 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001176
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301177 id = pScsiTmReply->TargetID;
1178 channel = pScsiTmReply->Bus;
1179 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001180
1181 /*
1182 * retry target reset
1183 */
1184 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301185 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001186 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301187 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001188 }
1189
1190 /*
1191 * enable work queue to remove device from upper layers
1192 */
1193 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301194 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1195 mptsas_queue_device_delete(ioc,
1196 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301197
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301198
Eric Mooredf9e0622007-01-29 09:46:21 -07001199 /*
1200 * issue target reset to next device in the queue
1201 */
1202
1203 head = &hd->target_reset_list;
1204 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301205 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001206
1207 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1208 list);
1209
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301210 id = target_reset_list->sas_event_data.TargetID;
1211 channel = target_reset_list->sas_event_data.Bus;
1212 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001213
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301214 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001215 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001216
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301217 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001218}
1219
1220/**
1221 * mptscsih_ioc_reset
1222 *
1223 * @ioc
1224 * @reset_phase
1225 *
1226 **/
1227static int
1228mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1229{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001230 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001231 int rc;
1232
1233 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301234 if ((ioc->bus_type != SAS) || (!rc))
1235 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001236
Eric Mooree7eae9f2007-09-29 10:15:59 -06001237 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001238 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001239 goto out;
1240
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301241 switch (reset_phase) {
1242 case MPT_IOC_SETUP_RESET:
1243 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1244 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1245 mptsas_fw_event_off(ioc);
1246 break;
1247 case MPT_IOC_PRE_RESET:
1248 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1249 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1250 break;
1251 case MPT_IOC_POST_RESET:
1252 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1253 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1254 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1255 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1256 complete(&ioc->sas_mgmt.done);
1257 }
1258 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301259 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301260 mptsas_fw_event_on(ioc);
1261 break;
1262 default:
1263 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001264 }
1265
1266 out:
1267 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001268}
1269
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301270
1271/**
1272 * enum device_state -
1273 * @DEVICE_RETRY: need to retry the TUR
1274 * @DEVICE_ERROR: TUR return error, don't add device
1275 * @DEVICE_READY: device can be added
1276 *
1277 */
1278enum device_state{
1279 DEVICE_RETRY,
1280 DEVICE_ERROR,
1281 DEVICE_READY,
1282};
1283
Christoph Hellwige3094442006-02-16 13:25:36 +01001284static int
Moore, Eric52435432006-03-14 09:14:15 -07001285mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001286 u32 form, u32 form_specific)
1287{
1288 ConfigExtendedPageHeader_t hdr;
1289 CONFIGPARMS cfg;
1290 SasEnclosurePage0_t *buffer;
1291 dma_addr_t dma_handle;
1292 int error;
1293 __le64 le_identifier;
1294
1295 memset(&hdr, 0, sizeof(hdr));
1296 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1297 hdr.PageNumber = 0;
1298 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1299 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1300
1301 cfg.cfghdr.ehdr = &hdr;
1302 cfg.physAddr = -1;
1303 cfg.pageAddr = form + form_specific;
1304 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1305 cfg.dir = 0; /* read */
1306 cfg.timeout = 10;
1307
1308 error = mpt_config(ioc, &cfg);
1309 if (error)
1310 goto out;
1311 if (!hdr.ExtPageLength) {
1312 error = -ENXIO;
1313 goto out;
1314 }
1315
1316 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1317 &dma_handle);
1318 if (!buffer) {
1319 error = -ENOMEM;
1320 goto out;
1321 }
1322
1323 cfg.physAddr = dma_handle;
1324 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1325
1326 error = mpt_config(ioc, &cfg);
1327 if (error)
1328 goto out_free_consistent;
1329
1330 /* save config data */
1331 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1332 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1333 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1334 enclosure->flags = le16_to_cpu(buffer->Flags);
1335 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1336 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1337 enclosure->start_id = buffer->StartTargetID;
1338 enclosure->start_channel = buffer->StartBus;
1339 enclosure->sep_id = buffer->SEPTargetID;
1340 enclosure->sep_channel = buffer->SEPBus;
1341
1342 out_free_consistent:
1343 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1344 buffer, dma_handle);
1345 out:
1346 return error;
1347}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001348
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301349/**
1350 * mptsas_add_end_device - report a new end device to sas transport layer
1351 * @ioc: Pointer to MPT_ADAPTER structure
1352 * @phy_info: decribes attached device
1353 *
1354 * return (0) success (1) failure
1355 *
1356 **/
1357static int
1358mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1359{
1360 struct sas_rphy *rphy;
1361 struct sas_port *port;
1362 struct sas_identify identify;
1363 char *ds = NULL;
1364 u8 fw_id;
1365
1366 if (!phy_info) {
1367 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1368 "%s: exit at line=%d\n", ioc->name,
1369 __func__, __LINE__));
1370 return 1;
1371 }
1372
1373 fw_id = phy_info->attached.id;
1374
1375 if (mptsas_get_rphy(phy_info)) {
1376 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1377 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1378 __func__, fw_id, __LINE__));
1379 return 2;
1380 }
1381
1382 port = mptsas_get_port(phy_info);
1383 if (!port) {
1384 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1385 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1386 __func__, fw_id, __LINE__));
1387 return 3;
1388 }
1389
1390 if (phy_info->attached.device_info &
1391 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1392 ds = "ssp";
1393 if (phy_info->attached.device_info &
1394 MPI_SAS_DEVICE_INFO_STP_TARGET)
1395 ds = "stp";
1396 if (phy_info->attached.device_info &
1397 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1398 ds = "sata";
1399
1400 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1401 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1402 phy_info->attached.channel, phy_info->attached.id,
1403 phy_info->attached.phy_id, (unsigned long long)
1404 phy_info->attached.sas_address);
1405
1406 mptsas_parse_device_info(&identify, &phy_info->attached);
1407 rphy = sas_end_device_alloc(port);
1408 if (!rphy) {
1409 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1410 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1411 __func__, fw_id, __LINE__));
1412 return 5; /* non-fatal: an rphy can be added later */
1413 }
1414
1415 rphy->identify = identify;
1416 if (sas_rphy_add(rphy)) {
1417 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1418 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1419 __func__, fw_id, __LINE__));
1420 sas_rphy_free(rphy);
1421 return 6;
1422 }
1423 mptsas_set_rphy(ioc, phy_info, rphy);
1424 return 0;
1425}
1426
1427/**
1428 * mptsas_del_end_device - report a deleted end device to sas transport
1429 * layer
1430 * @ioc: Pointer to MPT_ADAPTER structure
1431 * @phy_info: decribes attached device
1432 *
1433 **/
1434static void
1435mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1436{
1437 struct sas_rphy *rphy;
1438 struct sas_port *port;
1439 struct mptsas_portinfo *port_info;
1440 struct mptsas_phyinfo *phy_info_parent;
1441 int i;
1442 char *ds = NULL;
1443 u8 fw_id;
1444 u64 sas_address;
1445
1446 if (!phy_info)
1447 return;
1448
1449 fw_id = phy_info->attached.id;
1450 sas_address = phy_info->attached.sas_address;
1451
1452 if (!phy_info->port_details) {
1453 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1454 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1455 __func__, fw_id, __LINE__));
1456 return;
1457 }
1458 rphy = mptsas_get_rphy(phy_info);
1459 if (!rphy) {
1460 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1461 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1462 __func__, fw_id, __LINE__));
1463 return;
1464 }
1465
1466 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1467 || phy_info->attached.device_info
1468 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1469 || phy_info->attached.device_info
1470 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1471 ds = "initiator";
1472 if (phy_info->attached.device_info &
1473 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1474 ds = "ssp";
1475 if (phy_info->attached.device_info &
1476 MPI_SAS_DEVICE_INFO_STP_TARGET)
1477 ds = "stp";
1478 if (phy_info->attached.device_info &
1479 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1480 ds = "sata";
1481
1482 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1483 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1484 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1485 phy_info->attached.id, phy_info->attached.phy_id,
1486 (unsigned long long) sas_address);
1487
1488 port = mptsas_get_port(phy_info);
1489 if (!port) {
1490 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1491 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1492 __func__, fw_id, __LINE__));
1493 return;
1494 }
1495 port_info = phy_info->portinfo;
1496 phy_info_parent = port_info->phy_info;
1497 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1498 if (!phy_info_parent->phy)
1499 continue;
1500 if (phy_info_parent->attached.sas_address !=
1501 sas_address)
1502 continue;
1503 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1504 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1505 ioc->name, phy_info_parent->phy_id,
1506 phy_info_parent->phy);
1507 sas_port_delete_phy(port, phy_info_parent->phy);
1508 }
1509
1510 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1511 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1512 port->port_identifier, (unsigned long long)sas_address);
1513 sas_port_delete(port);
1514 mptsas_set_port(ioc, phy_info, NULL);
1515 mptsas_port_delete(ioc, phy_info->port_details);
1516}
1517
1518struct mptsas_phyinfo *
1519mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1520 struct mptsas_devinfo *sas_device)
1521{
1522 struct mptsas_phyinfo *phy_info;
1523 struct mptsas_portinfo *port_info;
1524 int i;
1525
1526 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1527 sas_device->sas_address);
1528 if (!phy_info)
1529 goto out;
1530 port_info = phy_info->portinfo;
1531 if (!port_info)
1532 goto out;
1533 mutex_lock(&ioc->sas_topology_mutex);
1534 for (i = 0; i < port_info->num_phys; i++) {
1535 if (port_info->phy_info[i].attached.sas_address !=
1536 sas_device->sas_address)
1537 continue;
1538 port_info->phy_info[i].attached.channel = sas_device->channel;
1539 port_info->phy_info[i].attached.id = sas_device->id;
1540 port_info->phy_info[i].attached.sas_address =
1541 sas_device->sas_address;
1542 port_info->phy_info[i].attached.handle = sas_device->handle;
1543 port_info->phy_info[i].attached.handle_parent =
1544 sas_device->handle_parent;
1545 port_info->phy_info[i].attached.handle_enclosure =
1546 sas_device->handle_enclosure;
1547 }
1548 mutex_unlock(&ioc->sas_topology_mutex);
1549 out:
1550 return phy_info;
1551}
1552
1553/**
1554 * mptsas_firmware_event_work - work thread for processing fw events
1555 * @work: work queue payload containing info describing the event
1556 * Context: user
1557 *
1558 */
1559static void
1560mptsas_firmware_event_work(struct work_struct *work)
1561{
1562 struct fw_event_work *fw_event =
1563 container_of(work, struct fw_event_work, work.work);
1564 MPT_ADAPTER *ioc = fw_event->ioc;
1565
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301566 /* special rescan topology handling */
1567 if (fw_event->event == -1) {
1568 if (ioc->in_rescan) {
1569 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1570 "%s: rescan ignored as it is in progress\n",
1571 ioc->name, __func__));
1572 return;
1573 }
1574 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1575 "reset\n", ioc->name, __func__));
1576 ioc->in_rescan = 1;
1577 mptsas_not_responding_devices(ioc);
1578 mptsas_scan_sas_topology(ioc);
1579 ioc->in_rescan = 0;
1580 mptsas_free_fw_event(ioc, fw_event);
1581 return;
1582 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301583
1584 /* events handling turned off during host reset */
1585 if (ioc->fw_events_off) {
1586 mptsas_free_fw_event(ioc, fw_event);
1587 return;
1588 }
1589
1590 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1591 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1592 (fw_event->event & 0xFF)));
1593
1594 switch (fw_event->event) {
1595 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1596 mptsas_send_sas_event(fw_event);
1597 break;
1598 case MPI_EVENT_INTEGRATED_RAID:
1599 mptsas_send_raid_event(fw_event);
1600 break;
1601 case MPI_EVENT_IR2:
1602 mptsas_send_ir2_event(fw_event);
1603 break;
1604 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1605 mptbase_sas_persist_operation(ioc,
1606 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1607 mptsas_free_fw_event(ioc, fw_event);
1608 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301609 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1610 mptsas_send_expander_event(fw_event);
1611 break;
1612 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1613 mptsas_send_link_status_event(fw_event);
1614 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301615 case MPI_EVENT_QUEUE_FULL:
1616 mptsas_handle_queue_full_event(fw_event);
1617 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301618 }
1619}
1620
1621
1622
James Bottomleyf013db32006-03-18 14:54:36 -06001623static int
1624mptsas_slave_configure(struct scsi_device *sdev)
1625{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301626 struct Scsi_Host *host = sdev->host;
1627 MPT_SCSI_HOST *hd = shost_priv(host);
1628 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301629 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001630
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301631 if (vdevice->vtarget->deleted) {
1632 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1633 vdevice->vtarget->deleted = 0;
1634 }
1635
1636 /*
1637 * RAID volumes placed beyond the last expected port.
1638 * Ignore sending sas mode pages in that case..
1639 */
1640 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1641 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001642 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301643 }
James Bottomleyf013db32006-03-18 14:54:36 -06001644
James Bottomleye8bf3942006-07-11 17:49:34 -04001645 sas_read_port_mode_page(sdev);
1646
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301647 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1648
James Bottomleye8bf3942006-07-11 17:49:34 -04001649 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001650 return mptscsih_slave_configure(sdev);
1651}
1652
Eric Moore547f9a22006-06-27 14:42:12 -06001653static int
1654mptsas_target_alloc(struct scsi_target *starget)
1655{
1656 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001657 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001658 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001659 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001660 struct sas_rphy *rphy;
1661 struct mptsas_portinfo *p;
1662 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001663 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001664
1665 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1666 if (!vtarget)
1667 return -ENOMEM;
1668
1669 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001670 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001671 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1672 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001673 channel = 0;
1674
Eric Moore793955f2007-01-29 09:42:20 -07001675 /*
1676 * RAID volumes placed beyond the last expected port.
1677 */
1678 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301679 if (!ioc->raid_data.pIocPg2) {
1680 kfree(vtarget);
1681 return -ENXIO;
1682 }
1683 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1684 if (id == ioc->raid_data.pIocPg2->
1685 RaidVolume[i].VolumeID) {
1686 channel = ioc->raid_data.pIocPg2->
1687 RaidVolume[i].VolumeBus;
1688 }
1689 }
1690 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001691 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001692 }
Eric Moore547f9a22006-06-27 14:42:12 -06001693
1694 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001695 mutex_lock(&ioc->sas_topology_mutex);
1696 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001697 for (i = 0; i < p->num_phys; i++) {
1698 if (p->phy_info[i].attached.sas_address !=
1699 rphy->identify.sas_address)
1700 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001701 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001702 channel = p->phy_info[i].attached.channel;
1703 mptsas_set_starget(&p->phy_info[i], starget);
1704
1705 /*
1706 * Exposing hidden raid components
1707 */
Eric Mooree80b0022007-09-14 18:49:03 -06001708 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1709 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001710 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001711 vtarget->tflags |=
1712 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001713 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001714 }
Eric Mooree80b0022007-09-14 18:49:03 -06001715 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001716 goto out;
1717 }
1718 }
Eric Mooree80b0022007-09-14 18:49:03 -06001719 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001720
1721 kfree(vtarget);
1722 return -ENXIO;
1723
1724 out:
Eric Moore793955f2007-01-29 09:42:20 -07001725 vtarget->id = id;
1726 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001727 starget->hostdata = vtarget;
1728 return 0;
1729}
1730
1731static void
1732mptsas_target_destroy(struct scsi_target *starget)
1733{
1734 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001735 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001736 struct sas_rphy *rphy;
1737 struct mptsas_portinfo *p;
1738 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301739 MPT_ADAPTER *ioc = hd->ioc;
1740 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001741
1742 if (!starget->hostdata)
1743 return;
1744
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301745 vtarget = starget->hostdata;
1746
Kashyap, Desai57e98512009-05-29 16:55:09 +05301747 mptsas_del_device_component_by_os(ioc, starget->channel,
1748 starget->id);
1749
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301750
James Bottomleye8bf3942006-07-11 17:49:34 -04001751 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001752 goto out;
1753
1754 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001755 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001756 for (i = 0; i < p->num_phys; i++) {
1757 if (p->phy_info[i].attached.sas_address !=
1758 rphy->identify.sas_address)
1759 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301760
1761 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1762 "delete device: fw_channel %d, fw_id %d, phy %d, "
1763 "sas_addr 0x%llx\n", ioc->name,
1764 p->phy_info[i].attached.channel,
1765 p->phy_info[i].attached.id,
1766 p->phy_info[i].attached.phy_id, (unsigned long long)
1767 p->phy_info[i].attached.sas_address);
1768
Eric Moore547f9a22006-06-27 14:42:12 -06001769 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001770 }
1771 }
1772
1773 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301774 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001775 kfree(starget->hostdata);
1776 starget->hostdata = NULL;
1777}
1778
1779
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001780static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001781mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001782{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001783 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001784 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001785 struct sas_rphy *rphy;
1786 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001787 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001788 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001789 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001790 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001791
Eric Moorea69de502007-09-14 18:48:19 -06001792 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1793 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001794 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001795 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001796 return -ENOMEM;
1797 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001798 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001799 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001800
James Bottomleye8bf3942006-07-11 17:49:34 -04001801 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001802 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001803
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001804 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001805 mutex_lock(&ioc->sas_topology_mutex);
1806 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001807 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001808 if (p->phy_info[i].attached.sas_address !=
1809 rphy->identify.sas_address)
1810 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001811 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001812 /*
1813 * Exposing hidden raid components
1814 */
Eric Mooree80b0022007-09-14 18:49:03 -06001815 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001816 p->phy_info[i].attached.channel,
1817 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001818 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001819 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001820 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001821 }
1822 }
Eric Mooree80b0022007-09-14 18:49:03 -06001823 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001824
Eric Moorea69de502007-09-14 18:48:19 -06001825 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001826 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001827
1828 out:
Eric Moorea69de502007-09-14 18:48:19 -06001829 vdevice->vtarget->num_luns++;
1830 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001831 return 0;
1832}
1833
Eric Moore547f9a22006-06-27 14:42:12 -06001834static int
1835mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001836{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301837 MPT_SCSI_HOST *hd;
1838 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001839 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001840
Eric Moorea69de502007-09-14 18:48:19 -06001841 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001842 SCpnt->result = DID_NO_CONNECT << 16;
1843 done(SCpnt);
1844 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001845 }
Eric Moore547f9a22006-06-27 14:42:12 -06001846
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301847 hd = shost_priv(SCpnt->device->host);
1848 ioc = hd->ioc;
1849
1850 if (ioc->sas_discovery_quiesce_io)
1851 return SCSI_MLQUEUE_HOST_BUSY;
1852
Eric Moore793955f2007-01-29 09:42:20 -07001853// scsi_print_command(SCpnt);
1854
Eric Moore547f9a22006-06-27 14:42:12 -06001855 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001856}
1857
Eric Moore547f9a22006-06-27 14:42:12 -06001858
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001859static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001860 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001861 .proc_name = "mptsas",
1862 .proc_info = mptscsih_proc_info,
1863 .name = "MPT SPI Host",
1864 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001865 .queuecommand = mptsas_qcmd,
1866 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001867 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001868 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001869 .target_destroy = mptsas_target_destroy,
1870 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001871 .change_queue_depth = mptscsih_change_queue_depth,
1872 .eh_abort_handler = mptscsih_abort,
1873 .eh_device_reset_handler = mptscsih_dev_reset,
1874 .eh_bus_reset_handler = mptscsih_bus_reset,
1875 .eh_host_reset_handler = mptscsih_host_reset,
1876 .bios_param = mptscsih_bios_param,
1877 .can_queue = MPT_FC_CAN_QUEUE,
1878 .this_id = -1,
1879 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1880 .max_sectors = 8192,
1881 .cmd_per_lun = 7,
1882 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301883 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001884};
1885
Christoph Hellwigb5141122005-10-28 22:07:41 +02001886static int mptsas_get_linkerrors(struct sas_phy *phy)
1887{
1888 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1889 ConfigExtendedPageHeader_t hdr;
1890 CONFIGPARMS cfg;
1891 SasPhyPage1_t *buffer;
1892 dma_addr_t dma_handle;
1893 int error;
1894
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001895 /* FIXME: only have link errors on local phys */
1896 if (!scsi_is_sas_phy_local(phy))
1897 return -EINVAL;
1898
Christoph Hellwigb5141122005-10-28 22:07:41 +02001899 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1900 hdr.ExtPageLength = 0;
1901 hdr.PageNumber = 1 /* page number 1*/;
1902 hdr.Reserved1 = 0;
1903 hdr.Reserved2 = 0;
1904 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1905 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1906
1907 cfg.cfghdr.ehdr = &hdr;
1908 cfg.physAddr = -1;
1909 cfg.pageAddr = phy->identify.phy_identifier;
1910 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1911 cfg.dir = 0; /* read */
1912 cfg.timeout = 10;
1913
1914 error = mpt_config(ioc, &cfg);
1915 if (error)
1916 return error;
1917 if (!hdr.ExtPageLength)
1918 return -ENXIO;
1919
1920 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1921 &dma_handle);
1922 if (!buffer)
1923 return -ENOMEM;
1924
1925 cfg.physAddr = dma_handle;
1926 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1927
1928 error = mpt_config(ioc, &cfg);
1929 if (error)
1930 goto out_free_consistent;
1931
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301932 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001933
1934 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1935 phy->running_disparity_error_count =
1936 le32_to_cpu(buffer->RunningDisparityErrorCount);
1937 phy->loss_of_dword_sync_count =
1938 le32_to_cpu(buffer->LossDwordSynchCount);
1939 phy->phy_reset_problem_count =
1940 le32_to_cpu(buffer->PhyResetProblemCount);
1941
1942 out_free_consistent:
1943 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1944 buffer, dma_handle);
1945 return error;
1946}
1947
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001948static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1949 MPT_FRAME_HDR *reply)
1950{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301951 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001952 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301953 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001954 memcpy(ioc->sas_mgmt.reply, reply,
1955 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1956 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05301957
1958 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1959 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
1960 complete(&ioc->sas_mgmt.done);
1961 return 1;
1962 }
1963 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001964}
1965
1966static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1967{
1968 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1969 SasIoUnitControlRequest_t *req;
1970 SasIoUnitControlReply_t *reply;
1971 MPT_FRAME_HDR *mf;
1972 MPIHeader_t *hdr;
1973 unsigned long timeleft;
1974 int error = -ERESTARTSYS;
1975
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001976 /* FIXME: fusion doesn't allow non-local phy reset */
1977 if (!scsi_is_sas_phy_local(phy))
1978 return -EINVAL;
1979
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001980 /* not implemented for expanders */
1981 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1982 return -ENXIO;
1983
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001984 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001985 goto out;
1986
1987 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1988 if (!mf) {
1989 error = -ENOMEM;
1990 goto out_unlock;
1991 }
1992
1993 hdr = (MPIHeader_t *) mf;
1994 req = (SasIoUnitControlRequest_t *)mf;
1995 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1996 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1997 req->MsgContext = hdr->MsgContext;
1998 req->Operation = hard_reset ?
1999 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2000 req->PhyNum = phy->identify.phy_identifier;
2001
Kashyap, Desai2f187862009-05-29 16:52:37 +05302002 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002003 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2004
2005 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2006 10 * HZ);
2007 if (!timeleft) {
2008 /* On timeout reset the board */
2009 mpt_free_msg_frame(ioc, mf);
2010 mpt_HardResetHandler(ioc, CAN_SLEEP);
2011 error = -ETIMEDOUT;
2012 goto out_unlock;
2013 }
2014
2015 /* a reply frame is expected */
2016 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302017 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002018 error = -ENXIO;
2019 goto out_unlock;
2020 }
2021
2022 /* process the completed Reply Message Frame */
2023 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2024 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002025 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002026 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002027 error = -ENXIO;
2028 goto out_unlock;
2029 }
2030
2031 error = 0;
2032
2033 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302034 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002035 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002036 out:
2037 return error;
2038}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002039
Christoph Hellwige3094442006-02-16 13:25:36 +01002040static int
2041mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2042{
2043 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2044 int i, error;
2045 struct mptsas_portinfo *p;
2046 struct mptsas_enclosure enclosure_info;
2047 u64 enclosure_handle;
2048
2049 mutex_lock(&ioc->sas_topology_mutex);
2050 list_for_each_entry(p, &ioc->sas_topology, list) {
2051 for (i = 0; i < p->num_phys; i++) {
2052 if (p->phy_info[i].attached.sas_address ==
2053 rphy->identify.sas_address) {
2054 enclosure_handle = p->phy_info[i].
2055 attached.handle_enclosure;
2056 goto found_info;
2057 }
2058 }
2059 }
2060 mutex_unlock(&ioc->sas_topology_mutex);
2061 return -ENXIO;
2062
2063 found_info:
2064 mutex_unlock(&ioc->sas_topology_mutex);
2065 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002066 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002067 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2068 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2069 if (!error)
2070 *identifier = enclosure_info.enclosure_logical_id;
2071 return error;
2072}
2073
2074static int
2075mptsas_get_bay_identifier(struct sas_rphy *rphy)
2076{
2077 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2078 struct mptsas_portinfo *p;
2079 int i, rc;
2080
2081 mutex_lock(&ioc->sas_topology_mutex);
2082 list_for_each_entry(p, &ioc->sas_topology, list) {
2083 for (i = 0; i < p->num_phys; i++) {
2084 if (p->phy_info[i].attached.sas_address ==
2085 rphy->identify.sas_address) {
2086 rc = p->phy_info[i].attached.slot;
2087 goto out;
2088 }
2089 }
2090 }
2091 rc = -ENXIO;
2092 out:
2093 mutex_unlock(&ioc->sas_topology_mutex);
2094 return rc;
2095}
2096
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002097static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2098 struct request *req)
2099{
2100 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2101 MPT_FRAME_HDR *mf;
2102 SmpPassthroughRequest_t *smpreq;
2103 struct request *rsp = req->next_rq;
2104 int ret;
2105 int flagsLength;
2106 unsigned long timeleft;
2107 char *psge;
2108 dma_addr_t dma_addr_in = 0;
2109 dma_addr_t dma_addr_out = 0;
2110 u64 sas_address = 0;
2111
2112 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002113 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002114 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002115 return -EINVAL;
2116 }
2117
2118 /* do we need to support multiple segments? */
2119 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002120 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002121 ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
Eric Moore29dd3602007-09-14 18:46:51 -06002122 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002123 return -EINVAL;
2124 }
2125
2126 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2127 if (ret)
2128 goto out;
2129
2130 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2131 if (!mf) {
2132 ret = -ENOMEM;
2133 goto out_unlock;
2134 }
2135
2136 smpreq = (SmpPassthroughRequest_t *)mf;
2137 memset(smpreq, 0, sizeof(*smpreq));
2138
2139 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
2140 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2141
2142 if (rphy)
2143 sas_address = rphy->identify.sas_address;
2144 else {
2145 struct mptsas_portinfo *port_info;
2146
2147 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302148 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002149 if (port_info && port_info->phy_info)
2150 sas_address =
2151 port_info->phy_info[0].phy->identify.sas_address;
2152 mutex_unlock(&ioc->sas_topology_mutex);
2153 }
2154
2155 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2156
2157 psge = (char *)
2158 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2159
2160 /* request */
2161 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2162 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302163 MPI_SGE_FLAGS_DIRECTION)
2164 << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002165 flagsLength |= (req->data_len - 4);
2166
2167 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
2168 req->data_len, PCI_DMA_BIDIRECTIONAL);
2169 if (!dma_addr_out)
2170 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302171 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302172 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002173
2174 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302175 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2176 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2177 MPI_SGE_FLAGS_IOC_TO_HOST |
2178 MPI_SGE_FLAGS_END_OF_BUFFER;
2179
2180 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002181 flagsLength |= rsp->data_len + 4;
2182 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
2183 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
2184 if (!dma_addr_in)
2185 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302186 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002187
Kashyap, Desai2f187862009-05-29 16:52:37 +05302188 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002189 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2190
2191 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2192 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002193 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002194 /* On timeout reset the board */
2195 mpt_HardResetHandler(ioc, CAN_SLEEP);
2196 ret = -ETIMEDOUT;
2197 goto unmap;
2198 }
2199 mf = NULL;
2200
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302201 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002202 SmpPassthroughReply_t *smprep;
2203
2204 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2205 memcpy(req->sense, smprep, sizeof(*smprep));
2206 req->sense_len = sizeof(*smprep);
FUJITA Tomonori38b31672007-12-30 19:34:52 +09002207 req->data_len = 0;
2208 rsp->data_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002209 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302210 printk(MYIOC_s_ERR_FMT
2211 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002212 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002213 ret = -ENXIO;
2214 }
2215unmap:
2216 if (dma_addr_out)
2217 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
2218 PCI_DMA_BIDIRECTIONAL);
2219 if (dma_addr_in)
2220 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
2221 PCI_DMA_BIDIRECTIONAL);
2222put_mf:
2223 if (mf)
2224 mpt_free_msg_frame(ioc, mf);
2225out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302226 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002227 mutex_unlock(&ioc->sas_mgmt.mutex);
2228out:
2229 return ret;
2230}
2231
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002232static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002233 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002234 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2235 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002236 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002237 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002238};
2239
2240static struct scsi_transport_template *mptsas_transport_template;
2241
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002242static int
2243mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2244{
2245 ConfigExtendedPageHeader_t hdr;
2246 CONFIGPARMS cfg;
2247 SasIOUnitPage0_t *buffer;
2248 dma_addr_t dma_handle;
2249 int error, i;
2250
2251 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2252 hdr.ExtPageLength = 0;
2253 hdr.PageNumber = 0;
2254 hdr.Reserved1 = 0;
2255 hdr.Reserved2 = 0;
2256 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2257 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2258
2259 cfg.cfghdr.ehdr = &hdr;
2260 cfg.physAddr = -1;
2261 cfg.pageAddr = 0;
2262 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2263 cfg.dir = 0; /* read */
2264 cfg.timeout = 10;
2265
2266 error = mpt_config(ioc, &cfg);
2267 if (error)
2268 goto out;
2269 if (!hdr.ExtPageLength) {
2270 error = -ENXIO;
2271 goto out;
2272 }
2273
2274 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2275 &dma_handle);
2276 if (!buffer) {
2277 error = -ENOMEM;
2278 goto out;
2279 }
2280
2281 cfg.physAddr = dma_handle;
2282 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2283
2284 error = mpt_config(ioc, &cfg);
2285 if (error)
2286 goto out_free_consistent;
2287
2288 port_info->num_phys = buffer->NumPhys;
2289 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302290 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002291 if (!port_info->phy_info) {
2292 error = -ENOMEM;
2293 goto out_free_consistent;
2294 }
2295
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302296 ioc->nvdata_version_persistent =
2297 le16_to_cpu(buffer->NvdataVersionPersistent);
2298 ioc->nvdata_version_default =
2299 le16_to_cpu(buffer->NvdataVersionDefault);
2300
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002301 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302302 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002303 port_info->phy_info[i].phy_id = i;
2304 port_info->phy_info[i].port_id =
2305 buffer->PhyData[i].Port;
2306 port_info->phy_info[i].negotiated_link_rate =
2307 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002308 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002309 port_info->phy_info[i].handle =
2310 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002311 }
2312
2313 out_free_consistent:
2314 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2315 buffer, dma_handle);
2316 out:
2317 return error;
2318}
2319
2320static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302321mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2322{
2323 ConfigExtendedPageHeader_t hdr;
2324 CONFIGPARMS cfg;
2325 SasIOUnitPage1_t *buffer;
2326 dma_addr_t dma_handle;
2327 int error;
2328 u16 device_missing_delay;
2329
2330 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2331 memset(&cfg, 0, sizeof(CONFIGPARMS));
2332
2333 cfg.cfghdr.ehdr = &hdr;
2334 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2335 cfg.timeout = 10;
2336 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2337 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2338 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2339 cfg.cfghdr.ehdr->PageNumber = 1;
2340
2341 error = mpt_config(ioc, &cfg);
2342 if (error)
2343 goto out;
2344 if (!hdr.ExtPageLength) {
2345 error = -ENXIO;
2346 goto out;
2347 }
2348
2349 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2350 &dma_handle);
2351 if (!buffer) {
2352 error = -ENOMEM;
2353 goto out;
2354 }
2355
2356 cfg.physAddr = dma_handle;
2357 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2358
2359 error = mpt_config(ioc, &cfg);
2360 if (error)
2361 goto out_free_consistent;
2362
2363 ioc->io_missing_delay =
2364 le16_to_cpu(buffer->IODeviceMissingDelay);
2365 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2366 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2367 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2368 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2369
2370 out_free_consistent:
2371 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2372 buffer, dma_handle);
2373 out:
2374 return error;
2375}
2376
2377static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002378mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2379 u32 form, u32 form_specific)
2380{
2381 ConfigExtendedPageHeader_t hdr;
2382 CONFIGPARMS cfg;
2383 SasPhyPage0_t *buffer;
2384 dma_addr_t dma_handle;
2385 int error;
2386
2387 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2388 hdr.ExtPageLength = 0;
2389 hdr.PageNumber = 0;
2390 hdr.Reserved1 = 0;
2391 hdr.Reserved2 = 0;
2392 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2393 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2394
2395 cfg.cfghdr.ehdr = &hdr;
2396 cfg.dir = 0; /* read */
2397 cfg.timeout = 10;
2398
2399 /* Get Phy Pg 0 for each Phy. */
2400 cfg.physAddr = -1;
2401 cfg.pageAddr = form + form_specific;
2402 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2403
2404 error = mpt_config(ioc, &cfg);
2405 if (error)
2406 goto out;
2407
2408 if (!hdr.ExtPageLength) {
2409 error = -ENXIO;
2410 goto out;
2411 }
2412
2413 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2414 &dma_handle);
2415 if (!buffer) {
2416 error = -ENOMEM;
2417 goto out;
2418 }
2419
2420 cfg.physAddr = dma_handle;
2421 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2422
2423 error = mpt_config(ioc, &cfg);
2424 if (error)
2425 goto out_free_consistent;
2426
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302427 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002428
2429 phy_info->hw_link_rate = buffer->HwLinkRate;
2430 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2431 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2432 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2433
2434 out_free_consistent:
2435 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2436 buffer, dma_handle);
2437 out:
2438 return error;
2439}
2440
2441static int
2442mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2443 u32 form, u32 form_specific)
2444{
2445 ConfigExtendedPageHeader_t hdr;
2446 CONFIGPARMS cfg;
2447 SasDevicePage0_t *buffer;
2448 dma_addr_t dma_handle;
2449 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002450 int error=0;
2451
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002452 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2453 hdr.ExtPageLength = 0;
2454 hdr.PageNumber = 0;
2455 hdr.Reserved1 = 0;
2456 hdr.Reserved2 = 0;
2457 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2458 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2459
2460 cfg.cfghdr.ehdr = &hdr;
2461 cfg.pageAddr = form + form_specific;
2462 cfg.physAddr = -1;
2463 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2464 cfg.dir = 0; /* read */
2465 cfg.timeout = 10;
2466
Moore, Ericdb9c9172006-03-14 09:14:18 -07002467 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002468 error = mpt_config(ioc, &cfg);
2469 if (error)
2470 goto out;
2471 if (!hdr.ExtPageLength) {
2472 error = -ENXIO;
2473 goto out;
2474 }
2475
2476 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2477 &dma_handle);
2478 if (!buffer) {
2479 error = -ENOMEM;
2480 goto out;
2481 }
2482
2483 cfg.physAddr = dma_handle;
2484 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2485
2486 error = mpt_config(ioc, &cfg);
2487 if (error)
2488 goto out_free_consistent;
2489
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302490 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002491
Kashyap, Desai2f187862009-05-29 16:52:37 +05302492 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002493 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002494 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002495 device_info->handle_enclosure =
2496 le16_to_cpu(buffer->EnclosureHandle);
2497 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002498 device_info->phy_id = buffer->PhyNum;
2499 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002500 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002501 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002502 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002503 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2504 device_info->sas_address = le64_to_cpu(sas_address);
2505 device_info->device_info =
2506 le32_to_cpu(buffer->DeviceInfo);
2507
2508 out_free_consistent:
2509 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2510 buffer, dma_handle);
2511 out:
2512 return error;
2513}
2514
2515static int
2516mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2517 u32 form, u32 form_specific)
2518{
2519 ConfigExtendedPageHeader_t hdr;
2520 CONFIGPARMS cfg;
2521 SasExpanderPage0_t *buffer;
2522 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002523 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302524 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002525
Kashyap, Desai2f187862009-05-29 16:52:37 +05302526 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002527 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2528 hdr.ExtPageLength = 0;
2529 hdr.PageNumber = 0;
2530 hdr.Reserved1 = 0;
2531 hdr.Reserved2 = 0;
2532 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2533 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2534
2535 cfg.cfghdr.ehdr = &hdr;
2536 cfg.physAddr = -1;
2537 cfg.pageAddr = form + form_specific;
2538 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2539 cfg.dir = 0; /* read */
2540 cfg.timeout = 10;
2541
Moore, Ericdb9c9172006-03-14 09:14:18 -07002542 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002543 error = mpt_config(ioc, &cfg);
2544 if (error)
2545 goto out;
2546
2547 if (!hdr.ExtPageLength) {
2548 error = -ENXIO;
2549 goto out;
2550 }
2551
2552 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2553 &dma_handle);
2554 if (!buffer) {
2555 error = -ENOMEM;
2556 goto out;
2557 }
2558
2559 cfg.physAddr = dma_handle;
2560 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2561
2562 error = mpt_config(ioc, &cfg);
2563 if (error)
2564 goto out_free_consistent;
2565
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002566 if (!buffer->NumPhys) {
2567 error = -ENODEV;
2568 goto out_free_consistent;
2569 }
2570
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002571 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302572 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002573 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302574 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002575 if (!port_info->phy_info) {
2576 error = -ENOMEM;
2577 goto out_free_consistent;
2578 }
2579
Kashyap, Desai2f187862009-05-29 16:52:37 +05302580 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002581 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002582 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002583 port_info->phy_info[i].handle =
2584 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302585 port_info->phy_info[i].identify.sas_address =
2586 le64_to_cpu(sas_address);
2587 port_info->phy_info[i].identify.handle_parent =
2588 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002589 }
Eric Moore547f9a22006-06-27 14:42:12 -06002590
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002591 out_free_consistent:
2592 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2593 buffer, dma_handle);
2594 out:
2595 return error;
2596}
2597
2598static int
2599mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2600 u32 form, u32 form_specific)
2601{
2602 ConfigExtendedPageHeader_t hdr;
2603 CONFIGPARMS cfg;
2604 SasExpanderPage1_t *buffer;
2605 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002606 int error=0;
2607
Kashyap, Desai2f187862009-05-29 16:52:37 +05302608 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002609 hdr.ExtPageLength = 0;
2610 hdr.PageNumber = 1;
2611 hdr.Reserved1 = 0;
2612 hdr.Reserved2 = 0;
2613 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2614 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2615
2616 cfg.cfghdr.ehdr = &hdr;
2617 cfg.physAddr = -1;
2618 cfg.pageAddr = form + form_specific;
2619 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2620 cfg.dir = 0; /* read */
2621 cfg.timeout = 10;
2622
2623 error = mpt_config(ioc, &cfg);
2624 if (error)
2625 goto out;
2626
2627 if (!hdr.ExtPageLength) {
2628 error = -ENXIO;
2629 goto out;
2630 }
2631
2632 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2633 &dma_handle);
2634 if (!buffer) {
2635 error = -ENOMEM;
2636 goto out;
2637 }
2638
2639 cfg.physAddr = dma_handle;
2640 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2641
2642 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302643
2644 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2645 error = -ENODEV;
2646 goto out;
2647 }
2648
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002649 if (error)
2650 goto out_free_consistent;
2651
2652
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302653 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002654
2655 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002656 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002657 phy_info->port_id = buffer->PhysicalPort;
2658 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2659 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2660 phy_info->hw_link_rate = buffer->HwLinkRate;
2661 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2662 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2663
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002664 out_free_consistent:
2665 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2666 buffer, dma_handle);
2667 out:
2668 return error;
2669}
2670
2671static void
2672mptsas_parse_device_info(struct sas_identify *identify,
2673 struct mptsas_devinfo *device_info)
2674{
2675 u16 protocols;
2676
2677 identify->sas_address = device_info->sas_address;
2678 identify->phy_identifier = device_info->phy_id;
2679
2680 /*
2681 * Fill in Phy Initiator Port Protocol.
2682 * Bits 6:3, more than one bit can be set, fall through cases.
2683 */
2684 protocols = device_info->device_info & 0x78;
2685 identify->initiator_port_protocols = 0;
2686 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2687 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2688 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2689 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2690 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2691 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2692 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2693 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2694
2695 /*
2696 * Fill in Phy Target Port Protocol.
2697 * Bits 10:7, more than one bit can be set, fall through cases.
2698 */
2699 protocols = device_info->device_info & 0x780;
2700 identify->target_port_protocols = 0;
2701 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2702 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2703 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2704 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2705 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2706 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2707 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2708 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2709
2710 /*
2711 * Fill in Attached device type.
2712 */
2713 switch (device_info->device_info &
2714 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2715 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2716 identify->device_type = SAS_PHY_UNUSED;
2717 break;
2718 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2719 identify->device_type = SAS_END_DEVICE;
2720 break;
2721 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2722 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2723 break;
2724 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2725 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2726 break;
2727 }
2728}
2729
2730static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002731 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002732{
Moore, Erice6b2d762006-03-14 09:14:24 -07002733 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002734 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002735 struct sas_port *port;
2736 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002737
Eric Moore547f9a22006-06-27 14:42:12 -06002738 if (!dev) {
2739 error = -ENODEV;
2740 goto out;
2741 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002742
2743 if (!phy_info->phy) {
2744 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002745 if (!phy) {
2746 error = -ENOMEM;
2747 goto out;
2748 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002749 } else
2750 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002751
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002752 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002753
2754 /*
2755 * Set Negotiated link rate.
2756 */
2757 switch (phy_info->negotiated_link_rate) {
2758 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002759 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002760 break;
2761 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002762 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002763 break;
2764 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002765 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002766 break;
2767 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002768 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002769 break;
2770 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2771 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2772 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002773 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002774 break;
2775 }
2776
2777 /*
2778 * Set Max hardware link rate.
2779 */
2780 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2781 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002782 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002783 break;
2784 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002785 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002786 break;
2787 default:
2788 break;
2789 }
2790
2791 /*
2792 * Set Max programmed link rate.
2793 */
2794 switch (phy_info->programmed_link_rate &
2795 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2796 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002797 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002798 break;
2799 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002800 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002801 break;
2802 default:
2803 break;
2804 }
2805
2806 /*
2807 * Set Min hardware link rate.
2808 */
2809 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2810 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002811 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002812 break;
2813 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002814 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002815 break;
2816 default:
2817 break;
2818 }
2819
2820 /*
2821 * Set Min programmed link rate.
2822 */
2823 switch (phy_info->programmed_link_rate &
2824 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2825 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002826 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002827 break;
2828 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002829 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002830 break;
2831 default:
2832 break;
2833 }
2834
Moore, Erice6b2d762006-03-14 09:14:24 -07002835 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002836
Moore, Erice6b2d762006-03-14 09:14:24 -07002837 error = sas_phy_add(phy);
2838 if (error) {
2839 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002840 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002841 }
2842 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002843 }
2844
Eric Moore547f9a22006-06-27 14:42:12 -06002845 if (!phy_info->attached.handle ||
2846 !phy_info->port_details)
2847 goto out;
2848
2849 port = mptsas_get_port(phy_info);
2850 ioc = phy_to_ioc(phy_info->phy);
2851
2852 if (phy_info->sas_port_add_phy) {
2853
2854 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002855 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002856 if (!port) {
2857 error = -ENOMEM;
2858 goto out;
2859 }
2860 error = sas_port_add(port);
2861 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302862 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002863 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002864 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002865 goto out;
2866 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302867 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302868 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
2869 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
2870 ioc->name, port->port_identifier,
2871 (unsigned long long)phy_info->
2872 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06002873 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302874 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2875 "sas_port_add_phy: phy_id=%d\n",
2876 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002877 sas_port_add_phy(port, phy_info->phy);
2878 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302879 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
2880 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
2881 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06002882 }
Eric Moore547f9a22006-06-27 14:42:12 -06002883 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002884
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002885 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002886 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002887 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002888
James Bottomley2686de22006-06-30 12:54:02 -05002889 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002890 /*
2891 * Let the hotplug_work thread handle processing
2892 * the adding/removing of devices that occur
2893 * after start of day.
2894 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302895 if (mptsas_is_end_device(&phy_info->attached) &&
2896 phy_info->attached.handle_parent) {
2897 goto out;
2898 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002899
James Bottomleyf013db32006-03-18 14:54:36 -06002900 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002901 if (scsi_is_host_device(parent)) {
2902 struct mptsas_portinfo *port_info;
2903 int i;
2904
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302905 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05002906
2907 for (i = 0; i < port_info->num_phys; i++)
2908 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002909 identify.sas_address) {
2910 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002911 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002912 }
James Bottomley2686de22006-06-30 12:54:02 -05002913
2914 } else if (scsi_is_sas_rphy(parent)) {
2915 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2916 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002917 parent_rphy->identify.sas_address) {
2918 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002919 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002920 }
James Bottomley2686de22006-06-30 12:54:02 -05002921 }
2922
James Bottomleyf013db32006-03-18 14:54:36 -06002923 switch (identify.device_type) {
2924 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002925 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002926 break;
2927 case SAS_EDGE_EXPANDER_DEVICE:
2928 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002929 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002930 break;
2931 default:
2932 rphy = NULL;
2933 break;
2934 }
Eric Moore547f9a22006-06-27 14:42:12 -06002935 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302936 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002937 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002938 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002939 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002940 }
2941
Eric Moore547f9a22006-06-27 14:42:12 -06002942 rphy->identify = identify;
2943 error = sas_rphy_add(rphy);
2944 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302945 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002946 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002947 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002948 sas_rphy_free(rphy);
2949 goto out;
2950 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302951 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002952 }
2953
Eric Moore547f9a22006-06-27 14:42:12 -06002954 out:
2955 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002956}
2957
2958static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002959mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002960{
Moore, Erice6b2d762006-03-14 09:14:24 -07002961 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002962 int error = -ENOMEM, i;
2963
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302964 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07002965 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002966 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002967
Moore, Erice6b2d762006-03-14 09:14:24 -07002968 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002969 if (error)
2970 goto out_free_port_info;
2971
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302972 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002973 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302974 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07002975 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302976 ioc->hba_port_info = port_info = hba;
2977 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07002978 list_add_tail(&port_info->list, &ioc->sas_topology);
2979 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002980 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002981 port_info->phy_info[i].negotiated_link_rate =
2982 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002983 port_info->phy_info[i].handle =
2984 hba->phy_info[i].handle;
2985 port_info->phy_info[i].port_id =
2986 hba->phy_info[i].port_id;
2987 }
Eric Moore547f9a22006-06-27 14:42:12 -06002988 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002989 kfree(hba);
2990 hba = NULL;
2991 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002992 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302993#if defined(CPQ_CIM)
2994 ioc->num_ports = port_info->num_phys;
2995#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002996 for (i = 0; i < port_info->num_phys; i++) {
2997 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2998 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2999 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303000 port_info->phy_info[i].identify.handle =
3001 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003002 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003003 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3004 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303005 port_info->phy_info[i].identify.handle);
3006 if (!ioc->hba_port_sas_addr)
3007 ioc->hba_port_sas_addr =
3008 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003009 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003010 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003011 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003012 mptsas_sas_device_pg0(ioc,
3013 &port_info->phy_info[i].attached,
3014 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3015 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3016 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003017 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003018
Eric Moore547f9a22006-06-27 14:42:12 -06003019 mptsas_setup_wide_ports(ioc, port_info);
3020
3021 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003022 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003023 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003024
3025 return 0;
3026
3027 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003028 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003029 out:
3030 return error;
3031}
3032
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303033static void
3034mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003035{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303036 struct mptsas_portinfo *parent;
3037 struct device *parent_dev;
3038 struct sas_rphy *rphy;
3039 int i;
3040 u64 sas_address; /* expander sas address */
3041 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003042
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303043 handle = port_info->phy_info[0].handle;
3044 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003045 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003046 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303047 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3048 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003049
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303050 mptsas_sas_device_pg0(ioc,
3051 &port_info->phy_info[i].identify,
3052 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3053 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3054 port_info->phy_info[i].identify.handle);
3055 port_info->phy_info[i].identify.phy_id =
3056 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003057
3058 if (port_info->phy_info[i].attached.handle) {
3059 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303060 &port_info->phy_info[i].attached,
3061 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3062 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3063 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003064 port_info->phy_info[i].attached.phy_id =
3065 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003066 }
Eric Moore547f9a22006-06-27 14:42:12 -06003067 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003068
Moore, Erice6b2d762006-03-14 09:14:24 -07003069 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303070 parent = mptsas_find_portinfo_by_handle(ioc,
3071 port_info->phy_info[0].identify.handle_parent);
3072 if (!parent) {
3073 mutex_unlock(&ioc->sas_topology_mutex);
3074 return;
3075 }
3076 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3077 i++) {
3078 if (parent->phy_info[i].attached.sas_address == sas_address) {
3079 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3080 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003081 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003082 }
3083 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303084
3085 mptsas_setup_wide_ports(ioc, port_info);
3086 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3087 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3088 ioc->sas_index, 0);
3089}
3090
3091static void
3092mptsas_expander_event_add(MPT_ADAPTER *ioc,
3093 MpiEventDataSasExpanderStatusChange_t *expander_data)
3094{
3095 struct mptsas_portinfo *port_info;
3096 int i;
3097 __le64 sas_address;
3098
3099 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3100 if (!port_info)
3101 BUG();
3102 port_info->num_phys = (expander_data->NumPhys) ?
3103 expander_data->NumPhys : 1;
3104 port_info->phy_info = kcalloc(port_info->num_phys,
3105 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3106 if (!port_info->phy_info)
3107 BUG();
3108 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3109 for (i = 0; i < port_info->num_phys; i++) {
3110 port_info->phy_info[i].portinfo = port_info;
3111 port_info->phy_info[i].handle =
3112 le16_to_cpu(expander_data->DevHandle);
3113 port_info->phy_info[i].identify.sas_address =
3114 le64_to_cpu(sas_address);
3115 port_info->phy_info[i].identify.handle_parent =
3116 le16_to_cpu(expander_data->ParentDevHandle);
3117 }
3118
3119 mutex_lock(&ioc->sas_topology_mutex);
3120 list_add_tail(&port_info->list, &ioc->sas_topology);
3121 mutex_unlock(&ioc->sas_topology_mutex);
3122
3123 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3124 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3125 (unsigned long long)sas_address);
3126
3127 mptsas_expander_refresh(ioc, port_info);
3128}
3129
3130/**
3131 * mptsas_delete_expander_siblings - remove siblings attached to expander
3132 * @ioc: Pointer to MPT_ADAPTER structure
3133 * @parent: the parent port_info object
3134 * @expander: the expander port_info object
3135 **/
3136static void
3137mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3138 *parent, struct mptsas_portinfo *expander)
3139{
3140 struct mptsas_phyinfo *phy_info;
3141 struct mptsas_portinfo *port_info;
3142 struct sas_rphy *rphy;
3143 int i;
3144
3145 phy_info = expander->phy_info;
3146 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3147 rphy = mptsas_get_rphy(phy_info);
3148 if (!rphy)
3149 continue;
3150 if (rphy->identify.device_type == SAS_END_DEVICE)
3151 mptsas_del_end_device(ioc, phy_info);
3152 }
3153
3154 phy_info = expander->phy_info;
3155 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3156 rphy = mptsas_get_rphy(phy_info);
3157 if (!rphy)
3158 continue;
3159 if (rphy->identify.device_type ==
3160 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3161 rphy->identify.device_type ==
3162 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3163 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3164 rphy->identify.sas_address);
3165 if (!port_info)
3166 continue;
3167 if (port_info == parent) /* backlink rphy */
3168 continue;
3169 /*
3170 Delete this expander even if the expdevpage is exists
3171 because the parent expander is already deleted
3172 */
3173 mptsas_expander_delete(ioc, port_info, 1);
3174 }
3175 }
3176}
3177
3178
3179/**
3180 * mptsas_expander_delete - remove this expander
3181 * @ioc: Pointer to MPT_ADAPTER structure
3182 * @port_info: expander port_info struct
3183 * @force: Flag to forcefully delete the expander
3184 *
3185 **/
3186
3187static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3188 struct mptsas_portinfo *port_info, u8 force)
3189{
3190
3191 struct mptsas_portinfo *parent;
3192 int i;
3193 u64 expander_sas_address;
3194 struct mptsas_phyinfo *phy_info;
3195 struct mptsas_portinfo buffer;
3196 struct mptsas_portinfo_details *port_details;
3197 struct sas_port *port;
3198
3199 if (!port_info)
3200 return;
3201
3202 /* see if expander is still there before deleting */
3203 mptsas_sas_expander_pg0(ioc, &buffer,
3204 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3205 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3206 port_info->phy_info[0].identify.handle);
3207
3208 if (buffer.num_phys) {
3209 kfree(buffer.phy_info);
3210 if (!force)
3211 return;
3212 }
3213
3214
3215 /*
3216 * Obtain the port_info instance to the parent port
3217 */
3218 port_details = NULL;
3219 expander_sas_address =
3220 port_info->phy_info[0].identify.sas_address;
3221 parent = mptsas_find_portinfo_by_handle(ioc,
3222 port_info->phy_info[0].identify.handle_parent);
3223 mptsas_delete_expander_siblings(ioc, parent, port_info);
3224 if (!parent)
3225 goto out;
3226
3227 /*
3228 * Delete rphys in the parent that point
3229 * to this expander.
3230 */
3231 phy_info = parent->phy_info;
3232 port = NULL;
3233 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3234 if (!phy_info->phy)
3235 continue;
3236 if (phy_info->attached.sas_address !=
3237 expander_sas_address)
3238 continue;
3239 if (!port) {
3240 port = mptsas_get_port(phy_info);
3241 port_details = phy_info->port_details;
3242 }
3243 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3244 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3245 phy_info->phy_id, phy_info->phy);
3246 sas_port_delete_phy(port, phy_info->phy);
3247 }
3248 if (port) {
3249 dev_printk(KERN_DEBUG, &port->dev,
3250 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3251 ioc->name, port->port_identifier,
3252 (unsigned long long)expander_sas_address);
3253 sas_port_delete(port);
3254 mptsas_port_delete(ioc, port_details);
3255 }
3256 out:
3257
3258 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3259 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3260 (unsigned long long)expander_sas_address);
3261
3262 /*
3263 * free link
3264 */
3265 list_del(&port_info->list);
3266 kfree(port_info->phy_info);
3267 kfree(port_info);
3268}
3269
3270
3271/**
3272 * mptsas_send_expander_event - expanders events
3273 * @ioc: Pointer to MPT_ADAPTER structure
3274 * @expander_data: event data
3275 *
3276 *
3277 * This function handles adding, removing, and refreshing
3278 * device handles within the expander objects.
3279 */
3280static void
3281mptsas_send_expander_event(struct fw_event_work *fw_event)
3282{
3283 MPT_ADAPTER *ioc;
3284 MpiEventDataSasExpanderStatusChange_t *expander_data;
3285 struct mptsas_portinfo *port_info;
3286 __le64 sas_address;
3287 int i;
3288
3289 ioc = fw_event->ioc;
3290 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3291 fw_event->event_data;
3292 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3293 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3294
3295 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3296 if (port_info) {
3297 for (i = 0; i < port_info->num_phys; i++) {
3298 port_info->phy_info[i].portinfo = port_info;
3299 port_info->phy_info[i].handle =
3300 le16_to_cpu(expander_data->DevHandle);
3301 port_info->phy_info[i].identify.sas_address =
3302 le64_to_cpu(sas_address);
3303 port_info->phy_info[i].identify.handle_parent =
3304 le16_to_cpu(expander_data->ParentDevHandle);
3305 }
3306 mptsas_expander_refresh(ioc, port_info);
3307 } else if (!port_info && expander_data->NumPhys)
3308 mptsas_expander_event_add(ioc, expander_data);
3309 } else if (expander_data->ReasonCode ==
3310 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3311 mptsas_expander_delete(ioc, port_info, 0);
3312
3313 mptsas_free_fw_event(ioc, fw_event);
3314}
3315
3316
3317/**
3318 * mptsas_expander_add -
3319 * @ioc: Pointer to MPT_ADAPTER structure
3320 * @handle:
3321 *
3322 */
3323struct mptsas_portinfo *
3324mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3325{
3326 struct mptsas_portinfo buffer, *port_info;
3327 int i;
3328
3329 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3330 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3331 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3332 return NULL;
3333
3334 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3335 if (!port_info) {
3336 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3337 "%s: exit at line=%d\n", ioc->name,
3338 __func__, __LINE__));
3339 return NULL;
3340 }
3341 port_info->num_phys = buffer.num_phys;
3342 port_info->phy_info = buffer.phy_info;
3343 for (i = 0; i < port_info->num_phys; i++)
3344 port_info->phy_info[i].portinfo = port_info;
3345 mutex_lock(&ioc->sas_topology_mutex);
3346 list_add_tail(&port_info->list, &ioc->sas_topology);
3347 mutex_unlock(&ioc->sas_topology_mutex);
3348 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3349 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3350 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3351 mptsas_expander_refresh(ioc, port_info);
3352 return port_info;
3353}
3354
3355static void
3356mptsas_send_link_status_event(struct fw_event_work *fw_event)
3357{
3358 MPT_ADAPTER *ioc;
3359 MpiEventDataSasPhyLinkStatus_t *link_data;
3360 struct mptsas_portinfo *port_info;
3361 struct mptsas_phyinfo *phy_info = NULL;
3362 __le64 sas_address;
3363 u8 phy_num;
3364 u8 link_rate;
3365
3366 ioc = fw_event->ioc;
3367 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3368
3369 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3370 sas_address = le64_to_cpu(sas_address);
3371 link_rate = link_data->LinkRates >> 4;
3372 phy_num = link_data->PhyNum;
3373
3374 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3375 if (port_info) {
3376 phy_info = &port_info->phy_info[phy_num];
3377 if (phy_info)
3378 phy_info->negotiated_link_rate = link_rate;
3379 }
3380
3381 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3382 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3383
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303384 if (!port_info) {
3385 if (ioc->old_sas_discovery_protocal) {
3386 port_info = mptsas_expander_add(ioc,
3387 le16_to_cpu(link_data->DevHandle));
3388 if (port_info)
3389 goto out;
3390 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303391 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303392 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303393
3394 if (port_info == ioc->hba_port_info)
3395 mptsas_probe_hba_phys(ioc);
3396 else
3397 mptsas_expander_refresh(ioc, port_info);
3398 } else if (phy_info && phy_info->phy) {
3399 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3400 phy_info->phy->negotiated_linkrate =
3401 SAS_PHY_DISABLED;
3402 else if (link_rate ==
3403 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3404 phy_info->phy->negotiated_linkrate =
3405 SAS_LINK_RATE_FAILED;
3406 else
3407 phy_info->phy->negotiated_linkrate =
3408 SAS_LINK_RATE_UNKNOWN;
3409 }
3410 out:
3411 mptsas_free_fw_event(ioc, fw_event);
3412}
3413
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303414static void
3415mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3416{
3417 struct mptsas_portinfo buffer, *port_info;
3418 struct mptsas_device_info *sas_info;
3419 struct mptsas_devinfo sas_device;
3420 u32 handle;
3421 VirtTarget *vtarget = NULL;
3422 struct mptsas_phyinfo *phy_info;
3423 u8 found_expander;
3424 int retval, retry_count;
3425 unsigned long flags;
3426
3427 mpt_findImVolumes(ioc);
3428
3429 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3430 if (ioc->ioc_reset_in_progress) {
3431 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3432 "%s: exiting due to a parallel reset \n", ioc->name,
3433 __func__));
3434 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3435 return;
3436 }
3437 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3438
3439 /* devices, logical volumes */
3440 mutex_lock(&ioc->sas_device_info_mutex);
3441 redo_device_scan:
3442 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303443 if (sas_info->is_cached)
3444 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303445 if (!sas_info->is_logical_volume) {
3446 sas_device.handle = 0;
3447 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303448retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303449 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303450 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3451 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3452 (sas_info->fw.channel << 8) +
3453 sas_info->fw.id);
3454
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303455 if (sas_device.handle)
3456 continue;
3457 if (retval == -EBUSY) {
3458 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3459 if (ioc->ioc_reset_in_progress) {
3460 dfailprintk(ioc,
3461 printk(MYIOC_s_DEBUG_FMT
3462 "%s: exiting due to reset\n",
3463 ioc->name, __func__));
3464 spin_unlock_irqrestore
3465 (&ioc->taskmgmt_lock, flags);
3466 mutex_unlock(&ioc->
3467 sas_device_info_mutex);
3468 return;
3469 }
3470 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3471 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303472 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303473
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303474 if (retval && (retval != -ENODEV)) {
3475 if (retry_count < 10) {
3476 retry_count++;
3477 goto retry_page;
3478 } else {
3479 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3480 "%s: Config page retry exceeded retry "
3481 "count deleting device 0x%llx\n",
3482 ioc->name, __func__,
3483 sas_info->sas_address));
3484 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303485 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303486
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303487 /* delete device */
3488 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303489 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303490
3491 if (vtarget)
3492 vtarget->deleted = 1;
3493
3494 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3495 sas_info->sas_address);
3496
3497 if (phy_info) {
3498 mptsas_del_end_device(ioc, phy_info);
3499 goto redo_device_scan;
3500 }
3501 } else
3502 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303503 }
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303504 mutex_lock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303505
3506 /* expanders */
3507 mutex_lock(&ioc->sas_topology_mutex);
3508 redo_expander_scan:
3509 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3510
3511 if (port_info->phy_info &&
3512 (!(port_info->phy_info[0].identify.device_info &
3513 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3514 continue;
3515 found_expander = 0;
3516 handle = 0xFFFF;
3517 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3518 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3519 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3520 !found_expander) {
3521
3522 handle = buffer.phy_info[0].handle;
3523 if (buffer.phy_info[0].identify.sas_address ==
3524 port_info->phy_info[0].identify.sas_address) {
3525 found_expander = 1;
3526 }
3527 kfree(buffer.phy_info);
3528 }
3529
3530 if (!found_expander) {
3531 mptsas_expander_delete(ioc, port_info, 0);
3532 goto redo_expander_scan;
3533 }
3534 }
3535 mutex_lock(&ioc->sas_topology_mutex);
3536}
3537
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303538/**
3539 * mptsas_probe_expanders - adding expanders
3540 * @ioc: Pointer to MPT_ADAPTER structure
3541 *
3542 **/
3543static void
3544mptsas_probe_expanders(MPT_ADAPTER *ioc)
3545{
3546 struct mptsas_portinfo buffer, *port_info;
3547 u32 handle;
3548 int i;
3549
3550 handle = 0xFFFF;
3551 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3552 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3553 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3554
3555 handle = buffer.phy_info[0].handle;
3556 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3557 buffer.phy_info[0].identify.sas_address);
3558
3559 if (port_info) {
3560 /* refreshing handles */
3561 for (i = 0; i < buffer.num_phys; i++) {
3562 port_info->phy_info[i].handle = handle;
3563 port_info->phy_info[i].identify.handle_parent =
3564 buffer.phy_info[0].identify.handle_parent;
3565 }
3566 mptsas_expander_refresh(ioc, port_info);
3567 kfree(buffer.phy_info);
3568 continue;
3569 }
3570
3571 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3572 if (!port_info) {
3573 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3574 "%s: exit at line=%d\n", ioc->name,
3575 __func__, __LINE__));
3576 return;
3577 }
3578 port_info->num_phys = buffer.num_phys;
3579 port_info->phy_info = buffer.phy_info;
3580 for (i = 0; i < port_info->num_phys; i++)
3581 port_info->phy_info[i].portinfo = port_info;
3582 mutex_lock(&ioc->sas_topology_mutex);
3583 list_add_tail(&port_info->list, &ioc->sas_topology);
3584 mutex_unlock(&ioc->sas_topology_mutex);
3585 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3586 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3587 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3588 mptsas_expander_refresh(ioc, port_info);
3589 }
3590}
3591
3592static void
3593mptsas_probe_devices(MPT_ADAPTER *ioc)
3594{
3595 u16 handle;
3596 struct mptsas_devinfo sas_device;
3597 struct mptsas_phyinfo *phy_info;
3598
3599 handle = 0xFFFF;
3600 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3601 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3602
3603 handle = sas_device.handle;
3604
3605 if ((sas_device.device_info &
3606 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3607 MPI_SAS_DEVICE_INFO_STP_TARGET |
3608 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3609 continue;
3610
3611 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3612 if (!phy_info)
3613 continue;
3614
3615 if (mptsas_get_rphy(phy_info))
3616 continue;
3617
3618 mptsas_add_end_device(ioc, phy_info);
3619 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003620}
3621
Kashyap, Desai2f187862009-05-29 16:52:37 +05303622/**
3623 * mptsas_scan_sas_topology -
3624 * @ioc: Pointer to MPT_ADAPTER structure
3625 * @sas_address:
3626 *
3627 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003628static void
3629mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3630{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303631 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003632 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003633
Moore, Erice6b2d762006-03-14 09:14:24 -07003634 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303635 mptsas_probe_expanders(ioc);
3636 mptsas_probe_devices(ioc);
3637
Moore, Ericf44e5462006-03-14 09:14:21 -07003638 /*
3639 Reporting RAID volumes.
3640 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303641 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3642 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3643 return;
Eric Moore793955f2007-01-29 09:42:20 -07003644 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303645 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3646 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3647 if (sdev) {
3648 scsi_device_put(sdev);
3649 continue;
3650 }
3651 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3652 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3653 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003654 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003655 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3656 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003657}
3658
Kashyap, Desai57e98512009-05-29 16:55:09 +05303659
3660static void
3661mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3662{
3663 MPT_ADAPTER *ioc;
3664 EventDataQueueFull_t *qfull_data;
3665 struct mptsas_device_info *sas_info;
3666 struct scsi_device *sdev;
3667 int depth;
3668 int id = -1;
3669 int channel = -1;
3670 int fw_id, fw_channel;
3671 u16 current_depth;
3672
3673
3674 ioc = fw_event->ioc;
3675 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3676 fw_id = qfull_data->TargetID;
3677 fw_channel = qfull_data->Bus;
3678 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3679
3680 /* if hidden raid component, look for the volume id */
3681 mutex_lock(&ioc->sas_device_info_mutex);
3682 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3683 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3684 list) {
3685 if (sas_info->is_cached ||
3686 sas_info->is_logical_volume)
3687 continue;
3688 if (sas_info->is_hidden_raid_component &&
3689 (sas_info->fw.channel == fw_channel &&
3690 sas_info->fw.id == fw_id)) {
3691 id = sas_info->volume_id;
3692 channel = MPTSAS_RAID_CHANNEL;
3693 goto out;
3694 }
3695 }
3696 } else {
3697 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3698 list) {
3699 if (sas_info->is_cached ||
3700 sas_info->is_hidden_raid_component ||
3701 sas_info->is_logical_volume)
3702 continue;
3703 if (sas_info->fw.channel == fw_channel &&
3704 sas_info->fw.id == fw_id) {
3705 id = sas_info->os.id;
3706 channel = sas_info->os.channel;
3707 goto out;
3708 }
3709 }
3710
3711 }
3712
3713 out:
3714 mutex_unlock(&ioc->sas_device_info_mutex);
3715
3716 if (id != -1) {
3717 shost_for_each_device(sdev, ioc->sh) {
3718 if (sdev->id == id && sdev->channel == channel) {
3719 if (current_depth > sdev->queue_depth) {
3720 sdev_printk(KERN_INFO, sdev,
3721 "strange observation, the queue "
3722 "depth is (%d) meanwhile fw queue "
3723 "depth (%d)\n", sdev->queue_depth,
3724 current_depth);
3725 continue;
3726 }
3727 depth = scsi_track_queue_full(sdev,
3728 current_depth - 1);
3729 if (depth > 0)
3730 sdev_printk(KERN_INFO, sdev,
3731 "Queue depth reduced to (%d)\n",
3732 depth);
3733 else if (depth < 0)
3734 sdev_printk(KERN_INFO, sdev,
3735 "Tagged Command Queueing is being "
3736 "disabled\n");
3737 else if (depth == 0)
3738 sdev_printk(KERN_INFO, sdev,
3739 "Queue depth not changed yet\n");
3740 }
3741 }
3742 }
3743
3744 mptsas_free_fw_event(ioc, fw_event);
3745}
3746
3747
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003748static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003749mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003750{
3751 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003752 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003753 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003754
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003755 mutex_lock(&ioc->sas_topology_mutex);
3756 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3757 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003758 if (!mptsas_is_end_device(
3759 &port_info->phy_info[i].attached))
3760 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003761 if (port_info->phy_info[i].attached.sas_address
3762 != sas_address)
3763 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003764 phy_info = &port_info->phy_info[i];
3765 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003766 }
3767 }
3768 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003769 return phy_info;
3770}
3771
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303772/**
3773 * mptsas_find_phyinfo_by_phys_disk_num -
3774 * @ioc: Pointer to MPT_ADAPTER structure
3775 * @phys_disk_num:
3776 * @channel:
3777 * @id:
3778 *
3779 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07003780static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303781mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
3782 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07003783{
Eric Mooreb506ade2007-01-29 09:45:37 -07003784 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303785 struct mptsas_portinfo *port_info;
3786 RaidPhysDiskPage1_t *phys_disk = NULL;
3787 int num_paths;
3788 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07003789 int i;
3790
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303791 phy_info = NULL;
3792 if (!ioc->raid_data.pIocPg3)
3793 return NULL;
3794 /* dual port support */
3795 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
3796 if (!num_paths)
3797 goto out;
3798 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
3799 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
3800 if (!phys_disk)
3801 goto out;
3802 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
3803 for (i = 0; i < num_paths; i++) {
3804 if ((phys_disk->Path[i].Flags & 1) != 0)
3805 /* entry no longer valid */
3806 continue;
3807 if ((id == phys_disk->Path[i].PhysDiskID) &&
3808 (channel == phys_disk->Path[i].PhysDiskBus)) {
3809 memcpy(&sas_address, &phys_disk->Path[i].WWID,
3810 sizeof(u64));
3811 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3812 sas_address);
3813 goto out;
3814 }
3815 }
3816
3817 out:
3818 kfree(phys_disk);
3819 if (phy_info)
3820 return phy_info;
3821
3822 /*
3823 * Extra code to handle RAID0 case, where the sas_address is not updated
3824 * in phys_disk_page_1 when hotswapped
3825 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003826 mutex_lock(&ioc->sas_topology_mutex);
3827 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303828 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07003829 if (!mptsas_is_end_device(
3830 &port_info->phy_info[i].attached))
3831 continue;
3832 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
3833 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303834 if ((port_info->phy_info[i].attached.phys_disk_num ==
3835 phys_disk_num) &&
3836 (port_info->phy_info[i].attached.id == id) &&
3837 (port_info->phy_info[i].attached.channel ==
3838 channel))
3839 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06003840 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003841 }
3842 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003843 return phy_info;
3844}
3845
3846static void
Moore, Ericf44e5462006-03-14 09:14:21 -07003847mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
3848{
Eric Mooref99be432007-01-04 20:46:54 -07003849 int rc;
3850
Moore, Ericf44e5462006-03-14 09:14:21 -07003851 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07003852 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07003853}
3854
3855static void
3856mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
3857{
3858 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
3859 mptsas_reprobe_lun);
3860}
3861
Eric Mooreb506ade2007-01-29 09:45:37 -07003862static void
3863mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
3864{
3865 CONFIGPARMS cfg;
3866 ConfigPageHeader_t hdr;
3867 dma_addr_t dma_handle;
3868 pRaidVolumePage0_t buffer = NULL;
3869 RaidPhysDiskPage0_t phys_disk;
3870 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303871 struct mptsas_phyinfo *phy_info;
3872 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07003873
3874 memset(&cfg, 0 , sizeof(CONFIGPARMS));
3875 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
3876 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
3877 cfg.pageAddr = (channel << 8) + id;
3878 cfg.cfghdr.hdr = &hdr;
3879 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3880
3881 if (mpt_config(ioc, &cfg) != 0)
3882 goto out;
3883
3884 if (!hdr.PageLength)
3885 goto out;
3886
3887 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
3888 &dma_handle);
3889
3890 if (!buffer)
3891 goto out;
3892
3893 cfg.physAddr = dma_handle;
3894 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3895
3896 if (mpt_config(ioc, &cfg) != 0)
3897 goto out;
3898
3899 if (!(buffer->VolumeStatus.Flags &
3900 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
3901 goto out;
3902
3903 if (!buffer->NumPhysDisks)
3904 goto out;
3905
3906 for (i = 0; i < buffer->NumPhysDisks; i++) {
3907
3908 if (mpt_raid_phys_disk_pg0(ioc,
3909 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
3910 continue;
3911
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303912 if (mptsas_sas_device_pg0(ioc, &sas_device,
3913 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3914 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3915 (phys_disk.PhysDiskBus << 8) +
3916 phys_disk.PhysDiskID))
3917 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003918
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303919 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3920 sas_device.sas_address);
3921 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07003922 }
3923
3924 out:
3925 if (buffer)
3926 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
3927 dma_handle);
3928}
Moore, Erice6b2d762006-03-14 09:14:24 -07003929/*
3930 * Work queue thread to handle SAS hotplug events
3931 */
Moore, Ericf44e5462006-03-14 09:14:21 -07003932static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303933mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
3934 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003935{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003936 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06003937 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003938 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07003939 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303940 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06003941
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303942 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003943
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303944 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07003945
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303946 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07003947 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003948
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303949 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
3950 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
3951 hot_plug_info->id) {
3952 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
3953 "to add hidden disk - target_id matchs "
3954 "volume_id\n", ioc->name);
3955 mptsas_free_fw_event(ioc, fw_event);
3956 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07003957 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003958 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303959 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003960
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003961 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303962 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
3963 mptsas_sas_device_pg0(ioc, &sas_device,
3964 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3965 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3966 (hot_plug_info->channel << 8) +
3967 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003968
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303969 if (!sas_device.handle)
3970 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06003971
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303972 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3973 if (!phy_info)
3974 break;
3975
3976 if (mptsas_get_rphy(phy_info))
3977 break;
3978
3979 mptsas_add_end_device(ioc, phy_info);
3980 break;
3981
3982 case MPTSAS_DEL_DEVICE:
3983 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3984 hot_plug_info->sas_address);
3985 mptsas_del_end_device(ioc, phy_info);
3986 break;
3987
3988 case MPTSAS_DEL_PHYSDISK:
3989
3990 mpt_findImVolumes(ioc);
3991
3992 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303993 ioc, hot_plug_info->phys_disk_num,
3994 hot_plug_info->channel,
3995 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303996 mptsas_del_end_device(ioc, phy_info);
3997 break;
3998
3999 case MPTSAS_ADD_PHYSDISK_REPROBE:
4000
Christoph Hellwige3094442006-02-16 13:25:36 +01004001 if (mptsas_sas_device_pg0(ioc, &sas_device,
4002 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004003 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304004 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4005 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4006 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4007 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004008 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004009 }
4010
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304011 phy_info = mptsas_find_phyinfo_by_sas_address(
4012 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004013
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304014 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304015 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304016 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4017 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004018 break;
4019 }
4020
4021 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304022 if (!starget) {
4023 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4024 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4025 __func__, hot_plug_info->id, __LINE__));
4026 break;
4027 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004028
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304029 vtarget = starget->hostdata;
4030 if (!vtarget) {
4031 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4032 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4033 __func__, hot_plug_info->id, __LINE__));
4034 break;
4035 }
Eric Moore547f9a22006-06-27 14:42:12 -06004036
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304037 mpt_findImVolumes(ioc);
4038
4039 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4040 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4041 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4042 hot_plug_info->phys_disk_num, (unsigned long long)
4043 sas_device.sas_address);
4044
4045 vtarget->id = hot_plug_info->phys_disk_num;
4046 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4047 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4048 mptsas_reprobe_target(starget, 1);
4049 break;
4050
4051 case MPTSAS_DEL_PHYSDISK_REPROBE:
4052
4053 if (mptsas_sas_device_pg0(ioc, &sas_device,
4054 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4055 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4056 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304057 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304058 "%s: fw_id=%d exit at line=%d\n",
4059 ioc->name, __func__,
4060 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004061 break;
4062 }
4063
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304064 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4065 sas_device.sas_address);
4066 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304067 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304068 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4069 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004070 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004071 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004072
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304073 starget = mptsas_get_starget(phy_info);
4074 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304075 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304076 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4077 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004078 break;
4079 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004080
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304081 vtarget = starget->hostdata;
4082 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304083 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304084 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4085 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004086 break;
4087 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304088
4089 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4090 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4091 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4092 __func__, hot_plug_info->id, __LINE__));
4093 break;
4094 }
4095
4096 mpt_findImVolumes(ioc);
4097
4098 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4099 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4100 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4101 hot_plug_info->phys_disk_num, (unsigned long long)
4102 sas_device.sas_address);
4103
4104 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4105 vtarget->id = hot_plug_info->id;
4106 phy_info->attached.phys_disk_num = ~0;
4107 mptsas_reprobe_target(starget, 0);
4108 mptsas_add_device_component_by_fw(ioc,
4109 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004110 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304111
Moore, Ericc73787ee2006-01-26 16:20:06 -07004112 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304113
Moore, Ericc73787ee2006-01-26 16:20:06 -07004114 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304115 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4116 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4117 hot_plug_info->id);
4118 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4119 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004120 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304121
Moore, Ericc73787ee2006-01-26 16:20:06 -07004122 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304123
Moore, Ericc73787ee2006-01-26 16:20:06 -07004124 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304125 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4126 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4127 hot_plug_info->id);
4128 scsi_remove_device(hot_plug_info->sdev);
4129 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004130 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304131
Eric Mooreb506ade2007-01-29 09:45:37 -07004132 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304133
4134 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004135 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304136 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004137 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304138
Moore, Ericbd23e942006-04-17 12:43:04 -06004139 default:
4140 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004141 }
4142
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304143 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004144}
4145
4146static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304147mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004148{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304149 MPT_ADAPTER *ioc;
4150 struct mptsas_hotplug_event hot_plug_info;
4151 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4152 u32 device_info;
4153 u64 sas_address;
4154
4155 ioc = fw_event->ioc;
4156 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4157 fw_event->event_data;
4158 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004159
4160 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304161 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4162 MPI_SAS_DEVICE_INFO_STP_TARGET |
4163 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4164 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004165 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304166 }
4167
4168 if (sas_event_data->ReasonCode ==
4169 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4170 mptbase_sas_persist_operation(ioc,
4171 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4172 mptsas_free_fw_event(ioc, fw_event);
4173 return;
4174 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004175
Moore, Eric4b766472006-03-14 09:14:12 -07004176 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004177 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004178 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304179 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4180 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4181 hot_plug_info.channel = sas_event_data->Bus;
4182 hot_plug_info.id = sas_event_data->TargetID;
4183 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004184 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304185 sizeof(u64));
4186 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4187 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004188 if (sas_event_data->ReasonCode &
4189 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304190 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004191 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304192 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4193 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004194 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304195
Moore, Eric4b766472006-03-14 09:14:12 -07004196 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304197 mptbase_sas_persist_operation(ioc,
4198 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4199 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004200 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304201
Moore, Eric4b766472006-03-14 09:14:12 -07004202 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304203 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004204 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304205 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004206 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304207 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004208 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004209 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004210}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304211
Moore, Ericc73787ee2006-01-26 16:20:06 -07004212static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304213mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004214{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304215 MPT_ADAPTER *ioc;
4216 EVENT_DATA_RAID *raid_event_data;
4217 struct mptsas_hotplug_event hot_plug_info;
4218 int status;
4219 int state;
4220 struct scsi_device *sdev = NULL;
4221 VirtDevice *vdevice = NULL;
4222 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004223
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304224 ioc = fw_event->ioc;
4225 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4226 status = le32_to_cpu(raid_event_data->SettingsStatus);
4227 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004228
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304229 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4230 hot_plug_info.id = raid_event_data->VolumeID;
4231 hot_plug_info.channel = raid_event_data->VolumeBus;
4232 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4233
4234 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4235 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4236 raid_event_data->ReasonCode ==
4237 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4238 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4239 hot_plug_info.id, 0);
4240 hot_plug_info.sdev = sdev;
4241 if (sdev)
4242 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004243 }
4244
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304245 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4246 "ReasonCode=%02x\n", ioc->name, __func__,
4247 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004248
4249 switch (raid_event_data->ReasonCode) {
4250 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304251 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004252 break;
4253 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304254 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004255 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004256 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4257 switch (state) {
4258 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004259 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304260 mpt_raid_phys_disk_pg0(ioc,
4261 raid_event_data->PhysDiskNum, &phys_disk);
4262 hot_plug_info.id = phys_disk.PhysDiskID;
4263 hot_plug_info.channel = phys_disk.PhysDiskBus;
4264 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004265 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304266 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004267 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004268 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4269 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4270 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304271 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004272 break;
4273 default:
4274 break;
4275 }
4276 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004277 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304278 if (!sdev)
4279 break;
4280 vdevice->vtarget->deleted = 1; /* block IO */
4281 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004282 break;
4283 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304284 if (sdev) {
4285 scsi_device_put(sdev);
4286 break;
4287 }
4288 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004289 break;
4290 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304291 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4292 if (!sdev)
4293 break;
4294 vdevice->vtarget->deleted = 1; /* block IO */
4295 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4296 break;
4297 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004298 switch (state) {
4299 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4300 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304301 if (!sdev)
4302 break;
4303 vdevice->vtarget->deleted = 1; /* block IO */
4304 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004305 break;
4306 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4307 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304308 if (sdev) {
4309 scsi_device_put(sdev);
4310 break;
4311 }
4312 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004313 break;
4314 default:
4315 break;
4316 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004317 break;
4318 default:
4319 break;
4320 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304321
4322 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4323 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4324 else
4325 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004326}
4327
Eric Mooreb506ade2007-01-29 09:45:37 -07004328/*
4329 * mptsas_send_ir2_event - handle exposing hidden disk when
4330 * an inactive raid volume is added
4331 *
4332 * @ioc: Pointer to MPT_ADAPTER structure
4333 * @ir2_data
4334 *
4335 */
4336static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304337mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004338{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304339 MPT_ADAPTER *ioc;
4340 struct mptsas_hotplug_event hot_plug_info;
4341 MPI_EVENT_DATA_IR2 *ir2_data;
4342 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304343 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004344
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304345 ioc = fw_event->ioc;
4346 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4347 reasonCode = ir2_data->ReasonCode;
4348
4349 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4350 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4351
4352 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4353 hot_plug_info.id = ir2_data->TargetID;
4354 hot_plug_info.channel = ir2_data->Bus;
4355 switch (reasonCode) {
4356 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4357 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4358 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304359 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4360 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4361 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4362 break;
4363 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4364 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4365 mpt_raid_phys_disk_pg0(ioc,
4366 ir2_data->PhysDiskNum, &phys_disk);
4367 hot_plug_info.id = phys_disk.PhysDiskID;
4368 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4369 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304370 default:
4371 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004372 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304373 }
4374 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4375}
Moore, Erice6b2d762006-03-14 09:14:24 -07004376
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004377static int
4378mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4379{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304380 u32 event = le32_to_cpu(reply->Event);
4381 int sz, event_data_sz;
4382 struct fw_event_work *fw_event;
4383 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004384
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304385 /* events turned off due to host reset or driver unloading */
4386 if (ioc->fw_events_off)
4387 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004388
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304389 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004390 switch (event) {
4391 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304392 {
4393 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4394 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4395
4396 if (sas_event_data->ReasonCode ==
4397 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4398 mptsas_target_reset_queue(ioc, sas_event_data);
4399 return 0;
4400 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004401 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304402 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304403 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4404 {
4405 MpiEventDataSasExpanderStatusChange_t *expander_data =
4406 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4407
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304408 if (ioc->old_sas_discovery_protocal)
4409 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304410
4411 if (expander_data->ReasonCode ==
4412 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4413 ioc->device_missing_delay)
4414 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004415 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304416 }
4417 case MPI_EVENT_SAS_DISCOVERY:
4418 {
4419 u32 discovery_status;
4420 EventDataSasDiscovery_t *discovery_data =
4421 (EventDataSasDiscovery_t *)reply->Data;
4422
4423 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4424 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304425 if (ioc->old_sas_discovery_protocal && !discovery_status)
4426 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304427 return 0;
4428 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304429 case MPI_EVENT_INTEGRATED_RAID:
4430 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004431 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304432 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4433 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004434 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004435 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304436 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004437 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004438
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304439 event_data_sz = ((reply->MsgLength * 4) -
4440 offsetof(EventNotificationReply_t, Data));
4441 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4442 fw_event = kzalloc(sz, GFP_ATOMIC);
4443 if (!fw_event) {
4444 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4445 __func__, __LINE__);
4446 return 0;
4447 }
4448 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4449 fw_event->event = event;
4450 fw_event->ioc = ioc;
4451 mptsas_add_fw_event(ioc, fw_event, delay);
4452 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004453}
4454
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304455/* Delete a volume when no longer listed in ioc pg2
4456 */
4457static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4458{
4459 struct scsi_device *sdev;
4460 int i;
4461
4462 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4463 if (!sdev)
4464 return;
4465 if (!ioc->raid_data.pIocPg2)
4466 goto out;
4467 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4468 goto out;
4469 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4470 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4471 goto release_sdev;
4472 out:
4473 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4474 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4475 scsi_remove_device(sdev);
4476 release_sdev:
4477 scsi_device_put(sdev);
4478}
4479
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004480static int
4481mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4482{
4483 struct Scsi_Host *sh;
4484 MPT_SCSI_HOST *hd;
4485 MPT_ADAPTER *ioc;
4486 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004487 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004488 int numSGE = 0;
4489 int scale;
4490 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004491 int error=0;
4492 int r;
4493
4494 r = mpt_attach(pdev,id);
4495 if (r)
4496 return r;
4497
4498 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304499 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004500 ioc->DoneCtx = mptsasDoneCtx;
4501 ioc->TaskCtx = mptsasTaskCtx;
4502 ioc->InternalCtx = mptsasInternalCtx;
4503
4504 /* Added sanity check on readiness of the MPT adapter.
4505 */
4506 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4507 printk(MYIOC_s_WARN_FMT
4508 "Skipping because it's not operational!\n",
4509 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004510 error = -ENODEV;
4511 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004512 }
4513
4514 if (!ioc->active) {
4515 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4516 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004517 error = -ENODEV;
4518 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004519 }
4520
4521 /* Sanity check - ensure at least 1 port is INITIATOR capable
4522 */
4523 ioc_cap = 0;
4524 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4525 if (ioc->pfacts[ii].ProtocolFlags &
4526 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4527 ioc_cap++;
4528 }
4529
4530 if (!ioc_cap) {
4531 printk(MYIOC_s_WARN_FMT
4532 "Skipping ioc=%p because SCSI Initiator mode "
4533 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004534 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004535 }
4536
4537 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4538 if (!sh) {
4539 printk(MYIOC_s_WARN_FMT
4540 "Unable to register controller with SCSI subsystem\n",
4541 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004542 error = -1;
4543 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004544 }
4545
4546 spin_lock_irqsave(&ioc->FreeQlock, flags);
4547
4548 /* Attach the SCSI Host to the IOC structure
4549 */
4550 ioc->sh = sh;
4551
4552 sh->io_port = 0;
4553 sh->n_io_port = 0;
4554 sh->irq = 0;
4555
4556 /* set 16 byte cdb's */
4557 sh->max_cmd_len = 16;
4558
Eric Moore793955f2007-01-29 09:42:20 -07004559 sh->max_id = ioc->pfacts[0].PortSCSIID;
4560 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004561
4562 sh->transportt = mptsas_transport_template;
4563
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004564 /* Required entry.
4565 */
4566 sh->unique_id = ioc->id;
4567
4568 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004569 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004570 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004571 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004572 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004573
4574 /* Verify that we won't exceed the maximum
4575 * number of chain buffers
4576 * We can optimize: ZZ = req_sz/sizeof(SGE)
4577 * For 32bit SGE's:
4578 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4579 * + (req_sz - 64)/sizeof(SGE)
4580 * A slightly different algorithm is required for
4581 * 64bit SGEs.
4582 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304583 scale = ioc->req_sz/ioc->SGE_size;
4584 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004585 numSGE = (scale - 1) *
4586 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304587 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004588 } else {
4589 numSGE = 1 + (scale - 1) *
4590 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304591 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004592 }
4593
4594 if (numSGE < sh->sg_tablesize) {
4595 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304596 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004597 "Resetting sg_tablesize to %d from %d\n",
4598 ioc->name, numSGE, sh->sg_tablesize));
4599 sh->sg_tablesize = numSGE;
4600 }
4601
Eric Mooree7eae9f2007-09-29 10:15:59 -06004602 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004603 hd->ioc = ioc;
4604
4605 /* SCSI needs scsi_cmnd lookup table!
4606 * (with size equal to req_depth*PtrSz!)
4607 */
Eric Mooree8206382007-09-29 10:16:53 -06004608 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
4609 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004610 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06004611 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004612 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004613 }
Eric Mooree8206382007-09-29 10:16:53 -06004614 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004615
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304616 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06004617 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004618
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004619 /* Clear the TM flags
4620 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004621 hd->abortSCpnt = NULL;
4622
4623 /* Clear the pointer used to store
4624 * single-threaded commands, i.e., those
4625 * issued during a bus scan, dv and
4626 * configuration pages.
4627 */
4628 hd->cmdPtr = NULL;
4629
4630 /* Initialize this SCSI Hosts' timers
4631 * To use, set the timer expires field
4632 * and add_timer
4633 */
4634 init_timer(&hd->timer);
4635 hd->timer.data = (unsigned long) hd;
4636 hd->timer.function = mptscsih_timer_expired;
4637
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004638 ioc->sas_data.ptClear = mpt_pt_clear;
4639
Eric Mooredf9e0622007-01-29 09:46:21 -07004640 hd->last_queue_full = 0;
4641 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304642 INIT_LIST_HEAD(&ioc->sas_device_info_list);
4643 mutex_init(&ioc->sas_device_info_mutex);
4644
Eric Mooredf9e0622007-01-29 09:46:21 -07004645 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4646
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004647 if (ioc->sas_data.ptClear==1) {
4648 mptbase_sas_persist_operation(
4649 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
4650 }
4651
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004652 error = scsi_add_host(sh, &ioc->pcidev->dev);
4653 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06004654 dprintk(ioc, printk(MYIOC_s_ERR_FMT
4655 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004656 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004657 }
4658
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304659 /* older firmware doesn't support expander events */
4660 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
4661 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004662 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304663 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004664 return 0;
4665
Eric Moore547f9a22006-06-27 14:42:12 -06004666 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004667
4668 mptscsih_remove(pdev);
4669 return error;
4670}
4671
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304672void
4673mptsas_shutdown(struct pci_dev *pdev)
4674{
4675 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4676
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304677 mptsas_fw_event_off(ioc);
4678 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304679}
4680
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004681static void __devexit mptsas_remove(struct pci_dev *pdev)
4682{
4683 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4684 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06004685 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004686
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304687 mptsas_shutdown(pdev);
4688
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304689 mptsas_del_device_components(ioc);
4690
Eric Mooreb506ade2007-01-29 09:45:37 -07004691 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004692 sas_remove_host(ioc->sh);
4693
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004694 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004695 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
4696 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06004697 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304698 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304699
Eric Moore547f9a22006-06-27 14:42:12 -06004700 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004701 kfree(p);
4702 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004703 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304704 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004705 mptscsih_remove(pdev);
4706}
4707
4708static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06004709 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004710 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004711 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004712 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004713 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004714 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004715 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004716 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004717 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004718 PCI_ANY_ID, PCI_ANY_ID },
4719 {0} /* Terminating entry */
4720};
4721MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
4722
4723
4724static struct pci_driver mptsas_driver = {
4725 .name = "mptsas",
4726 .id_table = mptsas_pci_table,
4727 .probe = mptsas_probe,
4728 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304729 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004730#ifdef CONFIG_PM
4731 .suspend = mptscsih_suspend,
4732 .resume = mptscsih_resume,
4733#endif
4734};
4735
4736static int __init
4737mptsas_init(void)
4738{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304739 int error;
4740
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004741 show_mptmod_ver(my_NAME, my_VERSION);
4742
4743 mptsas_transport_template =
4744 sas_attach_transport(&mptsas_transport_functions);
4745 if (!mptsas_transport_template)
4746 return -ENODEV;
4747
4748 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304749 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004750 mptsasInternalCtx =
4751 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004752 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304753 mptsasDeviceResetCtx =
4754 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004755
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304756 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
4757 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004758
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304759 error = pci_register_driver(&mptsas_driver);
4760 if (error)
4761 sas_release_transport(mptsas_transport_template);
4762
4763 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004764}
4765
4766static void __exit
4767mptsas_exit(void)
4768{
4769 pci_unregister_driver(&mptsas_driver);
4770 sas_release_transport(mptsas_transport_template);
4771
4772 mpt_reset_deregister(mptsasDoneCtx);
4773 mpt_event_deregister(mptsasDoneCtx);
4774
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004775 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004776 mpt_deregister(mptsasInternalCtx);
4777 mpt_deregister(mptsasTaskCtx);
4778 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304779 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004780}
4781
4782module_init(mptsas_init);
4783module_exit(mptsas_exit);