blob: da22141152d7a1caf7a1df01b2c767bbd53b2071 [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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530727 port_details = kzalloc(sizeof(struct
728 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600729 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, Desai3eb08222009-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, Desai3eb08222009-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
Kashyap, Desai2f187862009-05-29 16:52:37 +0530955 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -0700956 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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05301794
1795 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1796 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
1797 complete(&ioc->sas_mgmt.done);
1798 return 1;
1799 }
1800 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001801}
1802
1803static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1804{
1805 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1806 SasIoUnitControlRequest_t *req;
1807 SasIoUnitControlReply_t *reply;
1808 MPT_FRAME_HDR *mf;
1809 MPIHeader_t *hdr;
1810 unsigned long timeleft;
1811 int error = -ERESTARTSYS;
1812
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001813 /* FIXME: fusion doesn't allow non-local phy reset */
1814 if (!scsi_is_sas_phy_local(phy))
1815 return -EINVAL;
1816
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001817 /* not implemented for expanders */
1818 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1819 return -ENXIO;
1820
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001821 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001822 goto out;
1823
1824 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1825 if (!mf) {
1826 error = -ENOMEM;
1827 goto out_unlock;
1828 }
1829
1830 hdr = (MPIHeader_t *) mf;
1831 req = (SasIoUnitControlRequest_t *)mf;
1832 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1833 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1834 req->MsgContext = hdr->MsgContext;
1835 req->Operation = hard_reset ?
1836 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1837 req->PhyNum = phy->identify.phy_identifier;
1838
Kashyap, Desai2f187862009-05-29 16:52:37 +05301839 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001840 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1841
1842 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1843 10 * HZ);
1844 if (!timeleft) {
1845 /* On timeout reset the board */
1846 mpt_free_msg_frame(ioc, mf);
1847 mpt_HardResetHandler(ioc, CAN_SLEEP);
1848 error = -ETIMEDOUT;
1849 goto out_unlock;
1850 }
1851
1852 /* a reply frame is expected */
1853 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301854 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001855 error = -ENXIO;
1856 goto out_unlock;
1857 }
1858
1859 /* process the completed Reply Message Frame */
1860 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1861 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001862 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001863 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001864 error = -ENXIO;
1865 goto out_unlock;
1866 }
1867
1868 error = 0;
1869
1870 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05301871 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001872 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001873 out:
1874 return error;
1875}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001876
Christoph Hellwige3094442006-02-16 13:25:36 +01001877static int
1878mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1879{
1880 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1881 int i, error;
1882 struct mptsas_portinfo *p;
1883 struct mptsas_enclosure enclosure_info;
1884 u64 enclosure_handle;
1885
1886 mutex_lock(&ioc->sas_topology_mutex);
1887 list_for_each_entry(p, &ioc->sas_topology, list) {
1888 for (i = 0; i < p->num_phys; i++) {
1889 if (p->phy_info[i].attached.sas_address ==
1890 rphy->identify.sas_address) {
1891 enclosure_handle = p->phy_info[i].
1892 attached.handle_enclosure;
1893 goto found_info;
1894 }
1895 }
1896 }
1897 mutex_unlock(&ioc->sas_topology_mutex);
1898 return -ENXIO;
1899
1900 found_info:
1901 mutex_unlock(&ioc->sas_topology_mutex);
1902 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001903 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001904 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1905 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1906 if (!error)
1907 *identifier = enclosure_info.enclosure_logical_id;
1908 return error;
1909}
1910
1911static int
1912mptsas_get_bay_identifier(struct sas_rphy *rphy)
1913{
1914 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1915 struct mptsas_portinfo *p;
1916 int i, rc;
1917
1918 mutex_lock(&ioc->sas_topology_mutex);
1919 list_for_each_entry(p, &ioc->sas_topology, list) {
1920 for (i = 0; i < p->num_phys; i++) {
1921 if (p->phy_info[i].attached.sas_address ==
1922 rphy->identify.sas_address) {
1923 rc = p->phy_info[i].attached.slot;
1924 goto out;
1925 }
1926 }
1927 }
1928 rc = -ENXIO;
1929 out:
1930 mutex_unlock(&ioc->sas_topology_mutex);
1931 return rc;
1932}
1933
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001934static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1935 struct request *req)
1936{
1937 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1938 MPT_FRAME_HDR *mf;
1939 SmpPassthroughRequest_t *smpreq;
1940 struct request *rsp = req->next_rq;
1941 int ret;
1942 int flagsLength;
1943 unsigned long timeleft;
1944 char *psge;
1945 dma_addr_t dma_addr_in = 0;
1946 dma_addr_t dma_addr_out = 0;
1947 u64 sas_address = 0;
1948
1949 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06001950 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001951 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001952 return -EINVAL;
1953 }
1954
1955 /* do we need to support multiple segments? */
1956 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06001957 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001958 ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
Eric Moore29dd3602007-09-14 18:46:51 -06001959 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001960 return -EINVAL;
1961 }
1962
1963 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1964 if (ret)
1965 goto out;
1966
1967 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1968 if (!mf) {
1969 ret = -ENOMEM;
1970 goto out_unlock;
1971 }
1972
1973 smpreq = (SmpPassthroughRequest_t *)mf;
1974 memset(smpreq, 0, sizeof(*smpreq));
1975
1976 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1977 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1978
1979 if (rphy)
1980 sas_address = rphy->identify.sas_address;
1981 else {
1982 struct mptsas_portinfo *port_info;
1983
1984 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301985 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001986 if (port_info && port_info->phy_info)
1987 sas_address =
1988 port_info->phy_info[0].phy->identify.sas_address;
1989 mutex_unlock(&ioc->sas_topology_mutex);
1990 }
1991
1992 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1993
1994 psge = (char *)
1995 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1996
1997 /* request */
1998 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1999 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302000 MPI_SGE_FLAGS_DIRECTION)
2001 << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002002 flagsLength |= (req->data_len - 4);
2003
2004 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
2005 req->data_len, PCI_DMA_BIDIRECTIONAL);
2006 if (!dma_addr_out)
2007 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302008 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302009 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002010
2011 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302012 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2013 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2014 MPI_SGE_FLAGS_IOC_TO_HOST |
2015 MPI_SGE_FLAGS_END_OF_BUFFER;
2016
2017 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002018 flagsLength |= rsp->data_len + 4;
2019 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
2020 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
2021 if (!dma_addr_in)
2022 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302023 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002024
Kashyap, Desai2f187862009-05-29 16:52:37 +05302025 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002026 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2027
2028 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2029 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002030 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002031 /* On timeout reset the board */
2032 mpt_HardResetHandler(ioc, CAN_SLEEP);
2033 ret = -ETIMEDOUT;
2034 goto unmap;
2035 }
2036 mf = NULL;
2037
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302038 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002039 SmpPassthroughReply_t *smprep;
2040
2041 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2042 memcpy(req->sense, smprep, sizeof(*smprep));
2043 req->sense_len = sizeof(*smprep);
FUJITA Tomonori38b31672007-12-30 19:34:52 +09002044 req->data_len = 0;
2045 rsp->data_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002046 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302047 printk(MYIOC_s_ERR_FMT
2048 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002049 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002050 ret = -ENXIO;
2051 }
2052unmap:
2053 if (dma_addr_out)
2054 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
2055 PCI_DMA_BIDIRECTIONAL);
2056 if (dma_addr_in)
2057 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
2058 PCI_DMA_BIDIRECTIONAL);
2059put_mf:
2060 if (mf)
2061 mpt_free_msg_frame(ioc, mf);
2062out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302063 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002064 mutex_unlock(&ioc->sas_mgmt.mutex);
2065out:
2066 return ret;
2067}
2068
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002069static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002070 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002071 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2072 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002073 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002074 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002075};
2076
2077static struct scsi_transport_template *mptsas_transport_template;
2078
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002079static int
2080mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2081{
2082 ConfigExtendedPageHeader_t hdr;
2083 CONFIGPARMS cfg;
2084 SasIOUnitPage0_t *buffer;
2085 dma_addr_t dma_handle;
2086 int error, i;
2087
2088 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2089 hdr.ExtPageLength = 0;
2090 hdr.PageNumber = 0;
2091 hdr.Reserved1 = 0;
2092 hdr.Reserved2 = 0;
2093 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2094 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2095
2096 cfg.cfghdr.ehdr = &hdr;
2097 cfg.physAddr = -1;
2098 cfg.pageAddr = 0;
2099 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2100 cfg.dir = 0; /* read */
2101 cfg.timeout = 10;
2102
2103 error = mpt_config(ioc, &cfg);
2104 if (error)
2105 goto out;
2106 if (!hdr.ExtPageLength) {
2107 error = -ENXIO;
2108 goto out;
2109 }
2110
2111 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2112 &dma_handle);
2113 if (!buffer) {
2114 error = -ENOMEM;
2115 goto out;
2116 }
2117
2118 cfg.physAddr = dma_handle;
2119 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2120
2121 error = mpt_config(ioc, &cfg);
2122 if (error)
2123 goto out_free_consistent;
2124
2125 port_info->num_phys = buffer->NumPhys;
2126 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302127 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002128 if (!port_info->phy_info) {
2129 error = -ENOMEM;
2130 goto out_free_consistent;
2131 }
2132
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302133 ioc->nvdata_version_persistent =
2134 le16_to_cpu(buffer->NvdataVersionPersistent);
2135 ioc->nvdata_version_default =
2136 le16_to_cpu(buffer->NvdataVersionDefault);
2137
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002138 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302139 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002140 port_info->phy_info[i].phy_id = i;
2141 port_info->phy_info[i].port_id =
2142 buffer->PhyData[i].Port;
2143 port_info->phy_info[i].negotiated_link_rate =
2144 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002145 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002146 port_info->phy_info[i].handle =
2147 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002148 }
2149
2150 out_free_consistent:
2151 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2152 buffer, dma_handle);
2153 out:
2154 return error;
2155}
2156
2157static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302158mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2159{
2160 ConfigExtendedPageHeader_t hdr;
2161 CONFIGPARMS cfg;
2162 SasIOUnitPage1_t *buffer;
2163 dma_addr_t dma_handle;
2164 int error;
2165 u16 device_missing_delay;
2166
2167 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2168 memset(&cfg, 0, sizeof(CONFIGPARMS));
2169
2170 cfg.cfghdr.ehdr = &hdr;
2171 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2172 cfg.timeout = 10;
2173 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2174 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2175 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2176 cfg.cfghdr.ehdr->PageNumber = 1;
2177
2178 error = mpt_config(ioc, &cfg);
2179 if (error)
2180 goto out;
2181 if (!hdr.ExtPageLength) {
2182 error = -ENXIO;
2183 goto out;
2184 }
2185
2186 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2187 &dma_handle);
2188 if (!buffer) {
2189 error = -ENOMEM;
2190 goto out;
2191 }
2192
2193 cfg.physAddr = dma_handle;
2194 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2195
2196 error = mpt_config(ioc, &cfg);
2197 if (error)
2198 goto out_free_consistent;
2199
2200 ioc->io_missing_delay =
2201 le16_to_cpu(buffer->IODeviceMissingDelay);
2202 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2203 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2204 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2205 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2206
2207 out_free_consistent:
2208 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2209 buffer, dma_handle);
2210 out:
2211 return error;
2212}
2213
2214static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002215mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2216 u32 form, u32 form_specific)
2217{
2218 ConfigExtendedPageHeader_t hdr;
2219 CONFIGPARMS cfg;
2220 SasPhyPage0_t *buffer;
2221 dma_addr_t dma_handle;
2222 int error;
2223
2224 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2225 hdr.ExtPageLength = 0;
2226 hdr.PageNumber = 0;
2227 hdr.Reserved1 = 0;
2228 hdr.Reserved2 = 0;
2229 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2230 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2231
2232 cfg.cfghdr.ehdr = &hdr;
2233 cfg.dir = 0; /* read */
2234 cfg.timeout = 10;
2235
2236 /* Get Phy Pg 0 for each Phy. */
2237 cfg.physAddr = -1;
2238 cfg.pageAddr = form + form_specific;
2239 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2240
2241 error = mpt_config(ioc, &cfg);
2242 if (error)
2243 goto out;
2244
2245 if (!hdr.ExtPageLength) {
2246 error = -ENXIO;
2247 goto out;
2248 }
2249
2250 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2251 &dma_handle);
2252 if (!buffer) {
2253 error = -ENOMEM;
2254 goto out;
2255 }
2256
2257 cfg.physAddr = dma_handle;
2258 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2259
2260 error = mpt_config(ioc, &cfg);
2261 if (error)
2262 goto out_free_consistent;
2263
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302264 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002265
2266 phy_info->hw_link_rate = buffer->HwLinkRate;
2267 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2268 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2269 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2270
2271 out_free_consistent:
2272 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2273 buffer, dma_handle);
2274 out:
2275 return error;
2276}
2277
2278static int
2279mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2280 u32 form, u32 form_specific)
2281{
2282 ConfigExtendedPageHeader_t hdr;
2283 CONFIGPARMS cfg;
2284 SasDevicePage0_t *buffer;
2285 dma_addr_t dma_handle;
2286 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002287 int error=0;
2288
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002289 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2290 hdr.ExtPageLength = 0;
2291 hdr.PageNumber = 0;
2292 hdr.Reserved1 = 0;
2293 hdr.Reserved2 = 0;
2294 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2295 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2296
2297 cfg.cfghdr.ehdr = &hdr;
2298 cfg.pageAddr = form + form_specific;
2299 cfg.physAddr = -1;
2300 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2301 cfg.dir = 0; /* read */
2302 cfg.timeout = 10;
2303
Moore, Ericdb9c9172006-03-14 09:14:18 -07002304 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002305 error = mpt_config(ioc, &cfg);
2306 if (error)
2307 goto out;
2308 if (!hdr.ExtPageLength) {
2309 error = -ENXIO;
2310 goto out;
2311 }
2312
2313 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2314 &dma_handle);
2315 if (!buffer) {
2316 error = -ENOMEM;
2317 goto out;
2318 }
2319
2320 cfg.physAddr = dma_handle;
2321 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2322
2323 error = mpt_config(ioc, &cfg);
2324 if (error)
2325 goto out_free_consistent;
2326
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302327 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002328
Kashyap, Desai2f187862009-05-29 16:52:37 +05302329 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002330 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787e2006-01-26 16:20:06 -07002331 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002332 device_info->handle_enclosure =
2333 le16_to_cpu(buffer->EnclosureHandle);
2334 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002335 device_info->phy_id = buffer->PhyNum;
2336 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002337 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002338 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002339 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002340 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2341 device_info->sas_address = le64_to_cpu(sas_address);
2342 device_info->device_info =
2343 le32_to_cpu(buffer->DeviceInfo);
2344
2345 out_free_consistent:
2346 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2347 buffer, dma_handle);
2348 out:
2349 return error;
2350}
2351
2352static int
2353mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2354 u32 form, u32 form_specific)
2355{
2356 ConfigExtendedPageHeader_t hdr;
2357 CONFIGPARMS cfg;
2358 SasExpanderPage0_t *buffer;
2359 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002360 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302361 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002362
Kashyap, Desai2f187862009-05-29 16:52:37 +05302363 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002364 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2365 hdr.ExtPageLength = 0;
2366 hdr.PageNumber = 0;
2367 hdr.Reserved1 = 0;
2368 hdr.Reserved2 = 0;
2369 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2370 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2371
2372 cfg.cfghdr.ehdr = &hdr;
2373 cfg.physAddr = -1;
2374 cfg.pageAddr = form + form_specific;
2375 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2376 cfg.dir = 0; /* read */
2377 cfg.timeout = 10;
2378
Moore, Ericdb9c9172006-03-14 09:14:18 -07002379 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002380 error = mpt_config(ioc, &cfg);
2381 if (error)
2382 goto out;
2383
2384 if (!hdr.ExtPageLength) {
2385 error = -ENXIO;
2386 goto out;
2387 }
2388
2389 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2390 &dma_handle);
2391 if (!buffer) {
2392 error = -ENOMEM;
2393 goto out;
2394 }
2395
2396 cfg.physAddr = dma_handle;
2397 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2398
2399 error = mpt_config(ioc, &cfg);
2400 if (error)
2401 goto out_free_consistent;
2402
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002403 if (!buffer->NumPhys) {
2404 error = -ENODEV;
2405 goto out_free_consistent;
2406 }
2407
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002408 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302409 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002410 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302411 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002412 if (!port_info->phy_info) {
2413 error = -ENOMEM;
2414 goto out_free_consistent;
2415 }
2416
Kashyap, Desai2f187862009-05-29 16:52:37 +05302417 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002418 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002419 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002420 port_info->phy_info[i].handle =
2421 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302422 port_info->phy_info[i].identify.sas_address =
2423 le64_to_cpu(sas_address);
2424 port_info->phy_info[i].identify.handle_parent =
2425 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002426 }
Eric Moore547f9a22006-06-27 14:42:12 -06002427
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002428 out_free_consistent:
2429 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2430 buffer, dma_handle);
2431 out:
2432 return error;
2433}
2434
2435static int
2436mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2437 u32 form, u32 form_specific)
2438{
2439 ConfigExtendedPageHeader_t hdr;
2440 CONFIGPARMS cfg;
2441 SasExpanderPage1_t *buffer;
2442 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002443 int error=0;
2444
Kashyap, Desai2f187862009-05-29 16:52:37 +05302445 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002446 hdr.ExtPageLength = 0;
2447 hdr.PageNumber = 1;
2448 hdr.Reserved1 = 0;
2449 hdr.Reserved2 = 0;
2450 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2451 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2452
2453 cfg.cfghdr.ehdr = &hdr;
2454 cfg.physAddr = -1;
2455 cfg.pageAddr = form + form_specific;
2456 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2457 cfg.dir = 0; /* read */
2458 cfg.timeout = 10;
2459
2460 error = mpt_config(ioc, &cfg);
2461 if (error)
2462 goto out;
2463
2464 if (!hdr.ExtPageLength) {
2465 error = -ENXIO;
2466 goto out;
2467 }
2468
2469 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2470 &dma_handle);
2471 if (!buffer) {
2472 error = -ENOMEM;
2473 goto out;
2474 }
2475
2476 cfg.physAddr = dma_handle;
2477 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2478
2479 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302480
2481 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2482 error = -ENODEV;
2483 goto out;
2484 }
2485
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002486 if (error)
2487 goto out_free_consistent;
2488
2489
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302490 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002491
2492 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002493 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002494 phy_info->port_id = buffer->PhysicalPort;
2495 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2496 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2497 phy_info->hw_link_rate = buffer->HwLinkRate;
2498 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2499 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2500
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002501 out_free_consistent:
2502 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2503 buffer, dma_handle);
2504 out:
2505 return error;
2506}
2507
2508static void
2509mptsas_parse_device_info(struct sas_identify *identify,
2510 struct mptsas_devinfo *device_info)
2511{
2512 u16 protocols;
2513
2514 identify->sas_address = device_info->sas_address;
2515 identify->phy_identifier = device_info->phy_id;
2516
2517 /*
2518 * Fill in Phy Initiator Port Protocol.
2519 * Bits 6:3, more than one bit can be set, fall through cases.
2520 */
2521 protocols = device_info->device_info & 0x78;
2522 identify->initiator_port_protocols = 0;
2523 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2524 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2525 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2526 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2527 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2528 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2529 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2530 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2531
2532 /*
2533 * Fill in Phy Target Port Protocol.
2534 * Bits 10:7, more than one bit can be set, fall through cases.
2535 */
2536 protocols = device_info->device_info & 0x780;
2537 identify->target_port_protocols = 0;
2538 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2539 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2540 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2541 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2542 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2543 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2544 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2545 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2546
2547 /*
2548 * Fill in Attached device type.
2549 */
2550 switch (device_info->device_info &
2551 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2552 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2553 identify->device_type = SAS_PHY_UNUSED;
2554 break;
2555 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2556 identify->device_type = SAS_END_DEVICE;
2557 break;
2558 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2559 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2560 break;
2561 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2562 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2563 break;
2564 }
2565}
2566
2567static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002568 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002569{
Moore, Erice6b2d762006-03-14 09:14:24 -07002570 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002571 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002572 struct sas_port *port;
2573 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002574
Eric Moore547f9a22006-06-27 14:42:12 -06002575 if (!dev) {
2576 error = -ENODEV;
2577 goto out;
2578 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002579
2580 if (!phy_info->phy) {
2581 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002582 if (!phy) {
2583 error = -ENOMEM;
2584 goto out;
2585 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002586 } else
2587 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002588
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002589 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002590
2591 /*
2592 * Set Negotiated link rate.
2593 */
2594 switch (phy_info->negotiated_link_rate) {
2595 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002596 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002597 break;
2598 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002599 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002600 break;
2601 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002602 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002603 break;
2604 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002605 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002606 break;
2607 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2608 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2609 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002610 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002611 break;
2612 }
2613
2614 /*
2615 * Set Max hardware link rate.
2616 */
2617 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2618 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002619 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002620 break;
2621 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002622 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002623 break;
2624 default:
2625 break;
2626 }
2627
2628 /*
2629 * Set Max programmed link rate.
2630 */
2631 switch (phy_info->programmed_link_rate &
2632 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2633 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002634 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002635 break;
2636 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002637 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002638 break;
2639 default:
2640 break;
2641 }
2642
2643 /*
2644 * Set Min hardware link rate.
2645 */
2646 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2647 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002648 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002649 break;
2650 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002651 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002652 break;
2653 default:
2654 break;
2655 }
2656
2657 /*
2658 * Set Min programmed link rate.
2659 */
2660 switch (phy_info->programmed_link_rate &
2661 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2662 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002663 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002664 break;
2665 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002666 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002667 break;
2668 default:
2669 break;
2670 }
2671
Moore, Erice6b2d762006-03-14 09:14:24 -07002672 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002673
Moore, Erice6b2d762006-03-14 09:14:24 -07002674 error = sas_phy_add(phy);
2675 if (error) {
2676 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002677 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002678 }
2679 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002680 }
2681
Eric Moore547f9a22006-06-27 14:42:12 -06002682 if (!phy_info->attached.handle ||
2683 !phy_info->port_details)
2684 goto out;
2685
2686 port = mptsas_get_port(phy_info);
2687 ioc = phy_to_ioc(phy_info->phy);
2688
2689 if (phy_info->sas_port_add_phy) {
2690
2691 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002692 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002693 if (!port) {
2694 error = -ENOMEM;
2695 goto out;
2696 }
2697 error = sas_port_add(port);
2698 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302699 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002700 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002701 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002702 goto out;
2703 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302704 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302705 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
2706 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
2707 ioc->name, port->port_identifier,
2708 (unsigned long long)phy_info->
2709 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06002710 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302711 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2712 "sas_port_add_phy: phy_id=%d\n",
2713 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002714 sas_port_add_phy(port, phy_info->phy);
2715 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302716 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
2717 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
2718 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06002719 }
Eric Moore547f9a22006-06-27 14:42:12 -06002720 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002721
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002722 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002723 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002724 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002725
James Bottomley2686de22006-06-30 12:54:02 -05002726 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002727 /*
2728 * Let the hotplug_work thread handle processing
2729 * the adding/removing of devices that occur
2730 * after start of day.
2731 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302732 if (mptsas_is_end_device(&phy_info->attached) &&
2733 phy_info->attached.handle_parent) {
2734 goto out;
2735 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002736
James Bottomleyf013db32006-03-18 14:54:36 -06002737 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002738 if (scsi_is_host_device(parent)) {
2739 struct mptsas_portinfo *port_info;
2740 int i;
2741
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302742 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05002743
2744 for (i = 0; i < port_info->num_phys; i++)
2745 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002746 identify.sas_address) {
2747 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002748 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002749 }
James Bottomley2686de22006-06-30 12:54:02 -05002750
2751 } else if (scsi_is_sas_rphy(parent)) {
2752 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2753 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002754 parent_rphy->identify.sas_address) {
2755 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002756 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002757 }
James Bottomley2686de22006-06-30 12:54:02 -05002758 }
2759
James Bottomleyf013db32006-03-18 14:54:36 -06002760 switch (identify.device_type) {
2761 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002762 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002763 break;
2764 case SAS_EDGE_EXPANDER_DEVICE:
2765 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002766 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002767 break;
2768 default:
2769 rphy = NULL;
2770 break;
2771 }
Eric Moore547f9a22006-06-27 14:42:12 -06002772 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302773 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002774 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002775 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002776 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002777 }
2778
Eric Moore547f9a22006-06-27 14:42:12 -06002779 rphy->identify = identify;
2780 error = sas_rphy_add(rphy);
2781 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302782 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002783 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002784 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002785 sas_rphy_free(rphy);
2786 goto out;
2787 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302788 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002789 }
2790
Eric Moore547f9a22006-06-27 14:42:12 -06002791 out:
2792 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002793}
2794
2795static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002796mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002797{
Moore, Erice6b2d762006-03-14 09:14:24 -07002798 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002799 int error = -ENOMEM, i;
2800
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302801 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07002802 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002803 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002804
Moore, Erice6b2d762006-03-14 09:14:24 -07002805 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002806 if (error)
2807 goto out_free_port_info;
2808
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302809 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002810 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302811 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07002812 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302813 ioc->hba_port_info = port_info = hba;
2814 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07002815 list_add_tail(&port_info->list, &ioc->sas_topology);
2816 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002817 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002818 port_info->phy_info[i].negotiated_link_rate =
2819 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002820 port_info->phy_info[i].handle =
2821 hba->phy_info[i].handle;
2822 port_info->phy_info[i].port_id =
2823 hba->phy_info[i].port_id;
2824 }
Eric Moore547f9a22006-06-27 14:42:12 -06002825 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002826 kfree(hba);
2827 hba = NULL;
2828 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002829 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302830#if defined(CPQ_CIM)
2831 ioc->num_ports = port_info->num_phys;
2832#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002833 for (i = 0; i < port_info->num_phys; i++) {
2834 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2835 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2836 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302837 port_info->phy_info[i].identify.handle =
2838 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002839 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002840 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2841 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302842 port_info->phy_info[i].identify.handle);
2843 if (!ioc->hba_port_sas_addr)
2844 ioc->hba_port_sas_addr =
2845 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02002846 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002847 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002848 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002849 mptsas_sas_device_pg0(ioc,
2850 &port_info->phy_info[i].attached,
2851 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2852 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2853 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002854 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002855
Eric Moore547f9a22006-06-27 14:42:12 -06002856 mptsas_setup_wide_ports(ioc, port_info);
2857
2858 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002859 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002860 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002861
2862 return 0;
2863
2864 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002865 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002866 out:
2867 return error;
2868}
2869
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302870static void
2871mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002872{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302873 struct mptsas_portinfo *parent;
2874 struct device *parent_dev;
2875 struct sas_rphy *rphy;
2876 int i;
2877 u64 sas_address; /* expander sas address */
2878 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002879
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302880 handle = port_info->phy_info[0].handle;
2881 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002882 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002883 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302884 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2885 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002886
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302887 mptsas_sas_device_pg0(ioc,
2888 &port_info->phy_info[i].identify,
2889 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2890 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2891 port_info->phy_info[i].identify.handle);
2892 port_info->phy_info[i].identify.phy_id =
2893 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002894
2895 if (port_info->phy_info[i].attached.handle) {
2896 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302897 &port_info->phy_info[i].attached,
2898 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2899 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2900 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002901 port_info->phy_info[i].attached.phy_id =
2902 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002903 }
Eric Moore547f9a22006-06-27 14:42:12 -06002904 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002905
Moore, Erice6b2d762006-03-14 09:14:24 -07002906 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302907 parent = mptsas_find_portinfo_by_handle(ioc,
2908 port_info->phy_info[0].identify.handle_parent);
2909 if (!parent) {
2910 mutex_unlock(&ioc->sas_topology_mutex);
2911 return;
2912 }
2913 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
2914 i++) {
2915 if (parent->phy_info[i].attached.sas_address == sas_address) {
2916 rphy = mptsas_get_rphy(&parent->phy_info[i]);
2917 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07002918 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002919 }
2920 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302921
2922 mptsas_setup_wide_ports(ioc, port_info);
2923 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
2924 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
2925 ioc->sas_index, 0);
2926}
2927
2928static void
2929mptsas_expander_event_add(MPT_ADAPTER *ioc,
2930 MpiEventDataSasExpanderStatusChange_t *expander_data)
2931{
2932 struct mptsas_portinfo *port_info;
2933 int i;
2934 __le64 sas_address;
2935
2936 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
2937 if (!port_info)
2938 BUG();
2939 port_info->num_phys = (expander_data->NumPhys) ?
2940 expander_data->NumPhys : 1;
2941 port_info->phy_info = kcalloc(port_info->num_phys,
2942 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
2943 if (!port_info->phy_info)
2944 BUG();
2945 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
2946 for (i = 0; i < port_info->num_phys; i++) {
2947 port_info->phy_info[i].portinfo = port_info;
2948 port_info->phy_info[i].handle =
2949 le16_to_cpu(expander_data->DevHandle);
2950 port_info->phy_info[i].identify.sas_address =
2951 le64_to_cpu(sas_address);
2952 port_info->phy_info[i].identify.handle_parent =
2953 le16_to_cpu(expander_data->ParentDevHandle);
2954 }
2955
2956 mutex_lock(&ioc->sas_topology_mutex);
2957 list_add_tail(&port_info->list, &ioc->sas_topology);
2958 mutex_unlock(&ioc->sas_topology_mutex);
2959
2960 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
2961 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
2962 (unsigned long long)sas_address);
2963
2964 mptsas_expander_refresh(ioc, port_info);
2965}
2966
2967/**
2968 * mptsas_delete_expander_siblings - remove siblings attached to expander
2969 * @ioc: Pointer to MPT_ADAPTER structure
2970 * @parent: the parent port_info object
2971 * @expander: the expander port_info object
2972 **/
2973static void
2974mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
2975 *parent, struct mptsas_portinfo *expander)
2976{
2977 struct mptsas_phyinfo *phy_info;
2978 struct mptsas_portinfo *port_info;
2979 struct sas_rphy *rphy;
2980 int i;
2981
2982 phy_info = expander->phy_info;
2983 for (i = 0; i < expander->num_phys; i++, phy_info++) {
2984 rphy = mptsas_get_rphy(phy_info);
2985 if (!rphy)
2986 continue;
2987 if (rphy->identify.device_type == SAS_END_DEVICE)
2988 mptsas_del_end_device(ioc, phy_info);
2989 }
2990
2991 phy_info = expander->phy_info;
2992 for (i = 0; i < expander->num_phys; i++, phy_info++) {
2993 rphy = mptsas_get_rphy(phy_info);
2994 if (!rphy)
2995 continue;
2996 if (rphy->identify.device_type ==
2997 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2998 rphy->identify.device_type ==
2999 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3000 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3001 rphy->identify.sas_address);
3002 if (!port_info)
3003 continue;
3004 if (port_info == parent) /* backlink rphy */
3005 continue;
3006 /*
3007 Delete this expander even if the expdevpage is exists
3008 because the parent expander is already deleted
3009 */
3010 mptsas_expander_delete(ioc, port_info, 1);
3011 }
3012 }
3013}
3014
3015
3016/**
3017 * mptsas_expander_delete - remove this expander
3018 * @ioc: Pointer to MPT_ADAPTER structure
3019 * @port_info: expander port_info struct
3020 * @force: Flag to forcefully delete the expander
3021 *
3022 **/
3023
3024static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3025 struct mptsas_portinfo *port_info, u8 force)
3026{
3027
3028 struct mptsas_portinfo *parent;
3029 int i;
3030 u64 expander_sas_address;
3031 struct mptsas_phyinfo *phy_info;
3032 struct mptsas_portinfo buffer;
3033 struct mptsas_portinfo_details *port_details;
3034 struct sas_port *port;
3035
3036 if (!port_info)
3037 return;
3038
3039 /* see if expander is still there before deleting */
3040 mptsas_sas_expander_pg0(ioc, &buffer,
3041 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3042 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3043 port_info->phy_info[0].identify.handle);
3044
3045 if (buffer.num_phys) {
3046 kfree(buffer.phy_info);
3047 if (!force)
3048 return;
3049 }
3050
3051
3052 /*
3053 * Obtain the port_info instance to the parent port
3054 */
3055 port_details = NULL;
3056 expander_sas_address =
3057 port_info->phy_info[0].identify.sas_address;
3058 parent = mptsas_find_portinfo_by_handle(ioc,
3059 port_info->phy_info[0].identify.handle_parent);
3060 mptsas_delete_expander_siblings(ioc, parent, port_info);
3061 if (!parent)
3062 goto out;
3063
3064 /*
3065 * Delete rphys in the parent that point
3066 * to this expander.
3067 */
3068 phy_info = parent->phy_info;
3069 port = NULL;
3070 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3071 if (!phy_info->phy)
3072 continue;
3073 if (phy_info->attached.sas_address !=
3074 expander_sas_address)
3075 continue;
3076 if (!port) {
3077 port = mptsas_get_port(phy_info);
3078 port_details = phy_info->port_details;
3079 }
3080 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3081 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3082 phy_info->phy_id, phy_info->phy);
3083 sas_port_delete_phy(port, phy_info->phy);
3084 }
3085 if (port) {
3086 dev_printk(KERN_DEBUG, &port->dev,
3087 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3088 ioc->name, port->port_identifier,
3089 (unsigned long long)expander_sas_address);
3090 sas_port_delete(port);
3091 mptsas_port_delete(ioc, port_details);
3092 }
3093 out:
3094
3095 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3096 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3097 (unsigned long long)expander_sas_address);
3098
3099 /*
3100 * free link
3101 */
3102 list_del(&port_info->list);
3103 kfree(port_info->phy_info);
3104 kfree(port_info);
3105}
3106
3107
3108/**
3109 * mptsas_send_expander_event - expanders events
3110 * @ioc: Pointer to MPT_ADAPTER structure
3111 * @expander_data: event data
3112 *
3113 *
3114 * This function handles adding, removing, and refreshing
3115 * device handles within the expander objects.
3116 */
3117static void
3118mptsas_send_expander_event(struct fw_event_work *fw_event)
3119{
3120 MPT_ADAPTER *ioc;
3121 MpiEventDataSasExpanderStatusChange_t *expander_data;
3122 struct mptsas_portinfo *port_info;
3123 __le64 sas_address;
3124 int i;
3125
3126 ioc = fw_event->ioc;
3127 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3128 fw_event->event_data;
3129 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3130 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3131
3132 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3133 if (port_info) {
3134 for (i = 0; i < port_info->num_phys; i++) {
3135 port_info->phy_info[i].portinfo = port_info;
3136 port_info->phy_info[i].handle =
3137 le16_to_cpu(expander_data->DevHandle);
3138 port_info->phy_info[i].identify.sas_address =
3139 le64_to_cpu(sas_address);
3140 port_info->phy_info[i].identify.handle_parent =
3141 le16_to_cpu(expander_data->ParentDevHandle);
3142 }
3143 mptsas_expander_refresh(ioc, port_info);
3144 } else if (!port_info && expander_data->NumPhys)
3145 mptsas_expander_event_add(ioc, expander_data);
3146 } else if (expander_data->ReasonCode ==
3147 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3148 mptsas_expander_delete(ioc, port_info, 0);
3149
3150 mptsas_free_fw_event(ioc, fw_event);
3151}
3152
3153
3154/**
3155 * mptsas_expander_add -
3156 * @ioc: Pointer to MPT_ADAPTER structure
3157 * @handle:
3158 *
3159 */
3160struct mptsas_portinfo *
3161mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3162{
3163 struct mptsas_portinfo buffer, *port_info;
3164 int i;
3165
3166 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3167 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3168 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3169 return NULL;
3170
3171 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3172 if (!port_info) {
3173 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3174 "%s: exit at line=%d\n", ioc->name,
3175 __func__, __LINE__));
3176 return NULL;
3177 }
3178 port_info->num_phys = buffer.num_phys;
3179 port_info->phy_info = buffer.phy_info;
3180 for (i = 0; i < port_info->num_phys; i++)
3181 port_info->phy_info[i].portinfo = port_info;
3182 mutex_lock(&ioc->sas_topology_mutex);
3183 list_add_tail(&port_info->list, &ioc->sas_topology);
3184 mutex_unlock(&ioc->sas_topology_mutex);
3185 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3186 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3187 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3188 mptsas_expander_refresh(ioc, port_info);
3189 return port_info;
3190}
3191
3192static void
3193mptsas_send_link_status_event(struct fw_event_work *fw_event)
3194{
3195 MPT_ADAPTER *ioc;
3196 MpiEventDataSasPhyLinkStatus_t *link_data;
3197 struct mptsas_portinfo *port_info;
3198 struct mptsas_phyinfo *phy_info = NULL;
3199 __le64 sas_address;
3200 u8 phy_num;
3201 u8 link_rate;
3202
3203 ioc = fw_event->ioc;
3204 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3205
3206 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3207 sas_address = le64_to_cpu(sas_address);
3208 link_rate = link_data->LinkRates >> 4;
3209 phy_num = link_data->PhyNum;
3210
3211 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3212 if (port_info) {
3213 phy_info = &port_info->phy_info[phy_num];
3214 if (phy_info)
3215 phy_info->negotiated_link_rate = link_rate;
3216 }
3217
3218 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3219 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3220
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303221 if (!port_info) {
3222 if (ioc->old_sas_discovery_protocal) {
3223 port_info = mptsas_expander_add(ioc,
3224 le16_to_cpu(link_data->DevHandle));
3225 if (port_info)
3226 goto out;
3227 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303228 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303229 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303230
3231 if (port_info == ioc->hba_port_info)
3232 mptsas_probe_hba_phys(ioc);
3233 else
3234 mptsas_expander_refresh(ioc, port_info);
3235 } else if (phy_info && phy_info->phy) {
3236 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3237 phy_info->phy->negotiated_linkrate =
3238 SAS_PHY_DISABLED;
3239 else if (link_rate ==
3240 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3241 phy_info->phy->negotiated_linkrate =
3242 SAS_LINK_RATE_FAILED;
3243 else
3244 phy_info->phy->negotiated_linkrate =
3245 SAS_LINK_RATE_UNKNOWN;
3246 }
3247 out:
3248 mptsas_free_fw_event(ioc, fw_event);
3249}
3250
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303251static void
3252mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3253{
3254 struct mptsas_portinfo buffer, *port_info;
3255 struct mptsas_device_info *sas_info;
3256 struct mptsas_devinfo sas_device;
3257 u32 handle;
3258 VirtTarget *vtarget = NULL;
3259 struct mptsas_phyinfo *phy_info;
3260 u8 found_expander;
3261 int retval, retry_count;
3262 unsigned long flags;
3263
3264 mpt_findImVolumes(ioc);
3265
3266 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3267 if (ioc->ioc_reset_in_progress) {
3268 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3269 "%s: exiting due to a parallel reset \n", ioc->name,
3270 __func__));
3271 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3272 return;
3273 }
3274 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3275
3276 /* devices, logical volumes */
3277 mutex_lock(&ioc->sas_device_info_mutex);
3278 redo_device_scan:
3279 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
3280 sas_device.handle = 0;
3281 retry_count = 0;
3282retry_page:
3283 retval = mptsas_sas_device_pg0(ioc, &sas_device,
3284 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3285 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3286 (sas_info->fw.channel << 8) +
3287 sas_info->fw.id);
3288
3289 if (sas_device.handle)
3290 continue;
3291 if (retval == -EBUSY) {
3292 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3293 if (ioc->ioc_reset_in_progress) {
3294 dfailprintk(ioc,
3295 printk(MYIOC_s_DEBUG_FMT
3296 "%s: exiting due to reset\n",
3297 ioc->name, __func__));
3298 spin_unlock_irqrestore
3299 (&ioc->taskmgmt_lock, flags);
3300 mutex_unlock(&ioc->sas_device_info_mutex);
3301 return;
3302 }
3303 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3304 flags);
3305 }
3306
3307 if (retval && (retval != -ENODEV)) {
3308 if (retry_count < 10) {
3309 retry_count++;
3310 goto retry_page;
3311 } else {
3312 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3313 "%s: Config page retry exceeded retry "
3314 "count deleting device 0x%llx\n",
3315 ioc->name, __func__,
3316 sas_info->sas_address));
3317 }
3318 }
3319
3320 /* delete device */
3321 vtarget = mptsas_find_vtarget(ioc,
3322 sas_info->fw.channel, sas_info->fw.id);
3323 if (vtarget)
3324 vtarget->deleted = 1;
3325 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3326 sas_info->sas_address);
3327 if (phy_info) {
3328 mptsas_del_end_device(ioc, phy_info);
3329 goto redo_device_scan;
3330 }
3331 }
3332 mutex_unlock(&ioc->sas_device_info_mutex);
3333
3334 /* expanders */
3335 mutex_lock(&ioc->sas_topology_mutex);
3336 redo_expander_scan:
3337 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3338
3339 if (port_info->phy_info &&
3340 (!(port_info->phy_info[0].identify.device_info &
3341 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3342 continue;
3343 found_expander = 0;
3344 handle = 0xFFFF;
3345 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3346 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3347 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3348 !found_expander) {
3349
3350 handle = buffer.phy_info[0].handle;
3351 if (buffer.phy_info[0].identify.sas_address ==
3352 port_info->phy_info[0].identify.sas_address) {
3353 found_expander = 1;
3354 }
3355 kfree(buffer.phy_info);
3356 }
3357
3358 if (!found_expander) {
3359 mptsas_expander_delete(ioc, port_info, 0);
3360 goto redo_expander_scan;
3361 }
3362 }
3363 mutex_lock(&ioc->sas_topology_mutex);
3364}
3365
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303366/**
3367 * mptsas_probe_expanders - adding expanders
3368 * @ioc: Pointer to MPT_ADAPTER structure
3369 *
3370 **/
3371static void
3372mptsas_probe_expanders(MPT_ADAPTER *ioc)
3373{
3374 struct mptsas_portinfo buffer, *port_info;
3375 u32 handle;
3376 int i;
3377
3378 handle = 0xFFFF;
3379 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3380 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3381 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3382
3383 handle = buffer.phy_info[0].handle;
3384 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3385 buffer.phy_info[0].identify.sas_address);
3386
3387 if (port_info) {
3388 /* refreshing handles */
3389 for (i = 0; i < buffer.num_phys; i++) {
3390 port_info->phy_info[i].handle = handle;
3391 port_info->phy_info[i].identify.handle_parent =
3392 buffer.phy_info[0].identify.handle_parent;
3393 }
3394 mptsas_expander_refresh(ioc, port_info);
3395 kfree(buffer.phy_info);
3396 continue;
3397 }
3398
3399 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3400 if (!port_info) {
3401 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3402 "%s: exit at line=%d\n", ioc->name,
3403 __func__, __LINE__));
3404 return;
3405 }
3406 port_info->num_phys = buffer.num_phys;
3407 port_info->phy_info = buffer.phy_info;
3408 for (i = 0; i < port_info->num_phys; i++)
3409 port_info->phy_info[i].portinfo = port_info;
3410 mutex_lock(&ioc->sas_topology_mutex);
3411 list_add_tail(&port_info->list, &ioc->sas_topology);
3412 mutex_unlock(&ioc->sas_topology_mutex);
3413 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3414 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3415 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3416 mptsas_expander_refresh(ioc, port_info);
3417 }
3418}
3419
3420static void
3421mptsas_probe_devices(MPT_ADAPTER *ioc)
3422{
3423 u16 handle;
3424 struct mptsas_devinfo sas_device;
3425 struct mptsas_phyinfo *phy_info;
3426
3427 handle = 0xFFFF;
3428 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3429 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3430
3431 handle = sas_device.handle;
3432
3433 if ((sas_device.device_info &
3434 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3435 MPI_SAS_DEVICE_INFO_STP_TARGET |
3436 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3437 continue;
3438
3439 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3440 if (!phy_info)
3441 continue;
3442
3443 if (mptsas_get_rphy(phy_info))
3444 continue;
3445
3446 mptsas_add_end_device(ioc, phy_info);
3447 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003448}
3449
Kashyap, Desai2f187862009-05-29 16:52:37 +05303450/**
3451 * mptsas_scan_sas_topology -
3452 * @ioc: Pointer to MPT_ADAPTER structure
3453 * @sas_address:
3454 *
3455 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003456static void
3457mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3458{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303459 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003460 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003461
Moore, Erice6b2d762006-03-14 09:14:24 -07003462 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303463 mptsas_probe_expanders(ioc);
3464 mptsas_probe_devices(ioc);
3465
Moore, Ericf44e5462006-03-14 09:14:21 -07003466 /*
3467 Reporting RAID volumes.
3468 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303469 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3470 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3471 return;
Eric Moore793955f2007-01-29 09:42:20 -07003472 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303473 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3474 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3475 if (sdev) {
3476 scsi_device_put(sdev);
3477 continue;
3478 }
3479 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3480 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3481 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003482 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003483 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3484 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003485}
3486
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003487static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003488mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003489{
3490 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003491 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003492 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003493
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003494 mutex_lock(&ioc->sas_topology_mutex);
3495 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3496 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003497 if (!mptsas_is_end_device(
3498 &port_info->phy_info[i].attached))
3499 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003500 if (port_info->phy_info[i].attached.sas_address
3501 != sas_address)
3502 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003503 phy_info = &port_info->phy_info[i];
3504 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003505 }
3506 }
3507 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003508 return phy_info;
3509}
3510
Eric Mooreb506ade2007-01-29 09:45:37 -07003511
3512static struct mptsas_phyinfo *
3513mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
3514{
3515 struct mptsas_portinfo *port_info;
3516 struct mptsas_phyinfo *phy_info = NULL;
3517 int i;
3518
3519 mutex_lock(&ioc->sas_topology_mutex);
3520 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3521 for (i = 0; i < port_info->num_phys; i++) {
3522 if (!mptsas_is_end_device(
3523 &port_info->phy_info[i].attached))
3524 continue;
3525 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
3526 continue;
3527 if (port_info->phy_info[i].attached.phys_disk_num != id)
3528 continue;
3529 if (port_info->phy_info[i].attached.channel != channel)
3530 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003531 phy_info = &port_info->phy_info[i];
3532 break;
3533 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003534 }
3535 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003536 return phy_info;
3537}
3538
3539static void
Moore, Ericf44e5462006-03-14 09:14:21 -07003540mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
3541{
Eric Mooref99be432007-01-04 20:46:54 -07003542 int rc;
3543
Moore, Ericf44e5462006-03-14 09:14:21 -07003544 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07003545 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07003546}
3547
3548static void
3549mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
3550{
3551 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
3552 mptsas_reprobe_lun);
3553}
3554
Eric Mooreb506ade2007-01-29 09:45:37 -07003555static void
3556mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
3557{
3558 CONFIGPARMS cfg;
3559 ConfigPageHeader_t hdr;
3560 dma_addr_t dma_handle;
3561 pRaidVolumePage0_t buffer = NULL;
3562 RaidPhysDiskPage0_t phys_disk;
3563 int i;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303564 struct mptsas_phyinfo *phy_info;
3565 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07003566
3567 memset(&cfg, 0 , sizeof(CONFIGPARMS));
3568 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
3569 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
3570 cfg.pageAddr = (channel << 8) + id;
3571 cfg.cfghdr.hdr = &hdr;
3572 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3573
3574 if (mpt_config(ioc, &cfg) != 0)
3575 goto out;
3576
3577 if (!hdr.PageLength)
3578 goto out;
3579
3580 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
3581 &dma_handle);
3582
3583 if (!buffer)
3584 goto out;
3585
3586 cfg.physAddr = dma_handle;
3587 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3588
3589 if (mpt_config(ioc, &cfg) != 0)
3590 goto out;
3591
3592 if (!(buffer->VolumeStatus.Flags &
3593 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
3594 goto out;
3595
3596 if (!buffer->NumPhysDisks)
3597 goto out;
3598
3599 for (i = 0; i < buffer->NumPhysDisks; i++) {
3600
3601 if (mpt_raid_phys_disk_pg0(ioc,
3602 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
3603 continue;
3604
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303605 if (mptsas_sas_device_pg0(ioc, &sas_device,
3606 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3607 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3608 (phys_disk.PhysDiskBus << 8) +
3609 phys_disk.PhysDiskID))
3610 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003611
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303612 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3613 sas_device.sas_address);
3614 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07003615 }
3616
3617 out:
3618 if (buffer)
3619 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
3620 dma_handle);
3621}
Moore, Erice6b2d762006-03-14 09:14:24 -07003622/*
3623 * Work queue thread to handle SAS hotplug events
3624 */
Moore, Ericf44e5462006-03-14 09:14:21 -07003625static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303626mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
3627 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003628{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003629 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06003630 struct scsi_target * starget;
Moore, Ericc73787e2006-01-26 16:20:06 -07003631 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07003632 VirtTarget *vtarget;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303633 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06003634
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303635 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003636
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303637 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07003638
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303639 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07003640 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003641
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303642 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
3643 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
3644 hot_plug_info->id) {
3645 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
3646 "to add hidden disk - target_id matchs "
3647 "volume_id\n", ioc->name);
3648 mptsas_free_fw_event(ioc, fw_event);
3649 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07003650 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003651 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303652 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003653
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003654 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303655 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
3656 mptsas_sas_device_pg0(ioc, &sas_device,
3657 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3658 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3659 (hot_plug_info->channel << 8) +
3660 hot_plug_info->id);
Moore, Ericc73787e2006-01-26 16:20:06 -07003661
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303662 if (!sas_device.handle)
3663 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06003664
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303665 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3666 if (!phy_info)
3667 break;
3668
3669 if (mptsas_get_rphy(phy_info))
3670 break;
3671
3672 mptsas_add_end_device(ioc, phy_info);
3673 break;
3674
3675 case MPTSAS_DEL_DEVICE:
3676 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3677 hot_plug_info->sas_address);
3678 mptsas_del_end_device(ioc, phy_info);
3679 break;
3680
3681 case MPTSAS_DEL_PHYSDISK:
3682
3683 mpt_findImVolumes(ioc);
3684
3685 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
3686 ioc, hot_plug_info->channel,
3687 hot_plug_info->phys_disk_num);
3688 mptsas_del_end_device(ioc, phy_info);
3689 break;
3690
3691 case MPTSAS_ADD_PHYSDISK_REPROBE:
3692
Christoph Hellwige3094442006-02-16 13:25:36 +01003693 if (mptsas_sas_device_pg0(ioc, &sas_device,
3694 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07003695 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303696 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
3697 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3698 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3699 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01003700 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07003701 }
3702
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303703 phy_info = mptsas_find_phyinfo_by_sas_address(
3704 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07003705
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303706 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303707 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303708 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3709 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003710 break;
3711 }
3712
3713 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303714 if (!starget) {
3715 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3716 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3717 __func__, hot_plug_info->id, __LINE__));
3718 break;
3719 }
Eric Mooreb506ade2007-01-29 09:45:37 -07003720
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303721 vtarget = starget->hostdata;
3722 if (!vtarget) {
3723 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3724 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3725 __func__, hot_plug_info->id, __LINE__));
3726 break;
3727 }
Eric Moore547f9a22006-06-27 14:42:12 -06003728
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303729 mpt_findImVolumes(ioc);
3730
3731 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
3732 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
3733 ioc->name, hot_plug_info->channel, hot_plug_info->id,
3734 hot_plug_info->phys_disk_num, (unsigned long long)
3735 sas_device.sas_address);
3736
3737 vtarget->id = hot_plug_info->phys_disk_num;
3738 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
3739 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
3740 mptsas_reprobe_target(starget, 1);
3741 break;
3742
3743 case MPTSAS_DEL_PHYSDISK_REPROBE:
3744
3745 if (mptsas_sas_device_pg0(ioc, &sas_device,
3746 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3747 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3748 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303749 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303750 "%s: fw_id=%d exit at line=%d\n",
3751 ioc->name, __func__,
3752 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003753 break;
3754 }
3755
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303756 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3757 sas_device.sas_address);
3758 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303759 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303760 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3761 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003762 break;
Eric Moore547f9a22006-06-27 14:42:12 -06003763 }
Eric Mooreb506ade2007-01-29 09:45:37 -07003764
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303765 starget = mptsas_get_starget(phy_info);
3766 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303767 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303768 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3769 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003770 break;
3771 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003772
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303773 vtarget = starget->hostdata;
3774 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303775 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303776 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3777 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003778 break;
3779 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303780
3781 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
3782 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3783 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3784 __func__, hot_plug_info->id, __LINE__));
3785 break;
3786 }
3787
3788 mpt_findImVolumes(ioc);
3789
3790 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
3791 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
3792 ioc->name, hot_plug_info->channel, hot_plug_info->id,
3793 hot_plug_info->phys_disk_num, (unsigned long long)
3794 sas_device.sas_address);
3795
3796 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
3797 vtarget->id = hot_plug_info->id;
3798 phy_info->attached.phys_disk_num = ~0;
3799 mptsas_reprobe_target(starget, 0);
3800 mptsas_add_device_component_by_fw(ioc,
3801 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003802 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303803
Moore, Ericc73787e2006-01-26 16:20:06 -07003804 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303805
Moore, Ericc73787e2006-01-26 16:20:06 -07003806 mpt_findImVolumes(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303807 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3808 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3809 hot_plug_info->id);
3810 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
3811 hot_plug_info->id, 0);
Moore, Ericc73787e2006-01-26 16:20:06 -07003812 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303813
Moore, Ericc73787e2006-01-26 16:20:06 -07003814 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303815
Moore, Ericc73787e2006-01-26 16:20:06 -07003816 mpt_findImVolumes(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303817 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
3818 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3819 hot_plug_info->id);
3820 scsi_remove_device(hot_plug_info->sdev);
3821 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787e2006-01-26 16:20:06 -07003822 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303823
Eric Mooreb506ade2007-01-29 09:45:37 -07003824 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303825
3826 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07003827 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303828 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07003829 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303830
Moore, Ericbd23e942006-04-17 12:43:04 -06003831 default:
3832 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003833 }
3834
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303835 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003836}
3837
3838static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303839mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003840{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303841 MPT_ADAPTER *ioc;
3842 struct mptsas_hotplug_event hot_plug_info;
3843 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
3844 u32 device_info;
3845 u64 sas_address;
3846
3847 ioc = fw_event->ioc;
3848 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
3849 fw_event->event_data;
3850 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003851
3852 if ((device_info &
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303853 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3854 MPI_SAS_DEVICE_INFO_STP_TARGET |
3855 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
3856 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003857 return;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303858 }
3859
3860 if (sas_event_data->ReasonCode ==
3861 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
3862 mptbase_sas_persist_operation(ioc,
3863 MPI_SAS_OP_CLEAR_NOT_PRESENT);
3864 mptsas_free_fw_event(ioc, fw_event);
3865 return;
3866 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003867
Moore, Eric4b766472006-03-14 09:14:12 -07003868 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07003869 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07003870 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303871 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
3872 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
3873 hot_plug_info.channel = sas_event_data->Bus;
3874 hot_plug_info.id = sas_event_data->TargetID;
3875 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07003876 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303877 sizeof(u64));
3878 hot_plug_info.sas_address = le64_to_cpu(sas_address);
3879 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07003880 if (sas_event_data->ReasonCode &
3881 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303882 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07003883 else
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303884 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
3885 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07003886 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303887
Moore, Eric4b766472006-03-14 09:14:12 -07003888 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303889 mptbase_sas_persist_operation(ioc,
3890 MPI_SAS_OP_CLEAR_NOT_PRESENT);
3891 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07003892 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303893
Moore, Eric4b766472006-03-14 09:14:12 -07003894 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303895 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07003896 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303897 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07003898 default:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303899 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07003900 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003901 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003902}
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303903
Moore, Ericc73787e2006-01-26 16:20:06 -07003904static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303905mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787e2006-01-26 16:20:06 -07003906{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303907 MPT_ADAPTER *ioc;
3908 EVENT_DATA_RAID *raid_event_data;
3909 struct mptsas_hotplug_event hot_plug_info;
3910 int status;
3911 int state;
3912 struct scsi_device *sdev = NULL;
3913 VirtDevice *vdevice = NULL;
3914 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787e2006-01-26 16:20:06 -07003915
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303916 ioc = fw_event->ioc;
3917 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
3918 status = le32_to_cpu(raid_event_data->SettingsStatus);
3919 state = (status >> 8) & 0xff;
Moore, Ericc73787e2006-01-26 16:20:06 -07003920
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303921 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
3922 hot_plug_info.id = raid_event_data->VolumeID;
3923 hot_plug_info.channel = raid_event_data->VolumeBus;
3924 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
3925
3926 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
3927 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
3928 raid_event_data->ReasonCode ==
3929 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
3930 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3931 hot_plug_info.id, 0);
3932 hot_plug_info.sdev = sdev;
3933 if (sdev)
3934 vdevice = sdev->hostdata;
Moore, Ericc73787e2006-01-26 16:20:06 -07003935 }
3936
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303937 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
3938 "ReasonCode=%02x\n", ioc->name, __func__,
3939 raid_event_data->ReasonCode));
Moore, Ericc73787e2006-01-26 16:20:06 -07003940
3941 switch (raid_event_data->ReasonCode) {
3942 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303943 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07003944 break;
3945 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303946 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07003947 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06003948 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
3949 switch (state) {
3950 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07003951 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303952 mpt_raid_phys_disk_pg0(ioc,
3953 raid_event_data->PhysDiskNum, &phys_disk);
3954 hot_plug_info.id = phys_disk.PhysDiskID;
3955 hot_plug_info.channel = phys_disk.PhysDiskBus;
3956 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06003957 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303958 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06003959 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06003960 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
3961 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
3962 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303963 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06003964 break;
3965 default:
3966 break;
3967 }
3968 break;
Moore, Ericc73787e2006-01-26 16:20:06 -07003969 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303970 if (!sdev)
3971 break;
3972 vdevice->vtarget->deleted = 1; /* block IO */
3973 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07003974 break;
3975 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303976 if (sdev) {
3977 scsi_device_put(sdev);
3978 break;
3979 }
3980 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07003981 break;
3982 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303983 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
3984 if (!sdev)
3985 break;
3986 vdevice->vtarget->deleted = 1; /* block IO */
3987 hot_plug_info.event_type = MPTSAS_DEL_RAID;
3988 break;
3989 }
Moore, Ericbd23e942006-04-17 12:43:04 -06003990 switch (state) {
3991 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
3992 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303993 if (!sdev)
3994 break;
3995 vdevice->vtarget->deleted = 1; /* block IO */
3996 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06003997 break;
3998 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
3999 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304000 if (sdev) {
4001 scsi_device_put(sdev);
4002 break;
4003 }
4004 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004005 break;
4006 default:
4007 break;
4008 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004009 break;
4010 default:
4011 break;
4012 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304013
4014 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4015 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4016 else
4017 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787e2006-01-26 16:20:06 -07004018}
4019
Eric Mooreb506ade2007-01-29 09:45:37 -07004020/*
4021 * mptsas_send_ir2_event - handle exposing hidden disk when
4022 * an inactive raid volume is added
4023 *
4024 * @ioc: Pointer to MPT_ADAPTER structure
4025 * @ir2_data
4026 *
4027 */
4028static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304029mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004030{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304031 MPT_ADAPTER *ioc;
4032 struct mptsas_hotplug_event hot_plug_info;
4033 MPI_EVENT_DATA_IR2 *ir2_data;
4034 u8 reasonCode;
Eric Mooreb506ade2007-01-29 09:45:37 -07004035
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304036 ioc = fw_event->ioc;
4037 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4038 reasonCode = ir2_data->ReasonCode;
4039
4040 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4041 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4042
4043 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4044 hot_plug_info.id = ir2_data->TargetID;
4045 hot_plug_info.channel = ir2_data->Bus;
4046 switch (reasonCode) {
4047 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4048 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4049 break;
4050 default:
4051 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004052 return;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304053 }
4054 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4055}
Moore, Erice6b2d762006-03-14 09:14:24 -07004056
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004057static int
4058mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4059{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304060 u32 event = le32_to_cpu(reply->Event);
4061 int sz, event_data_sz;
4062 struct fw_event_work *fw_event;
4063 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004064
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304065 /* events turned off due to host reset or driver unloading */
4066 if (ioc->fw_events_off)
4067 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004068
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304069 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004070 switch (event) {
4071 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304072 {
4073 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4074 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4075
4076 if (sas_event_data->ReasonCode ==
4077 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4078 mptsas_target_reset_queue(ioc, sas_event_data);
4079 return 0;
4080 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004081 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304082 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304083 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4084 {
4085 MpiEventDataSasExpanderStatusChange_t *expander_data =
4086 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4087
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304088 if (ioc->old_sas_discovery_protocal)
4089 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304090
4091 if (expander_data->ReasonCode ==
4092 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4093 ioc->device_missing_delay)
4094 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004095 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304096 }
4097 case MPI_EVENT_SAS_DISCOVERY:
4098 {
4099 u32 discovery_status;
4100 EventDataSasDiscovery_t *discovery_data =
4101 (EventDataSasDiscovery_t *)reply->Data;
4102
4103 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4104 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304105 if (ioc->old_sas_discovery_protocal && !discovery_status)
4106 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304107 return 0;
4108 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304109 case MPI_EVENT_INTEGRATED_RAID:
4110 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004111 case MPI_EVENT_IR2:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304112 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4113 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004114 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004115 default:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304116 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004117 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004118
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304119 event_data_sz = ((reply->MsgLength * 4) -
4120 offsetof(EventNotificationReply_t, Data));
4121 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4122 fw_event = kzalloc(sz, GFP_ATOMIC);
4123 if (!fw_event) {
4124 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4125 __func__, __LINE__);
4126 return 0;
4127 }
4128 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4129 fw_event->event = event;
4130 fw_event->ioc = ioc;
4131 mptsas_add_fw_event(ioc, fw_event, delay);
4132 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004133}
4134
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004135static int
4136mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4137{
4138 struct Scsi_Host *sh;
4139 MPT_SCSI_HOST *hd;
4140 MPT_ADAPTER *ioc;
4141 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004142 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004143 int numSGE = 0;
4144 int scale;
4145 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004146 int error=0;
4147 int r;
4148
4149 r = mpt_attach(pdev,id);
4150 if (r)
4151 return r;
4152
4153 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304154 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004155 ioc->DoneCtx = mptsasDoneCtx;
4156 ioc->TaskCtx = mptsasTaskCtx;
4157 ioc->InternalCtx = mptsasInternalCtx;
4158
4159 /* Added sanity check on readiness of the MPT adapter.
4160 */
4161 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4162 printk(MYIOC_s_WARN_FMT
4163 "Skipping because it's not operational!\n",
4164 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004165 error = -ENODEV;
4166 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004167 }
4168
4169 if (!ioc->active) {
4170 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4171 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004172 error = -ENODEV;
4173 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004174 }
4175
4176 /* Sanity check - ensure at least 1 port is INITIATOR capable
4177 */
4178 ioc_cap = 0;
4179 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4180 if (ioc->pfacts[ii].ProtocolFlags &
4181 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4182 ioc_cap++;
4183 }
4184
4185 if (!ioc_cap) {
4186 printk(MYIOC_s_WARN_FMT
4187 "Skipping ioc=%p because SCSI Initiator mode "
4188 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004189 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004190 }
4191
4192 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4193 if (!sh) {
4194 printk(MYIOC_s_WARN_FMT
4195 "Unable to register controller with SCSI subsystem\n",
4196 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004197 error = -1;
4198 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004199 }
4200
4201 spin_lock_irqsave(&ioc->FreeQlock, flags);
4202
4203 /* Attach the SCSI Host to the IOC structure
4204 */
4205 ioc->sh = sh;
4206
4207 sh->io_port = 0;
4208 sh->n_io_port = 0;
4209 sh->irq = 0;
4210
4211 /* set 16 byte cdb's */
4212 sh->max_cmd_len = 16;
4213
Eric Moore793955f2007-01-29 09:42:20 -07004214 sh->max_id = ioc->pfacts[0].PortSCSIID;
4215 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004216
4217 sh->transportt = mptsas_transport_template;
4218
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004219 /* Required entry.
4220 */
4221 sh->unique_id = ioc->id;
4222
4223 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004224 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004225 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004226 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004227 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004228
4229 /* Verify that we won't exceed the maximum
4230 * number of chain buffers
4231 * We can optimize: ZZ = req_sz/sizeof(SGE)
4232 * For 32bit SGE's:
4233 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4234 * + (req_sz - 64)/sizeof(SGE)
4235 * A slightly different algorithm is required for
4236 * 64bit SGEs.
4237 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304238 scale = ioc->req_sz/ioc->SGE_size;
4239 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004240 numSGE = (scale - 1) *
4241 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304242 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004243 } else {
4244 numSGE = 1 + (scale - 1) *
4245 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304246 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004247 }
4248
4249 if (numSGE < sh->sg_tablesize) {
4250 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304251 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004252 "Resetting sg_tablesize to %d from %d\n",
4253 ioc->name, numSGE, sh->sg_tablesize));
4254 sh->sg_tablesize = numSGE;
4255 }
4256
Eric Mooree7eae9f2007-09-29 10:15:59 -06004257 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004258 hd->ioc = ioc;
4259
4260 /* SCSI needs scsi_cmnd lookup table!
4261 * (with size equal to req_depth*PtrSz!)
4262 */
Eric Mooree8206382007-09-29 10:16:53 -06004263 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
4264 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004265 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06004266 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004267 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004268 }
Eric Mooree8206382007-09-29 10:16:53 -06004269 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004270
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304271 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06004272 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004273
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004274 /* Clear the TM flags
4275 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004276 hd->abortSCpnt = NULL;
4277
4278 /* Clear the pointer used to store
4279 * single-threaded commands, i.e., those
4280 * issued during a bus scan, dv and
4281 * configuration pages.
4282 */
4283 hd->cmdPtr = NULL;
4284
4285 /* Initialize this SCSI Hosts' timers
4286 * To use, set the timer expires field
4287 * and add_timer
4288 */
4289 init_timer(&hd->timer);
4290 hd->timer.data = (unsigned long) hd;
4291 hd->timer.function = mptscsih_timer_expired;
4292
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004293 ioc->sas_data.ptClear = mpt_pt_clear;
4294
Eric Mooredf9e0622007-01-29 09:46:21 -07004295 hd->last_queue_full = 0;
4296 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304297 INIT_LIST_HEAD(&ioc->sas_device_info_list);
4298 mutex_init(&ioc->sas_device_info_mutex);
4299
Eric Mooredf9e0622007-01-29 09:46:21 -07004300 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4301
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004302 if (ioc->sas_data.ptClear==1) {
4303 mptbase_sas_persist_operation(
4304 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
4305 }
4306
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004307 error = scsi_add_host(sh, &ioc->pcidev->dev);
4308 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06004309 dprintk(ioc, printk(MYIOC_s_ERR_FMT
4310 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004311 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004312 }
4313
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304314 /* older firmware doesn't support expander events */
4315 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
4316 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004317 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304318 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004319 return 0;
4320
Eric Moore547f9a22006-06-27 14:42:12 -06004321 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004322
4323 mptscsih_remove(pdev);
4324 return error;
4325}
4326
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304327void
4328mptsas_shutdown(struct pci_dev *pdev)
4329{
4330 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4331
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304332 mptsas_fw_event_off(ioc);
4333 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304334}
4335
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004336static void __devexit mptsas_remove(struct pci_dev *pdev)
4337{
4338 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4339 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06004340 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004341
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304342 mptsas_shutdown(pdev);
4343
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304344 mptsas_del_device_components(ioc);
4345
Eric Mooreb506ade2007-01-29 09:45:37 -07004346 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004347 sas_remove_host(ioc->sh);
4348
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004349 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004350 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
4351 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06004352 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304353 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304354
Eric Moore547f9a22006-06-27 14:42:12 -06004355 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004356 kfree(p);
4357 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004358 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304359 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004360 mptscsih_remove(pdev);
4361}
4362
4363static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06004364 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004365 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004366 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004367 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004368 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004369 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004370 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004371 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004372 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004373 PCI_ANY_ID, PCI_ANY_ID },
4374 {0} /* Terminating entry */
4375};
4376MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
4377
4378
4379static struct pci_driver mptsas_driver = {
4380 .name = "mptsas",
4381 .id_table = mptsas_pci_table,
4382 .probe = mptsas_probe,
4383 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304384 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004385#ifdef CONFIG_PM
4386 .suspend = mptscsih_suspend,
4387 .resume = mptscsih_resume,
4388#endif
4389};
4390
4391static int __init
4392mptsas_init(void)
4393{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304394 int error;
4395
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004396 show_mptmod_ver(my_NAME, my_VERSION);
4397
4398 mptsas_transport_template =
4399 sas_attach_transport(&mptsas_transport_functions);
4400 if (!mptsas_transport_template)
4401 return -ENODEV;
4402
4403 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304404 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004405 mptsasInternalCtx =
4406 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004407 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304408 mptsasDeviceResetCtx =
4409 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004410
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304411 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
4412 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004413
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304414 error = pci_register_driver(&mptsas_driver);
4415 if (error)
4416 sas_release_transport(mptsas_transport_template);
4417
4418 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004419}
4420
4421static void __exit
4422mptsas_exit(void)
4423{
4424 pci_unregister_driver(&mptsas_driver);
4425 sas_release_transport(mptsas_transport_template);
4426
4427 mpt_reset_deregister(mptsasDoneCtx);
4428 mpt_event_deregister(mptsasDoneCtx);
4429
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004430 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004431 mpt_deregister(mptsasInternalCtx);
4432 mpt_deregister(mptsasTaskCtx);
4433 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304434 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004435}
4436
4437module_init(mptsas_init);
4438module_exit(mptsas_exit);