blob: 6aa91268afe9a9e9633b1a4d21d372f3489b586b [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);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200124
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530125static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
126 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200127{
Eric Moore29dd3602007-09-14 18:46:51 -0600128 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
129 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
130 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
131 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
132 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
133 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
134 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
135 ioc->name, phy_data->Port));
136 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
137 ioc->name, phy_data->PortFlags));
138 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
139 ioc->name, phy_data->PhyFlags));
140 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
141 ioc->name, phy_data->NegotiatedLinkRate));
142 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
143 "Controller PHY Device Info=0x%X\n", ioc->name,
144 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
145 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
146 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200147}
148
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530149static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200150{
151 __le64 sas_address;
152
153 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
154
Eric Moore29dd3602007-09-14 18:46:51 -0600155 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
156 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
157 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
158 "Attached Device Handle=0x%X\n", ioc->name,
159 le16_to_cpu(pg0->AttachedDevHandle)));
160 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
161 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
162 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
163 "Attached PHY Identifier=0x%X\n", ioc->name,
164 pg0->AttachedPhyIdentifier));
165 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
166 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
167 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
168 ioc->name, pg0->ProgrammedLinkRate));
169 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
170 ioc->name, pg0->ChangeCount));
171 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
172 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200173}
174
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530175static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200176{
Eric Moore29dd3602007-09-14 18:46:51 -0600177 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
178 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
179 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
180 ioc->name, pg1->InvalidDwordCount));
181 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
182 "Running Disparity Error Count=0x%x\n", ioc->name,
183 pg1->RunningDisparityErrorCount));
184 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
185 "Loss Dword Synch Count=0x%x\n", ioc->name,
186 pg1->LossDwordSynchCount));
187 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
188 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
189 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200190}
191
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530192static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200193{
194 __le64 sas_address;
195
196 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
197
Eric Moore29dd3602007-09-14 18:46:51 -0600198 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
199 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
200 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
201 ioc->name, le16_to_cpu(pg0->DevHandle)));
202 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
203 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
204 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
205 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
206 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
207 ioc->name, le16_to_cpu(pg0->Slot)));
208 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
209 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
210 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
211 ioc->name, pg0->TargetID));
212 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
213 ioc->name, pg0->Bus));
214 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
215 ioc->name, pg0->PhyNum));
216 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
217 ioc->name, le16_to_cpu(pg0->AccessStatus)));
218 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
219 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
220 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
221 ioc->name, le16_to_cpu(pg0->Flags)));
222 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
223 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200224}
225
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530226static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200227{
Eric Moore29dd3602007-09-14 18:46:51 -0600228 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
229 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
230 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
231 ioc->name, pg1->PhysicalPort));
232 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
233 ioc->name, pg1->PhyIdentifier));
234 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
235 ioc->name, pg1->NegotiatedLinkRate));
236 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
237 ioc->name, pg1->ProgrammedLinkRate));
238 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
239 ioc->name, pg1->HwLinkRate));
240 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
241 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
242 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
243 "Attached Device Handle=0x%X\n\n", ioc->name,
244 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200245}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200246
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530247/* inhibit sas firmware event handling */
248static void
249mptsas_fw_event_off(MPT_ADAPTER *ioc)
250{
251 unsigned long flags;
252
253 spin_lock_irqsave(&ioc->fw_event_lock, flags);
254 ioc->fw_events_off = 1;
255 ioc->sas_discovery_quiesce_io = 0;
256 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
257
258}
259
260/* enable sas firmware event handling */
261static void
262mptsas_fw_event_on(MPT_ADAPTER *ioc)
263{
264 unsigned long flags;
265
266 spin_lock_irqsave(&ioc->fw_event_lock, flags);
267 ioc->fw_events_off = 0;
268 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
269}
270
271/* queue a sas firmware event */
272static void
273mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
274 unsigned long delay)
275{
276 unsigned long flags;
277
278 spin_lock_irqsave(&ioc->fw_event_lock, flags);
279 list_add_tail(&fw_event->list, &ioc->fw_event_list);
280 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
281 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
282 ioc->name, __func__, fw_event));
283 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
284 delay);
285 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
286}
287
288/* free memory assoicated to a sas firmware event */
289static void
290mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
291{
292 unsigned long flags;
293
294 spin_lock_irqsave(&ioc->fw_event_lock, flags);
295 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
296 ioc->name, __func__, fw_event));
297 list_del(&fw_event->list);
298 kfree(fw_event);
299 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
300}
301
302/* walk the firmware event queue, and either stop or wait for
303 * outstanding events to complete */
304static void
305mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
306{
307 struct fw_event_work *fw_event, *next;
308 struct mptsas_target_reset_event *target_reset_list, *n;
309 u8 flush_q;
310 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
311
312 /* flush the target_reset_list */
313 if (!list_empty(&hd->target_reset_list)) {
314 list_for_each_entry_safe(target_reset_list, n,
315 &hd->target_reset_list, list) {
316 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
317 "%s: removing target reset for id=%d\n",
318 ioc->name, __func__,
319 target_reset_list->sas_event_data.TargetID));
320 list_del(&target_reset_list->list);
321 kfree(target_reset_list);
322 }
323 }
324
325 if (list_empty(&ioc->fw_event_list) ||
326 !ioc->fw_event_q || in_interrupt())
327 return;
328
329 flush_q = 0;
330 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
331 if (cancel_delayed_work(&fw_event->work))
332 mptsas_free_fw_event(ioc, fw_event);
333 else
334 flush_q = 1;
335 }
336 if (flush_q)
337 flush_workqueue(ioc->fw_event_q);
338}
339
340
Christoph Hellwige3094442006-02-16 13:25:36 +0100341static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
342{
343 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
344 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
345}
346
347static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
348{
349 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
350 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
351}
352
Moore, Erice6b2d762006-03-14 09:14:24 -0700353/*
354 * mptsas_find_portinfo_by_handle
355 *
356 * This function should be called with the sas_topology_mutex already held
357 */
358static struct mptsas_portinfo *
359mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
360{
361 struct mptsas_portinfo *port_info, *rc=NULL;
362 int i;
363
364 list_for_each_entry(port_info, &ioc->sas_topology, list)
365 for (i = 0; i < port_info->num_phys; i++)
366 if (port_info->phy_info[i].identify.handle == handle) {
367 rc = port_info;
368 goto out;
369 }
370 out:
371 return rc;
372}
373
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530374/**
375 * mptsas_find_portinfo_by_sas_address -
376 * @ioc: Pointer to MPT_ADAPTER structure
377 * @handle:
378 *
379 * This function should be called with the sas_topology_mutex already held
380 *
381 **/
382static struct mptsas_portinfo *
383mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
384{
385 struct mptsas_portinfo *port_info, *rc = NULL;
386 int i;
387
388 if (sas_address >= ioc->hba_port_sas_addr &&
389 sas_address < (ioc->hba_port_sas_addr +
390 ioc->hba_port_num_phy))
391 return ioc->hba_port_info;
392
393 mutex_lock(&ioc->sas_topology_mutex);
394 list_for_each_entry(port_info, &ioc->sas_topology, list)
395 for (i = 0; i < port_info->num_phys; i++)
396 if (port_info->phy_info[i].identify.sas_address ==
397 sas_address) {
398 rc = port_info;
399 goto out;
400 }
401 out:
402 mutex_unlock(&ioc->sas_topology_mutex);
403 return rc;
404}
405
Moore, Ericbd23e942006-04-17 12:43:04 -0600406/*
407 * Returns true if there is a scsi end device
408 */
409static inline int
410mptsas_is_end_device(struct mptsas_devinfo * attached)
411{
Eric Moore547f9a22006-06-27 14:42:12 -0600412 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600413 (attached->device_info &
414 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
415 ((attached->device_info &
416 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
417 (attached->device_info &
418 MPI_SAS_DEVICE_INFO_STP_TARGET) |
419 (attached->device_info &
420 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
421 return 1;
422 else
423 return 0;
424}
425
Eric Moore547f9a22006-06-27 14:42:12 -0600426/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600427static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530428mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600429{
430 struct mptsas_portinfo *port_info;
431 struct mptsas_phyinfo *phy_info;
432 u8 i;
433
434 if (!port_details)
435 return;
436
437 port_info = port_details->port_info;
438 phy_info = port_info->phy_info;
439
Eric Moore29dd3602007-09-14 18:46:51 -0600440 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700441 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700442 port_details->num_phys, (unsigned long long)
443 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600444
445 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
446 if(phy_info->port_details != port_details)
447 continue;
448 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530449 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600450 phy_info->port_details = NULL;
451 }
452 kfree(port_details);
453}
454
455static inline struct sas_rphy *
456mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
457{
458 if (phy_info->port_details)
459 return phy_info->port_details->rphy;
460 else
461 return NULL;
462}
463
464static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530465mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600466{
467 if (phy_info->port_details) {
468 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600469 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
470 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600471 }
472
Eric Moore547f9a22006-06-27 14:42:12 -0600473 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600474 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
475 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600476 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
477 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600478 }
Eric Moore547f9a22006-06-27 14:42:12 -0600479}
480
481static inline struct sas_port *
482mptsas_get_port(struct mptsas_phyinfo *phy_info)
483{
484 if (phy_info->port_details)
485 return phy_info->port_details->port;
486 else
487 return NULL;
488}
489
490static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530491mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600492{
493 if (phy_info->port_details)
494 phy_info->port_details->port = port;
495
Eric Moore547f9a22006-06-27 14:42:12 -0600496 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600497 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
498 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600499 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
500 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600501 }
Eric Moore547f9a22006-06-27 14:42:12 -0600502}
503
504static inline struct scsi_target *
505mptsas_get_starget(struct mptsas_phyinfo *phy_info)
506{
507 if (phy_info->port_details)
508 return phy_info->port_details->starget;
509 else
510 return NULL;
511}
512
513static inline void
514mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
515starget)
516{
517 if (phy_info->port_details)
518 phy_info->port_details->starget = starget;
519}
520
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530521/**
522 * mptsas_add_device_component -
523 * @ioc: Pointer to MPT_ADAPTER structure
524 * @channel: fw mapped id's
525 * @id:
526 * @sas_address:
527 * @device_info:
528 *
529 **/
530static void
531mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
532 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
533{
534 struct mptsas_device_info *sas_info, *next;
535 struct scsi_device *sdev;
536 struct scsi_target *starget;
537 struct sas_rphy *rphy;
538
539 /*
540 * Delete all matching devices out of the list
541 */
542 mutex_lock(&ioc->sas_device_info_mutex);
543 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
544 list) {
545 if ((sas_info->sas_address == sas_address ||
546 (sas_info->fw.channel == channel &&
547 sas_info->fw.id == id))) {
548 list_del(&sas_info->list);
549 kfree(sas_info);
550 }
551 }
552
553 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
554 if (!sas_info)
555 goto out;
556
557 /*
558 * Set Firmware mapping
559 */
560 sas_info->fw.id = id;
561 sas_info->fw.channel = channel;
562
563 sas_info->sas_address = sas_address;
564 sas_info->device_info = device_info;
565 sas_info->slot = slot;
566 sas_info->enclosure_logical_id = enclosure_logical_id;
567 INIT_LIST_HEAD(&sas_info->list);
568 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
569
570 /*
571 * Set OS mapping
572 */
573 shost_for_each_device(sdev, ioc->sh) {
574 starget = scsi_target(sdev);
575 rphy = dev_to_rphy(starget->dev.parent);
576 if (rphy->identify.sas_address == sas_address) {
577 sas_info->os.id = starget->id;
578 sas_info->os.channel = starget->channel;
579 }
580 }
581
582 out:
583 mutex_unlock(&ioc->sas_device_info_mutex);
584 return;
585}
586
587/**
588 * mptsas_add_device_component_by_fw -
589 * @ioc: Pointer to MPT_ADAPTER structure
590 * @channel: fw mapped id's
591 * @id:
592 *
593 **/
594static void
595mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
596{
597 struct mptsas_devinfo sas_device;
598 struct mptsas_enclosure enclosure_info;
599 int rc;
600
601 rc = mptsas_sas_device_pg0(ioc, &sas_device,
602 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
603 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
604 (channel << 8) + id);
605 if (rc)
606 return;
607
608 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
609 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
610 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
611 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
612 sas_device.handle_enclosure);
613
614 mptsas_add_device_component(ioc, sas_device.channel,
615 sas_device.id, sas_device.sas_address, sas_device.device_info,
616 sas_device.slot, enclosure_info.enclosure_logical_id);
617}
618
619/**
620 * mptsas_add_device_component_starget -
621 * @ioc: Pointer to MPT_ADAPTER structure
622 * @starget:
623 *
624 **/
625static void
626mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
627 struct scsi_target *starget)
628{
629 VirtTarget *vtarget;
630 struct sas_rphy *rphy;
631 struct mptsas_phyinfo *phy_info = NULL;
632 struct mptsas_enclosure enclosure_info;
633
634 rphy = dev_to_rphy(starget->dev.parent);
635 vtarget = starget->hostdata;
636 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
637 rphy->identify.sas_address);
638 if (!phy_info)
639 return;
640
641 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
642 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
643 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
644 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
645 phy_info->attached.handle_enclosure);
646
647 mptsas_add_device_component(ioc, phy_info->attached.channel,
648 phy_info->attached.id, phy_info->attached.sas_address,
649 phy_info->attached.device_info,
650 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
651}
652
653/**
654 * mptsas_del_device_components - Cleaning the list
655 * @ioc: Pointer to MPT_ADAPTER structure
656 *
657 **/
658static void
659mptsas_del_device_components(MPT_ADAPTER *ioc)
660{
661 struct mptsas_device_info *sas_info, *next;
662
663 mutex_lock(&ioc->sas_device_info_mutex);
664 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
665 list) {
666 list_del(&sas_info->list);
667 kfree(sas_info);
668 }
669 mutex_unlock(&ioc->sas_device_info_mutex);
670}
671
Eric Moore547f9a22006-06-27 14:42:12 -0600672
673/*
674 * mptsas_setup_wide_ports
675 *
676 * Updates for new and existing narrow/wide port configuration
677 * in the sas_topology
678 */
Eric Moore376ac832006-06-29 17:36:26 -0600679static void
Eric Moore547f9a22006-06-27 14:42:12 -0600680mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
681{
682 struct mptsas_portinfo_details * port_details;
683 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
684 u64 sas_address;
685 int i, j;
686
687 mutex_lock(&ioc->sas_topology_mutex);
688
689 phy_info = port_info->phy_info;
690 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
691 if (phy_info->attached.handle)
692 continue;
693 port_details = phy_info->port_details;
694 if (!port_details)
695 continue;
696 if (port_details->num_phys < 2)
697 continue;
698 /*
699 * Removing a phy from a port, letting the last
700 * phy be removed by firmware events.
701 */
Eric Moore29dd3602007-09-14 18:46:51 -0600702 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
703 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700704 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600705 port_details->num_phys--;
706 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
707 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
708 sas_port_delete_phy(port_details->port, phy_info->phy);
709 phy_info->port_details = NULL;
710 }
711
712 /*
713 * Populate and refresh the tree
714 */
715 phy_info = port_info->phy_info;
716 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
717 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600718 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
719 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600720 if (!sas_address)
721 continue;
722 port_details = phy_info->port_details;
723 /*
724 * Forming a port
725 */
726 if (!port_details) {
727 port_details = kzalloc(sizeof(*port_details),
728 GFP_KERNEL);
729 if (!port_details)
730 goto out;
731 port_details->num_phys = 1;
732 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600733 if (phy_info->phy_id < 64 )
734 port_details->phy_bitmask |=
735 (1 << phy_info->phy_id);
736 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600737 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700738 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600739 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600740 phy_info->port_details = port_details;
741 }
742
743 if (i == port_info->num_phys - 1)
744 continue;
745 phy_info_cmp = &port_info->phy_info[i + 1];
746 for (j = i + 1 ; j < port_info->num_phys ; j++,
747 phy_info_cmp++) {
748 if (!phy_info_cmp->attached.sas_address)
749 continue;
750 if (sas_address != phy_info_cmp->attached.sas_address)
751 continue;
752 if (phy_info_cmp->port_details == port_details )
753 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600754 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700755 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600756 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700757 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600758 if (phy_info_cmp->port_details) {
759 port_details->rphy =
760 mptsas_get_rphy(phy_info_cmp);
761 port_details->port =
762 mptsas_get_port(phy_info_cmp);
763 port_details->starget =
764 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600765 port_details->num_phys =
766 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600767 if (!phy_info_cmp->port_details->num_phys)
768 kfree(phy_info_cmp->port_details);
769 } else
770 phy_info_cmp->sas_port_add_phy=1;
771 /*
772 * Adding a phy to a port
773 */
774 phy_info_cmp->port_details = port_details;
775 if (phy_info_cmp->phy_id < 64 )
776 port_details->phy_bitmask |=
777 (1 << phy_info_cmp->phy_id);
778 port_details->num_phys++;
779 }
780 }
781
782 out:
783
Eric Moore547f9a22006-06-27 14:42:12 -0600784 for (i = 0; i < port_info->num_phys; i++) {
785 port_details = port_info->phy_info[i].port_details;
786 if (!port_details)
787 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600788 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700789 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700790 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700791 port_details, i, port_details->num_phys,
792 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600793 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
794 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600795 }
Eric Moore29dd3602007-09-14 18:46:51 -0600796 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600797 mutex_unlock(&ioc->sas_topology_mutex);
798}
799
Eric Mooredf9e0622007-01-29 09:46:21 -0700800/**
801 * csmisas_find_vtarget
802 *
803 * @ioc
804 * @volume_id
805 * @volume_bus
806 *
807 **/
808static VirtTarget *
809mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600810{
Eric Mooredf9e0622007-01-29 09:46:21 -0700811 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600812 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700813 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600814
Eric Mooredf9e0622007-01-29 09:46:21 -0700815 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530816 vdevice = sdev->hostdata;
817 if ((vdevice == NULL) ||
818 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700819 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600820 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530821 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600822 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600823 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700824 return vtarget;
825}
826
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530827static void
828mptsas_queue_device_delete(MPT_ADAPTER *ioc,
829 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
830{
831 struct fw_event_work *fw_event;
832 int sz;
833
834 sz = offsetof(struct fw_event_work, event_data) +
835 sizeof(MpiEventDataSasDeviceStatusChange_t);
836 fw_event = kzalloc(sz, GFP_ATOMIC);
837 if (!fw_event) {
838 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
839 ioc->name, __func__, __LINE__);
840 return;
841 }
842 memcpy(fw_event->event_data, sas_event_data,
843 sizeof(MpiEventDataSasDeviceStatusChange_t));
844 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
845 fw_event->ioc = ioc;
846 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
847}
848
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530849static void
850mptsas_queue_rescan(MPT_ADAPTER *ioc)
851{
852 struct fw_event_work *fw_event;
853 int sz;
854
855 sz = offsetof(struct fw_event_work, event_data);
856 fw_event = kzalloc(sz, GFP_ATOMIC);
857 if (!fw_event) {
858 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
859 ioc->name, __func__, __LINE__);
860 return;
861 }
862 fw_event->event = -1;
863 fw_event->ioc = ioc;
864 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
865}
866
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530867
Eric Mooredf9e0622007-01-29 09:46:21 -0700868/**
869 * mptsas_target_reset
870 *
871 * Issues TARGET_RESET to end device using handshaking method
872 *
873 * @ioc
874 * @channel
875 * @id
876 *
877 * Returns (1) success
878 * (0) failure
879 *
880 **/
881static int
882mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
883{
884 MPT_FRAME_HDR *mf;
885 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530886 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
887 return 0;
888
Eric Mooredf9e0622007-01-29 09:46:21 -0700889
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530890 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
891 if (mf == NULL) {
892 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530893 "%s, no msg frames @%d!!\n", ioc->name,
894 __func__, __LINE__));
895 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -0700896 }
897
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530898 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
899 ioc->name, mf));
900
Eric Mooredf9e0622007-01-29 09:46:21 -0700901 /* Format the Request
902 */
903 pScsiTm = (SCSITaskMgmt_t *) mf;
904 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
905 pScsiTm->TargetID = id;
906 pScsiTm->Bus = channel;
907 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
908 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
909 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
910
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530911 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700912
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530913 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
914 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
915 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
916
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530917 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700918
919 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530920
921 out_fail:
922
923 mpt_clear_taskmgmt_in_progress_flag(ioc);
924 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -0700925}
926
927/**
928 * mptsas_target_reset_queue
929 *
930 * Receive request for TARGET_RESET after recieving an firmware
931 * event NOT_RESPONDING_EVENT, then put command in link list
932 * and queue if task_queue already in use.
933 *
934 * @ioc
935 * @sas_event_data
936 *
937 **/
938static void
939mptsas_target_reset_queue(MPT_ADAPTER *ioc,
940 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
941{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600942 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700943 VirtTarget *vtarget = NULL;
944 struct mptsas_target_reset_event *target_reset_list;
945 u8 id, channel;
946
947 id = sas_event_data->TargetID;
948 channel = sas_event_data->Bus;
949
950 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
951 return;
952
953 vtarget->deleted = 1; /* block IO */
954
955 target_reset_list = kzalloc(sizeof(*target_reset_list),
956 GFP_ATOMIC);
957 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530958 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
959 "%s, failed to allocate mem @%d..!!\n",
960 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -0700961 return;
962 }
963
964 memcpy(&target_reset_list->sas_event_data, sas_event_data,
965 sizeof(*sas_event_data));
966 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
967
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530968 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -0700969
970 if (mptsas_target_reset(ioc, channel, id)) {
971 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700972 }
973}
974
975/**
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530976 * mptsas_taskmgmt_complete - Completion for TARGET_RESET after
977 * NOT_RESPONDING_EVENT, enable work queue to finish off removing device
978 * from upper layers. then send next TARGET_RESET in the queue.
979 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -0700980 *
981 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530982static int
983mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -0700984{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600985 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700986 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -0700987 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530988 struct mptsas_target_reset_event *target_reset_list;
989 SCSITaskMgmtReply_t *pScsiTmReply;
990
991 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
992 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
993
994 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
995 if (pScsiTmReply) {
996 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
997 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
998 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
999 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1000 "term_cmnds = %d\n", ioc->name,
1001 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1002 pScsiTmReply->TaskType,
1003 le16_to_cpu(pScsiTmReply->IOCStatus),
1004 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1005 pScsiTmReply->ResponseCode,
1006 le32_to_cpu(pScsiTmReply->TerminationCount)));
1007
1008 if (pScsiTmReply->ResponseCode)
1009 mptscsih_taskmgmt_response_code(ioc,
1010 pScsiTmReply->ResponseCode);
1011 }
1012
1013 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1014 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1015 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1016 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1017 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1018 memcpy(ioc->taskmgmt_cmds.reply, mr,
1019 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1020 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1021 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1022 complete(&ioc->taskmgmt_cmds.done);
1023 return 1;
1024 }
1025 return 0;
1026 }
1027
1028 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001029
1030 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301031 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001032
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301033 target_reset_list = list_entry(head->next,
1034 struct mptsas_target_reset_event, list);
1035
1036 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1037 "TaskMgmt: completed (%d seconds)\n",
1038 ioc->name, jiffies_to_msecs(jiffies -
1039 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001040
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301041 id = pScsiTmReply->TargetID;
1042 channel = pScsiTmReply->Bus;
1043 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001044
1045 /*
1046 * retry target reset
1047 */
1048 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301049 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001050 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301051 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001052 }
1053
1054 /*
1055 * enable work queue to remove device from upper layers
1056 */
1057 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301058 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1059 mptsas_queue_device_delete(ioc,
1060 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301061
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301062
Eric Mooredf9e0622007-01-29 09:46:21 -07001063 /*
1064 * issue target reset to next device in the queue
1065 */
1066
1067 head = &hd->target_reset_list;
1068 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301069 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001070
1071 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1072 list);
1073
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301074 id = target_reset_list->sas_event_data.TargetID;
1075 channel = target_reset_list->sas_event_data.Bus;
1076 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001077
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301078 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001079 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001080
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301081 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001082}
1083
1084/**
1085 * mptscsih_ioc_reset
1086 *
1087 * @ioc
1088 * @reset_phase
1089 *
1090 **/
1091static int
1092mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1093{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001094 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001095 int rc;
1096
1097 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301098 if ((ioc->bus_type != SAS) || (!rc))
1099 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001100
Eric Mooree7eae9f2007-09-29 10:15:59 -06001101 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001102 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001103 goto out;
1104
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301105 switch (reset_phase) {
1106 case MPT_IOC_SETUP_RESET:
1107 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1108 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1109 mptsas_fw_event_off(ioc);
1110 break;
1111 case MPT_IOC_PRE_RESET:
1112 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1113 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1114 break;
1115 case MPT_IOC_POST_RESET:
1116 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1117 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1118 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1119 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1120 complete(&ioc->sas_mgmt.done);
1121 }
1122 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301123 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301124 mptsas_fw_event_on(ioc);
1125 break;
1126 default:
1127 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001128 }
1129
1130 out:
1131 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001132}
1133
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301134
1135/**
1136 * enum device_state -
1137 * @DEVICE_RETRY: need to retry the TUR
1138 * @DEVICE_ERROR: TUR return error, don't add device
1139 * @DEVICE_READY: device can be added
1140 *
1141 */
1142enum device_state{
1143 DEVICE_RETRY,
1144 DEVICE_ERROR,
1145 DEVICE_READY,
1146};
1147
Christoph Hellwige3094442006-02-16 13:25:36 +01001148static int
Moore, Eric52435432006-03-14 09:14:15 -07001149mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001150 u32 form, u32 form_specific)
1151{
1152 ConfigExtendedPageHeader_t hdr;
1153 CONFIGPARMS cfg;
1154 SasEnclosurePage0_t *buffer;
1155 dma_addr_t dma_handle;
1156 int error;
1157 __le64 le_identifier;
1158
1159 memset(&hdr, 0, sizeof(hdr));
1160 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1161 hdr.PageNumber = 0;
1162 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1163 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1164
1165 cfg.cfghdr.ehdr = &hdr;
1166 cfg.physAddr = -1;
1167 cfg.pageAddr = form + form_specific;
1168 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1169 cfg.dir = 0; /* read */
1170 cfg.timeout = 10;
1171
1172 error = mpt_config(ioc, &cfg);
1173 if (error)
1174 goto out;
1175 if (!hdr.ExtPageLength) {
1176 error = -ENXIO;
1177 goto out;
1178 }
1179
1180 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1181 &dma_handle);
1182 if (!buffer) {
1183 error = -ENOMEM;
1184 goto out;
1185 }
1186
1187 cfg.physAddr = dma_handle;
1188 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1189
1190 error = mpt_config(ioc, &cfg);
1191 if (error)
1192 goto out_free_consistent;
1193
1194 /* save config data */
1195 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1196 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1197 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1198 enclosure->flags = le16_to_cpu(buffer->Flags);
1199 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1200 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1201 enclosure->start_id = buffer->StartTargetID;
1202 enclosure->start_channel = buffer->StartBus;
1203 enclosure->sep_id = buffer->SEPTargetID;
1204 enclosure->sep_channel = buffer->SEPBus;
1205
1206 out_free_consistent:
1207 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1208 buffer, dma_handle);
1209 out:
1210 return error;
1211}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001212
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301213/**
1214 * mptsas_add_end_device - report a new end device to sas transport layer
1215 * @ioc: Pointer to MPT_ADAPTER structure
1216 * @phy_info: decribes attached device
1217 *
1218 * return (0) success (1) failure
1219 *
1220 **/
1221static int
1222mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1223{
1224 struct sas_rphy *rphy;
1225 struct sas_port *port;
1226 struct sas_identify identify;
1227 char *ds = NULL;
1228 u8 fw_id;
1229
1230 if (!phy_info) {
1231 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1232 "%s: exit at line=%d\n", ioc->name,
1233 __func__, __LINE__));
1234 return 1;
1235 }
1236
1237 fw_id = phy_info->attached.id;
1238
1239 if (mptsas_get_rphy(phy_info)) {
1240 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1241 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1242 __func__, fw_id, __LINE__));
1243 return 2;
1244 }
1245
1246 port = mptsas_get_port(phy_info);
1247 if (!port) {
1248 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1249 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1250 __func__, fw_id, __LINE__));
1251 return 3;
1252 }
1253
1254 if (phy_info->attached.device_info &
1255 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1256 ds = "ssp";
1257 if (phy_info->attached.device_info &
1258 MPI_SAS_DEVICE_INFO_STP_TARGET)
1259 ds = "stp";
1260 if (phy_info->attached.device_info &
1261 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1262 ds = "sata";
1263
1264 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1265 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1266 phy_info->attached.channel, phy_info->attached.id,
1267 phy_info->attached.phy_id, (unsigned long long)
1268 phy_info->attached.sas_address);
1269
1270 mptsas_parse_device_info(&identify, &phy_info->attached);
1271 rphy = sas_end_device_alloc(port);
1272 if (!rphy) {
1273 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1274 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1275 __func__, fw_id, __LINE__));
1276 return 5; /* non-fatal: an rphy can be added later */
1277 }
1278
1279 rphy->identify = identify;
1280 if (sas_rphy_add(rphy)) {
1281 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1282 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1283 __func__, fw_id, __LINE__));
1284 sas_rphy_free(rphy);
1285 return 6;
1286 }
1287 mptsas_set_rphy(ioc, phy_info, rphy);
1288 return 0;
1289}
1290
1291/**
1292 * mptsas_del_end_device - report a deleted end device to sas transport
1293 * layer
1294 * @ioc: Pointer to MPT_ADAPTER structure
1295 * @phy_info: decribes attached device
1296 *
1297 **/
1298static void
1299mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1300{
1301 struct sas_rphy *rphy;
1302 struct sas_port *port;
1303 struct mptsas_portinfo *port_info;
1304 struct mptsas_phyinfo *phy_info_parent;
1305 int i;
1306 char *ds = NULL;
1307 u8 fw_id;
1308 u64 sas_address;
1309
1310 if (!phy_info)
1311 return;
1312
1313 fw_id = phy_info->attached.id;
1314 sas_address = phy_info->attached.sas_address;
1315
1316 if (!phy_info->port_details) {
1317 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1318 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1319 __func__, fw_id, __LINE__));
1320 return;
1321 }
1322 rphy = mptsas_get_rphy(phy_info);
1323 if (!rphy) {
1324 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1325 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1326 __func__, fw_id, __LINE__));
1327 return;
1328 }
1329
1330 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1331 || phy_info->attached.device_info
1332 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1333 || phy_info->attached.device_info
1334 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1335 ds = "initiator";
1336 if (phy_info->attached.device_info &
1337 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1338 ds = "ssp";
1339 if (phy_info->attached.device_info &
1340 MPI_SAS_DEVICE_INFO_STP_TARGET)
1341 ds = "stp";
1342 if (phy_info->attached.device_info &
1343 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1344 ds = "sata";
1345
1346 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1347 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1348 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1349 phy_info->attached.id, phy_info->attached.phy_id,
1350 (unsigned long long) sas_address);
1351
1352 port = mptsas_get_port(phy_info);
1353 if (!port) {
1354 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1355 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1356 __func__, fw_id, __LINE__));
1357 return;
1358 }
1359 port_info = phy_info->portinfo;
1360 phy_info_parent = port_info->phy_info;
1361 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1362 if (!phy_info_parent->phy)
1363 continue;
1364 if (phy_info_parent->attached.sas_address !=
1365 sas_address)
1366 continue;
1367 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1368 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1369 ioc->name, phy_info_parent->phy_id,
1370 phy_info_parent->phy);
1371 sas_port_delete_phy(port, phy_info_parent->phy);
1372 }
1373
1374 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1375 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1376 port->port_identifier, (unsigned long long)sas_address);
1377 sas_port_delete(port);
1378 mptsas_set_port(ioc, phy_info, NULL);
1379 mptsas_port_delete(ioc, phy_info->port_details);
1380}
1381
1382struct mptsas_phyinfo *
1383mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1384 struct mptsas_devinfo *sas_device)
1385{
1386 struct mptsas_phyinfo *phy_info;
1387 struct mptsas_portinfo *port_info;
1388 int i;
1389
1390 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1391 sas_device->sas_address);
1392 if (!phy_info)
1393 goto out;
1394 port_info = phy_info->portinfo;
1395 if (!port_info)
1396 goto out;
1397 mutex_lock(&ioc->sas_topology_mutex);
1398 for (i = 0; i < port_info->num_phys; i++) {
1399 if (port_info->phy_info[i].attached.sas_address !=
1400 sas_device->sas_address)
1401 continue;
1402 port_info->phy_info[i].attached.channel = sas_device->channel;
1403 port_info->phy_info[i].attached.id = sas_device->id;
1404 port_info->phy_info[i].attached.sas_address =
1405 sas_device->sas_address;
1406 port_info->phy_info[i].attached.handle = sas_device->handle;
1407 port_info->phy_info[i].attached.handle_parent =
1408 sas_device->handle_parent;
1409 port_info->phy_info[i].attached.handle_enclosure =
1410 sas_device->handle_enclosure;
1411 }
1412 mutex_unlock(&ioc->sas_topology_mutex);
1413 out:
1414 return phy_info;
1415}
1416
1417/**
1418 * mptsas_firmware_event_work - work thread for processing fw events
1419 * @work: work queue payload containing info describing the event
1420 * Context: user
1421 *
1422 */
1423static void
1424mptsas_firmware_event_work(struct work_struct *work)
1425{
1426 struct fw_event_work *fw_event =
1427 container_of(work, struct fw_event_work, work.work);
1428 MPT_ADAPTER *ioc = fw_event->ioc;
1429
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301430 /* special rescan topology handling */
1431 if (fw_event->event == -1) {
1432 if (ioc->in_rescan) {
1433 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1434 "%s: rescan ignored as it is in progress\n",
1435 ioc->name, __func__));
1436 return;
1437 }
1438 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1439 "reset\n", ioc->name, __func__));
1440 ioc->in_rescan = 1;
1441 mptsas_not_responding_devices(ioc);
1442 mptsas_scan_sas_topology(ioc);
1443 ioc->in_rescan = 0;
1444 mptsas_free_fw_event(ioc, fw_event);
1445 return;
1446 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301447
1448 /* events handling turned off during host reset */
1449 if (ioc->fw_events_off) {
1450 mptsas_free_fw_event(ioc, fw_event);
1451 return;
1452 }
1453
1454 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1455 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1456 (fw_event->event & 0xFF)));
1457
1458 switch (fw_event->event) {
1459 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1460 mptsas_send_sas_event(fw_event);
1461 break;
1462 case MPI_EVENT_INTEGRATED_RAID:
1463 mptsas_send_raid_event(fw_event);
1464 break;
1465 case MPI_EVENT_IR2:
1466 mptsas_send_ir2_event(fw_event);
1467 break;
1468 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1469 mptbase_sas_persist_operation(ioc,
1470 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1471 mptsas_free_fw_event(ioc, fw_event);
1472 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301473 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1474 mptsas_send_expander_event(fw_event);
1475 break;
1476 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1477 mptsas_send_link_status_event(fw_event);
1478 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301479 }
1480}
1481
1482
1483
James Bottomleyf013db32006-03-18 14:54:36 -06001484static int
1485mptsas_slave_configure(struct scsi_device *sdev)
1486{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301487 struct Scsi_Host *host = sdev->host;
1488 MPT_SCSI_HOST *hd = shost_priv(host);
1489 MPT_ADAPTER *ioc = hd->ioc;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001490
James Bottomleye8bf3942006-07-11 17:49:34 -04001491 if (sdev->channel == MPTSAS_RAID_CHANNEL)
1492 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -06001493
James Bottomleye8bf3942006-07-11 17:49:34 -04001494 sas_read_port_mode_page(sdev);
1495
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301496 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1497
James Bottomleye8bf3942006-07-11 17:49:34 -04001498 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001499 return mptscsih_slave_configure(sdev);
1500}
1501
Eric Moore547f9a22006-06-27 14:42:12 -06001502static int
1503mptsas_target_alloc(struct scsi_target *starget)
1504{
1505 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001506 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001507 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001508 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001509 struct sas_rphy *rphy;
1510 struct mptsas_portinfo *p;
1511 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001512 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001513
1514 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1515 if (!vtarget)
1516 return -ENOMEM;
1517
1518 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001519 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001520 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1521 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001522 channel = 0;
1523
Eric Moore793955f2007-01-29 09:42:20 -07001524 /*
1525 * RAID volumes placed beyond the last expected port.
1526 */
1527 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001528 for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
1529 if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
1530 channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -06001531 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001532 }
Eric Moore547f9a22006-06-27 14:42:12 -06001533
1534 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001535 mutex_lock(&ioc->sas_topology_mutex);
1536 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001537 for (i = 0; i < p->num_phys; i++) {
1538 if (p->phy_info[i].attached.sas_address !=
1539 rphy->identify.sas_address)
1540 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001541 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001542 channel = p->phy_info[i].attached.channel;
1543 mptsas_set_starget(&p->phy_info[i], starget);
1544
1545 /*
1546 * Exposing hidden raid components
1547 */
Eric Mooree80b0022007-09-14 18:49:03 -06001548 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1549 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001550 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001551 vtarget->tflags |=
1552 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001553 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001554 }
Eric Mooree80b0022007-09-14 18:49:03 -06001555 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001556 goto out;
1557 }
1558 }
Eric Mooree80b0022007-09-14 18:49:03 -06001559 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001560
1561 kfree(vtarget);
1562 return -ENXIO;
1563
1564 out:
Eric Moore793955f2007-01-29 09:42:20 -07001565 vtarget->id = id;
1566 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001567 starget->hostdata = vtarget;
1568 return 0;
1569}
1570
1571static void
1572mptsas_target_destroy(struct scsi_target *starget)
1573{
1574 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001575 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001576 struct sas_rphy *rphy;
1577 struct mptsas_portinfo *p;
1578 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301579 MPT_ADAPTER *ioc = hd->ioc;
1580 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001581
1582 if (!starget->hostdata)
1583 return;
1584
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301585 vtarget = starget->hostdata;
1586
1587
James Bottomleye8bf3942006-07-11 17:49:34 -04001588 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001589 goto out;
1590
1591 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001592 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001593 for (i = 0; i < p->num_phys; i++) {
1594 if (p->phy_info[i].attached.sas_address !=
1595 rphy->identify.sas_address)
1596 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301597
1598 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1599 "delete device: fw_channel %d, fw_id %d, phy %d, "
1600 "sas_addr 0x%llx\n", ioc->name,
1601 p->phy_info[i].attached.channel,
1602 p->phy_info[i].attached.id,
1603 p->phy_info[i].attached.phy_id, (unsigned long long)
1604 p->phy_info[i].attached.sas_address);
1605
Eric Moore547f9a22006-06-27 14:42:12 -06001606 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001607 }
1608 }
1609
1610 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301611 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001612 kfree(starget->hostdata);
1613 starget->hostdata = NULL;
1614}
1615
1616
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001617static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001618mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001619{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001620 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001621 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001622 struct sas_rphy *rphy;
1623 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001624 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001625 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001626 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001627 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001628
Eric Moorea69de502007-09-14 18:48:19 -06001629 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1630 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001631 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001632 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001633 return -ENOMEM;
1634 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001635 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001636 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001637
James Bottomleye8bf3942006-07-11 17:49:34 -04001638 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001639 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001640
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001641 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001642 mutex_lock(&ioc->sas_topology_mutex);
1643 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001644 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001645 if (p->phy_info[i].attached.sas_address !=
1646 rphy->identify.sas_address)
1647 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001648 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001649 /*
1650 * Exposing hidden raid components
1651 */
Eric Mooree80b0022007-09-14 18:49:03 -06001652 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001653 p->phy_info[i].attached.channel,
1654 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001655 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001656 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001657 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001658 }
1659 }
Eric Mooree80b0022007-09-14 18:49:03 -06001660 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001661
Eric Moorea69de502007-09-14 18:48:19 -06001662 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001663 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001664
1665 out:
Eric Moorea69de502007-09-14 18:48:19 -06001666 vdevice->vtarget->num_luns++;
1667 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001668 return 0;
1669}
1670
Eric Moore547f9a22006-06-27 14:42:12 -06001671static int
1672mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001673{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301674 MPT_SCSI_HOST *hd;
1675 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001676 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001677
Eric Moorea69de502007-09-14 18:48:19 -06001678 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001679 SCpnt->result = DID_NO_CONNECT << 16;
1680 done(SCpnt);
1681 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001682 }
Eric Moore547f9a22006-06-27 14:42:12 -06001683
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301684 hd = shost_priv(SCpnt->device->host);
1685 ioc = hd->ioc;
1686
1687 if (ioc->sas_discovery_quiesce_io)
1688 return SCSI_MLQUEUE_HOST_BUSY;
1689
Eric Moore793955f2007-01-29 09:42:20 -07001690// scsi_print_command(SCpnt);
1691
Eric Moore547f9a22006-06-27 14:42:12 -06001692 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001693}
1694
Eric Moore547f9a22006-06-27 14:42:12 -06001695
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001696static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001697 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001698 .proc_name = "mptsas",
1699 .proc_info = mptscsih_proc_info,
1700 .name = "MPT SPI Host",
1701 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001702 .queuecommand = mptsas_qcmd,
1703 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001704 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001705 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001706 .target_destroy = mptsas_target_destroy,
1707 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001708 .change_queue_depth = mptscsih_change_queue_depth,
1709 .eh_abort_handler = mptscsih_abort,
1710 .eh_device_reset_handler = mptscsih_dev_reset,
1711 .eh_bus_reset_handler = mptscsih_bus_reset,
1712 .eh_host_reset_handler = mptscsih_host_reset,
1713 .bios_param = mptscsih_bios_param,
1714 .can_queue = MPT_FC_CAN_QUEUE,
1715 .this_id = -1,
1716 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1717 .max_sectors = 8192,
1718 .cmd_per_lun = 7,
1719 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301720 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001721};
1722
Christoph Hellwigb5141122005-10-28 22:07:41 +02001723static int mptsas_get_linkerrors(struct sas_phy *phy)
1724{
1725 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1726 ConfigExtendedPageHeader_t hdr;
1727 CONFIGPARMS cfg;
1728 SasPhyPage1_t *buffer;
1729 dma_addr_t dma_handle;
1730 int error;
1731
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001732 /* FIXME: only have link errors on local phys */
1733 if (!scsi_is_sas_phy_local(phy))
1734 return -EINVAL;
1735
Christoph Hellwigb5141122005-10-28 22:07:41 +02001736 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1737 hdr.ExtPageLength = 0;
1738 hdr.PageNumber = 1 /* page number 1*/;
1739 hdr.Reserved1 = 0;
1740 hdr.Reserved2 = 0;
1741 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1742 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1743
1744 cfg.cfghdr.ehdr = &hdr;
1745 cfg.physAddr = -1;
1746 cfg.pageAddr = phy->identify.phy_identifier;
1747 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1748 cfg.dir = 0; /* read */
1749 cfg.timeout = 10;
1750
1751 error = mpt_config(ioc, &cfg);
1752 if (error)
1753 return error;
1754 if (!hdr.ExtPageLength)
1755 return -ENXIO;
1756
1757 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1758 &dma_handle);
1759 if (!buffer)
1760 return -ENOMEM;
1761
1762 cfg.physAddr = dma_handle;
1763 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1764
1765 error = mpt_config(ioc, &cfg);
1766 if (error)
1767 goto out_free_consistent;
1768
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301769 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001770
1771 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1772 phy->running_disparity_error_count =
1773 le32_to_cpu(buffer->RunningDisparityErrorCount);
1774 phy->loss_of_dword_sync_count =
1775 le32_to_cpu(buffer->LossDwordSynchCount);
1776 phy->phy_reset_problem_count =
1777 le32_to_cpu(buffer->PhyResetProblemCount);
1778
1779 out_free_consistent:
1780 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1781 buffer, dma_handle);
1782 return error;
1783}
1784
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001785static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1786 MPT_FRAME_HDR *reply)
1787{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301788 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001789 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301790 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001791 memcpy(ioc->sas_mgmt.reply, reply,
1792 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1793 }
1794 complete(&ioc->sas_mgmt.done);
1795 return 1;
1796}
1797
1798static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1799{
1800 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1801 SasIoUnitControlRequest_t *req;
1802 SasIoUnitControlReply_t *reply;
1803 MPT_FRAME_HDR *mf;
1804 MPIHeader_t *hdr;
1805 unsigned long timeleft;
1806 int error = -ERESTARTSYS;
1807
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001808 /* FIXME: fusion doesn't allow non-local phy reset */
1809 if (!scsi_is_sas_phy_local(phy))
1810 return -EINVAL;
1811
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001812 /* not implemented for expanders */
1813 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1814 return -ENXIO;
1815
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001816 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001817 goto out;
1818
1819 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1820 if (!mf) {
1821 error = -ENOMEM;
1822 goto out_unlock;
1823 }
1824
1825 hdr = (MPIHeader_t *) mf;
1826 req = (SasIoUnitControlRequest_t *)mf;
1827 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1828 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1829 req->MsgContext = hdr->MsgContext;
1830 req->Operation = hard_reset ?
1831 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1832 req->PhyNum = phy->identify.phy_identifier;
1833
1834 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1835
1836 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1837 10 * HZ);
1838 if (!timeleft) {
1839 /* On timeout reset the board */
1840 mpt_free_msg_frame(ioc, mf);
1841 mpt_HardResetHandler(ioc, CAN_SLEEP);
1842 error = -ETIMEDOUT;
1843 goto out_unlock;
1844 }
1845
1846 /* a reply frame is expected */
1847 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301848 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001849 error = -ENXIO;
1850 goto out_unlock;
1851 }
1852
1853 /* process the completed Reply Message Frame */
1854 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1855 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001856 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001857 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001858 error = -ENXIO;
1859 goto out_unlock;
1860 }
1861
1862 error = 0;
1863
1864 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001865 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001866 out:
1867 return error;
1868}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001869
Christoph Hellwige3094442006-02-16 13:25:36 +01001870static int
1871mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1872{
1873 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1874 int i, error;
1875 struct mptsas_portinfo *p;
1876 struct mptsas_enclosure enclosure_info;
1877 u64 enclosure_handle;
1878
1879 mutex_lock(&ioc->sas_topology_mutex);
1880 list_for_each_entry(p, &ioc->sas_topology, list) {
1881 for (i = 0; i < p->num_phys; i++) {
1882 if (p->phy_info[i].attached.sas_address ==
1883 rphy->identify.sas_address) {
1884 enclosure_handle = p->phy_info[i].
1885 attached.handle_enclosure;
1886 goto found_info;
1887 }
1888 }
1889 }
1890 mutex_unlock(&ioc->sas_topology_mutex);
1891 return -ENXIO;
1892
1893 found_info:
1894 mutex_unlock(&ioc->sas_topology_mutex);
1895 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001896 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001897 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1898 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1899 if (!error)
1900 *identifier = enclosure_info.enclosure_logical_id;
1901 return error;
1902}
1903
1904static int
1905mptsas_get_bay_identifier(struct sas_rphy *rphy)
1906{
1907 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1908 struct mptsas_portinfo *p;
1909 int i, rc;
1910
1911 mutex_lock(&ioc->sas_topology_mutex);
1912 list_for_each_entry(p, &ioc->sas_topology, list) {
1913 for (i = 0; i < p->num_phys; i++) {
1914 if (p->phy_info[i].attached.sas_address ==
1915 rphy->identify.sas_address) {
1916 rc = p->phy_info[i].attached.slot;
1917 goto out;
1918 }
1919 }
1920 }
1921 rc = -ENXIO;
1922 out:
1923 mutex_unlock(&ioc->sas_topology_mutex);
1924 return rc;
1925}
1926
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001927static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1928 struct request *req)
1929{
1930 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1931 MPT_FRAME_HDR *mf;
1932 SmpPassthroughRequest_t *smpreq;
1933 struct request *rsp = req->next_rq;
1934 int ret;
1935 int flagsLength;
1936 unsigned long timeleft;
1937 char *psge;
1938 dma_addr_t dma_addr_in = 0;
1939 dma_addr_t dma_addr_out = 0;
1940 u64 sas_address = 0;
1941
1942 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06001943 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001944 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001945 return -EINVAL;
1946 }
1947
1948 /* do we need to support multiple segments? */
1949 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06001950 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001951 ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
Eric Moore29dd3602007-09-14 18:46:51 -06001952 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001953 return -EINVAL;
1954 }
1955
1956 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1957 if (ret)
1958 goto out;
1959
1960 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1961 if (!mf) {
1962 ret = -ENOMEM;
1963 goto out_unlock;
1964 }
1965
1966 smpreq = (SmpPassthroughRequest_t *)mf;
1967 memset(smpreq, 0, sizeof(*smpreq));
1968
1969 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1970 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1971
1972 if (rphy)
1973 sas_address = rphy->identify.sas_address;
1974 else {
1975 struct mptsas_portinfo *port_info;
1976
1977 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301978 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001979 if (port_info && port_info->phy_info)
1980 sas_address =
1981 port_info->phy_info[0].phy->identify.sas_address;
1982 mutex_unlock(&ioc->sas_topology_mutex);
1983 }
1984
1985 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1986
1987 psge = (char *)
1988 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1989
1990 /* request */
1991 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1992 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301993 MPI_SGE_FLAGS_DIRECTION)
1994 << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001995 flagsLength |= (req->data_len - 4);
1996
1997 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1998 req->data_len, PCI_DMA_BIDIRECTIONAL);
1999 if (!dma_addr_out)
2000 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302001 ioc->add_sge(psge, flagsLength, dma_addr_out);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002002 psge += (sizeof(u32) + sizeof(dma_addr_t));
2003
2004 /* response */
2005 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
2006 flagsLength |= rsp->data_len + 4;
2007 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
2008 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
2009 if (!dma_addr_in)
2010 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302011 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002012
2013 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2014
2015 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2016 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002017 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002018 /* On timeout reset the board */
2019 mpt_HardResetHandler(ioc, CAN_SLEEP);
2020 ret = -ETIMEDOUT;
2021 goto unmap;
2022 }
2023 mf = NULL;
2024
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302025 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002026 SmpPassthroughReply_t *smprep;
2027
2028 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2029 memcpy(req->sense, smprep, sizeof(*smprep));
2030 req->sense_len = sizeof(*smprep);
FUJITA Tomonori38b31672007-12-30 19:34:52 +09002031 req->data_len = 0;
2032 rsp->data_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002033 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06002034 printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002035 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002036 ret = -ENXIO;
2037 }
2038unmap:
2039 if (dma_addr_out)
2040 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
2041 PCI_DMA_BIDIRECTIONAL);
2042 if (dma_addr_in)
2043 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
2044 PCI_DMA_BIDIRECTIONAL);
2045put_mf:
2046 if (mf)
2047 mpt_free_msg_frame(ioc, mf);
2048out_unlock:
2049 mutex_unlock(&ioc->sas_mgmt.mutex);
2050out:
2051 return ret;
2052}
2053
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002054static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002055 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002056 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2057 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002058 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002059 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002060};
2061
2062static struct scsi_transport_template *mptsas_transport_template;
2063
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002064static int
2065mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2066{
2067 ConfigExtendedPageHeader_t hdr;
2068 CONFIGPARMS cfg;
2069 SasIOUnitPage0_t *buffer;
2070 dma_addr_t dma_handle;
2071 int error, i;
2072
2073 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2074 hdr.ExtPageLength = 0;
2075 hdr.PageNumber = 0;
2076 hdr.Reserved1 = 0;
2077 hdr.Reserved2 = 0;
2078 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2079 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2080
2081 cfg.cfghdr.ehdr = &hdr;
2082 cfg.physAddr = -1;
2083 cfg.pageAddr = 0;
2084 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2085 cfg.dir = 0; /* read */
2086 cfg.timeout = 10;
2087
2088 error = mpt_config(ioc, &cfg);
2089 if (error)
2090 goto out;
2091 if (!hdr.ExtPageLength) {
2092 error = -ENXIO;
2093 goto out;
2094 }
2095
2096 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2097 &dma_handle);
2098 if (!buffer) {
2099 error = -ENOMEM;
2100 goto out;
2101 }
2102
2103 cfg.physAddr = dma_handle;
2104 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2105
2106 error = mpt_config(ioc, &cfg);
2107 if (error)
2108 goto out_free_consistent;
2109
2110 port_info->num_phys = buffer->NumPhys;
2111 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06002112 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002113 if (!port_info->phy_info) {
2114 error = -ENOMEM;
2115 goto out_free_consistent;
2116 }
2117
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302118 ioc->nvdata_version_persistent =
2119 le16_to_cpu(buffer->NvdataVersionPersistent);
2120 ioc->nvdata_version_default =
2121 le16_to_cpu(buffer->NvdataVersionDefault);
2122
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002123 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302124 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002125 port_info->phy_info[i].phy_id = i;
2126 port_info->phy_info[i].port_id =
2127 buffer->PhyData[i].Port;
2128 port_info->phy_info[i].negotiated_link_rate =
2129 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002130 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002131 port_info->phy_info[i].handle =
2132 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002133 }
2134
2135 out_free_consistent:
2136 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2137 buffer, dma_handle);
2138 out:
2139 return error;
2140}
2141
2142static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302143mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2144{
2145 ConfigExtendedPageHeader_t hdr;
2146 CONFIGPARMS cfg;
2147 SasIOUnitPage1_t *buffer;
2148 dma_addr_t dma_handle;
2149 int error;
2150 u16 device_missing_delay;
2151
2152 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2153 memset(&cfg, 0, sizeof(CONFIGPARMS));
2154
2155 cfg.cfghdr.ehdr = &hdr;
2156 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2157 cfg.timeout = 10;
2158 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2159 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2160 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2161 cfg.cfghdr.ehdr->PageNumber = 1;
2162
2163 error = mpt_config(ioc, &cfg);
2164 if (error)
2165 goto out;
2166 if (!hdr.ExtPageLength) {
2167 error = -ENXIO;
2168 goto out;
2169 }
2170
2171 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2172 &dma_handle);
2173 if (!buffer) {
2174 error = -ENOMEM;
2175 goto out;
2176 }
2177
2178 cfg.physAddr = dma_handle;
2179 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2180
2181 error = mpt_config(ioc, &cfg);
2182 if (error)
2183 goto out_free_consistent;
2184
2185 ioc->io_missing_delay =
2186 le16_to_cpu(buffer->IODeviceMissingDelay);
2187 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2188 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2189 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2190 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2191
2192 out_free_consistent:
2193 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2194 buffer, dma_handle);
2195 out:
2196 return error;
2197}
2198
2199static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002200mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2201 u32 form, u32 form_specific)
2202{
2203 ConfigExtendedPageHeader_t hdr;
2204 CONFIGPARMS cfg;
2205 SasPhyPage0_t *buffer;
2206 dma_addr_t dma_handle;
2207 int error;
2208
2209 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2210 hdr.ExtPageLength = 0;
2211 hdr.PageNumber = 0;
2212 hdr.Reserved1 = 0;
2213 hdr.Reserved2 = 0;
2214 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2215 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2216
2217 cfg.cfghdr.ehdr = &hdr;
2218 cfg.dir = 0; /* read */
2219 cfg.timeout = 10;
2220
2221 /* Get Phy Pg 0 for each Phy. */
2222 cfg.physAddr = -1;
2223 cfg.pageAddr = form + form_specific;
2224 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2225
2226 error = mpt_config(ioc, &cfg);
2227 if (error)
2228 goto out;
2229
2230 if (!hdr.ExtPageLength) {
2231 error = -ENXIO;
2232 goto out;
2233 }
2234
2235 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2236 &dma_handle);
2237 if (!buffer) {
2238 error = -ENOMEM;
2239 goto out;
2240 }
2241
2242 cfg.physAddr = dma_handle;
2243 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2244
2245 error = mpt_config(ioc, &cfg);
2246 if (error)
2247 goto out_free_consistent;
2248
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302249 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002250
2251 phy_info->hw_link_rate = buffer->HwLinkRate;
2252 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2253 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2254 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2255
2256 out_free_consistent:
2257 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2258 buffer, dma_handle);
2259 out:
2260 return error;
2261}
2262
2263static int
2264mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2265 u32 form, u32 form_specific)
2266{
2267 ConfigExtendedPageHeader_t hdr;
2268 CONFIGPARMS cfg;
2269 SasDevicePage0_t *buffer;
2270 dma_addr_t dma_handle;
2271 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002272 int error=0;
2273
2274 if (ioc->sas_discovery_runtime &&
2275 mptsas_is_end_device(device_info))
2276 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002277
2278 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2279 hdr.ExtPageLength = 0;
2280 hdr.PageNumber = 0;
2281 hdr.Reserved1 = 0;
2282 hdr.Reserved2 = 0;
2283 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2284 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2285
2286 cfg.cfghdr.ehdr = &hdr;
2287 cfg.pageAddr = form + form_specific;
2288 cfg.physAddr = -1;
2289 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2290 cfg.dir = 0; /* read */
2291 cfg.timeout = 10;
2292
Moore, Ericdb9c9172006-03-14 09:14:18 -07002293 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002294 error = mpt_config(ioc, &cfg);
2295 if (error)
2296 goto out;
2297 if (!hdr.ExtPageLength) {
2298 error = -ENXIO;
2299 goto out;
2300 }
2301
2302 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2303 &dma_handle);
2304 if (!buffer) {
2305 error = -ENOMEM;
2306 goto out;
2307 }
2308
2309 cfg.physAddr = dma_handle;
2310 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2311
2312 error = mpt_config(ioc, &cfg);
2313 if (error)
2314 goto out_free_consistent;
2315
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302316 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002317
2318 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002319 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002320 device_info->handle_enclosure =
2321 le16_to_cpu(buffer->EnclosureHandle);
2322 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002323 device_info->phy_id = buffer->PhyNum;
2324 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002325 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002326 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002327 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002328 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2329 device_info->sas_address = le64_to_cpu(sas_address);
2330 device_info->device_info =
2331 le32_to_cpu(buffer->DeviceInfo);
2332
2333 out_free_consistent:
2334 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2335 buffer, dma_handle);
2336 out:
2337 return error;
2338}
2339
2340static int
2341mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2342 u32 form, u32 form_specific)
2343{
2344 ConfigExtendedPageHeader_t hdr;
2345 CONFIGPARMS cfg;
2346 SasExpanderPage0_t *buffer;
2347 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002348 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002349
2350 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2351 hdr.ExtPageLength = 0;
2352 hdr.PageNumber = 0;
2353 hdr.Reserved1 = 0;
2354 hdr.Reserved2 = 0;
2355 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2356 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2357
2358 cfg.cfghdr.ehdr = &hdr;
2359 cfg.physAddr = -1;
2360 cfg.pageAddr = form + form_specific;
2361 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2362 cfg.dir = 0; /* read */
2363 cfg.timeout = 10;
2364
Moore, Ericdb9c9172006-03-14 09:14:18 -07002365 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002366 error = mpt_config(ioc, &cfg);
2367 if (error)
2368 goto out;
2369
2370 if (!hdr.ExtPageLength) {
2371 error = -ENXIO;
2372 goto out;
2373 }
2374
2375 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2376 &dma_handle);
2377 if (!buffer) {
2378 error = -ENOMEM;
2379 goto out;
2380 }
2381
2382 cfg.physAddr = dma_handle;
2383 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2384
2385 error = mpt_config(ioc, &cfg);
2386 if (error)
2387 goto out_free_consistent;
2388
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002389 if (!buffer->NumPhys) {
2390 error = -ENODEV;
2391 goto out_free_consistent;
2392 }
2393
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002394 /* save config data */
2395 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002396 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06002397 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002398 if (!port_info->phy_info) {
2399 error = -ENOMEM;
2400 goto out_free_consistent;
2401 }
2402
Eric Moore2ecce492007-01-29 09:47:08 -07002403 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002404 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002405 port_info->phy_info[i].handle =
2406 le16_to_cpu(buffer->DevHandle);
2407 }
Eric Moore547f9a22006-06-27 14:42:12 -06002408
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002409 out_free_consistent:
2410 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2411 buffer, dma_handle);
2412 out:
2413 return error;
2414}
2415
2416static int
2417mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2418 u32 form, u32 form_specific)
2419{
2420 ConfigExtendedPageHeader_t hdr;
2421 CONFIGPARMS cfg;
2422 SasExpanderPage1_t *buffer;
2423 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002424 int error=0;
2425
2426 if (ioc->sas_discovery_runtime &&
2427 mptsas_is_end_device(&phy_info->attached))
2428 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002429
2430 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2431 hdr.ExtPageLength = 0;
2432 hdr.PageNumber = 1;
2433 hdr.Reserved1 = 0;
2434 hdr.Reserved2 = 0;
2435 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2436 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2437
2438 cfg.cfghdr.ehdr = &hdr;
2439 cfg.physAddr = -1;
2440 cfg.pageAddr = form + form_specific;
2441 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2442 cfg.dir = 0; /* read */
2443 cfg.timeout = 10;
2444
2445 error = mpt_config(ioc, &cfg);
2446 if (error)
2447 goto out;
2448
2449 if (!hdr.ExtPageLength) {
2450 error = -ENXIO;
2451 goto out;
2452 }
2453
2454 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2455 &dma_handle);
2456 if (!buffer) {
2457 error = -ENOMEM;
2458 goto out;
2459 }
2460
2461 cfg.physAddr = dma_handle;
2462 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2463
2464 error = mpt_config(ioc, &cfg);
2465 if (error)
2466 goto out_free_consistent;
2467
2468
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302469 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002470
2471 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002472 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002473 phy_info->port_id = buffer->PhysicalPort;
2474 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2475 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2476 phy_info->hw_link_rate = buffer->HwLinkRate;
2477 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2478 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2479
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002480 out_free_consistent:
2481 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2482 buffer, dma_handle);
2483 out:
2484 return error;
2485}
2486
2487static void
2488mptsas_parse_device_info(struct sas_identify *identify,
2489 struct mptsas_devinfo *device_info)
2490{
2491 u16 protocols;
2492
2493 identify->sas_address = device_info->sas_address;
2494 identify->phy_identifier = device_info->phy_id;
2495
2496 /*
2497 * Fill in Phy Initiator Port Protocol.
2498 * Bits 6:3, more than one bit can be set, fall through cases.
2499 */
2500 protocols = device_info->device_info & 0x78;
2501 identify->initiator_port_protocols = 0;
2502 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2503 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2504 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2505 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2506 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2507 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2508 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2509 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2510
2511 /*
2512 * Fill in Phy Target Port Protocol.
2513 * Bits 10:7, more than one bit can be set, fall through cases.
2514 */
2515 protocols = device_info->device_info & 0x780;
2516 identify->target_port_protocols = 0;
2517 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2518 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2519 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2520 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2521 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2522 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2523 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2524 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2525
2526 /*
2527 * Fill in Attached device type.
2528 */
2529 switch (device_info->device_info &
2530 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2531 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2532 identify->device_type = SAS_PHY_UNUSED;
2533 break;
2534 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2535 identify->device_type = SAS_END_DEVICE;
2536 break;
2537 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2538 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2539 break;
2540 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2541 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2542 break;
2543 }
2544}
2545
2546static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002547 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002548{
Moore, Erice6b2d762006-03-14 09:14:24 -07002549 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002550 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002551 struct sas_port *port;
2552 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002553
Eric Moore547f9a22006-06-27 14:42:12 -06002554 if (!dev) {
2555 error = -ENODEV;
2556 goto out;
2557 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002558
2559 if (!phy_info->phy) {
2560 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002561 if (!phy) {
2562 error = -ENOMEM;
2563 goto out;
2564 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002565 } else
2566 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002567
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002568 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002569
2570 /*
2571 * Set Negotiated link rate.
2572 */
2573 switch (phy_info->negotiated_link_rate) {
2574 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002575 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002576 break;
2577 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002578 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002579 break;
2580 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002581 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002582 break;
2583 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002584 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002585 break;
2586 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2587 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2588 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002589 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002590 break;
2591 }
2592
2593 /*
2594 * Set Max hardware link rate.
2595 */
2596 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2597 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002598 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002599 break;
2600 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002601 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002602 break;
2603 default:
2604 break;
2605 }
2606
2607 /*
2608 * Set Max programmed link rate.
2609 */
2610 switch (phy_info->programmed_link_rate &
2611 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2612 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002613 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002614 break;
2615 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002616 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002617 break;
2618 default:
2619 break;
2620 }
2621
2622 /*
2623 * Set Min hardware link rate.
2624 */
2625 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2626 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002627 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002628 break;
2629 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002630 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002631 break;
2632 default:
2633 break;
2634 }
2635
2636 /*
2637 * Set Min programmed link rate.
2638 */
2639 switch (phy_info->programmed_link_rate &
2640 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2641 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002642 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002643 break;
2644 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002645 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002646 break;
2647 default:
2648 break;
2649 }
2650
Moore, Erice6b2d762006-03-14 09:14:24 -07002651 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002652
Moore, Erice6b2d762006-03-14 09:14:24 -07002653 error = sas_phy_add(phy);
2654 if (error) {
2655 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002656 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002657 }
2658 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002659 }
2660
Eric Moore547f9a22006-06-27 14:42:12 -06002661 if (!phy_info->attached.handle ||
2662 !phy_info->port_details)
2663 goto out;
2664
2665 port = mptsas_get_port(phy_info);
2666 ioc = phy_to_ioc(phy_info->phy);
2667
2668 if (phy_info->sas_port_add_phy) {
2669
2670 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002671 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002672 if (!port) {
2673 error = -ENOMEM;
2674 goto out;
2675 }
2676 error = sas_port_add(port);
2677 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302678 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002679 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002680 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002681 goto out;
2682 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302683 mptsas_set_port(ioc, phy_info, port);
Eric Moore29dd3602007-09-14 18:46:51 -06002684 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooredc22f162006-07-06 11:23:14 -06002685 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002686 ioc->name, port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002687 }
Eric Moore29dd3602007-09-14 18:46:51 -06002688 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
2689 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002690 sas_port_add_phy(port, phy_info->phy);
2691 phy_info->sas_port_add_phy = 0;
2692 }
2693
2694 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002695
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002696 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002697 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002698 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002699
James Bottomley2686de22006-06-30 12:54:02 -05002700 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002701 /*
2702 * Let the hotplug_work thread handle processing
2703 * the adding/removing of devices that occur
2704 * after start of day.
2705 */
2706 if (ioc->sas_discovery_runtime &&
2707 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002708 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002709
James Bottomleyf013db32006-03-18 14:54:36 -06002710 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002711 if (scsi_is_host_device(parent)) {
2712 struct mptsas_portinfo *port_info;
2713 int i;
2714
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302715 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05002716
2717 for (i = 0; i < port_info->num_phys; i++)
2718 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002719 identify.sas_address) {
2720 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002721 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002722 }
James Bottomley2686de22006-06-30 12:54:02 -05002723
2724 } else if (scsi_is_sas_rphy(parent)) {
2725 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2726 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002727 parent_rphy->identify.sas_address) {
2728 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002729 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002730 }
James Bottomley2686de22006-06-30 12:54:02 -05002731 }
2732
James Bottomleyf013db32006-03-18 14:54:36 -06002733 switch (identify.device_type) {
2734 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002735 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002736 break;
2737 case SAS_EDGE_EXPANDER_DEVICE:
2738 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002739 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002740 break;
2741 default:
2742 rphy = NULL;
2743 break;
2744 }
Eric Moore547f9a22006-06-27 14:42:12 -06002745 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302746 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002747 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002748 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002749 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002750 }
2751
Eric Moore547f9a22006-06-27 14:42:12 -06002752 rphy->identify = identify;
2753 error = sas_rphy_add(rphy);
2754 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302755 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002756 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002757 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002758 sas_rphy_free(rphy);
2759 goto out;
2760 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302761 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002762 }
2763
Eric Moore547f9a22006-06-27 14:42:12 -06002764 out:
2765 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002766}
2767
2768static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002769mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002770{
Moore, Erice6b2d762006-03-14 09:14:24 -07002771 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002772 int error = -ENOMEM, i;
2773
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302774 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07002775 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002776 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002777
Moore, Erice6b2d762006-03-14 09:14:24 -07002778 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002779 if (error)
2780 goto out_free_port_info;
2781
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302782 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002783 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302784 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07002785 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302786 ioc->hba_port_info = port_info = hba;
2787 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07002788 list_add_tail(&port_info->list, &ioc->sas_topology);
2789 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002790 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002791 port_info->phy_info[i].negotiated_link_rate =
2792 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002793 port_info->phy_info[i].handle =
2794 hba->phy_info[i].handle;
2795 port_info->phy_info[i].port_id =
2796 hba->phy_info[i].port_id;
2797 }
Eric Moore547f9a22006-06-27 14:42:12 -06002798 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002799 kfree(hba);
2800 hba = NULL;
2801 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002802 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302803#if defined(CPQ_CIM)
2804 ioc->num_ports = port_info->num_phys;
2805#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002806 for (i = 0; i < port_info->num_phys; i++) {
2807 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2808 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2809 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302810 port_info->phy_info[i].identify.handle =
2811 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002812 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002813 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2814 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302815 port_info->phy_info[i].identify.handle);
2816 if (!ioc->hba_port_sas_addr)
2817 ioc->hba_port_sas_addr =
2818 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02002819 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002820 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002821 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002822 mptsas_sas_device_pg0(ioc,
2823 &port_info->phy_info[i].attached,
2824 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2825 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2826 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002827 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002828
Eric Moore547f9a22006-06-27 14:42:12 -06002829 mptsas_setup_wide_ports(ioc, port_info);
2830
2831 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002832 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002833 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002834
2835 return 0;
2836
2837 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002838 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002839 out:
2840 return error;
2841}
2842
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302843static void
2844mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002845{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302846 struct mptsas_portinfo *parent;
2847 struct device *parent_dev;
2848 struct sas_rphy *rphy;
2849 int i;
2850 u64 sas_address; /* expander sas address */
2851 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002852
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302853 handle = port_info->phy_info[0].handle;
2854 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002855 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002856 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302857 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2858 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002859
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302860 mptsas_sas_device_pg0(ioc,
2861 &port_info->phy_info[i].identify,
2862 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2863 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2864 port_info->phy_info[i].identify.handle);
2865 port_info->phy_info[i].identify.phy_id =
2866 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002867
2868 if (port_info->phy_info[i].attached.handle) {
2869 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302870 &port_info->phy_info[i].attached,
2871 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2872 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2873 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002874 port_info->phy_info[i].attached.phy_id =
2875 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002876 }
Eric Moore547f9a22006-06-27 14:42:12 -06002877 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002878
Moore, Erice6b2d762006-03-14 09:14:24 -07002879 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302880 parent = mptsas_find_portinfo_by_handle(ioc,
2881 port_info->phy_info[0].identify.handle_parent);
2882 if (!parent) {
2883 mutex_unlock(&ioc->sas_topology_mutex);
2884 return;
2885 }
2886 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
2887 i++) {
2888 if (parent->phy_info[i].attached.sas_address == sas_address) {
2889 rphy = mptsas_get_rphy(&parent->phy_info[i]);
2890 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07002891 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002892 }
2893 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302894
2895 mptsas_setup_wide_ports(ioc, port_info);
2896 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
2897 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
2898 ioc->sas_index, 0);
2899}
2900
2901static void
2902mptsas_expander_event_add(MPT_ADAPTER *ioc,
2903 MpiEventDataSasExpanderStatusChange_t *expander_data)
2904{
2905 struct mptsas_portinfo *port_info;
2906 int i;
2907 __le64 sas_address;
2908
2909 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
2910 if (!port_info)
2911 BUG();
2912 port_info->num_phys = (expander_data->NumPhys) ?
2913 expander_data->NumPhys : 1;
2914 port_info->phy_info = kcalloc(port_info->num_phys,
2915 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
2916 if (!port_info->phy_info)
2917 BUG();
2918 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
2919 for (i = 0; i < port_info->num_phys; i++) {
2920 port_info->phy_info[i].portinfo = port_info;
2921 port_info->phy_info[i].handle =
2922 le16_to_cpu(expander_data->DevHandle);
2923 port_info->phy_info[i].identify.sas_address =
2924 le64_to_cpu(sas_address);
2925 port_info->phy_info[i].identify.handle_parent =
2926 le16_to_cpu(expander_data->ParentDevHandle);
2927 }
2928
2929 mutex_lock(&ioc->sas_topology_mutex);
2930 list_add_tail(&port_info->list, &ioc->sas_topology);
2931 mutex_unlock(&ioc->sas_topology_mutex);
2932
2933 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
2934 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
2935 (unsigned long long)sas_address);
2936
2937 mptsas_expander_refresh(ioc, port_info);
2938}
2939
2940/**
2941 * mptsas_delete_expander_siblings - remove siblings attached to expander
2942 * @ioc: Pointer to MPT_ADAPTER structure
2943 * @parent: the parent port_info object
2944 * @expander: the expander port_info object
2945 **/
2946static void
2947mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
2948 *parent, struct mptsas_portinfo *expander)
2949{
2950 struct mptsas_phyinfo *phy_info;
2951 struct mptsas_portinfo *port_info;
2952 struct sas_rphy *rphy;
2953 int i;
2954
2955 phy_info = expander->phy_info;
2956 for (i = 0; i < expander->num_phys; i++, phy_info++) {
2957 rphy = mptsas_get_rphy(phy_info);
2958 if (!rphy)
2959 continue;
2960 if (rphy->identify.device_type == SAS_END_DEVICE)
2961 mptsas_del_end_device(ioc, phy_info);
2962 }
2963
2964 phy_info = expander->phy_info;
2965 for (i = 0; i < expander->num_phys; i++, phy_info++) {
2966 rphy = mptsas_get_rphy(phy_info);
2967 if (!rphy)
2968 continue;
2969 if (rphy->identify.device_type ==
2970 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2971 rphy->identify.device_type ==
2972 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
2973 port_info = mptsas_find_portinfo_by_sas_address(ioc,
2974 rphy->identify.sas_address);
2975 if (!port_info)
2976 continue;
2977 if (port_info == parent) /* backlink rphy */
2978 continue;
2979 /*
2980 Delete this expander even if the expdevpage is exists
2981 because the parent expander is already deleted
2982 */
2983 mptsas_expander_delete(ioc, port_info, 1);
2984 }
2985 }
2986}
2987
2988
2989/**
2990 * mptsas_expander_delete - remove this expander
2991 * @ioc: Pointer to MPT_ADAPTER structure
2992 * @port_info: expander port_info struct
2993 * @force: Flag to forcefully delete the expander
2994 *
2995 **/
2996
2997static void mptsas_expander_delete(MPT_ADAPTER *ioc,
2998 struct mptsas_portinfo *port_info, u8 force)
2999{
3000
3001 struct mptsas_portinfo *parent;
3002 int i;
3003 u64 expander_sas_address;
3004 struct mptsas_phyinfo *phy_info;
3005 struct mptsas_portinfo buffer;
3006 struct mptsas_portinfo_details *port_details;
3007 struct sas_port *port;
3008
3009 if (!port_info)
3010 return;
3011
3012 /* see if expander is still there before deleting */
3013 mptsas_sas_expander_pg0(ioc, &buffer,
3014 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3015 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3016 port_info->phy_info[0].identify.handle);
3017
3018 if (buffer.num_phys) {
3019 kfree(buffer.phy_info);
3020 if (!force)
3021 return;
3022 }
3023
3024
3025 /*
3026 * Obtain the port_info instance to the parent port
3027 */
3028 port_details = NULL;
3029 expander_sas_address =
3030 port_info->phy_info[0].identify.sas_address;
3031 parent = mptsas_find_portinfo_by_handle(ioc,
3032 port_info->phy_info[0].identify.handle_parent);
3033 mptsas_delete_expander_siblings(ioc, parent, port_info);
3034 if (!parent)
3035 goto out;
3036
3037 /*
3038 * Delete rphys in the parent that point
3039 * to this expander.
3040 */
3041 phy_info = parent->phy_info;
3042 port = NULL;
3043 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3044 if (!phy_info->phy)
3045 continue;
3046 if (phy_info->attached.sas_address !=
3047 expander_sas_address)
3048 continue;
3049 if (!port) {
3050 port = mptsas_get_port(phy_info);
3051 port_details = phy_info->port_details;
3052 }
3053 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3054 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3055 phy_info->phy_id, phy_info->phy);
3056 sas_port_delete_phy(port, phy_info->phy);
3057 }
3058 if (port) {
3059 dev_printk(KERN_DEBUG, &port->dev,
3060 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3061 ioc->name, port->port_identifier,
3062 (unsigned long long)expander_sas_address);
3063 sas_port_delete(port);
3064 mptsas_port_delete(ioc, port_details);
3065 }
3066 out:
3067
3068 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3069 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3070 (unsigned long long)expander_sas_address);
3071
3072 /*
3073 * free link
3074 */
3075 list_del(&port_info->list);
3076 kfree(port_info->phy_info);
3077 kfree(port_info);
3078}
3079
3080
3081/**
3082 * mptsas_send_expander_event - expanders events
3083 * @ioc: Pointer to MPT_ADAPTER structure
3084 * @expander_data: event data
3085 *
3086 *
3087 * This function handles adding, removing, and refreshing
3088 * device handles within the expander objects.
3089 */
3090static void
3091mptsas_send_expander_event(struct fw_event_work *fw_event)
3092{
3093 MPT_ADAPTER *ioc;
3094 MpiEventDataSasExpanderStatusChange_t *expander_data;
3095 struct mptsas_portinfo *port_info;
3096 __le64 sas_address;
3097 int i;
3098
3099 ioc = fw_event->ioc;
3100 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3101 fw_event->event_data;
3102 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3103 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3104
3105 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3106 if (port_info) {
3107 for (i = 0; i < port_info->num_phys; i++) {
3108 port_info->phy_info[i].portinfo = port_info;
3109 port_info->phy_info[i].handle =
3110 le16_to_cpu(expander_data->DevHandle);
3111 port_info->phy_info[i].identify.sas_address =
3112 le64_to_cpu(sas_address);
3113 port_info->phy_info[i].identify.handle_parent =
3114 le16_to_cpu(expander_data->ParentDevHandle);
3115 }
3116 mptsas_expander_refresh(ioc, port_info);
3117 } else if (!port_info && expander_data->NumPhys)
3118 mptsas_expander_event_add(ioc, expander_data);
3119 } else if (expander_data->ReasonCode ==
3120 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3121 mptsas_expander_delete(ioc, port_info, 0);
3122
3123 mptsas_free_fw_event(ioc, fw_event);
3124}
3125
3126
3127/**
3128 * mptsas_expander_add -
3129 * @ioc: Pointer to MPT_ADAPTER structure
3130 * @handle:
3131 *
3132 */
3133struct mptsas_portinfo *
3134mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3135{
3136 struct mptsas_portinfo buffer, *port_info;
3137 int i;
3138
3139 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3140 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3141 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3142 return NULL;
3143
3144 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3145 if (!port_info) {
3146 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3147 "%s: exit at line=%d\n", ioc->name,
3148 __func__, __LINE__));
3149 return NULL;
3150 }
3151 port_info->num_phys = buffer.num_phys;
3152 port_info->phy_info = buffer.phy_info;
3153 for (i = 0; i < port_info->num_phys; i++)
3154 port_info->phy_info[i].portinfo = port_info;
3155 mutex_lock(&ioc->sas_topology_mutex);
3156 list_add_tail(&port_info->list, &ioc->sas_topology);
3157 mutex_unlock(&ioc->sas_topology_mutex);
3158 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3159 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3160 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3161 mptsas_expander_refresh(ioc, port_info);
3162 return port_info;
3163}
3164
3165static void
3166mptsas_send_link_status_event(struct fw_event_work *fw_event)
3167{
3168 MPT_ADAPTER *ioc;
3169 MpiEventDataSasPhyLinkStatus_t *link_data;
3170 struct mptsas_portinfo *port_info;
3171 struct mptsas_phyinfo *phy_info = NULL;
3172 __le64 sas_address;
3173 u8 phy_num;
3174 u8 link_rate;
3175
3176 ioc = fw_event->ioc;
3177 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3178
3179 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3180 sas_address = le64_to_cpu(sas_address);
3181 link_rate = link_data->LinkRates >> 4;
3182 phy_num = link_data->PhyNum;
3183
3184 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3185 if (port_info) {
3186 phy_info = &port_info->phy_info[phy_num];
3187 if (phy_info)
3188 phy_info->negotiated_link_rate = link_rate;
3189 }
3190
3191 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3192 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3193
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303194 if (!port_info) {
3195 if (ioc->old_sas_discovery_protocal) {
3196 port_info = mptsas_expander_add(ioc,
3197 le16_to_cpu(link_data->DevHandle));
3198 if (port_info)
3199 goto out;
3200 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303201 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303202 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303203
3204 if (port_info == ioc->hba_port_info)
3205 mptsas_probe_hba_phys(ioc);
3206 else
3207 mptsas_expander_refresh(ioc, port_info);
3208 } else if (phy_info && phy_info->phy) {
3209 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3210 phy_info->phy->negotiated_linkrate =
3211 SAS_PHY_DISABLED;
3212 else if (link_rate ==
3213 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3214 phy_info->phy->negotiated_linkrate =
3215 SAS_LINK_RATE_FAILED;
3216 else
3217 phy_info->phy->negotiated_linkrate =
3218 SAS_LINK_RATE_UNKNOWN;
3219 }
3220 out:
3221 mptsas_free_fw_event(ioc, fw_event);
3222}
3223
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303224static void
3225mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3226{
3227 struct mptsas_portinfo buffer, *port_info;
3228 struct mptsas_device_info *sas_info;
3229 struct mptsas_devinfo sas_device;
3230 u32 handle;
3231 VirtTarget *vtarget = NULL;
3232 struct mptsas_phyinfo *phy_info;
3233 u8 found_expander;
3234 int retval, retry_count;
3235 unsigned long flags;
3236
3237 mpt_findImVolumes(ioc);
3238
3239 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3240 if (ioc->ioc_reset_in_progress) {
3241 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3242 "%s: exiting due to a parallel reset \n", ioc->name,
3243 __func__));
3244 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3245 return;
3246 }
3247 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3248
3249 /* devices, logical volumes */
3250 mutex_lock(&ioc->sas_device_info_mutex);
3251 redo_device_scan:
3252 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
3253 sas_device.handle = 0;
3254 retry_count = 0;
3255retry_page:
3256 retval = mptsas_sas_device_pg0(ioc, &sas_device,
3257 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3258 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3259 (sas_info->fw.channel << 8) +
3260 sas_info->fw.id);
3261
3262 if (sas_device.handle)
3263 continue;
3264 if (retval == -EBUSY) {
3265 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3266 if (ioc->ioc_reset_in_progress) {
3267 dfailprintk(ioc,
3268 printk(MYIOC_s_DEBUG_FMT
3269 "%s: exiting due to reset\n",
3270 ioc->name, __func__));
3271 spin_unlock_irqrestore
3272 (&ioc->taskmgmt_lock, flags);
3273 mutex_unlock(&ioc->sas_device_info_mutex);
3274 return;
3275 }
3276 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3277 flags);
3278 }
3279
3280 if (retval && (retval != -ENODEV)) {
3281 if (retry_count < 10) {
3282 retry_count++;
3283 goto retry_page;
3284 } else {
3285 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3286 "%s: Config page retry exceeded retry "
3287 "count deleting device 0x%llx\n",
3288 ioc->name, __func__,
3289 sas_info->sas_address));
3290 }
3291 }
3292
3293 /* delete device */
3294 vtarget = mptsas_find_vtarget(ioc,
3295 sas_info->fw.channel, sas_info->fw.id);
3296 if (vtarget)
3297 vtarget->deleted = 1;
3298 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3299 sas_info->sas_address);
3300 if (phy_info) {
3301 mptsas_del_end_device(ioc, phy_info);
3302 goto redo_device_scan;
3303 }
3304 }
3305 mutex_unlock(&ioc->sas_device_info_mutex);
3306
3307 /* expanders */
3308 mutex_lock(&ioc->sas_topology_mutex);
3309 redo_expander_scan:
3310 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3311
3312 if (port_info->phy_info &&
3313 (!(port_info->phy_info[0].identify.device_info &
3314 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3315 continue;
3316 found_expander = 0;
3317 handle = 0xFFFF;
3318 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3319 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3320 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3321 !found_expander) {
3322
3323 handle = buffer.phy_info[0].handle;
3324 if (buffer.phy_info[0].identify.sas_address ==
3325 port_info->phy_info[0].identify.sas_address) {
3326 found_expander = 1;
3327 }
3328 kfree(buffer.phy_info);
3329 }
3330
3331 if (!found_expander) {
3332 mptsas_expander_delete(ioc, port_info, 0);
3333 goto redo_expander_scan;
3334 }
3335 }
3336 mutex_lock(&ioc->sas_topology_mutex);
3337}
3338
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303339/**
3340 * mptsas_probe_expanders - adding expanders
3341 * @ioc: Pointer to MPT_ADAPTER structure
3342 *
3343 **/
3344static void
3345mptsas_probe_expanders(MPT_ADAPTER *ioc)
3346{
3347 struct mptsas_portinfo buffer, *port_info;
3348 u32 handle;
3349 int i;
3350
3351 handle = 0xFFFF;
3352 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3353 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3354 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3355
3356 handle = buffer.phy_info[0].handle;
3357 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3358 buffer.phy_info[0].identify.sas_address);
3359
3360 if (port_info) {
3361 /* refreshing handles */
3362 for (i = 0; i < buffer.num_phys; i++) {
3363 port_info->phy_info[i].handle = handle;
3364 port_info->phy_info[i].identify.handle_parent =
3365 buffer.phy_info[0].identify.handle_parent;
3366 }
3367 mptsas_expander_refresh(ioc, port_info);
3368 kfree(buffer.phy_info);
3369 continue;
3370 }
3371
3372 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3373 if (!port_info) {
3374 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3375 "%s: exit at line=%d\n", ioc->name,
3376 __func__, __LINE__));
3377 return;
3378 }
3379 port_info->num_phys = buffer.num_phys;
3380 port_info->phy_info = buffer.phy_info;
3381 for (i = 0; i < port_info->num_phys; i++)
3382 port_info->phy_info[i].portinfo = port_info;
3383 mutex_lock(&ioc->sas_topology_mutex);
3384 list_add_tail(&port_info->list, &ioc->sas_topology);
3385 mutex_unlock(&ioc->sas_topology_mutex);
3386 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3387 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3388 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3389 mptsas_expander_refresh(ioc, port_info);
3390 }
3391}
3392
3393static void
3394mptsas_probe_devices(MPT_ADAPTER *ioc)
3395{
3396 u16 handle;
3397 struct mptsas_devinfo sas_device;
3398 struct mptsas_phyinfo *phy_info;
3399
3400 handle = 0xFFFF;
3401 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3402 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3403
3404 handle = sas_device.handle;
3405
3406 if ((sas_device.device_info &
3407 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3408 MPI_SAS_DEVICE_INFO_STP_TARGET |
3409 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3410 continue;
3411
3412 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3413 if (!phy_info)
3414 continue;
3415
3416 if (mptsas_get_rphy(phy_info))
3417 continue;
3418
3419 mptsas_add_end_device(ioc, phy_info);
3420 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003421}
3422
3423/*
3424 * Start of day discovery
3425 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003426static void
3427mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3428{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303429 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003430 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003431
Moore, Erice6b2d762006-03-14 09:14:24 -07003432 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303433 mptsas_probe_expanders(ioc);
3434 mptsas_probe_devices(ioc);
3435
Moore, Ericf44e5462006-03-14 09:14:21 -07003436 /*
3437 Reporting RAID volumes.
3438 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303439 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3440 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3441 return;
Eric Moore793955f2007-01-29 09:42:20 -07003442 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303443 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3444 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3445 if (sdev) {
3446 scsi_device_put(sdev);
3447 continue;
3448 }
3449 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3450 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3451 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003452 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003453 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3454 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003455}
3456
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003457static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003458mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003459{
3460 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003461 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003462 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003463
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003464 mutex_lock(&ioc->sas_topology_mutex);
3465 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3466 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003467 if (!mptsas_is_end_device(
3468 &port_info->phy_info[i].attached))
3469 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003470 if (port_info->phy_info[i].attached.sas_address
3471 != sas_address)
3472 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003473 phy_info = &port_info->phy_info[i];
3474 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003475 }
3476 }
3477 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003478 return phy_info;
3479}
3480
Eric Mooreb506ade2007-01-29 09:45:37 -07003481
3482static struct mptsas_phyinfo *
3483mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
3484{
3485 struct mptsas_portinfo *port_info;
3486 struct mptsas_phyinfo *phy_info = NULL;
3487 int i;
3488
3489 mutex_lock(&ioc->sas_topology_mutex);
3490 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3491 for (i = 0; i < port_info->num_phys; i++) {
3492 if (!mptsas_is_end_device(
3493 &port_info->phy_info[i].attached))
3494 continue;
3495 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
3496 continue;
3497 if (port_info->phy_info[i].attached.phys_disk_num != id)
3498 continue;
3499 if (port_info->phy_info[i].attached.channel != channel)
3500 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003501 phy_info = &port_info->phy_info[i];
3502 break;
3503 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003504 }
3505 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003506 return phy_info;
3507}
3508
3509static void
Moore, Ericf44e5462006-03-14 09:14:21 -07003510mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
3511{
Eric Mooref99be432007-01-04 20:46:54 -07003512 int rc;
3513
Moore, Ericf44e5462006-03-14 09:14:21 -07003514 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07003515 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07003516}
3517
3518static void
3519mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
3520{
3521 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
3522 mptsas_reprobe_lun);
3523}
3524
Eric Mooreb506ade2007-01-29 09:45:37 -07003525static void
3526mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
3527{
3528 CONFIGPARMS cfg;
3529 ConfigPageHeader_t hdr;
3530 dma_addr_t dma_handle;
3531 pRaidVolumePage0_t buffer = NULL;
3532 RaidPhysDiskPage0_t phys_disk;
3533 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303534 struct mptsas_phyinfo *phy_info;
3535 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07003536
3537 memset(&cfg, 0 , sizeof(CONFIGPARMS));
3538 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
3539 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
3540 cfg.pageAddr = (channel << 8) + id;
3541 cfg.cfghdr.hdr = &hdr;
3542 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3543
3544 if (mpt_config(ioc, &cfg) != 0)
3545 goto out;
3546
3547 if (!hdr.PageLength)
3548 goto out;
3549
3550 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
3551 &dma_handle);
3552
3553 if (!buffer)
3554 goto out;
3555
3556 cfg.physAddr = dma_handle;
3557 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3558
3559 if (mpt_config(ioc, &cfg) != 0)
3560 goto out;
3561
3562 if (!(buffer->VolumeStatus.Flags &
3563 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
3564 goto out;
3565
3566 if (!buffer->NumPhysDisks)
3567 goto out;
3568
3569 for (i = 0; i < buffer->NumPhysDisks; i++) {
3570
3571 if (mpt_raid_phys_disk_pg0(ioc,
3572 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
3573 continue;
3574
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303575 if (mptsas_sas_device_pg0(ioc, &sas_device,
3576 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3577 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3578 (phys_disk.PhysDiskBus << 8) +
3579 phys_disk.PhysDiskID))
3580 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003581
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303582 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3583 sas_device.sas_address);
3584 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07003585 }
3586
3587 out:
3588 if (buffer)
3589 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
3590 dma_handle);
3591}
Moore, Erice6b2d762006-03-14 09:14:24 -07003592/*
3593 * Work queue thread to handle SAS hotplug events
3594 */
Moore, Ericf44e5462006-03-14 09:14:21 -07003595static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303596mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
3597 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003598{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003599 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06003600 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003601 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07003602 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303603 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06003604
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303605 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003606
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303607 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07003608
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303609 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07003610 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003611
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303612 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
3613 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
3614 hot_plug_info->id) {
3615 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
3616 "to add hidden disk - target_id matchs "
3617 "volume_id\n", ioc->name);
3618 mptsas_free_fw_event(ioc, fw_event);
3619 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07003620 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003621 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303622 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003623
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003624 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303625 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
3626 mptsas_sas_device_pg0(ioc, &sas_device,
3627 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3628 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3629 (hot_plug_info->channel << 8) +
3630 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003631
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303632 if (!sas_device.handle)
3633 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06003634
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303635 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3636 if (!phy_info)
3637 break;
3638
3639 if (mptsas_get_rphy(phy_info))
3640 break;
3641
3642 mptsas_add_end_device(ioc, phy_info);
3643 break;
3644
3645 case MPTSAS_DEL_DEVICE:
3646 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3647 hot_plug_info->sas_address);
3648 mptsas_del_end_device(ioc, phy_info);
3649 break;
3650
3651 case MPTSAS_DEL_PHYSDISK:
3652
3653 mpt_findImVolumes(ioc);
3654
3655 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
3656 ioc, hot_plug_info->channel,
3657 hot_plug_info->phys_disk_num);
3658 mptsas_del_end_device(ioc, phy_info);
3659 break;
3660
3661 case MPTSAS_ADD_PHYSDISK_REPROBE:
3662
Christoph Hellwige3094442006-02-16 13:25:36 +01003663 if (mptsas_sas_device_pg0(ioc, &sas_device,
3664 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07003665 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303666 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
3667 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3668 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3669 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01003670 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07003671 }
3672
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303673 phy_info = mptsas_find_phyinfo_by_sas_address(
3674 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07003675
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303676 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303677 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303678 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3679 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003680 break;
3681 }
3682
3683 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303684 if (!starget) {
3685 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3686 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3687 __func__, hot_plug_info->id, __LINE__));
3688 break;
3689 }
Eric Mooreb506ade2007-01-29 09:45:37 -07003690
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303691 vtarget = starget->hostdata;
3692 if (!vtarget) {
3693 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3694 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3695 __func__, hot_plug_info->id, __LINE__));
3696 break;
3697 }
Eric Moore547f9a22006-06-27 14:42:12 -06003698
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303699 mpt_findImVolumes(ioc);
3700
3701 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
3702 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
3703 ioc->name, hot_plug_info->channel, hot_plug_info->id,
3704 hot_plug_info->phys_disk_num, (unsigned long long)
3705 sas_device.sas_address);
3706
3707 vtarget->id = hot_plug_info->phys_disk_num;
3708 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
3709 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
3710 mptsas_reprobe_target(starget, 1);
3711 break;
3712
3713 case MPTSAS_DEL_PHYSDISK_REPROBE:
3714
3715 if (mptsas_sas_device_pg0(ioc, &sas_device,
3716 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3717 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3718 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303719 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303720 "%s: fw_id=%d exit at line=%d\n",
3721 ioc->name, __func__,
3722 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003723 break;
3724 }
3725
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303726 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3727 sas_device.sas_address);
3728 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303729 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303730 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3731 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003732 break;
Eric Moore547f9a22006-06-27 14:42:12 -06003733 }
Eric Mooreb506ade2007-01-29 09:45:37 -07003734
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303735 starget = mptsas_get_starget(phy_info);
3736 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303737 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303738 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3739 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003740 break;
3741 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003742
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303743 vtarget = starget->hostdata;
3744 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303745 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303746 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3747 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003748 break;
3749 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303750
3751 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
3752 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3753 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3754 __func__, hot_plug_info->id, __LINE__));
3755 break;
3756 }
3757
3758 mpt_findImVolumes(ioc);
3759
3760 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
3761 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
3762 ioc->name, hot_plug_info->channel, hot_plug_info->id,
3763 hot_plug_info->phys_disk_num, (unsigned long long)
3764 sas_device.sas_address);
3765
3766 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
3767 vtarget->id = hot_plug_info->id;
3768 phy_info->attached.phys_disk_num = ~0;
3769 mptsas_reprobe_target(starget, 0);
3770 mptsas_add_device_component_by_fw(ioc,
3771 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003772 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303773
Moore, Ericc73787ee2006-01-26 16:20:06 -07003774 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303775
Moore, Ericc73787ee2006-01-26 16:20:06 -07003776 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303777 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3778 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3779 hot_plug_info->id);
3780 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
3781 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003782 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303783
Moore, Ericc73787ee2006-01-26 16:20:06 -07003784 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303785
Moore, Ericc73787ee2006-01-26 16:20:06 -07003786 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303787 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
3788 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3789 hot_plug_info->id);
3790 scsi_remove_device(hot_plug_info->sdev);
3791 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003792 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303793
Eric Mooreb506ade2007-01-29 09:45:37 -07003794 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303795
3796 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07003797 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303798 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07003799 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303800
Moore, Ericbd23e942006-04-17 12:43:04 -06003801 default:
3802 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003803 }
3804
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303805 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003806}
3807
3808static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303809mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003810{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303811 MPT_ADAPTER *ioc;
3812 struct mptsas_hotplug_event hot_plug_info;
3813 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
3814 u32 device_info;
3815 u64 sas_address;
3816
3817 ioc = fw_event->ioc;
3818 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
3819 fw_event->event_data;
3820 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003821
3822 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303823 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3824 MPI_SAS_DEVICE_INFO_STP_TARGET |
3825 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
3826 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003827 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303828 }
3829
3830 if (sas_event_data->ReasonCode ==
3831 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
3832 mptbase_sas_persist_operation(ioc,
3833 MPI_SAS_OP_CLEAR_NOT_PRESENT);
3834 mptsas_free_fw_event(ioc, fw_event);
3835 return;
3836 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003837
Moore, Eric4b766472006-03-14 09:14:12 -07003838 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07003839 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07003840 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303841 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
3842 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
3843 hot_plug_info.channel = sas_event_data->Bus;
3844 hot_plug_info.id = sas_event_data->TargetID;
3845 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07003846 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303847 sizeof(u64));
3848 hot_plug_info.sas_address = le64_to_cpu(sas_address);
3849 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07003850 if (sas_event_data->ReasonCode &
3851 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303852 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07003853 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303854 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
3855 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07003856 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303857
Moore, Eric4b766472006-03-14 09:14:12 -07003858 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303859 mptbase_sas_persist_operation(ioc,
3860 MPI_SAS_OP_CLEAR_NOT_PRESENT);
3861 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07003862 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303863
Moore, Eric4b766472006-03-14 09:14:12 -07003864 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303865 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07003866 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303867 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07003868 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303869 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07003870 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003871 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003872}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303873
Moore, Ericc73787ee2006-01-26 16:20:06 -07003874static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303875mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003876{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303877 MPT_ADAPTER *ioc;
3878 EVENT_DATA_RAID *raid_event_data;
3879 struct mptsas_hotplug_event hot_plug_info;
3880 int status;
3881 int state;
3882 struct scsi_device *sdev = NULL;
3883 VirtDevice *vdevice = NULL;
3884 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003885
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303886 ioc = fw_event->ioc;
3887 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
3888 status = le32_to_cpu(raid_event_data->SettingsStatus);
3889 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003890
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303891 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
3892 hot_plug_info.id = raid_event_data->VolumeID;
3893 hot_plug_info.channel = raid_event_data->VolumeBus;
3894 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
3895
3896 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
3897 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
3898 raid_event_data->ReasonCode ==
3899 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
3900 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3901 hot_plug_info.id, 0);
3902 hot_plug_info.sdev = sdev;
3903 if (sdev)
3904 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003905 }
3906
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303907 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
3908 "ReasonCode=%02x\n", ioc->name, __func__,
3909 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07003910
3911 switch (raid_event_data->ReasonCode) {
3912 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303913 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003914 break;
3915 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303916 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003917 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06003918 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
3919 switch (state) {
3920 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07003921 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303922 mpt_raid_phys_disk_pg0(ioc,
3923 raid_event_data->PhysDiskNum, &phys_disk);
3924 hot_plug_info.id = phys_disk.PhysDiskID;
3925 hot_plug_info.channel = phys_disk.PhysDiskBus;
3926 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06003927 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303928 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06003929 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06003930 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
3931 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
3932 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303933 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06003934 break;
3935 default:
3936 break;
3937 }
3938 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003939 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303940 if (!sdev)
3941 break;
3942 vdevice->vtarget->deleted = 1; /* block IO */
3943 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003944 break;
3945 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303946 if (sdev) {
3947 scsi_device_put(sdev);
3948 break;
3949 }
3950 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003951 break;
3952 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303953 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
3954 if (!sdev)
3955 break;
3956 vdevice->vtarget->deleted = 1; /* block IO */
3957 hot_plug_info.event_type = MPTSAS_DEL_RAID;
3958 break;
3959 }
Moore, Ericbd23e942006-04-17 12:43:04 -06003960 switch (state) {
3961 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
3962 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303963 if (!sdev)
3964 break;
3965 vdevice->vtarget->deleted = 1; /* block IO */
3966 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06003967 break;
3968 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
3969 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303970 if (sdev) {
3971 scsi_device_put(sdev);
3972 break;
3973 }
3974 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06003975 break;
3976 default:
3977 break;
3978 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003979 break;
3980 default:
3981 break;
3982 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303983
3984 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
3985 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
3986 else
3987 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003988}
3989
Eric Mooreb506ade2007-01-29 09:45:37 -07003990/*
3991 * mptsas_send_ir2_event - handle exposing hidden disk when
3992 * an inactive raid volume is added
3993 *
3994 * @ioc: Pointer to MPT_ADAPTER structure
3995 * @ir2_data
3996 *
3997 */
3998static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303999mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004000{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304001 MPT_ADAPTER *ioc;
4002 struct mptsas_hotplug_event hot_plug_info;
4003 MPI_EVENT_DATA_IR2 *ir2_data;
4004 u8 reasonCode;
Eric Mooreb506ade2007-01-29 09:45:37 -07004005
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304006 ioc = fw_event->ioc;
4007 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4008 reasonCode = ir2_data->ReasonCode;
4009
4010 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4011 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4012
4013 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4014 hot_plug_info.id = ir2_data->TargetID;
4015 hot_plug_info.channel = ir2_data->Bus;
4016 switch (reasonCode) {
4017 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4018 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4019 break;
4020 default:
4021 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004022 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304023 }
4024 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4025}
Moore, Erice6b2d762006-03-14 09:14:24 -07004026
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004027static int
4028mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4029{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304030 u32 event = le32_to_cpu(reply->Event);
4031 int sz, event_data_sz;
4032 struct fw_event_work *fw_event;
4033 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004034
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304035 /* events turned off due to host reset or driver unloading */
4036 if (ioc->fw_events_off)
4037 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004038
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304039 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004040 switch (event) {
4041 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304042 {
4043 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4044 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4045
4046 if (sas_event_data->ReasonCode ==
4047 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4048 mptsas_target_reset_queue(ioc, sas_event_data);
4049 return 0;
4050 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004051 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304052 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304053 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4054 {
4055 MpiEventDataSasExpanderStatusChange_t *expander_data =
4056 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4057
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304058 if (ioc->old_sas_discovery_protocal)
4059 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304060
4061 if (expander_data->ReasonCode ==
4062 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4063 ioc->device_missing_delay)
4064 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004065 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304066 }
4067 case MPI_EVENT_SAS_DISCOVERY:
4068 {
4069 u32 discovery_status;
4070 EventDataSasDiscovery_t *discovery_data =
4071 (EventDataSasDiscovery_t *)reply->Data;
4072
4073 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4074 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304075 if (ioc->old_sas_discovery_protocal && !discovery_status)
4076 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304077 return 0;
4078 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304079 case MPI_EVENT_INTEGRATED_RAID:
4080 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004081 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304082 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4083 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004084 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004085 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304086 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004087 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004088
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304089 event_data_sz = ((reply->MsgLength * 4) -
4090 offsetof(EventNotificationReply_t, Data));
4091 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4092 fw_event = kzalloc(sz, GFP_ATOMIC);
4093 if (!fw_event) {
4094 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4095 __func__, __LINE__);
4096 return 0;
4097 }
4098 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4099 fw_event->event = event;
4100 fw_event->ioc = ioc;
4101 mptsas_add_fw_event(ioc, fw_event, delay);
4102 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004103}
4104
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004105static int
4106mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4107{
4108 struct Scsi_Host *sh;
4109 MPT_SCSI_HOST *hd;
4110 MPT_ADAPTER *ioc;
4111 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004112 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004113 int numSGE = 0;
4114 int scale;
4115 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004116 int error=0;
4117 int r;
4118
4119 r = mpt_attach(pdev,id);
4120 if (r)
4121 return r;
4122
4123 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304124 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004125 ioc->DoneCtx = mptsasDoneCtx;
4126 ioc->TaskCtx = mptsasTaskCtx;
4127 ioc->InternalCtx = mptsasInternalCtx;
4128
4129 /* Added sanity check on readiness of the MPT adapter.
4130 */
4131 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4132 printk(MYIOC_s_WARN_FMT
4133 "Skipping because it's not operational!\n",
4134 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004135 error = -ENODEV;
4136 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004137 }
4138
4139 if (!ioc->active) {
4140 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4141 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004142 error = -ENODEV;
4143 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004144 }
4145
4146 /* Sanity check - ensure at least 1 port is INITIATOR capable
4147 */
4148 ioc_cap = 0;
4149 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4150 if (ioc->pfacts[ii].ProtocolFlags &
4151 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4152 ioc_cap++;
4153 }
4154
4155 if (!ioc_cap) {
4156 printk(MYIOC_s_WARN_FMT
4157 "Skipping ioc=%p because SCSI Initiator mode "
4158 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004159 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004160 }
4161
4162 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4163 if (!sh) {
4164 printk(MYIOC_s_WARN_FMT
4165 "Unable to register controller with SCSI subsystem\n",
4166 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004167 error = -1;
4168 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004169 }
4170
4171 spin_lock_irqsave(&ioc->FreeQlock, flags);
4172
4173 /* Attach the SCSI Host to the IOC structure
4174 */
4175 ioc->sh = sh;
4176
4177 sh->io_port = 0;
4178 sh->n_io_port = 0;
4179 sh->irq = 0;
4180
4181 /* set 16 byte cdb's */
4182 sh->max_cmd_len = 16;
4183
Eric Moore793955f2007-01-29 09:42:20 -07004184 sh->max_id = ioc->pfacts[0].PortSCSIID;
4185 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004186
4187 sh->transportt = mptsas_transport_template;
4188
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004189 /* Required entry.
4190 */
4191 sh->unique_id = ioc->id;
4192
4193 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004194 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004195 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004196 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004197 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004198
4199 /* Verify that we won't exceed the maximum
4200 * number of chain buffers
4201 * We can optimize: ZZ = req_sz/sizeof(SGE)
4202 * For 32bit SGE's:
4203 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4204 * + (req_sz - 64)/sizeof(SGE)
4205 * A slightly different algorithm is required for
4206 * 64bit SGEs.
4207 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304208 scale = ioc->req_sz/ioc->SGE_size;
4209 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004210 numSGE = (scale - 1) *
4211 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304212 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004213 } else {
4214 numSGE = 1 + (scale - 1) *
4215 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304216 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004217 }
4218
4219 if (numSGE < sh->sg_tablesize) {
4220 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304221 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004222 "Resetting sg_tablesize to %d from %d\n",
4223 ioc->name, numSGE, sh->sg_tablesize));
4224 sh->sg_tablesize = numSGE;
4225 }
4226
Eric Mooree7eae9f2007-09-29 10:15:59 -06004227 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004228 hd->ioc = ioc;
4229
4230 /* SCSI needs scsi_cmnd lookup table!
4231 * (with size equal to req_depth*PtrSz!)
4232 */
Eric Mooree8206382007-09-29 10:16:53 -06004233 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
4234 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004235 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06004236 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004237 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004238 }
Eric Mooree8206382007-09-29 10:16:53 -06004239 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004240
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304241 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06004242 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004243
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004244 /* Clear the TM flags
4245 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004246 hd->abortSCpnt = NULL;
4247
4248 /* Clear the pointer used to store
4249 * single-threaded commands, i.e., those
4250 * issued during a bus scan, dv and
4251 * configuration pages.
4252 */
4253 hd->cmdPtr = NULL;
4254
4255 /* Initialize this SCSI Hosts' timers
4256 * To use, set the timer expires field
4257 * and add_timer
4258 */
4259 init_timer(&hd->timer);
4260 hd->timer.data = (unsigned long) hd;
4261 hd->timer.function = mptscsih_timer_expired;
4262
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004263 ioc->sas_data.ptClear = mpt_pt_clear;
4264
Eric Mooredf9e0622007-01-29 09:46:21 -07004265 hd->last_queue_full = 0;
4266 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304267 INIT_LIST_HEAD(&ioc->sas_device_info_list);
4268 mutex_init(&ioc->sas_device_info_mutex);
4269
Eric Mooredf9e0622007-01-29 09:46:21 -07004270 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4271
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004272 if (ioc->sas_data.ptClear==1) {
4273 mptbase_sas_persist_operation(
4274 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
4275 }
4276
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004277 error = scsi_add_host(sh, &ioc->pcidev->dev);
4278 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06004279 dprintk(ioc, printk(MYIOC_s_ERR_FMT
4280 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004281 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004282 }
4283
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304284 /* older firmware doesn't support expander events */
4285 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
4286 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004287 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304288 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004289 return 0;
4290
Eric Moore547f9a22006-06-27 14:42:12 -06004291 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004292
4293 mptscsih_remove(pdev);
4294 return error;
4295}
4296
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304297void
4298mptsas_shutdown(struct pci_dev *pdev)
4299{
4300 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4301
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304302 mptsas_fw_event_off(ioc);
4303 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304304}
4305
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004306static void __devexit mptsas_remove(struct pci_dev *pdev)
4307{
4308 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4309 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06004310 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004311
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304312 mptsas_shutdown(pdev);
4313
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304314 mptsas_del_device_components(ioc);
4315
Eric Mooreb506ade2007-01-29 09:45:37 -07004316 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004317 sas_remove_host(ioc->sh);
4318
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004319 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004320 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
4321 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06004322 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304323 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304324
Eric Moore547f9a22006-06-27 14:42:12 -06004325 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004326 kfree(p);
4327 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004328 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304329 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004330 mptscsih_remove(pdev);
4331}
4332
4333static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06004334 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004335 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004336 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004337 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004338 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004339 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004340 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004341 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004342 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004343 PCI_ANY_ID, PCI_ANY_ID },
4344 {0} /* Terminating entry */
4345};
4346MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
4347
4348
4349static struct pci_driver mptsas_driver = {
4350 .name = "mptsas",
4351 .id_table = mptsas_pci_table,
4352 .probe = mptsas_probe,
4353 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304354 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004355#ifdef CONFIG_PM
4356 .suspend = mptscsih_suspend,
4357 .resume = mptscsih_resume,
4358#endif
4359};
4360
4361static int __init
4362mptsas_init(void)
4363{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304364 int error;
4365
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004366 show_mptmod_ver(my_NAME, my_VERSION);
4367
4368 mptsas_transport_template =
4369 sas_attach_transport(&mptsas_transport_functions);
4370 if (!mptsas_transport_template)
4371 return -ENODEV;
4372
4373 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304374 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004375 mptsasInternalCtx =
4376 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004377 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304378 mptsasDeviceResetCtx =
4379 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004380
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304381 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
4382 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004383
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304384 error = pci_register_driver(&mptsas_driver);
4385 if (error)
4386 sas_release_transport(mptsas_transport_template);
4387
4388 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004389}
4390
4391static void __exit
4392mptsas_exit(void)
4393{
4394 pci_unregister_driver(&mptsas_driver);
4395 sas_release_transport(mptsas_transport_template);
4396
4397 mpt_reset_deregister(mptsasDoneCtx);
4398 mpt_event_deregister(mptsasDoneCtx);
4399
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004400 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004401 mpt_deregister(mptsasInternalCtx);
4402 mpt_deregister(mptsasTaskCtx);
4403 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304404 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004405}
4406
4407module_init(mptsas_init);
4408module_exit(mptsas_exit);