blob: 22a027ec9e5d927f7267487850a6fc905015f07d [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02008 */
9/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10/*
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; version 2 of the License.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 NO WARRANTY
21 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
22 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
23 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
24 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
25 solely responsible for determining the appropriateness of using and
26 distributing the Program and assumes all risks associated with its
27 exercise of rights under this Agreement, including but not limited to
28 the risks and costs of program errors, damage to or loss of data,
29 programs or equipment, and unavailability or interruption of operations.
30
31 DISCLAIMER OF LIABILITY
32 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
33 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
35 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
38 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
39
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43*/
44/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
45
46#include <linux/module.h>
47#include <linux/kernel.h>
48#include <linux/init.h>
49#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080050#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020051#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060052#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020053
Eric Moore547f9a22006-06-27 14:42:12 -060054#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020055#include <scsi/scsi_cmnd.h>
56#include <scsi/scsi_device.h>
57#include <scsi/scsi_host.h>
58#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060059#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020060
61#include "mptbase.h"
62#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053063#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020064
65
66#define my_NAME "Fusion MPT SAS Host driver"
67#define my_VERSION MPT_LINUX_VERSION_COMMON
68#define MYNAM "mptsas"
69
James Bottomleye8bf3942006-07-11 17:49:34 -040070/*
71 * Reserved channel for integrated raid
72 */
73#define MPTSAS_RAID_CHANNEL 1
74
Christoph Hellwig0c33b272005-09-09 16:27:19 +020075MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020079
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080static int mpt_pt_clear;
81module_param(mpt_pt_clear, int, 0);
82MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060083 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020084 "(default=MPTSCSIH_PT_CLEAR=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
87#define MPTSAS_MAX_LUN (16895)
88static int max_lun = MPTSAS_MAX_LUN;
89module_param(max_lun, int, 0);
90MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
91
Prakash, Sathyaf606f572007-08-14 16:12:53 +053092static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
93static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
95static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053096static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020097
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +053098static void mptsas_firmware_event_work(struct work_struct *work);
99static void mptsas_send_sas_event(struct fw_event_work *fw_event);
100static void mptsas_send_raid_event(struct fw_event_work *fw_event);
101static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
102static void mptsas_parse_device_info(struct sas_identify *identify,
103 struct mptsas_devinfo *device_info);
104static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
105 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
106static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
107 (MPT_ADAPTER *ioc, u64 sas_address);
108static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
109 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
110static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
111 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
112static int mptsas_add_end_device(MPT_ADAPTER *ioc,
113 struct mptsas_phyinfo *phy_info);
114static void mptsas_del_end_device(MPT_ADAPTER *ioc,
115 struct mptsas_phyinfo *phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200116
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530117static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
118 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200119{
Eric Moore29dd3602007-09-14 18:46:51 -0600120 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
121 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
122 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
123 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
124 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
125 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
126 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
127 ioc->name, phy_data->Port));
128 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
129 ioc->name, phy_data->PortFlags));
130 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
131 ioc->name, phy_data->PhyFlags));
132 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
133 ioc->name, phy_data->NegotiatedLinkRate));
134 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
135 "Controller PHY Device Info=0x%X\n", ioc->name,
136 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
137 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
138 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200139}
140
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530141static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200142{
143 __le64 sas_address;
144
145 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
146
Eric Moore29dd3602007-09-14 18:46:51 -0600147 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
148 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
149 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
150 "Attached Device Handle=0x%X\n", ioc->name,
151 le16_to_cpu(pg0->AttachedDevHandle)));
152 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
153 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
154 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
155 "Attached PHY Identifier=0x%X\n", ioc->name,
156 pg0->AttachedPhyIdentifier));
157 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
158 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
159 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
160 ioc->name, pg0->ProgrammedLinkRate));
161 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
162 ioc->name, pg0->ChangeCount));
163 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
164 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200165}
166
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530167static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200168{
Eric Moore29dd3602007-09-14 18:46:51 -0600169 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
170 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
171 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
172 ioc->name, pg1->InvalidDwordCount));
173 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
174 "Running Disparity Error Count=0x%x\n", ioc->name,
175 pg1->RunningDisparityErrorCount));
176 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
177 "Loss Dword Synch Count=0x%x\n", ioc->name,
178 pg1->LossDwordSynchCount));
179 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
180 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
181 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200182}
183
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530184static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200185{
186 __le64 sas_address;
187
188 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
189
Eric Moore29dd3602007-09-14 18:46:51 -0600190 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
191 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
192 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
193 ioc->name, le16_to_cpu(pg0->DevHandle)));
194 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
195 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
196 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
197 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
198 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
199 ioc->name, le16_to_cpu(pg0->Slot)));
200 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
201 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
202 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
203 ioc->name, pg0->TargetID));
204 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
205 ioc->name, pg0->Bus));
206 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
207 ioc->name, pg0->PhyNum));
208 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
209 ioc->name, le16_to_cpu(pg0->AccessStatus)));
210 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
211 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
212 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
213 ioc->name, le16_to_cpu(pg0->Flags)));
214 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
215 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200216}
217
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530218static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200219{
Eric Moore29dd3602007-09-14 18:46:51 -0600220 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
221 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
222 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
223 ioc->name, pg1->PhysicalPort));
224 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
225 ioc->name, pg1->PhyIdentifier));
226 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
227 ioc->name, pg1->NegotiatedLinkRate));
228 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
229 ioc->name, pg1->ProgrammedLinkRate));
230 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
231 ioc->name, pg1->HwLinkRate));
232 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
233 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
234 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
235 "Attached Device Handle=0x%X\n\n", ioc->name,
236 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200237}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200238
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530239/* inhibit sas firmware event handling */
240static void
241mptsas_fw_event_off(MPT_ADAPTER *ioc)
242{
243 unsigned long flags;
244
245 spin_lock_irqsave(&ioc->fw_event_lock, flags);
246 ioc->fw_events_off = 1;
247 ioc->sas_discovery_quiesce_io = 0;
248 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
249
250}
251
252/* enable sas firmware event handling */
253static void
254mptsas_fw_event_on(MPT_ADAPTER *ioc)
255{
256 unsigned long flags;
257
258 spin_lock_irqsave(&ioc->fw_event_lock, flags);
259 ioc->fw_events_off = 0;
260 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
261}
262
263/* queue a sas firmware event */
264static void
265mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
266 unsigned long delay)
267{
268 unsigned long flags;
269
270 spin_lock_irqsave(&ioc->fw_event_lock, flags);
271 list_add_tail(&fw_event->list, &ioc->fw_event_list);
272 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
273 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
274 ioc->name, __func__, fw_event));
275 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
276 delay);
277 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
278}
279
280/* free memory assoicated to a sas firmware event */
281static void
282mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
283{
284 unsigned long flags;
285
286 spin_lock_irqsave(&ioc->fw_event_lock, flags);
287 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
288 ioc->name, __func__, fw_event));
289 list_del(&fw_event->list);
290 kfree(fw_event);
291 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
292}
293
294/* walk the firmware event queue, and either stop or wait for
295 * outstanding events to complete */
296static void
297mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
298{
299 struct fw_event_work *fw_event, *next;
300 struct mptsas_target_reset_event *target_reset_list, *n;
301 u8 flush_q;
302 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
303
304 /* flush the target_reset_list */
305 if (!list_empty(&hd->target_reset_list)) {
306 list_for_each_entry_safe(target_reset_list, n,
307 &hd->target_reset_list, list) {
308 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
309 "%s: removing target reset for id=%d\n",
310 ioc->name, __func__,
311 target_reset_list->sas_event_data.TargetID));
312 list_del(&target_reset_list->list);
313 kfree(target_reset_list);
314 }
315 }
316
317 if (list_empty(&ioc->fw_event_list) ||
318 !ioc->fw_event_q || in_interrupt())
319 return;
320
321 flush_q = 0;
322 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
323 if (cancel_delayed_work(&fw_event->work))
324 mptsas_free_fw_event(ioc, fw_event);
325 else
326 flush_q = 1;
327 }
328 if (flush_q)
329 flush_workqueue(ioc->fw_event_q);
330}
331
332
Christoph Hellwige3094442006-02-16 13:25:36 +0100333static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
334{
335 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
336 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
337}
338
339static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
340{
341 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
342 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
343}
344
Michael Reed77483692008-03-20 17:32:05 -0500345static struct mptsas_portinfo *
346mptsas_get_hba_portinfo(MPT_ADAPTER *ioc)
347{
348 struct list_head *head = &ioc->sas_topology;
349 struct mptsas_portinfo *pi = NULL;
350
351 /* always the first entry on sas_topology list */
352
353 if (!list_empty(head))
354 pi = list_entry(head->next, struct mptsas_portinfo, list);
355
356 return pi;
357}
358
Moore, Erice6b2d762006-03-14 09:14:24 -0700359/*
360 * mptsas_find_portinfo_by_handle
361 *
362 * This function should be called with the sas_topology_mutex already held
363 */
364static struct mptsas_portinfo *
365mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
366{
367 struct mptsas_portinfo *port_info, *rc=NULL;
368 int i;
369
370 list_for_each_entry(port_info, &ioc->sas_topology, list)
371 for (i = 0; i < port_info->num_phys; i++)
372 if (port_info->phy_info[i].identify.handle == handle) {
373 rc = port_info;
374 goto out;
375 }
376 out:
377 return rc;
378}
379
Moore, Ericbd23e942006-04-17 12:43:04 -0600380/*
381 * Returns true if there is a scsi end device
382 */
383static inline int
384mptsas_is_end_device(struct mptsas_devinfo * attached)
385{
Eric Moore547f9a22006-06-27 14:42:12 -0600386 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600387 (attached->device_info &
388 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
389 ((attached->device_info &
390 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
391 (attached->device_info &
392 MPI_SAS_DEVICE_INFO_STP_TARGET) |
393 (attached->device_info &
394 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
395 return 1;
396 else
397 return 0;
398}
399
Eric Moore547f9a22006-06-27 14:42:12 -0600400/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600401static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530402mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600403{
404 struct mptsas_portinfo *port_info;
405 struct mptsas_phyinfo *phy_info;
406 u8 i;
407
408 if (!port_details)
409 return;
410
411 port_info = port_details->port_info;
412 phy_info = port_info->phy_info;
413
Eric Moore29dd3602007-09-14 18:46:51 -0600414 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700415 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700416 port_details->num_phys, (unsigned long long)
417 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600418
419 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
420 if(phy_info->port_details != port_details)
421 continue;
422 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530423 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600424 phy_info->port_details = NULL;
425 }
426 kfree(port_details);
427}
428
429static inline struct sas_rphy *
430mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
431{
432 if (phy_info->port_details)
433 return phy_info->port_details->rphy;
434 else
435 return NULL;
436}
437
438static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530439mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600440{
441 if (phy_info->port_details) {
442 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600443 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
444 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600445 }
446
Eric Moore547f9a22006-06-27 14:42:12 -0600447 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600448 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
449 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600450 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
451 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600452 }
Eric Moore547f9a22006-06-27 14:42:12 -0600453}
454
455static inline struct sas_port *
456mptsas_get_port(struct mptsas_phyinfo *phy_info)
457{
458 if (phy_info->port_details)
459 return phy_info->port_details->port;
460 else
461 return NULL;
462}
463
464static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530465mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600466{
467 if (phy_info->port_details)
468 phy_info->port_details->port = port;
469
Eric Moore547f9a22006-06-27 14:42:12 -0600470 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600471 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
472 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600473 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
474 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600475 }
Eric Moore547f9a22006-06-27 14:42:12 -0600476}
477
478static inline struct scsi_target *
479mptsas_get_starget(struct mptsas_phyinfo *phy_info)
480{
481 if (phy_info->port_details)
482 return phy_info->port_details->starget;
483 else
484 return NULL;
485}
486
487static inline void
488mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
489starget)
490{
491 if (phy_info->port_details)
492 phy_info->port_details->starget = starget;
493}
494
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530495/**
496 * mptsas_add_device_component -
497 * @ioc: Pointer to MPT_ADAPTER structure
498 * @channel: fw mapped id's
499 * @id:
500 * @sas_address:
501 * @device_info:
502 *
503 **/
504static void
505mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
506 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
507{
508 struct mptsas_device_info *sas_info, *next;
509 struct scsi_device *sdev;
510 struct scsi_target *starget;
511 struct sas_rphy *rphy;
512
513 /*
514 * Delete all matching devices out of the list
515 */
516 mutex_lock(&ioc->sas_device_info_mutex);
517 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
518 list) {
519 if ((sas_info->sas_address == sas_address ||
520 (sas_info->fw.channel == channel &&
521 sas_info->fw.id == id))) {
522 list_del(&sas_info->list);
523 kfree(sas_info);
524 }
525 }
526
527 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
528 if (!sas_info)
529 goto out;
530
531 /*
532 * Set Firmware mapping
533 */
534 sas_info->fw.id = id;
535 sas_info->fw.channel = channel;
536
537 sas_info->sas_address = sas_address;
538 sas_info->device_info = device_info;
539 sas_info->slot = slot;
540 sas_info->enclosure_logical_id = enclosure_logical_id;
541 INIT_LIST_HEAD(&sas_info->list);
542 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
543
544 /*
545 * Set OS mapping
546 */
547 shost_for_each_device(sdev, ioc->sh) {
548 starget = scsi_target(sdev);
549 rphy = dev_to_rphy(starget->dev.parent);
550 if (rphy->identify.sas_address == sas_address) {
551 sas_info->os.id = starget->id;
552 sas_info->os.channel = starget->channel;
553 }
554 }
555
556 out:
557 mutex_unlock(&ioc->sas_device_info_mutex);
558 return;
559}
560
561/**
562 * mptsas_add_device_component_by_fw -
563 * @ioc: Pointer to MPT_ADAPTER structure
564 * @channel: fw mapped id's
565 * @id:
566 *
567 **/
568static void
569mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
570{
571 struct mptsas_devinfo sas_device;
572 struct mptsas_enclosure enclosure_info;
573 int rc;
574
575 rc = mptsas_sas_device_pg0(ioc, &sas_device,
576 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
577 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
578 (channel << 8) + id);
579 if (rc)
580 return;
581
582 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
583 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
584 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
585 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
586 sas_device.handle_enclosure);
587
588 mptsas_add_device_component(ioc, sas_device.channel,
589 sas_device.id, sas_device.sas_address, sas_device.device_info,
590 sas_device.slot, enclosure_info.enclosure_logical_id);
591}
592
593/**
594 * mptsas_add_device_component_starget -
595 * @ioc: Pointer to MPT_ADAPTER structure
596 * @starget:
597 *
598 **/
599static void
600mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
601 struct scsi_target *starget)
602{
603 VirtTarget *vtarget;
604 struct sas_rphy *rphy;
605 struct mptsas_phyinfo *phy_info = NULL;
606 struct mptsas_enclosure enclosure_info;
607
608 rphy = dev_to_rphy(starget->dev.parent);
609 vtarget = starget->hostdata;
610 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
611 rphy->identify.sas_address);
612 if (!phy_info)
613 return;
614
615 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
616 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
617 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
618 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
619 phy_info->attached.handle_enclosure);
620
621 mptsas_add_device_component(ioc, phy_info->attached.channel,
622 phy_info->attached.id, phy_info->attached.sas_address,
623 phy_info->attached.device_info,
624 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
625}
626
627/**
628 * mptsas_del_device_components - Cleaning the list
629 * @ioc: Pointer to MPT_ADAPTER structure
630 *
631 **/
632static void
633mptsas_del_device_components(MPT_ADAPTER *ioc)
634{
635 struct mptsas_device_info *sas_info, *next;
636
637 mutex_lock(&ioc->sas_device_info_mutex);
638 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
639 list) {
640 list_del(&sas_info->list);
641 kfree(sas_info);
642 }
643 mutex_unlock(&ioc->sas_device_info_mutex);
644}
645
Eric Moore547f9a22006-06-27 14:42:12 -0600646
647/*
648 * mptsas_setup_wide_ports
649 *
650 * Updates for new and existing narrow/wide port configuration
651 * in the sas_topology
652 */
Eric Moore376ac832006-06-29 17:36:26 -0600653static void
Eric Moore547f9a22006-06-27 14:42:12 -0600654mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
655{
656 struct mptsas_portinfo_details * port_details;
657 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
658 u64 sas_address;
659 int i, j;
660
661 mutex_lock(&ioc->sas_topology_mutex);
662
663 phy_info = port_info->phy_info;
664 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
665 if (phy_info->attached.handle)
666 continue;
667 port_details = phy_info->port_details;
668 if (!port_details)
669 continue;
670 if (port_details->num_phys < 2)
671 continue;
672 /*
673 * Removing a phy from a port, letting the last
674 * phy be removed by firmware events.
675 */
Eric Moore29dd3602007-09-14 18:46:51 -0600676 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
677 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700678 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600679 port_details->num_phys--;
680 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
681 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
682 sas_port_delete_phy(port_details->port, phy_info->phy);
683 phy_info->port_details = NULL;
684 }
685
686 /*
687 * Populate and refresh the tree
688 */
689 phy_info = port_info->phy_info;
690 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
691 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600692 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
693 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600694 if (!sas_address)
695 continue;
696 port_details = phy_info->port_details;
697 /*
698 * Forming a port
699 */
700 if (!port_details) {
701 port_details = kzalloc(sizeof(*port_details),
702 GFP_KERNEL);
703 if (!port_details)
704 goto out;
705 port_details->num_phys = 1;
706 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600707 if (phy_info->phy_id < 64 )
708 port_details->phy_bitmask |=
709 (1 << phy_info->phy_id);
710 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600711 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700712 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600713 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600714 phy_info->port_details = port_details;
715 }
716
717 if (i == port_info->num_phys - 1)
718 continue;
719 phy_info_cmp = &port_info->phy_info[i + 1];
720 for (j = i + 1 ; j < port_info->num_phys ; j++,
721 phy_info_cmp++) {
722 if (!phy_info_cmp->attached.sas_address)
723 continue;
724 if (sas_address != phy_info_cmp->attached.sas_address)
725 continue;
726 if (phy_info_cmp->port_details == port_details )
727 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600728 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700729 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600730 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700731 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600732 if (phy_info_cmp->port_details) {
733 port_details->rphy =
734 mptsas_get_rphy(phy_info_cmp);
735 port_details->port =
736 mptsas_get_port(phy_info_cmp);
737 port_details->starget =
738 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600739 port_details->num_phys =
740 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600741 if (!phy_info_cmp->port_details->num_phys)
742 kfree(phy_info_cmp->port_details);
743 } else
744 phy_info_cmp->sas_port_add_phy=1;
745 /*
746 * Adding a phy to a port
747 */
748 phy_info_cmp->port_details = port_details;
749 if (phy_info_cmp->phy_id < 64 )
750 port_details->phy_bitmask |=
751 (1 << phy_info_cmp->phy_id);
752 port_details->num_phys++;
753 }
754 }
755
756 out:
757
Eric Moore547f9a22006-06-27 14:42:12 -0600758 for (i = 0; i < port_info->num_phys; i++) {
759 port_details = port_info->phy_info[i].port_details;
760 if (!port_details)
761 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600762 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700763 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700764 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700765 port_details, i, port_details->num_phys,
766 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600767 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
768 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600769 }
Eric Moore29dd3602007-09-14 18:46:51 -0600770 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600771 mutex_unlock(&ioc->sas_topology_mutex);
772}
773
Eric Mooredf9e0622007-01-29 09:46:21 -0700774/**
775 * csmisas_find_vtarget
776 *
777 * @ioc
778 * @volume_id
779 * @volume_bus
780 *
781 **/
782static VirtTarget *
783mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600784{
Eric Mooredf9e0622007-01-29 09:46:21 -0700785 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600786 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700787 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600788
Eric Mooredf9e0622007-01-29 09:46:21 -0700789 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530790 vdevice = sdev->hostdata;
791 if ((vdevice == NULL) ||
792 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700793 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600794 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530795 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600796 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600797 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700798 return vtarget;
799}
800
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530801static void
802mptsas_queue_device_delete(MPT_ADAPTER *ioc,
803 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
804{
805 struct fw_event_work *fw_event;
806 int sz;
807
808 sz = offsetof(struct fw_event_work, event_data) +
809 sizeof(MpiEventDataSasDeviceStatusChange_t);
810 fw_event = kzalloc(sz, GFP_ATOMIC);
811 if (!fw_event) {
812 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
813 ioc->name, __func__, __LINE__);
814 return;
815 }
816 memcpy(fw_event->event_data, sas_event_data,
817 sizeof(MpiEventDataSasDeviceStatusChange_t));
818 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
819 fw_event->ioc = ioc;
820 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
821}
822
823
Eric Mooredf9e0622007-01-29 09:46:21 -0700824/**
825 * mptsas_target_reset
826 *
827 * Issues TARGET_RESET to end device using handshaking method
828 *
829 * @ioc
830 * @channel
831 * @id
832 *
833 * Returns (1) success
834 * (0) failure
835 *
836 **/
837static int
838mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
839{
840 MPT_FRAME_HDR *mf;
841 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530842 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
843 return 0;
844
Eric Mooredf9e0622007-01-29 09:46:21 -0700845
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530846 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
847 if (mf == NULL) {
848 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530849 "%s, no msg frames @%d!!\n", ioc->name,
850 __func__, __LINE__));
851 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -0700852 }
853
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530854 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
855 ioc->name, mf));
856
Eric Mooredf9e0622007-01-29 09:46:21 -0700857 /* Format the Request
858 */
859 pScsiTm = (SCSITaskMgmt_t *) mf;
860 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
861 pScsiTm->TargetID = id;
862 pScsiTm->Bus = channel;
863 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
864 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
865 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
866
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530867 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700868
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530869 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
870 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
871 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
872
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530873 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700874
875 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530876
877 out_fail:
878
879 mpt_clear_taskmgmt_in_progress_flag(ioc);
880 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -0700881}
882
883/**
884 * mptsas_target_reset_queue
885 *
886 * Receive request for TARGET_RESET after recieving an firmware
887 * event NOT_RESPONDING_EVENT, then put command in link list
888 * and queue if task_queue already in use.
889 *
890 * @ioc
891 * @sas_event_data
892 *
893 **/
894static void
895mptsas_target_reset_queue(MPT_ADAPTER *ioc,
896 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
897{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600898 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700899 VirtTarget *vtarget = NULL;
900 struct mptsas_target_reset_event *target_reset_list;
901 u8 id, channel;
902
903 id = sas_event_data->TargetID;
904 channel = sas_event_data->Bus;
905
906 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
907 return;
908
909 vtarget->deleted = 1; /* block IO */
910
911 target_reset_list = kzalloc(sizeof(*target_reset_list),
912 GFP_ATOMIC);
913 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530914 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
915 "%s, failed to allocate mem @%d..!!\n",
916 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -0700917 return;
918 }
919
920 memcpy(&target_reset_list->sas_event_data, sas_event_data,
921 sizeof(*sas_event_data));
922 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
923
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530924 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -0700925
926 if (mptsas_target_reset(ioc, channel, id)) {
927 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700928 }
929}
930
931/**
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530932 * mptsas_taskmgmt_complete - Completion for TARGET_RESET after
933 * NOT_RESPONDING_EVENT, enable work queue to finish off removing device
934 * from upper layers. then send next TARGET_RESET in the queue.
935 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -0700936 *
937 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530938static int
939mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -0700940{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600941 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700942 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -0700943 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
944 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530945 struct mptsas_target_reset_event *target_reset_list;
946 SCSITaskMgmtReply_t *pScsiTmReply;
947
948 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
949 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
950
951 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
952 if (pScsiTmReply) {
953 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
954 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
955 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
956 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
957 "term_cmnds = %d\n", ioc->name,
958 pScsiTmReply->Bus, pScsiTmReply->TargetID,
959 pScsiTmReply->TaskType,
960 le16_to_cpu(pScsiTmReply->IOCStatus),
961 le32_to_cpu(pScsiTmReply->IOCLogInfo),
962 pScsiTmReply->ResponseCode,
963 le32_to_cpu(pScsiTmReply->TerminationCount)));
964
965 if (pScsiTmReply->ResponseCode)
966 mptscsih_taskmgmt_response_code(ioc,
967 pScsiTmReply->ResponseCode);
968 }
969
970 if (pScsiTmReply && (pScsiTmReply->TaskType ==
971 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
972 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
973 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
974 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
975 memcpy(ioc->taskmgmt_cmds.reply, mr,
976 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
977 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
978 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
979 complete(&ioc->taskmgmt_cmds.done);
980 return 1;
981 }
982 return 0;
983 }
984
985 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -0700986
987 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530988 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700989
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530990 target_reset_list = list_entry(head->next,
991 struct mptsas_target_reset_event, list);
992
993 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
994 "TaskMgmt: completed (%d seconds)\n",
995 ioc->name, jiffies_to_msecs(jiffies -
996 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -0700997
998 sas_event_data = &target_reset_list->sas_event_data;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530999 id = pScsiTmReply->TargetID;
1000 channel = pScsiTmReply->Bus;
1001 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001002
1003 /*
1004 * retry target reset
1005 */
1006 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301007 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001008 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301009 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001010 }
1011
1012 /*
1013 * enable work queue to remove device from upper layers
1014 */
1015 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301016 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1017 mptsas_queue_device_delete(ioc,
1018 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301019
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301020
Eric Mooredf9e0622007-01-29 09:46:21 -07001021 /*
1022 * issue target reset to next device in the queue
1023 */
1024
1025 head = &hd->target_reset_list;
1026 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301027 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001028
1029 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1030 list);
1031
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301032 id = target_reset_list->sas_event_data.TargetID;
1033 channel = target_reset_list->sas_event_data.Bus;
1034 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001035
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301036 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001037 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001038
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301039 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001040}
1041
1042/**
1043 * mptscsih_ioc_reset
1044 *
1045 * @ioc
1046 * @reset_phase
1047 *
1048 **/
1049static int
1050mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1051{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001052 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001053 int rc;
1054
1055 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301056 if ((ioc->bus_type != SAS) || (!rc))
1057 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001058
Eric Mooree7eae9f2007-09-29 10:15:59 -06001059 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001060 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001061 goto out;
1062
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301063 switch (reset_phase) {
1064 case MPT_IOC_SETUP_RESET:
1065 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1066 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1067 mptsas_fw_event_off(ioc);
1068 break;
1069 case MPT_IOC_PRE_RESET:
1070 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1071 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1072 break;
1073 case MPT_IOC_POST_RESET:
1074 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1075 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1076 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1077 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1078 complete(&ioc->sas_mgmt.done);
1079 }
1080 mptsas_cleanup_fw_event_q(ioc);
1081 mptsas_fw_event_on(ioc);
1082 break;
1083 default:
1084 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001085 }
1086
1087 out:
1088 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001089}
1090
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301091
1092/**
1093 * enum device_state -
1094 * @DEVICE_RETRY: need to retry the TUR
1095 * @DEVICE_ERROR: TUR return error, don't add device
1096 * @DEVICE_READY: device can be added
1097 *
1098 */
1099enum device_state{
1100 DEVICE_RETRY,
1101 DEVICE_ERROR,
1102 DEVICE_READY,
1103};
1104
Christoph Hellwige3094442006-02-16 13:25:36 +01001105static int
Moore, Eric52435432006-03-14 09:14:15 -07001106mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001107 u32 form, u32 form_specific)
1108{
1109 ConfigExtendedPageHeader_t hdr;
1110 CONFIGPARMS cfg;
1111 SasEnclosurePage0_t *buffer;
1112 dma_addr_t dma_handle;
1113 int error;
1114 __le64 le_identifier;
1115
1116 memset(&hdr, 0, sizeof(hdr));
1117 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1118 hdr.PageNumber = 0;
1119 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1120 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1121
1122 cfg.cfghdr.ehdr = &hdr;
1123 cfg.physAddr = -1;
1124 cfg.pageAddr = form + form_specific;
1125 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1126 cfg.dir = 0; /* read */
1127 cfg.timeout = 10;
1128
1129 error = mpt_config(ioc, &cfg);
1130 if (error)
1131 goto out;
1132 if (!hdr.ExtPageLength) {
1133 error = -ENXIO;
1134 goto out;
1135 }
1136
1137 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1138 &dma_handle);
1139 if (!buffer) {
1140 error = -ENOMEM;
1141 goto out;
1142 }
1143
1144 cfg.physAddr = dma_handle;
1145 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1146
1147 error = mpt_config(ioc, &cfg);
1148 if (error)
1149 goto out_free_consistent;
1150
1151 /* save config data */
1152 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1153 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1154 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1155 enclosure->flags = le16_to_cpu(buffer->Flags);
1156 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1157 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1158 enclosure->start_id = buffer->StartTargetID;
1159 enclosure->start_channel = buffer->StartBus;
1160 enclosure->sep_id = buffer->SEPTargetID;
1161 enclosure->sep_channel = buffer->SEPBus;
1162
1163 out_free_consistent:
1164 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1165 buffer, dma_handle);
1166 out:
1167 return error;
1168}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001169
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301170/**
1171 * mptsas_add_end_device - report a new end device to sas transport layer
1172 * @ioc: Pointer to MPT_ADAPTER structure
1173 * @phy_info: decribes attached device
1174 *
1175 * return (0) success (1) failure
1176 *
1177 **/
1178static int
1179mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1180{
1181 struct sas_rphy *rphy;
1182 struct sas_port *port;
1183 struct sas_identify identify;
1184 char *ds = NULL;
1185 u8 fw_id;
1186
1187 if (!phy_info) {
1188 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1189 "%s: exit at line=%d\n", ioc->name,
1190 __func__, __LINE__));
1191 return 1;
1192 }
1193
1194 fw_id = phy_info->attached.id;
1195
1196 if (mptsas_get_rphy(phy_info)) {
1197 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1198 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1199 __func__, fw_id, __LINE__));
1200 return 2;
1201 }
1202
1203 port = mptsas_get_port(phy_info);
1204 if (!port) {
1205 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1206 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1207 __func__, fw_id, __LINE__));
1208 return 3;
1209 }
1210
1211 if (phy_info->attached.device_info &
1212 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1213 ds = "ssp";
1214 if (phy_info->attached.device_info &
1215 MPI_SAS_DEVICE_INFO_STP_TARGET)
1216 ds = "stp";
1217 if (phy_info->attached.device_info &
1218 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1219 ds = "sata";
1220
1221 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1222 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1223 phy_info->attached.channel, phy_info->attached.id,
1224 phy_info->attached.phy_id, (unsigned long long)
1225 phy_info->attached.sas_address);
1226
1227 mptsas_parse_device_info(&identify, &phy_info->attached);
1228 rphy = sas_end_device_alloc(port);
1229 if (!rphy) {
1230 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1231 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1232 __func__, fw_id, __LINE__));
1233 return 5; /* non-fatal: an rphy can be added later */
1234 }
1235
1236 rphy->identify = identify;
1237 if (sas_rphy_add(rphy)) {
1238 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1239 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1240 __func__, fw_id, __LINE__));
1241 sas_rphy_free(rphy);
1242 return 6;
1243 }
1244 mptsas_set_rphy(ioc, phy_info, rphy);
1245 return 0;
1246}
1247
1248/**
1249 * mptsas_del_end_device - report a deleted end device to sas transport
1250 * layer
1251 * @ioc: Pointer to MPT_ADAPTER structure
1252 * @phy_info: decribes attached device
1253 *
1254 **/
1255static void
1256mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1257{
1258 struct sas_rphy *rphy;
1259 struct sas_port *port;
1260 struct mptsas_portinfo *port_info;
1261 struct mptsas_phyinfo *phy_info_parent;
1262 int i;
1263 char *ds = NULL;
1264 u8 fw_id;
1265 u64 sas_address;
1266
1267 if (!phy_info)
1268 return;
1269
1270 fw_id = phy_info->attached.id;
1271 sas_address = phy_info->attached.sas_address;
1272
1273 if (!phy_info->port_details) {
1274 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1275 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1276 __func__, fw_id, __LINE__));
1277 return;
1278 }
1279 rphy = mptsas_get_rphy(phy_info);
1280 if (!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 return;
1285 }
1286
1287 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1288 || phy_info->attached.device_info
1289 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1290 || phy_info->attached.device_info
1291 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1292 ds = "initiator";
1293 if (phy_info->attached.device_info &
1294 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1295 ds = "ssp";
1296 if (phy_info->attached.device_info &
1297 MPI_SAS_DEVICE_INFO_STP_TARGET)
1298 ds = "stp";
1299 if (phy_info->attached.device_info &
1300 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1301 ds = "sata";
1302
1303 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1304 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1305 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1306 phy_info->attached.id, phy_info->attached.phy_id,
1307 (unsigned long long) sas_address);
1308
1309 port = mptsas_get_port(phy_info);
1310 if (!port) {
1311 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1312 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1313 __func__, fw_id, __LINE__));
1314 return;
1315 }
1316 port_info = phy_info->portinfo;
1317 phy_info_parent = port_info->phy_info;
1318 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1319 if (!phy_info_parent->phy)
1320 continue;
1321 if (phy_info_parent->attached.sas_address !=
1322 sas_address)
1323 continue;
1324 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1325 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1326 ioc->name, phy_info_parent->phy_id,
1327 phy_info_parent->phy);
1328 sas_port_delete_phy(port, phy_info_parent->phy);
1329 }
1330
1331 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1332 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1333 port->port_identifier, (unsigned long long)sas_address);
1334 sas_port_delete(port);
1335 mptsas_set_port(ioc, phy_info, NULL);
1336 mptsas_port_delete(ioc, phy_info->port_details);
1337}
1338
1339struct mptsas_phyinfo *
1340mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1341 struct mptsas_devinfo *sas_device)
1342{
1343 struct mptsas_phyinfo *phy_info;
1344 struct mptsas_portinfo *port_info;
1345 int i;
1346
1347 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1348 sas_device->sas_address);
1349 if (!phy_info)
1350 goto out;
1351 port_info = phy_info->portinfo;
1352 if (!port_info)
1353 goto out;
1354 mutex_lock(&ioc->sas_topology_mutex);
1355 for (i = 0; i < port_info->num_phys; i++) {
1356 if (port_info->phy_info[i].attached.sas_address !=
1357 sas_device->sas_address)
1358 continue;
1359 port_info->phy_info[i].attached.channel = sas_device->channel;
1360 port_info->phy_info[i].attached.id = sas_device->id;
1361 port_info->phy_info[i].attached.sas_address =
1362 sas_device->sas_address;
1363 port_info->phy_info[i].attached.handle = sas_device->handle;
1364 port_info->phy_info[i].attached.handle_parent =
1365 sas_device->handle_parent;
1366 port_info->phy_info[i].attached.handle_enclosure =
1367 sas_device->handle_enclosure;
1368 }
1369 mutex_unlock(&ioc->sas_topology_mutex);
1370 out:
1371 return phy_info;
1372}
1373
1374/**
1375 * mptsas_firmware_event_work - work thread for processing fw events
1376 * @work: work queue payload containing info describing the event
1377 * Context: user
1378 *
1379 */
1380static void
1381mptsas_firmware_event_work(struct work_struct *work)
1382{
1383 struct fw_event_work *fw_event =
1384 container_of(work, struct fw_event_work, work.work);
1385 MPT_ADAPTER *ioc = fw_event->ioc;
1386
1387
1388 /* events handling turned off during host reset */
1389 if (ioc->fw_events_off) {
1390 mptsas_free_fw_event(ioc, fw_event);
1391 return;
1392 }
1393
1394 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1395 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1396 (fw_event->event & 0xFF)));
1397
1398 switch (fw_event->event) {
1399 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1400 mptsas_send_sas_event(fw_event);
1401 break;
1402 case MPI_EVENT_INTEGRATED_RAID:
1403 mptsas_send_raid_event(fw_event);
1404 break;
1405 case MPI_EVENT_IR2:
1406 mptsas_send_ir2_event(fw_event);
1407 break;
1408 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1409 mptbase_sas_persist_operation(ioc,
1410 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1411 mptsas_free_fw_event(ioc, fw_event);
1412 break;
1413 }
1414}
1415
1416
1417
James Bottomleyf013db32006-03-18 14:54:36 -06001418static int
1419mptsas_slave_configure(struct scsi_device *sdev)
1420{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301421 struct Scsi_Host *host = sdev->host;
1422 MPT_SCSI_HOST *hd = shost_priv(host);
1423 MPT_ADAPTER *ioc = hd->ioc;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001424
James Bottomleye8bf3942006-07-11 17:49:34 -04001425 if (sdev->channel == MPTSAS_RAID_CHANNEL)
1426 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -06001427
James Bottomleye8bf3942006-07-11 17:49:34 -04001428 sas_read_port_mode_page(sdev);
1429
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301430 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1431
James Bottomleye8bf3942006-07-11 17:49:34 -04001432 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001433 return mptscsih_slave_configure(sdev);
1434}
1435
Eric Moore547f9a22006-06-27 14:42:12 -06001436static int
1437mptsas_target_alloc(struct scsi_target *starget)
1438{
1439 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001440 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001441 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001442 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001443 struct sas_rphy *rphy;
1444 struct mptsas_portinfo *p;
1445 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001446 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001447
1448 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1449 if (!vtarget)
1450 return -ENOMEM;
1451
1452 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001453 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001454 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1455 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001456 channel = 0;
1457
Eric Moore793955f2007-01-29 09:42:20 -07001458 /*
1459 * RAID volumes placed beyond the last expected port.
1460 */
1461 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001462 for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
1463 if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
1464 channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -06001465 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001466 }
Eric Moore547f9a22006-06-27 14:42:12 -06001467
1468 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001469 mutex_lock(&ioc->sas_topology_mutex);
1470 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001471 for (i = 0; i < p->num_phys; i++) {
1472 if (p->phy_info[i].attached.sas_address !=
1473 rphy->identify.sas_address)
1474 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001475 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001476 channel = p->phy_info[i].attached.channel;
1477 mptsas_set_starget(&p->phy_info[i], starget);
1478
1479 /*
1480 * Exposing hidden raid components
1481 */
Eric Mooree80b0022007-09-14 18:49:03 -06001482 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1483 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001484 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001485 vtarget->tflags |=
1486 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001487 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001488 }
Eric Mooree80b0022007-09-14 18:49:03 -06001489 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001490 goto out;
1491 }
1492 }
Eric Mooree80b0022007-09-14 18:49:03 -06001493 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001494
1495 kfree(vtarget);
1496 return -ENXIO;
1497
1498 out:
Eric Moore793955f2007-01-29 09:42:20 -07001499 vtarget->id = id;
1500 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001501 starget->hostdata = vtarget;
1502 return 0;
1503}
1504
1505static void
1506mptsas_target_destroy(struct scsi_target *starget)
1507{
1508 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001509 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001510 struct sas_rphy *rphy;
1511 struct mptsas_portinfo *p;
1512 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301513 MPT_ADAPTER *ioc = hd->ioc;
1514 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001515
1516 if (!starget->hostdata)
1517 return;
1518
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301519 vtarget = starget->hostdata;
1520
1521
James Bottomleye8bf3942006-07-11 17:49:34 -04001522 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001523 goto out;
1524
1525 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001526 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001527 for (i = 0; i < p->num_phys; i++) {
1528 if (p->phy_info[i].attached.sas_address !=
1529 rphy->identify.sas_address)
1530 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301531
1532 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1533 "delete device: fw_channel %d, fw_id %d, phy %d, "
1534 "sas_addr 0x%llx\n", ioc->name,
1535 p->phy_info[i].attached.channel,
1536 p->phy_info[i].attached.id,
1537 p->phy_info[i].attached.phy_id, (unsigned long long)
1538 p->phy_info[i].attached.sas_address);
1539
Eric Moore547f9a22006-06-27 14:42:12 -06001540 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001541 }
1542 }
1543
1544 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301545 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001546 kfree(starget->hostdata);
1547 starget->hostdata = NULL;
1548}
1549
1550
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001551static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001552mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001553{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001554 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001555 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001556 struct sas_rphy *rphy;
1557 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001558 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001559 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001560 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001561 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001562
Eric Moorea69de502007-09-14 18:48:19 -06001563 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1564 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001565 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001566 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001567 return -ENOMEM;
1568 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001569 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001570 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001571
James Bottomleye8bf3942006-07-11 17:49:34 -04001572 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001573 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001574
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001575 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001576 mutex_lock(&ioc->sas_topology_mutex);
1577 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001578 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001579 if (p->phy_info[i].attached.sas_address !=
1580 rphy->identify.sas_address)
1581 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001582 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001583 /*
1584 * Exposing hidden raid components
1585 */
Eric Mooree80b0022007-09-14 18:49:03 -06001586 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001587 p->phy_info[i].attached.channel,
1588 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001589 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001590 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001591 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001592 }
1593 }
Eric Mooree80b0022007-09-14 18:49:03 -06001594 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001595
Eric Moorea69de502007-09-14 18:48:19 -06001596 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001597 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001598
1599 out:
Eric Moorea69de502007-09-14 18:48:19 -06001600 vdevice->vtarget->num_luns++;
1601 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001602 return 0;
1603}
1604
Eric Moore547f9a22006-06-27 14:42:12 -06001605static int
1606mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001607{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301608 MPT_SCSI_HOST *hd;
1609 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001610 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001611
Eric Moorea69de502007-09-14 18:48:19 -06001612 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001613 SCpnt->result = DID_NO_CONNECT << 16;
1614 done(SCpnt);
1615 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001616 }
Eric Moore547f9a22006-06-27 14:42:12 -06001617
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301618 hd = shost_priv(SCpnt->device->host);
1619 ioc = hd->ioc;
1620
1621 if (ioc->sas_discovery_quiesce_io)
1622 return SCSI_MLQUEUE_HOST_BUSY;
1623
Eric Moore793955f2007-01-29 09:42:20 -07001624// scsi_print_command(SCpnt);
1625
Eric Moore547f9a22006-06-27 14:42:12 -06001626 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001627}
1628
Eric Moore547f9a22006-06-27 14:42:12 -06001629
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001630static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001631 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001632 .proc_name = "mptsas",
1633 .proc_info = mptscsih_proc_info,
1634 .name = "MPT SPI Host",
1635 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001636 .queuecommand = mptsas_qcmd,
1637 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001638 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001639 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001640 .target_destroy = mptsas_target_destroy,
1641 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001642 .change_queue_depth = mptscsih_change_queue_depth,
1643 .eh_abort_handler = mptscsih_abort,
1644 .eh_device_reset_handler = mptscsih_dev_reset,
1645 .eh_bus_reset_handler = mptscsih_bus_reset,
1646 .eh_host_reset_handler = mptscsih_host_reset,
1647 .bios_param = mptscsih_bios_param,
1648 .can_queue = MPT_FC_CAN_QUEUE,
1649 .this_id = -1,
1650 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1651 .max_sectors = 8192,
1652 .cmd_per_lun = 7,
1653 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301654 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001655};
1656
Christoph Hellwigb5141122005-10-28 22:07:41 +02001657static int mptsas_get_linkerrors(struct sas_phy *phy)
1658{
1659 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1660 ConfigExtendedPageHeader_t hdr;
1661 CONFIGPARMS cfg;
1662 SasPhyPage1_t *buffer;
1663 dma_addr_t dma_handle;
1664 int error;
1665
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001666 /* FIXME: only have link errors on local phys */
1667 if (!scsi_is_sas_phy_local(phy))
1668 return -EINVAL;
1669
Christoph Hellwigb5141122005-10-28 22:07:41 +02001670 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1671 hdr.ExtPageLength = 0;
1672 hdr.PageNumber = 1 /* page number 1*/;
1673 hdr.Reserved1 = 0;
1674 hdr.Reserved2 = 0;
1675 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1676 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1677
1678 cfg.cfghdr.ehdr = &hdr;
1679 cfg.physAddr = -1;
1680 cfg.pageAddr = phy->identify.phy_identifier;
1681 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1682 cfg.dir = 0; /* read */
1683 cfg.timeout = 10;
1684
1685 error = mpt_config(ioc, &cfg);
1686 if (error)
1687 return error;
1688 if (!hdr.ExtPageLength)
1689 return -ENXIO;
1690
1691 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1692 &dma_handle);
1693 if (!buffer)
1694 return -ENOMEM;
1695
1696 cfg.physAddr = dma_handle;
1697 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1698
1699 error = mpt_config(ioc, &cfg);
1700 if (error)
1701 goto out_free_consistent;
1702
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301703 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001704
1705 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1706 phy->running_disparity_error_count =
1707 le32_to_cpu(buffer->RunningDisparityErrorCount);
1708 phy->loss_of_dword_sync_count =
1709 le32_to_cpu(buffer->LossDwordSynchCount);
1710 phy->phy_reset_problem_count =
1711 le32_to_cpu(buffer->PhyResetProblemCount);
1712
1713 out_free_consistent:
1714 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1715 buffer, dma_handle);
1716 return error;
1717}
1718
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001719static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1720 MPT_FRAME_HDR *reply)
1721{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301722 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001723 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301724 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001725 memcpy(ioc->sas_mgmt.reply, reply,
1726 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1727 }
1728 complete(&ioc->sas_mgmt.done);
1729 return 1;
1730}
1731
1732static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1733{
1734 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1735 SasIoUnitControlRequest_t *req;
1736 SasIoUnitControlReply_t *reply;
1737 MPT_FRAME_HDR *mf;
1738 MPIHeader_t *hdr;
1739 unsigned long timeleft;
1740 int error = -ERESTARTSYS;
1741
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001742 /* FIXME: fusion doesn't allow non-local phy reset */
1743 if (!scsi_is_sas_phy_local(phy))
1744 return -EINVAL;
1745
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001746 /* not implemented for expanders */
1747 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1748 return -ENXIO;
1749
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001750 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001751 goto out;
1752
1753 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1754 if (!mf) {
1755 error = -ENOMEM;
1756 goto out_unlock;
1757 }
1758
1759 hdr = (MPIHeader_t *) mf;
1760 req = (SasIoUnitControlRequest_t *)mf;
1761 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1762 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1763 req->MsgContext = hdr->MsgContext;
1764 req->Operation = hard_reset ?
1765 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1766 req->PhyNum = phy->identify.phy_identifier;
1767
1768 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1769
1770 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1771 10 * HZ);
1772 if (!timeleft) {
1773 /* On timeout reset the board */
1774 mpt_free_msg_frame(ioc, mf);
1775 mpt_HardResetHandler(ioc, CAN_SLEEP);
1776 error = -ETIMEDOUT;
1777 goto out_unlock;
1778 }
1779
1780 /* a reply frame is expected */
1781 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301782 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001783 error = -ENXIO;
1784 goto out_unlock;
1785 }
1786
1787 /* process the completed Reply Message Frame */
1788 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1789 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001790 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001791 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001792 error = -ENXIO;
1793 goto out_unlock;
1794 }
1795
1796 error = 0;
1797
1798 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001799 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001800 out:
1801 return error;
1802}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001803
Christoph Hellwige3094442006-02-16 13:25:36 +01001804static int
1805mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1806{
1807 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1808 int i, error;
1809 struct mptsas_portinfo *p;
1810 struct mptsas_enclosure enclosure_info;
1811 u64 enclosure_handle;
1812
1813 mutex_lock(&ioc->sas_topology_mutex);
1814 list_for_each_entry(p, &ioc->sas_topology, list) {
1815 for (i = 0; i < p->num_phys; i++) {
1816 if (p->phy_info[i].attached.sas_address ==
1817 rphy->identify.sas_address) {
1818 enclosure_handle = p->phy_info[i].
1819 attached.handle_enclosure;
1820 goto found_info;
1821 }
1822 }
1823 }
1824 mutex_unlock(&ioc->sas_topology_mutex);
1825 return -ENXIO;
1826
1827 found_info:
1828 mutex_unlock(&ioc->sas_topology_mutex);
1829 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001830 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001831 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1832 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1833 if (!error)
1834 *identifier = enclosure_info.enclosure_logical_id;
1835 return error;
1836}
1837
1838static int
1839mptsas_get_bay_identifier(struct sas_rphy *rphy)
1840{
1841 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1842 struct mptsas_portinfo *p;
1843 int i, rc;
1844
1845 mutex_lock(&ioc->sas_topology_mutex);
1846 list_for_each_entry(p, &ioc->sas_topology, list) {
1847 for (i = 0; i < p->num_phys; i++) {
1848 if (p->phy_info[i].attached.sas_address ==
1849 rphy->identify.sas_address) {
1850 rc = p->phy_info[i].attached.slot;
1851 goto out;
1852 }
1853 }
1854 }
1855 rc = -ENXIO;
1856 out:
1857 mutex_unlock(&ioc->sas_topology_mutex);
1858 return rc;
1859}
1860
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001861static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1862 struct request *req)
1863{
1864 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1865 MPT_FRAME_HDR *mf;
1866 SmpPassthroughRequest_t *smpreq;
1867 struct request *rsp = req->next_rq;
1868 int ret;
1869 int flagsLength;
1870 unsigned long timeleft;
1871 char *psge;
1872 dma_addr_t dma_addr_in = 0;
1873 dma_addr_t dma_addr_out = 0;
1874 u64 sas_address = 0;
1875
1876 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06001877 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001878 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001879 return -EINVAL;
1880 }
1881
1882 /* do we need to support multiple segments? */
1883 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06001884 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001885 ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
Eric Moore29dd3602007-09-14 18:46:51 -06001886 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001887 return -EINVAL;
1888 }
1889
1890 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1891 if (ret)
1892 goto out;
1893
1894 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1895 if (!mf) {
1896 ret = -ENOMEM;
1897 goto out_unlock;
1898 }
1899
1900 smpreq = (SmpPassthroughRequest_t *)mf;
1901 memset(smpreq, 0, sizeof(*smpreq));
1902
1903 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1904 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1905
1906 if (rphy)
1907 sas_address = rphy->identify.sas_address;
1908 else {
1909 struct mptsas_portinfo *port_info;
1910
1911 mutex_lock(&ioc->sas_topology_mutex);
Michael Reed77483692008-03-20 17:32:05 -05001912 port_info = mptsas_get_hba_portinfo(ioc);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001913 if (port_info && port_info->phy_info)
1914 sas_address =
1915 port_info->phy_info[0].phy->identify.sas_address;
1916 mutex_unlock(&ioc->sas_topology_mutex);
1917 }
1918
1919 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1920
1921 psge = (char *)
1922 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1923
1924 /* request */
1925 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1926 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301927 MPI_SGE_FLAGS_DIRECTION)
1928 << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001929 flagsLength |= (req->data_len - 4);
1930
1931 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1932 req->data_len, PCI_DMA_BIDIRECTIONAL);
1933 if (!dma_addr_out)
1934 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301935 ioc->add_sge(psge, flagsLength, dma_addr_out);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001936 psge += (sizeof(u32) + sizeof(dma_addr_t));
1937
1938 /* response */
1939 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1940 flagsLength |= rsp->data_len + 4;
1941 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1942 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1943 if (!dma_addr_in)
1944 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301945 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001946
1947 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1948
1949 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1950 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001951 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001952 /* On timeout reset the board */
1953 mpt_HardResetHandler(ioc, CAN_SLEEP);
1954 ret = -ETIMEDOUT;
1955 goto unmap;
1956 }
1957 mf = NULL;
1958
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301959 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001960 SmpPassthroughReply_t *smprep;
1961
1962 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1963 memcpy(req->sense, smprep, sizeof(*smprep));
1964 req->sense_len = sizeof(*smprep);
FUJITA Tomonori38b31672007-12-30 19:34:52 +09001965 req->data_len = 0;
1966 rsp->data_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001967 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001968 printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001969 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001970 ret = -ENXIO;
1971 }
1972unmap:
1973 if (dma_addr_out)
1974 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1975 PCI_DMA_BIDIRECTIONAL);
1976 if (dma_addr_in)
1977 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1978 PCI_DMA_BIDIRECTIONAL);
1979put_mf:
1980 if (mf)
1981 mpt_free_msg_frame(ioc, mf);
1982out_unlock:
1983 mutex_unlock(&ioc->sas_mgmt.mutex);
1984out:
1985 return ret;
1986}
1987
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001988static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001989 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001990 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1991 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001992 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001993 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001994};
1995
1996static struct scsi_transport_template *mptsas_transport_template;
1997
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001998static int
1999mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2000{
2001 ConfigExtendedPageHeader_t hdr;
2002 CONFIGPARMS cfg;
2003 SasIOUnitPage0_t *buffer;
2004 dma_addr_t dma_handle;
2005 int error, i;
2006
2007 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2008 hdr.ExtPageLength = 0;
2009 hdr.PageNumber = 0;
2010 hdr.Reserved1 = 0;
2011 hdr.Reserved2 = 0;
2012 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2013 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2014
2015 cfg.cfghdr.ehdr = &hdr;
2016 cfg.physAddr = -1;
2017 cfg.pageAddr = 0;
2018 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2019 cfg.dir = 0; /* read */
2020 cfg.timeout = 10;
2021
2022 error = mpt_config(ioc, &cfg);
2023 if (error)
2024 goto out;
2025 if (!hdr.ExtPageLength) {
2026 error = -ENXIO;
2027 goto out;
2028 }
2029
2030 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2031 &dma_handle);
2032 if (!buffer) {
2033 error = -ENOMEM;
2034 goto out;
2035 }
2036
2037 cfg.physAddr = dma_handle;
2038 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2039
2040 error = mpt_config(ioc, &cfg);
2041 if (error)
2042 goto out_free_consistent;
2043
2044 port_info->num_phys = buffer->NumPhys;
2045 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06002046 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002047 if (!port_info->phy_info) {
2048 error = -ENOMEM;
2049 goto out_free_consistent;
2050 }
2051
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302052 ioc->nvdata_version_persistent =
2053 le16_to_cpu(buffer->NvdataVersionPersistent);
2054 ioc->nvdata_version_default =
2055 le16_to_cpu(buffer->NvdataVersionDefault);
2056
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002057 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302058 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002059 port_info->phy_info[i].phy_id = i;
2060 port_info->phy_info[i].port_id =
2061 buffer->PhyData[i].Port;
2062 port_info->phy_info[i].negotiated_link_rate =
2063 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002064 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002065 port_info->phy_info[i].handle =
2066 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002067 }
2068
2069 out_free_consistent:
2070 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2071 buffer, dma_handle);
2072 out:
2073 return error;
2074}
2075
2076static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302077mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2078{
2079 ConfigExtendedPageHeader_t hdr;
2080 CONFIGPARMS cfg;
2081 SasIOUnitPage1_t *buffer;
2082 dma_addr_t dma_handle;
2083 int error;
2084 u16 device_missing_delay;
2085
2086 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2087 memset(&cfg, 0, sizeof(CONFIGPARMS));
2088
2089 cfg.cfghdr.ehdr = &hdr;
2090 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2091 cfg.timeout = 10;
2092 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2093 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2094 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2095 cfg.cfghdr.ehdr->PageNumber = 1;
2096
2097 error = mpt_config(ioc, &cfg);
2098 if (error)
2099 goto out;
2100 if (!hdr.ExtPageLength) {
2101 error = -ENXIO;
2102 goto out;
2103 }
2104
2105 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2106 &dma_handle);
2107 if (!buffer) {
2108 error = -ENOMEM;
2109 goto out;
2110 }
2111
2112 cfg.physAddr = dma_handle;
2113 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2114
2115 error = mpt_config(ioc, &cfg);
2116 if (error)
2117 goto out_free_consistent;
2118
2119 ioc->io_missing_delay =
2120 le16_to_cpu(buffer->IODeviceMissingDelay);
2121 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2122 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2123 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2124 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2125
2126 out_free_consistent:
2127 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2128 buffer, dma_handle);
2129 out:
2130 return error;
2131}
2132
2133static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002134mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2135 u32 form, u32 form_specific)
2136{
2137 ConfigExtendedPageHeader_t hdr;
2138 CONFIGPARMS cfg;
2139 SasPhyPage0_t *buffer;
2140 dma_addr_t dma_handle;
2141 int error;
2142
2143 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2144 hdr.ExtPageLength = 0;
2145 hdr.PageNumber = 0;
2146 hdr.Reserved1 = 0;
2147 hdr.Reserved2 = 0;
2148 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2149 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2150
2151 cfg.cfghdr.ehdr = &hdr;
2152 cfg.dir = 0; /* read */
2153 cfg.timeout = 10;
2154
2155 /* Get Phy Pg 0 for each Phy. */
2156 cfg.physAddr = -1;
2157 cfg.pageAddr = form + form_specific;
2158 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2159
2160 error = mpt_config(ioc, &cfg);
2161 if (error)
2162 goto out;
2163
2164 if (!hdr.ExtPageLength) {
2165 error = -ENXIO;
2166 goto out;
2167 }
2168
2169 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2170 &dma_handle);
2171 if (!buffer) {
2172 error = -ENOMEM;
2173 goto out;
2174 }
2175
2176 cfg.physAddr = dma_handle;
2177 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2178
2179 error = mpt_config(ioc, &cfg);
2180 if (error)
2181 goto out_free_consistent;
2182
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302183 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002184
2185 phy_info->hw_link_rate = buffer->HwLinkRate;
2186 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2187 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2188 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2189
2190 out_free_consistent:
2191 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2192 buffer, dma_handle);
2193 out:
2194 return error;
2195}
2196
2197static int
2198mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2199 u32 form, u32 form_specific)
2200{
2201 ConfigExtendedPageHeader_t hdr;
2202 CONFIGPARMS cfg;
2203 SasDevicePage0_t *buffer;
2204 dma_addr_t dma_handle;
2205 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002206 int error=0;
2207
2208 if (ioc->sas_discovery_runtime &&
2209 mptsas_is_end_device(device_info))
2210 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002211
2212 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2213 hdr.ExtPageLength = 0;
2214 hdr.PageNumber = 0;
2215 hdr.Reserved1 = 0;
2216 hdr.Reserved2 = 0;
2217 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2218 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2219
2220 cfg.cfghdr.ehdr = &hdr;
2221 cfg.pageAddr = form + form_specific;
2222 cfg.physAddr = -1;
2223 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2224 cfg.dir = 0; /* read */
2225 cfg.timeout = 10;
2226
Moore, Ericdb9c9172006-03-14 09:14:18 -07002227 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002228 error = mpt_config(ioc, &cfg);
2229 if (error)
2230 goto out;
2231 if (!hdr.ExtPageLength) {
2232 error = -ENXIO;
2233 goto out;
2234 }
2235
2236 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2237 &dma_handle);
2238 if (!buffer) {
2239 error = -ENOMEM;
2240 goto out;
2241 }
2242
2243 cfg.physAddr = dma_handle;
2244 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2245
2246 error = mpt_config(ioc, &cfg);
2247 if (error)
2248 goto out_free_consistent;
2249
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302250 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002251
2252 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002253 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002254 device_info->handle_enclosure =
2255 le16_to_cpu(buffer->EnclosureHandle);
2256 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002257 device_info->phy_id = buffer->PhyNum;
2258 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002259 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002260 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002261 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002262 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2263 device_info->sas_address = le64_to_cpu(sas_address);
2264 device_info->device_info =
2265 le32_to_cpu(buffer->DeviceInfo);
2266
2267 out_free_consistent:
2268 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2269 buffer, dma_handle);
2270 out:
2271 return error;
2272}
2273
2274static int
2275mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2276 u32 form, u32 form_specific)
2277{
2278 ConfigExtendedPageHeader_t hdr;
2279 CONFIGPARMS cfg;
2280 SasExpanderPage0_t *buffer;
2281 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002282 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002283
2284 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2285 hdr.ExtPageLength = 0;
2286 hdr.PageNumber = 0;
2287 hdr.Reserved1 = 0;
2288 hdr.Reserved2 = 0;
2289 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2290 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2291
2292 cfg.cfghdr.ehdr = &hdr;
2293 cfg.physAddr = -1;
2294 cfg.pageAddr = form + form_specific;
2295 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2296 cfg.dir = 0; /* read */
2297 cfg.timeout = 10;
2298
Moore, Ericdb9c9172006-03-14 09:14:18 -07002299 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002300 error = mpt_config(ioc, &cfg);
2301 if (error)
2302 goto out;
2303
2304 if (!hdr.ExtPageLength) {
2305 error = -ENXIO;
2306 goto out;
2307 }
2308
2309 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2310 &dma_handle);
2311 if (!buffer) {
2312 error = -ENOMEM;
2313 goto out;
2314 }
2315
2316 cfg.physAddr = dma_handle;
2317 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2318
2319 error = mpt_config(ioc, &cfg);
2320 if (error)
2321 goto out_free_consistent;
2322
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002323 if (!buffer->NumPhys) {
2324 error = -ENODEV;
2325 goto out_free_consistent;
2326 }
2327
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002328 /* save config data */
2329 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002330 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06002331 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002332 if (!port_info->phy_info) {
2333 error = -ENOMEM;
2334 goto out_free_consistent;
2335 }
2336
Eric Moore2ecce492007-01-29 09:47:08 -07002337 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002338 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002339 port_info->phy_info[i].handle =
2340 le16_to_cpu(buffer->DevHandle);
2341 }
Eric Moore547f9a22006-06-27 14:42:12 -06002342
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002343 out_free_consistent:
2344 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2345 buffer, dma_handle);
2346 out:
2347 return error;
2348}
2349
2350static int
2351mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2352 u32 form, u32 form_specific)
2353{
2354 ConfigExtendedPageHeader_t hdr;
2355 CONFIGPARMS cfg;
2356 SasExpanderPage1_t *buffer;
2357 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002358 int error=0;
2359
2360 if (ioc->sas_discovery_runtime &&
2361 mptsas_is_end_device(&phy_info->attached))
2362 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002363
2364 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2365 hdr.ExtPageLength = 0;
2366 hdr.PageNumber = 1;
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
2379 error = mpt_config(ioc, &cfg);
2380 if (error)
2381 goto out;
2382
2383 if (!hdr.ExtPageLength) {
2384 error = -ENXIO;
2385 goto out;
2386 }
2387
2388 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2389 &dma_handle);
2390 if (!buffer) {
2391 error = -ENOMEM;
2392 goto out;
2393 }
2394
2395 cfg.physAddr = dma_handle;
2396 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2397
2398 error = mpt_config(ioc, &cfg);
2399 if (error)
2400 goto out_free_consistent;
2401
2402
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302403 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002404
2405 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002406 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002407 phy_info->port_id = buffer->PhysicalPort;
2408 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2409 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2410 phy_info->hw_link_rate = buffer->HwLinkRate;
2411 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2412 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2413
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002414 out_free_consistent:
2415 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2416 buffer, dma_handle);
2417 out:
2418 return error;
2419}
2420
2421static void
2422mptsas_parse_device_info(struct sas_identify *identify,
2423 struct mptsas_devinfo *device_info)
2424{
2425 u16 protocols;
2426
2427 identify->sas_address = device_info->sas_address;
2428 identify->phy_identifier = device_info->phy_id;
2429
2430 /*
2431 * Fill in Phy Initiator Port Protocol.
2432 * Bits 6:3, more than one bit can be set, fall through cases.
2433 */
2434 protocols = device_info->device_info & 0x78;
2435 identify->initiator_port_protocols = 0;
2436 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2437 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2438 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2439 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2440 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2441 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2442 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2443 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2444
2445 /*
2446 * Fill in Phy Target Port Protocol.
2447 * Bits 10:7, more than one bit can be set, fall through cases.
2448 */
2449 protocols = device_info->device_info & 0x780;
2450 identify->target_port_protocols = 0;
2451 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2452 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2453 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2454 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2455 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2456 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2457 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2458 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2459
2460 /*
2461 * Fill in Attached device type.
2462 */
2463 switch (device_info->device_info &
2464 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2465 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2466 identify->device_type = SAS_PHY_UNUSED;
2467 break;
2468 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2469 identify->device_type = SAS_END_DEVICE;
2470 break;
2471 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2472 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2473 break;
2474 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2475 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2476 break;
2477 }
2478}
2479
2480static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002481 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002482{
Moore, Erice6b2d762006-03-14 09:14:24 -07002483 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002484 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002485 struct sas_port *port;
2486 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002487
Eric Moore547f9a22006-06-27 14:42:12 -06002488 if (!dev) {
2489 error = -ENODEV;
2490 goto out;
2491 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002492
2493 if (!phy_info->phy) {
2494 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002495 if (!phy) {
2496 error = -ENOMEM;
2497 goto out;
2498 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002499 } else
2500 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002501
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002502 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002503
2504 /*
2505 * Set Negotiated link rate.
2506 */
2507 switch (phy_info->negotiated_link_rate) {
2508 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002509 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002510 break;
2511 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002512 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002513 break;
2514 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002515 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002516 break;
2517 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002518 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002519 break;
2520 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2521 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2522 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002523 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002524 break;
2525 }
2526
2527 /*
2528 * Set Max hardware link rate.
2529 */
2530 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2531 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002532 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002533 break;
2534 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002535 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002536 break;
2537 default:
2538 break;
2539 }
2540
2541 /*
2542 * Set Max programmed link rate.
2543 */
2544 switch (phy_info->programmed_link_rate &
2545 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2546 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002547 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002548 break;
2549 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002550 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002551 break;
2552 default:
2553 break;
2554 }
2555
2556 /*
2557 * Set Min hardware link rate.
2558 */
2559 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2560 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002561 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002562 break;
2563 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002564 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002565 break;
2566 default:
2567 break;
2568 }
2569
2570 /*
2571 * Set Min programmed link rate.
2572 */
2573 switch (phy_info->programmed_link_rate &
2574 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2575 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002576 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002577 break;
2578 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002579 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002580 break;
2581 default:
2582 break;
2583 }
2584
Moore, Erice6b2d762006-03-14 09:14:24 -07002585 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002586
Moore, Erice6b2d762006-03-14 09:14:24 -07002587 error = sas_phy_add(phy);
2588 if (error) {
2589 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002590 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002591 }
2592 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002593 }
2594
Eric Moore547f9a22006-06-27 14:42:12 -06002595 if (!phy_info->attached.handle ||
2596 !phy_info->port_details)
2597 goto out;
2598
2599 port = mptsas_get_port(phy_info);
2600 ioc = phy_to_ioc(phy_info->phy);
2601
2602 if (phy_info->sas_port_add_phy) {
2603
2604 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002605 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002606 if (!port) {
2607 error = -ENOMEM;
2608 goto out;
2609 }
2610 error = sas_port_add(port);
2611 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302612 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002613 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002614 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002615 goto out;
2616 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302617 mptsas_set_port(ioc, phy_info, port);
Eric Moore29dd3602007-09-14 18:46:51 -06002618 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooredc22f162006-07-06 11:23:14 -06002619 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002620 ioc->name, port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002621 }
Eric Moore29dd3602007-09-14 18:46:51 -06002622 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
2623 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002624 sas_port_add_phy(port, phy_info->phy);
2625 phy_info->sas_port_add_phy = 0;
2626 }
2627
2628 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002629
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002630 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002631 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002632 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002633
James Bottomley2686de22006-06-30 12:54:02 -05002634 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002635 /*
2636 * Let the hotplug_work thread handle processing
2637 * the adding/removing of devices that occur
2638 * after start of day.
2639 */
2640 if (ioc->sas_discovery_runtime &&
2641 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002642 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002643
James Bottomleyf013db32006-03-18 14:54:36 -06002644 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002645 if (scsi_is_host_device(parent)) {
2646 struct mptsas_portinfo *port_info;
2647 int i;
2648
2649 mutex_lock(&ioc->sas_topology_mutex);
Michael Reed77483692008-03-20 17:32:05 -05002650 port_info = mptsas_get_hba_portinfo(ioc);
James Bottomley2686de22006-06-30 12:54:02 -05002651 mutex_unlock(&ioc->sas_topology_mutex);
2652
2653 for (i = 0; i < port_info->num_phys; i++)
2654 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002655 identify.sas_address) {
2656 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002657 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002658 }
James Bottomley2686de22006-06-30 12:54:02 -05002659
2660 } else if (scsi_is_sas_rphy(parent)) {
2661 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2662 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002663 parent_rphy->identify.sas_address) {
2664 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002665 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002666 }
James Bottomley2686de22006-06-30 12:54:02 -05002667 }
2668
James Bottomleyf013db32006-03-18 14:54:36 -06002669 switch (identify.device_type) {
2670 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002671 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002672 break;
2673 case SAS_EDGE_EXPANDER_DEVICE:
2674 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002675 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002676 break;
2677 default:
2678 rphy = NULL;
2679 break;
2680 }
Eric Moore547f9a22006-06-27 14:42:12 -06002681 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302682 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002683 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002684 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002685 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002686 }
2687
Eric Moore547f9a22006-06-27 14:42:12 -06002688 rphy->identify = identify;
2689 error = sas_rphy_add(rphy);
2690 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302691 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002692 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002693 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002694 sas_rphy_free(rphy);
2695 goto out;
2696 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302697 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002698 }
2699
Eric Moore547f9a22006-06-27 14:42:12 -06002700 out:
2701 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002702}
2703
2704static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002705mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002706{
Moore, Erice6b2d762006-03-14 09:14:24 -07002707 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002708 int error = -ENOMEM, i;
2709
Moore, Erice6b2d762006-03-14 09:14:24 -07002710 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2711 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002712 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002713
Moore, Erice6b2d762006-03-14 09:14:24 -07002714 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002715 if (error)
2716 goto out_free_port_info;
2717
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302718 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002719 mutex_lock(&ioc->sas_topology_mutex);
Michael Reed77483692008-03-20 17:32:05 -05002720 port_info = mptsas_get_hba_portinfo(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002721 if (!port_info) {
2722 port_info = hba;
2723 list_add_tail(&port_info->list, &ioc->sas_topology);
2724 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002725 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002726 port_info->phy_info[i].negotiated_link_rate =
2727 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002728 port_info->phy_info[i].handle =
2729 hba->phy_info[i].handle;
2730 port_info->phy_info[i].port_id =
2731 hba->phy_info[i].port_id;
2732 }
Eric Moore547f9a22006-06-27 14:42:12 -06002733 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002734 kfree(hba);
2735 hba = NULL;
2736 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002737 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002738 for (i = 0; i < port_info->num_phys; i++) {
2739 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2740 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2741 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2742
2743 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002744 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2745 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2746 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002747 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002748 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002749 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002750 mptsas_sas_device_pg0(ioc,
2751 &port_info->phy_info[i].attached,
2752 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2753 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2754 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002755 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002756
Eric Moore547f9a22006-06-27 14:42:12 -06002757 mptsas_setup_wide_ports(ioc, port_info);
2758
2759 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002760 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002761 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002762
2763 return 0;
2764
2765 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002766 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002767 out:
2768 return error;
2769}
2770
2771static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002772mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002773{
Moore, Erice6b2d762006-03-14 09:14:24 -07002774 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002775 struct device *parent;
2776 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002777 int error = -ENOMEM, i, j;
2778
Moore, Erice6b2d762006-03-14 09:14:24 -07002779 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2780 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002781 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002782
Moore, Erice6b2d762006-03-14 09:14:24 -07002783 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002784 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2785 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002786 if (error)
2787 goto out_free_port_info;
2788
Eric Moore2ecce492007-01-29 09:47:08 -07002789 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002790
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002791 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002792 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2793 if (!port_info) {
2794 port_info = ex;
2795 list_add_tail(&port_info->list, &ioc->sas_topology);
2796 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002797 for (i = 0; i < ex->num_phys; i++) {
2798 port_info->phy_info[i].handle =
2799 ex->phy_info[i].handle;
2800 port_info->phy_info[i].port_id =
2801 ex->phy_info[i].port_id;
2802 }
Eric Moore547f9a22006-06-27 14:42:12 -06002803 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002804 kfree(ex);
2805 ex = NULL;
2806 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002807 mutex_unlock(&ioc->sas_topology_mutex);
2808
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002809 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002810 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2811 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2812 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2813
2814 if (port_info->phy_info[i].identify.handle) {
2815 mptsas_sas_device_pg0(ioc,
2816 &port_info->phy_info[i].identify,
2817 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2818 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2819 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002820 port_info->phy_info[i].identify.phy_id =
2821 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002822 }
2823
2824 if (port_info->phy_info[i].attached.handle) {
2825 mptsas_sas_device_pg0(ioc,
2826 &port_info->phy_info[i].attached,
2827 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2828 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2829 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002830 port_info->phy_info[i].attached.phy_id =
2831 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002832 }
Eric Moore547f9a22006-06-27 14:42:12 -06002833 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002834
Eric Moore547f9a22006-06-27 14:42:12 -06002835 parent = &ioc->sh->shost_gendev;
2836 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002837 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002838 list_for_each_entry(p, &ioc->sas_topology, list) {
2839 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002840 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002841 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002842 continue;
2843 rphy = mptsas_get_rphy(&p->phy_info[j]);
2844 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002845 }
2846 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002847 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002848 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002849
Eric Moore547f9a22006-06-27 14:42:12 -06002850 mptsas_setup_wide_ports(ioc, port_info);
2851
2852 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002853 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002854 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002855
2856 return 0;
2857
2858 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002859 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002860 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002861 kfree(ex);
2862 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002863 out:
2864 return error;
2865}
2866
Moore, Erice6b2d762006-03-14 09:14:24 -07002867/*
2868 * mptsas_delete_expander_phys
2869 *
2870 *
2871 * This will traverse topology, and remove expanders
2872 * that are no longer present
2873 */
2874static void
2875mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2876{
2877 struct mptsas_portinfo buffer;
2878 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002879 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002880 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002881 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002882 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002883
2884 mutex_lock(&ioc->sas_topology_mutex);
2885 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2886
Alan Coxd58069a2009-04-01 15:00:29 +01002887 if (!(port_info->phy_info[0].identify.device_info &
2888 MPI_SAS_DEVICE_INFO_SMP_TARGET))
Moore, Erice6b2d762006-03-14 09:14:24 -07002889 continue;
2890
2891 if (mptsas_sas_expander_pg0(ioc, &buffer,
2892 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002893 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2894 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002895
2896 /*
2897 * Obtain the port_info instance to the parent port
2898 */
2899 parent = mptsas_find_portinfo_by_handle(ioc,
2900 port_info->phy_info[0].identify.handle_parent);
2901
2902 if (!parent)
2903 goto next_port;
2904
Eric Moore547f9a22006-06-27 14:42:12 -06002905 expander_sas_address =
2906 port_info->phy_info[0].identify.sas_address;
2907
Moore, Erice6b2d762006-03-14 09:14:24 -07002908 /*
2909 * Delete rphys in the parent that point
2910 * to this expander. The transport layer will
2911 * cleanup all the children.
2912 */
Eric Moore547f9a22006-06-27 14:42:12 -06002913 phy_info = parent->phy_info;
2914 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2915 port = mptsas_get_port(phy_info);
2916 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002917 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002918 if (phy_info->attached.sas_address !=
2919 expander_sas_address)
2920 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302921 dsaswideprintk(ioc,
Eric Moorec51d0be2007-09-29 10:17:21 -06002922 dev_printk(KERN_DEBUG, &port->dev,
2923 MYIOC_s_FMT "delete port (%d)\n", ioc->name,
2924 port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002925 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302926 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002927 }
2928 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002929
2930 phy_info = port_info->phy_info;
2931 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302932 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002933
Moore, Erice6b2d762006-03-14 09:14:24 -07002934 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002935 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002936 kfree(port_info);
2937 }
2938 /*
2939 * Free this memory allocated from inside
2940 * mptsas_sas_expander_pg0
2941 */
Eric Moore547f9a22006-06-27 14:42:12 -06002942 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002943 }
2944 mutex_unlock(&ioc->sas_topology_mutex);
2945}
2946
2947/*
2948 * Start of day discovery
2949 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002950static void
2951mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2952{
2953 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002954 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002955
Moore, Erice6b2d762006-03-14 09:14:24 -07002956 mutex_lock(&ioc->sas_discovery_mutex);
2957 mptsas_probe_hba_phys(ioc);
2958 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002959 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002960 /*
2961 Reporting RAID volumes.
2962 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002963 if (!ioc->ir_firmware)
2964 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002965 if (!ioc->raid_data.pIocPg2)
2966 goto out;
2967 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2968 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002969 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002970 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002971 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2972 }
2973 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002974 mutex_unlock(&ioc->sas_discovery_mutex);
2975}
2976
2977/*
2978 * Work queue thread to handle Runtime discovery
2979 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002980 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002981 */
2982static void
Eric Moore547f9a22006-06-27 14:42:12 -06002983__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002984{
Moore, Erice6b2d762006-03-14 09:14:24 -07002985 u32 handle = 0xFFFF;
2986
Moore, Erice6b2d762006-03-14 09:14:24 -07002987 ioc->sas_discovery_runtime=1;
2988 mptsas_delete_expander_phys(ioc);
2989 mptsas_probe_hba_phys(ioc);
2990 while (!mptsas_probe_expander_phys(ioc, &handle))
2991 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002992 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002993}
2994
2995/*
2996 * Work queue thread to handle Runtime discovery
2997 * Mere purpose is the hot add/delete of expanders
2998 *(Mutex LOCKED)
2999 */
3000static void
David Howellsc4028952006-11-22 14:57:56 +00003001mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06003002{
David Howellsc4028952006-11-22 14:57:56 +00003003 struct mptsas_discovery_event *ev =
3004 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06003005 MPT_ADAPTER *ioc = ev->ioc;
3006
3007 mutex_lock(&ioc->sas_discovery_mutex);
3008 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07003009 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06003010 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003011}
3012
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303013
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003014static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003015mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003016{
3017 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003018 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003019 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003020
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003021 mutex_lock(&ioc->sas_topology_mutex);
3022 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3023 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003024 if (!mptsas_is_end_device(
3025 &port_info->phy_info[i].attached))
3026 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003027 if (port_info->phy_info[i].attached.sas_address
3028 != sas_address)
3029 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003030 phy_info = &port_info->phy_info[i];
3031 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003032 }
3033 }
3034 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003035 return phy_info;
3036}
3037
Eric Mooreb506ade2007-01-29 09:45:37 -07003038
3039static struct mptsas_phyinfo *
3040mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
3041{
3042 struct mptsas_portinfo *port_info;
3043 struct mptsas_phyinfo *phy_info = NULL;
3044 int i;
3045
3046 mutex_lock(&ioc->sas_topology_mutex);
3047 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3048 for (i = 0; i < port_info->num_phys; i++) {
3049 if (!mptsas_is_end_device(
3050 &port_info->phy_info[i].attached))
3051 continue;
3052 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
3053 continue;
3054 if (port_info->phy_info[i].attached.phys_disk_num != id)
3055 continue;
3056 if (port_info->phy_info[i].attached.channel != channel)
3057 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003058 phy_info = &port_info->phy_info[i];
3059 break;
3060 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003061 }
3062 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003063 return phy_info;
3064}
3065
3066static void
Moore, Ericf44e5462006-03-14 09:14:21 -07003067mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
3068{
Eric Mooref99be432007-01-04 20:46:54 -07003069 int rc;
3070
Moore, Ericf44e5462006-03-14 09:14:21 -07003071 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07003072 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07003073}
3074
3075static void
3076mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
3077{
3078 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
3079 mptsas_reprobe_lun);
3080}
3081
Eric Mooreb506ade2007-01-29 09:45:37 -07003082static void
3083mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
3084{
3085 CONFIGPARMS cfg;
3086 ConfigPageHeader_t hdr;
3087 dma_addr_t dma_handle;
3088 pRaidVolumePage0_t buffer = NULL;
3089 RaidPhysDiskPage0_t phys_disk;
3090 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303091 struct mptsas_phyinfo *phy_info;
3092 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07003093
3094 memset(&cfg, 0 , sizeof(CONFIGPARMS));
3095 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
3096 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
3097 cfg.pageAddr = (channel << 8) + id;
3098 cfg.cfghdr.hdr = &hdr;
3099 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3100
3101 if (mpt_config(ioc, &cfg) != 0)
3102 goto out;
3103
3104 if (!hdr.PageLength)
3105 goto out;
3106
3107 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
3108 &dma_handle);
3109
3110 if (!buffer)
3111 goto out;
3112
3113 cfg.physAddr = dma_handle;
3114 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3115
3116 if (mpt_config(ioc, &cfg) != 0)
3117 goto out;
3118
3119 if (!(buffer->VolumeStatus.Flags &
3120 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
3121 goto out;
3122
3123 if (!buffer->NumPhysDisks)
3124 goto out;
3125
3126 for (i = 0; i < buffer->NumPhysDisks; i++) {
3127
3128 if (mpt_raid_phys_disk_pg0(ioc,
3129 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
3130 continue;
3131
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303132 if (mptsas_sas_device_pg0(ioc, &sas_device,
3133 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3134 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3135 (phys_disk.PhysDiskBus << 8) +
3136 phys_disk.PhysDiskID))
3137 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003138
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303139 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3140 sas_device.sas_address);
3141 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07003142 }
3143
3144 out:
3145 if (buffer)
3146 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
3147 dma_handle);
3148}
Moore, Erice6b2d762006-03-14 09:14:24 -07003149/*
3150 * Work queue thread to handle SAS hotplug events
3151 */
Moore, Ericf44e5462006-03-14 09:14:21 -07003152static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303153mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
3154 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003155{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003156 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06003157 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003158 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07003159 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303160 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06003161
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303162 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003163
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303164 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07003165
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303166 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07003167 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003168
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303169 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
3170 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
3171 hot_plug_info->id) {
3172 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
3173 "to add hidden disk - target_id matchs "
3174 "volume_id\n", ioc->name);
3175 mptsas_free_fw_event(ioc, fw_event);
3176 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07003177 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003178 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303179 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003180
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003181 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303182 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
3183 mptsas_sas_device_pg0(ioc, &sas_device,
3184 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3185 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3186 (hot_plug_info->channel << 8) +
3187 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003188
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303189 if (!sas_device.handle)
3190 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06003191
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303192 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3193 if (!phy_info)
3194 break;
3195
3196 if (mptsas_get_rphy(phy_info))
3197 break;
3198
3199 mptsas_add_end_device(ioc, phy_info);
3200 break;
3201
3202 case MPTSAS_DEL_DEVICE:
3203 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3204 hot_plug_info->sas_address);
3205 mptsas_del_end_device(ioc, phy_info);
3206 break;
3207
3208 case MPTSAS_DEL_PHYSDISK:
3209
3210 mpt_findImVolumes(ioc);
3211
3212 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
3213 ioc, hot_plug_info->channel,
3214 hot_plug_info->phys_disk_num);
3215 mptsas_del_end_device(ioc, phy_info);
3216 break;
3217
3218 case MPTSAS_ADD_PHYSDISK_REPROBE:
3219
Christoph Hellwige3094442006-02-16 13:25:36 +01003220 if (mptsas_sas_device_pg0(ioc, &sas_device,
3221 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07003222 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303223 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
3224 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3225 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3226 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01003227 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07003228 }
3229
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303230 phy_info = mptsas_find_phyinfo_by_sas_address(
3231 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07003232
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303233 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303234 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303235 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3236 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003237 break;
3238 }
3239
3240 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303241 if (!starget) {
3242 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3243 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3244 __func__, hot_plug_info->id, __LINE__));
3245 break;
3246 }
Eric Mooreb506ade2007-01-29 09:45:37 -07003247
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303248 vtarget = starget->hostdata;
3249 if (!vtarget) {
3250 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3251 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3252 __func__, hot_plug_info->id, __LINE__));
3253 break;
3254 }
Eric Moore547f9a22006-06-27 14:42:12 -06003255
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303256 mpt_findImVolumes(ioc);
3257
3258 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
3259 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
3260 ioc->name, hot_plug_info->channel, hot_plug_info->id,
3261 hot_plug_info->phys_disk_num, (unsigned long long)
3262 sas_device.sas_address);
3263
3264 vtarget->id = hot_plug_info->phys_disk_num;
3265 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
3266 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
3267 mptsas_reprobe_target(starget, 1);
3268 break;
3269
3270 case MPTSAS_DEL_PHYSDISK_REPROBE:
3271
3272 if (mptsas_sas_device_pg0(ioc, &sas_device,
3273 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3274 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3275 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303276 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303277 "%s: fw_id=%d exit at line=%d\n",
3278 ioc->name, __func__,
3279 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003280 break;
3281 }
3282
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303283 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3284 sas_device.sas_address);
3285 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303286 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303287 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3288 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003289 break;
Eric Moore547f9a22006-06-27 14:42:12 -06003290 }
Eric Mooreb506ade2007-01-29 09:45:37 -07003291
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303292 starget = mptsas_get_starget(phy_info);
3293 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303294 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303295 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3296 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003297 break;
3298 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003299
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303300 vtarget = starget->hostdata;
3301 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303302 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303303 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3304 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003305 break;
3306 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303307
3308 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
3309 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3310 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3311 __func__, hot_plug_info->id, __LINE__));
3312 break;
3313 }
3314
3315 mpt_findImVolumes(ioc);
3316
3317 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
3318 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
3319 ioc->name, hot_plug_info->channel, hot_plug_info->id,
3320 hot_plug_info->phys_disk_num, (unsigned long long)
3321 sas_device.sas_address);
3322
3323 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
3324 vtarget->id = hot_plug_info->id;
3325 phy_info->attached.phys_disk_num = ~0;
3326 mptsas_reprobe_target(starget, 0);
3327 mptsas_add_device_component_by_fw(ioc,
3328 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003329 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303330
Moore, Ericc73787ee2006-01-26 16:20:06 -07003331 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303332
Moore, Ericc73787ee2006-01-26 16:20:06 -07003333 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303334 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3335 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3336 hot_plug_info->id);
3337 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
3338 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003339 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303340
Moore, Ericc73787ee2006-01-26 16:20:06 -07003341 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303342
Moore, Ericc73787ee2006-01-26 16:20:06 -07003343 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303344 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
3345 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3346 hot_plug_info->id);
3347 scsi_remove_device(hot_plug_info->sdev);
3348 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003349 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303350
Eric Mooreb506ade2007-01-29 09:45:37 -07003351 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303352
3353 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07003354 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303355 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07003356 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303357
Moore, Ericbd23e942006-04-17 12:43:04 -06003358 default:
3359 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003360 }
3361
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303362 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003363}
3364
3365static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303366mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003367{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303368 MPT_ADAPTER *ioc;
3369 struct mptsas_hotplug_event hot_plug_info;
3370 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
3371 u32 device_info;
3372 u64 sas_address;
3373
3374 ioc = fw_event->ioc;
3375 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
3376 fw_event->event_data;
3377 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003378
3379 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303380 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3381 MPI_SAS_DEVICE_INFO_STP_TARGET |
3382 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
3383 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003384 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303385 }
3386
3387 if (sas_event_data->ReasonCode ==
3388 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
3389 mptbase_sas_persist_operation(ioc,
3390 MPI_SAS_OP_CLEAR_NOT_PRESENT);
3391 mptsas_free_fw_event(ioc, fw_event);
3392 return;
3393 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003394
Moore, Eric4b766472006-03-14 09:14:12 -07003395 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07003396 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07003397 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303398 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
3399 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
3400 hot_plug_info.channel = sas_event_data->Bus;
3401 hot_plug_info.id = sas_event_data->TargetID;
3402 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07003403 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303404 sizeof(u64));
3405 hot_plug_info.sas_address = le64_to_cpu(sas_address);
3406 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07003407 if (sas_event_data->ReasonCode &
3408 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303409 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07003410 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303411 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
3412 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07003413 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303414
Moore, Eric4b766472006-03-14 09:14:12 -07003415 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303416 mptbase_sas_persist_operation(ioc,
3417 MPI_SAS_OP_CLEAR_NOT_PRESENT);
3418 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07003419 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303420
Moore, Eric4b766472006-03-14 09:14:12 -07003421 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303422 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07003423 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303424 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07003425 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303426 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07003427 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003428 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003429}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303430
Moore, Ericc73787ee2006-01-26 16:20:06 -07003431static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303432mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003433{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303434 MPT_ADAPTER *ioc;
3435 EVENT_DATA_RAID *raid_event_data;
3436 struct mptsas_hotplug_event hot_plug_info;
3437 int status;
3438 int state;
3439 struct scsi_device *sdev = NULL;
3440 VirtDevice *vdevice = NULL;
3441 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003442
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303443 ioc = fw_event->ioc;
3444 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
3445 status = le32_to_cpu(raid_event_data->SettingsStatus);
3446 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003447
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303448 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
3449 hot_plug_info.id = raid_event_data->VolumeID;
3450 hot_plug_info.channel = raid_event_data->VolumeBus;
3451 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
3452
3453 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
3454 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
3455 raid_event_data->ReasonCode ==
3456 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
3457 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3458 hot_plug_info.id, 0);
3459 hot_plug_info.sdev = sdev;
3460 if (sdev)
3461 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003462 }
3463
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303464 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
3465 "ReasonCode=%02x\n", ioc->name, __func__,
3466 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07003467
3468 switch (raid_event_data->ReasonCode) {
3469 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303470 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003471 break;
3472 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303473 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003474 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06003475 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
3476 switch (state) {
3477 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07003478 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303479 mpt_raid_phys_disk_pg0(ioc,
3480 raid_event_data->PhysDiskNum, &phys_disk);
3481 hot_plug_info.id = phys_disk.PhysDiskID;
3482 hot_plug_info.channel = phys_disk.PhysDiskBus;
3483 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06003484 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303485 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06003486 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06003487 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
3488 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
3489 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303490 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06003491 break;
3492 default:
3493 break;
3494 }
3495 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003496 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303497 if (!sdev)
3498 break;
3499 vdevice->vtarget->deleted = 1; /* block IO */
3500 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003501 break;
3502 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303503 if (sdev) {
3504 scsi_device_put(sdev);
3505 break;
3506 }
3507 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003508 break;
3509 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303510 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
3511 if (!sdev)
3512 break;
3513 vdevice->vtarget->deleted = 1; /* block IO */
3514 hot_plug_info.event_type = MPTSAS_DEL_RAID;
3515 break;
3516 }
Moore, Ericbd23e942006-04-17 12:43:04 -06003517 switch (state) {
3518 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
3519 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303520 if (!sdev)
3521 break;
3522 vdevice->vtarget->deleted = 1; /* block IO */
3523 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06003524 break;
3525 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
3526 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303527 if (sdev) {
3528 scsi_device_put(sdev);
3529 break;
3530 }
3531 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06003532 break;
3533 default:
3534 break;
3535 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003536 break;
3537 default:
3538 break;
3539 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303540
3541 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
3542 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
3543 else
3544 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003545}
3546
Moore, Erice6b2d762006-03-14 09:14:24 -07003547static void
Eric Moore547f9a22006-06-27 14:42:12 -06003548mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003549 EVENT_DATA_SAS_DISCOVERY *discovery_data)
3550{
3551 struct mptsas_discovery_event *ev;
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303552 u32 discovery_status;
Moore, Erice6b2d762006-03-14 09:14:24 -07003553
3554 /*
3555 * DiscoveryStatus
3556 *
3557 * This flag will be non-zero when firmware
3558 * kicks off discovery, and return to zero
3559 * once its completed.
3560 */
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303561 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
3562 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
3563 if (discovery_status)
Moore, Erice6b2d762006-03-14 09:14:24 -07003564 return;
3565
Eric Moore547f9a22006-06-27 14:42:12 -06003566 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07003567 if (!ev)
3568 return;
David Howellsc4028952006-11-22 14:57:56 +00003569 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07003570 ev->ioc = ioc;
3571 schedule_work(&ev->work);
3572};
3573
Eric Mooreb506ade2007-01-29 09:45:37 -07003574/*
3575 * mptsas_send_ir2_event - handle exposing hidden disk when
3576 * an inactive raid volume is added
3577 *
3578 * @ioc: Pointer to MPT_ADAPTER structure
3579 * @ir2_data
3580 *
3581 */
3582static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303583mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07003584{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303585 MPT_ADAPTER *ioc;
3586 struct mptsas_hotplug_event hot_plug_info;
3587 MPI_EVENT_DATA_IR2 *ir2_data;
3588 u8 reasonCode;
Eric Mooreb506ade2007-01-29 09:45:37 -07003589
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303590 ioc = fw_event->ioc;
3591 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
3592 reasonCode = ir2_data->ReasonCode;
3593
3594 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
3595 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
3596
3597 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
3598 hot_plug_info.id = ir2_data->TargetID;
3599 hot_plug_info.channel = ir2_data->Bus;
3600 switch (reasonCode) {
3601 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
3602 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3603 break;
3604 default:
3605 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07003606 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303607 }
3608 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
3609}
Moore, Erice6b2d762006-03-14 09:14:24 -07003610
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003611static int
3612mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3613{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303614 u32 event = le32_to_cpu(reply->Event);
3615 int sz, event_data_sz;
3616 struct fw_event_work *fw_event;
3617 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003618
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303619 /* events turned off due to host reset or driver unloading */
3620 if (ioc->fw_events_off)
3621 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003622
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303623 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003624 switch (event) {
3625 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303626 {
3627 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
3628 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
3629
3630 if (sas_event_data->ReasonCode ==
3631 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
3632 mptsas_target_reset_queue(ioc, sas_event_data);
3633 return 0;
3634 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003635 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303636 }
3637 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003638 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003639 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3640 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303641 case MPI_EVENT_INTEGRATED_RAID:
3642 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07003643 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303644 case MPI_EVENT_SAS_PHY_LINK_STATUS:
3645 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07003646 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003647 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303648 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003649 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003650
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303651 event_data_sz = ((reply->MsgLength * 4) -
3652 offsetof(EventNotificationReply_t, Data));
3653 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
3654 fw_event = kzalloc(sz, GFP_ATOMIC);
3655 if (!fw_event) {
3656 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
3657 __func__, __LINE__);
3658 return 0;
3659 }
3660 memcpy(fw_event->event_data, reply->Data, event_data_sz);
3661 fw_event->event = event;
3662 fw_event->ioc = ioc;
3663 mptsas_add_fw_event(ioc, fw_event, delay);
3664 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003665}
3666
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003667static int
3668mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3669{
3670 struct Scsi_Host *sh;
3671 MPT_SCSI_HOST *hd;
3672 MPT_ADAPTER *ioc;
3673 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003674 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003675 int numSGE = 0;
3676 int scale;
3677 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003678 int error=0;
3679 int r;
3680
3681 r = mpt_attach(pdev,id);
3682 if (r)
3683 return r;
3684
3685 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303686 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003687 ioc->DoneCtx = mptsasDoneCtx;
3688 ioc->TaskCtx = mptsasTaskCtx;
3689 ioc->InternalCtx = mptsasInternalCtx;
3690
3691 /* Added sanity check on readiness of the MPT adapter.
3692 */
3693 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3694 printk(MYIOC_s_WARN_FMT
3695 "Skipping because it's not operational!\n",
3696 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003697 error = -ENODEV;
3698 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003699 }
3700
3701 if (!ioc->active) {
3702 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3703 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003704 error = -ENODEV;
3705 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003706 }
3707
3708 /* Sanity check - ensure at least 1 port is INITIATOR capable
3709 */
3710 ioc_cap = 0;
3711 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3712 if (ioc->pfacts[ii].ProtocolFlags &
3713 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3714 ioc_cap++;
3715 }
3716
3717 if (!ioc_cap) {
3718 printk(MYIOC_s_WARN_FMT
3719 "Skipping ioc=%p because SCSI Initiator mode "
3720 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003721 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003722 }
3723
3724 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3725 if (!sh) {
3726 printk(MYIOC_s_WARN_FMT
3727 "Unable to register controller with SCSI subsystem\n",
3728 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003729 error = -1;
3730 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003731 }
3732
3733 spin_lock_irqsave(&ioc->FreeQlock, flags);
3734
3735 /* Attach the SCSI Host to the IOC structure
3736 */
3737 ioc->sh = sh;
3738
3739 sh->io_port = 0;
3740 sh->n_io_port = 0;
3741 sh->irq = 0;
3742
3743 /* set 16 byte cdb's */
3744 sh->max_cmd_len = 16;
3745
Eric Moore793955f2007-01-29 09:42:20 -07003746 sh->max_id = ioc->pfacts[0].PortSCSIID;
3747 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003748
3749 sh->transportt = mptsas_transport_template;
3750
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003751 /* Required entry.
3752 */
3753 sh->unique_id = ioc->id;
3754
3755 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003756 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003757 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003758 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003759 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003760
3761 /* Verify that we won't exceed the maximum
3762 * number of chain buffers
3763 * We can optimize: ZZ = req_sz/sizeof(SGE)
3764 * For 32bit SGE's:
3765 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3766 * + (req_sz - 64)/sizeof(SGE)
3767 * A slightly different algorithm is required for
3768 * 64bit SGEs.
3769 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303770 scale = ioc->req_sz/ioc->SGE_size;
3771 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003772 numSGE = (scale - 1) *
3773 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303774 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003775 } else {
3776 numSGE = 1 + (scale - 1) *
3777 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303778 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003779 }
3780
3781 if (numSGE < sh->sg_tablesize) {
3782 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303783 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003784 "Resetting sg_tablesize to %d from %d\n",
3785 ioc->name, numSGE, sh->sg_tablesize));
3786 sh->sg_tablesize = numSGE;
3787 }
3788
Eric Mooree7eae9f2007-09-29 10:15:59 -06003789 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003790 hd->ioc = ioc;
3791
3792 /* SCSI needs scsi_cmnd lookup table!
3793 * (with size equal to req_depth*PtrSz!)
3794 */
Eric Mooree8206382007-09-29 10:16:53 -06003795 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3796 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003797 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06003798 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003799 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003800 }
Eric Mooree8206382007-09-29 10:16:53 -06003801 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003802
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303803 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06003804 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003805
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003806 /* Clear the TM flags
3807 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003808 hd->abortSCpnt = NULL;
3809
3810 /* Clear the pointer used to store
3811 * single-threaded commands, i.e., those
3812 * issued during a bus scan, dv and
3813 * configuration pages.
3814 */
3815 hd->cmdPtr = NULL;
3816
3817 /* Initialize this SCSI Hosts' timers
3818 * To use, set the timer expires field
3819 * and add_timer
3820 */
3821 init_timer(&hd->timer);
3822 hd->timer.data = (unsigned long) hd;
3823 hd->timer.function = mptscsih_timer_expired;
3824
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003825 ioc->sas_data.ptClear = mpt_pt_clear;
3826
Eric Mooredf9e0622007-01-29 09:46:21 -07003827 hd->last_queue_full = 0;
3828 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303829 INIT_LIST_HEAD(&ioc->sas_device_info_list);
3830 mutex_init(&ioc->sas_device_info_mutex);
3831
Eric Mooredf9e0622007-01-29 09:46:21 -07003832 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3833
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003834 if (ioc->sas_data.ptClear==1) {
3835 mptbase_sas_persist_operation(
3836 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3837 }
3838
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003839 error = scsi_add_host(sh, &ioc->pcidev->dev);
3840 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06003841 dprintk(ioc, printk(MYIOC_s_ERR_FMT
3842 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003843 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003844 }
3845
3846 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303847 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003848 return 0;
3849
Eric Moore547f9a22006-06-27 14:42:12 -06003850 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003851
3852 mptscsih_remove(pdev);
3853 return error;
3854}
3855
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303856void
3857mptsas_shutdown(struct pci_dev *pdev)
3858{
3859 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3860
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303861 mptsas_fw_event_off(ioc);
3862 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303863}
3864
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003865static void __devexit mptsas_remove(struct pci_dev *pdev)
3866{
3867 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3868 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003869 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003870
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303871 mptsas_shutdown(pdev);
3872
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303873 mptsas_del_device_components(ioc);
3874
Eric Mooreb506ade2007-01-29 09:45:37 -07003875 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003876 sas_remove_host(ioc->sh);
3877
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003878 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003879 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3880 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003881 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303882 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303883
Eric Moore547f9a22006-06-27 14:42:12 -06003884 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003885 kfree(p);
3886 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003887 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003888
3889 mptscsih_remove(pdev);
3890}
3891
3892static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003893 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003894 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003895 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003896 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003897 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003898 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003899 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003900 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003901 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003902 PCI_ANY_ID, PCI_ANY_ID },
3903 {0} /* Terminating entry */
3904};
3905MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3906
3907
3908static struct pci_driver mptsas_driver = {
3909 .name = "mptsas",
3910 .id_table = mptsas_pci_table,
3911 .probe = mptsas_probe,
3912 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303913 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003914#ifdef CONFIG_PM
3915 .suspend = mptscsih_suspend,
3916 .resume = mptscsih_resume,
3917#endif
3918};
3919
3920static int __init
3921mptsas_init(void)
3922{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303923 int error;
3924
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003925 show_mptmod_ver(my_NAME, my_VERSION);
3926
3927 mptsas_transport_template =
3928 sas_attach_transport(&mptsas_transport_functions);
3929 if (!mptsas_transport_template)
3930 return -ENODEV;
3931
3932 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05303933 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003934 mptsasInternalCtx =
3935 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003936 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05303937 mptsasDeviceResetCtx =
3938 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003939
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303940 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3941 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003942
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303943 error = pci_register_driver(&mptsas_driver);
3944 if (error)
3945 sas_release_transport(mptsas_transport_template);
3946
3947 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003948}
3949
3950static void __exit
3951mptsas_exit(void)
3952{
3953 pci_unregister_driver(&mptsas_driver);
3954 sas_release_transport(mptsas_transport_template);
3955
3956 mpt_reset_deregister(mptsasDoneCtx);
3957 mpt_event_deregister(mptsasDoneCtx);
3958
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003959 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003960 mpt_deregister(mptsasInternalCtx);
3961 mpt_deregister(mptsasTaskCtx);
3962 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05303963 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003964}
3965
3966module_init(mptsas_init);
3967module_exit(mptsas_exit);