blob: 7f2f76f0db3fec9aceb300c6a45f2c03ffc9e9fe [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02008 */
9/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10/*
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; version 2 of the License.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 NO WARRANTY
21 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
22 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
23 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
24 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
25 solely responsible for determining the appropriateness of using and
26 distributing the Program and assumes all risks associated with its
27 exercise of rights under this Agreement, including but not limited to
28 the risks and costs of program errors, damage to or loss of data,
29 programs or equipment, and unavailability or interruption of operations.
30
31 DISCLAIMER OF LIABILITY
32 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
33 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
35 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
38 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
39
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43*/
44/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
45
46#include <linux/module.h>
47#include <linux/kernel.h>
48#include <linux/init.h>
49#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080050#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020051#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060052#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020053
Eric Moore547f9a22006-06-27 14:42:12 -060054#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020055#include <scsi/scsi_cmnd.h>
56#include <scsi/scsi_device.h>
57#include <scsi/scsi_host.h>
58#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060059#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020060
61#include "mptbase.h"
62#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053063#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020064
65
66#define my_NAME "Fusion MPT SAS Host driver"
67#define my_VERSION MPT_LINUX_VERSION_COMMON
68#define MYNAM "mptsas"
69
James Bottomleye8bf3942006-07-11 17:49:34 -040070/*
71 * Reserved channel for integrated raid
72 */
73#define MPTSAS_RAID_CHANNEL 1
74
Christoph Hellwig0c33b272005-09-09 16:27:19 +020075MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020079
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080static int mpt_pt_clear;
81module_param(mpt_pt_clear, int, 0);
82MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060083 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020084 "(default=MPTSCSIH_PT_CLEAR=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
87#define MPTSAS_MAX_LUN (16895)
88static int max_lun = MPTSAS_MAX_LUN;
89module_param(max_lun, int, 0);
90MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
91
Prakash, Sathyaf606f572007-08-14 16:12:53 +053092static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
93static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
95static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053096static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020097
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +053098static void mptsas_firmware_event_work(struct work_struct *work);
99static void mptsas_send_sas_event(struct fw_event_work *fw_event);
100static void mptsas_send_raid_event(struct fw_event_work *fw_event);
101static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
102static void mptsas_parse_device_info(struct sas_identify *identify,
103 struct mptsas_devinfo *device_info);
104static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
105 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
106static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
107 (MPT_ADAPTER *ioc, u64 sas_address);
108static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
109 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
110static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
111 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
112static int mptsas_add_end_device(MPT_ADAPTER *ioc,
113 struct mptsas_phyinfo *phy_info);
114static void mptsas_del_end_device(MPT_ADAPTER *ioc,
115 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530116static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
117static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
118 (MPT_ADAPTER *ioc, u64 sas_address);
119static void mptsas_expander_delete(MPT_ADAPTER *ioc,
120 struct mptsas_portinfo *port_info, u8 force);
121static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200122
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530123static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
124 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200125{
Eric Moore29dd3602007-09-14 18:46:51 -0600126 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
127 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
128 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
129 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
130 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
131 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
132 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
133 ioc->name, phy_data->Port));
134 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
135 ioc->name, phy_data->PortFlags));
136 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
137 ioc->name, phy_data->PhyFlags));
138 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
139 ioc->name, phy_data->NegotiatedLinkRate));
140 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
141 "Controller PHY Device Info=0x%X\n", ioc->name,
142 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
143 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
144 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200145}
146
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530147static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200148{
149 __le64 sas_address;
150
151 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
152
Eric Moore29dd3602007-09-14 18:46:51 -0600153 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
154 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
155 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
156 "Attached Device Handle=0x%X\n", ioc->name,
157 le16_to_cpu(pg0->AttachedDevHandle)));
158 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
159 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
160 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
161 "Attached PHY Identifier=0x%X\n", ioc->name,
162 pg0->AttachedPhyIdentifier));
163 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
164 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
165 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
166 ioc->name, pg0->ProgrammedLinkRate));
167 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
168 ioc->name, pg0->ChangeCount));
169 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
170 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200171}
172
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530173static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200174{
Eric Moore29dd3602007-09-14 18:46:51 -0600175 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
176 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
177 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
178 ioc->name, pg1->InvalidDwordCount));
179 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
180 "Running Disparity Error Count=0x%x\n", ioc->name,
181 pg1->RunningDisparityErrorCount));
182 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
183 "Loss Dword Synch Count=0x%x\n", ioc->name,
184 pg1->LossDwordSynchCount));
185 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
186 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
187 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200188}
189
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530190static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200191{
192 __le64 sas_address;
193
194 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
195
Eric Moore29dd3602007-09-14 18:46:51 -0600196 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
197 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
198 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
199 ioc->name, le16_to_cpu(pg0->DevHandle)));
200 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
201 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
202 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
203 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
204 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
205 ioc->name, le16_to_cpu(pg0->Slot)));
206 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
207 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
208 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
209 ioc->name, pg0->TargetID));
210 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
211 ioc->name, pg0->Bus));
212 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
213 ioc->name, pg0->PhyNum));
214 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
215 ioc->name, le16_to_cpu(pg0->AccessStatus)));
216 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
217 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
218 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
219 ioc->name, le16_to_cpu(pg0->Flags)));
220 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
221 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200222}
223
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530224static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200225{
Eric Moore29dd3602007-09-14 18:46:51 -0600226 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
227 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
228 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
229 ioc->name, pg1->PhysicalPort));
230 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
231 ioc->name, pg1->PhyIdentifier));
232 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
233 ioc->name, pg1->NegotiatedLinkRate));
234 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
235 ioc->name, pg1->ProgrammedLinkRate));
236 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
237 ioc->name, pg1->HwLinkRate));
238 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
239 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
240 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
241 "Attached Device Handle=0x%X\n\n", ioc->name,
242 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200243}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200244
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530245/* inhibit sas firmware event handling */
246static void
247mptsas_fw_event_off(MPT_ADAPTER *ioc)
248{
249 unsigned long flags;
250
251 spin_lock_irqsave(&ioc->fw_event_lock, flags);
252 ioc->fw_events_off = 1;
253 ioc->sas_discovery_quiesce_io = 0;
254 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
255
256}
257
258/* enable sas firmware event handling */
259static void
260mptsas_fw_event_on(MPT_ADAPTER *ioc)
261{
262 unsigned long flags;
263
264 spin_lock_irqsave(&ioc->fw_event_lock, flags);
265 ioc->fw_events_off = 0;
266 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
267}
268
269/* queue a sas firmware event */
270static void
271mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
272 unsigned long delay)
273{
274 unsigned long flags;
275
276 spin_lock_irqsave(&ioc->fw_event_lock, flags);
277 list_add_tail(&fw_event->list, &ioc->fw_event_list);
278 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
279 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
280 ioc->name, __func__, fw_event));
281 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
282 delay);
283 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
284}
285
286/* free memory assoicated to a sas firmware event */
287static void
288mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
289{
290 unsigned long flags;
291
292 spin_lock_irqsave(&ioc->fw_event_lock, flags);
293 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
294 ioc->name, __func__, fw_event));
295 list_del(&fw_event->list);
296 kfree(fw_event);
297 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
298}
299
300/* walk the firmware event queue, and either stop or wait for
301 * outstanding events to complete */
302static void
303mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
304{
305 struct fw_event_work *fw_event, *next;
306 struct mptsas_target_reset_event *target_reset_list, *n;
307 u8 flush_q;
308 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
309
310 /* flush the target_reset_list */
311 if (!list_empty(&hd->target_reset_list)) {
312 list_for_each_entry_safe(target_reset_list, n,
313 &hd->target_reset_list, list) {
314 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
315 "%s: removing target reset for id=%d\n",
316 ioc->name, __func__,
317 target_reset_list->sas_event_data.TargetID));
318 list_del(&target_reset_list->list);
319 kfree(target_reset_list);
320 }
321 }
322
323 if (list_empty(&ioc->fw_event_list) ||
324 !ioc->fw_event_q || in_interrupt())
325 return;
326
327 flush_q = 0;
328 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
329 if (cancel_delayed_work(&fw_event->work))
330 mptsas_free_fw_event(ioc, fw_event);
331 else
332 flush_q = 1;
333 }
334 if (flush_q)
335 flush_workqueue(ioc->fw_event_q);
336}
337
338
Christoph Hellwige3094442006-02-16 13:25:36 +0100339static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
340{
341 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
342 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
343}
344
345static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
346{
347 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
348 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
349}
350
Moore, Erice6b2d762006-03-14 09:14:24 -0700351/*
352 * mptsas_find_portinfo_by_handle
353 *
354 * This function should be called with the sas_topology_mutex already held
355 */
356static struct mptsas_portinfo *
357mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
358{
359 struct mptsas_portinfo *port_info, *rc=NULL;
360 int i;
361
362 list_for_each_entry(port_info, &ioc->sas_topology, list)
363 for (i = 0; i < port_info->num_phys; i++)
364 if (port_info->phy_info[i].identify.handle == handle) {
365 rc = port_info;
366 goto out;
367 }
368 out:
369 return rc;
370}
371
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530372/**
373 * mptsas_find_portinfo_by_sas_address -
374 * @ioc: Pointer to MPT_ADAPTER structure
375 * @handle:
376 *
377 * This function should be called with the sas_topology_mutex already held
378 *
379 **/
380static struct mptsas_portinfo *
381mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
382{
383 struct mptsas_portinfo *port_info, *rc = NULL;
384 int i;
385
386 if (sas_address >= ioc->hba_port_sas_addr &&
387 sas_address < (ioc->hba_port_sas_addr +
388 ioc->hba_port_num_phy))
389 return ioc->hba_port_info;
390
391 mutex_lock(&ioc->sas_topology_mutex);
392 list_for_each_entry(port_info, &ioc->sas_topology, list)
393 for (i = 0; i < port_info->num_phys; i++)
394 if (port_info->phy_info[i].identify.sas_address ==
395 sas_address) {
396 rc = port_info;
397 goto out;
398 }
399 out:
400 mutex_unlock(&ioc->sas_topology_mutex);
401 return rc;
402}
403
Moore, Ericbd23e942006-04-17 12:43:04 -0600404/*
405 * Returns true if there is a scsi end device
406 */
407static inline int
408mptsas_is_end_device(struct mptsas_devinfo * attached)
409{
Eric Moore547f9a22006-06-27 14:42:12 -0600410 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600411 (attached->device_info &
412 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
413 ((attached->device_info &
414 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
415 (attached->device_info &
416 MPI_SAS_DEVICE_INFO_STP_TARGET) |
417 (attached->device_info &
418 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
419 return 1;
420 else
421 return 0;
422}
423
Eric Moore547f9a22006-06-27 14:42:12 -0600424/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600425static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530426mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600427{
428 struct mptsas_portinfo *port_info;
429 struct mptsas_phyinfo *phy_info;
430 u8 i;
431
432 if (!port_details)
433 return;
434
435 port_info = port_details->port_info;
436 phy_info = port_info->phy_info;
437
Eric Moore29dd3602007-09-14 18:46:51 -0600438 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700439 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700440 port_details->num_phys, (unsigned long long)
441 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600442
443 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
444 if(phy_info->port_details != port_details)
445 continue;
446 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530447 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600448 phy_info->port_details = NULL;
449 }
450 kfree(port_details);
451}
452
453static inline struct sas_rphy *
454mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
455{
456 if (phy_info->port_details)
457 return phy_info->port_details->rphy;
458 else
459 return NULL;
460}
461
462static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530463mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600464{
465 if (phy_info->port_details) {
466 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600467 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
468 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600469 }
470
Eric Moore547f9a22006-06-27 14:42:12 -0600471 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600472 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
473 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600474 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
475 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600476 }
Eric Moore547f9a22006-06-27 14:42:12 -0600477}
478
479static inline struct sas_port *
480mptsas_get_port(struct mptsas_phyinfo *phy_info)
481{
482 if (phy_info->port_details)
483 return phy_info->port_details->port;
484 else
485 return NULL;
486}
487
488static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530489mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600490{
491 if (phy_info->port_details)
492 phy_info->port_details->port = port;
493
Eric Moore547f9a22006-06-27 14:42:12 -0600494 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600495 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
496 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600497 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
498 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600499 }
Eric Moore547f9a22006-06-27 14:42:12 -0600500}
501
502static inline struct scsi_target *
503mptsas_get_starget(struct mptsas_phyinfo *phy_info)
504{
505 if (phy_info->port_details)
506 return phy_info->port_details->starget;
507 else
508 return NULL;
509}
510
511static inline void
512mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
513starget)
514{
515 if (phy_info->port_details)
516 phy_info->port_details->starget = starget;
517}
518
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530519/**
520 * mptsas_add_device_component -
521 * @ioc: Pointer to MPT_ADAPTER structure
522 * @channel: fw mapped id's
523 * @id:
524 * @sas_address:
525 * @device_info:
526 *
527 **/
528static void
529mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
530 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
531{
532 struct mptsas_device_info *sas_info, *next;
533 struct scsi_device *sdev;
534 struct scsi_target *starget;
535 struct sas_rphy *rphy;
536
537 /*
538 * Delete all matching devices out of the list
539 */
540 mutex_lock(&ioc->sas_device_info_mutex);
541 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
542 list) {
543 if ((sas_info->sas_address == sas_address ||
544 (sas_info->fw.channel == channel &&
545 sas_info->fw.id == id))) {
546 list_del(&sas_info->list);
547 kfree(sas_info);
548 }
549 }
550
551 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
552 if (!sas_info)
553 goto out;
554
555 /*
556 * Set Firmware mapping
557 */
558 sas_info->fw.id = id;
559 sas_info->fw.channel = channel;
560
561 sas_info->sas_address = sas_address;
562 sas_info->device_info = device_info;
563 sas_info->slot = slot;
564 sas_info->enclosure_logical_id = enclosure_logical_id;
565 INIT_LIST_HEAD(&sas_info->list);
566 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
567
568 /*
569 * Set OS mapping
570 */
571 shost_for_each_device(sdev, ioc->sh) {
572 starget = scsi_target(sdev);
573 rphy = dev_to_rphy(starget->dev.parent);
574 if (rphy->identify.sas_address == sas_address) {
575 sas_info->os.id = starget->id;
576 sas_info->os.channel = starget->channel;
577 }
578 }
579
580 out:
581 mutex_unlock(&ioc->sas_device_info_mutex);
582 return;
583}
584
585/**
586 * mptsas_add_device_component_by_fw -
587 * @ioc: Pointer to MPT_ADAPTER structure
588 * @channel: fw mapped id's
589 * @id:
590 *
591 **/
592static void
593mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
594{
595 struct mptsas_devinfo sas_device;
596 struct mptsas_enclosure enclosure_info;
597 int rc;
598
599 rc = mptsas_sas_device_pg0(ioc, &sas_device,
600 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
601 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
602 (channel << 8) + id);
603 if (rc)
604 return;
605
606 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
607 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
608 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
609 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
610 sas_device.handle_enclosure);
611
612 mptsas_add_device_component(ioc, sas_device.channel,
613 sas_device.id, sas_device.sas_address, sas_device.device_info,
614 sas_device.slot, enclosure_info.enclosure_logical_id);
615}
616
617/**
618 * mptsas_add_device_component_starget -
619 * @ioc: Pointer to MPT_ADAPTER structure
620 * @starget:
621 *
622 **/
623static void
624mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
625 struct scsi_target *starget)
626{
627 VirtTarget *vtarget;
628 struct sas_rphy *rphy;
629 struct mptsas_phyinfo *phy_info = NULL;
630 struct mptsas_enclosure enclosure_info;
631
632 rphy = dev_to_rphy(starget->dev.parent);
633 vtarget = starget->hostdata;
634 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
635 rphy->identify.sas_address);
636 if (!phy_info)
637 return;
638
639 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
640 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
641 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
642 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
643 phy_info->attached.handle_enclosure);
644
645 mptsas_add_device_component(ioc, phy_info->attached.channel,
646 phy_info->attached.id, phy_info->attached.sas_address,
647 phy_info->attached.device_info,
648 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
649}
650
651/**
652 * mptsas_del_device_components - Cleaning the list
653 * @ioc: Pointer to MPT_ADAPTER structure
654 *
655 **/
656static void
657mptsas_del_device_components(MPT_ADAPTER *ioc)
658{
659 struct mptsas_device_info *sas_info, *next;
660
661 mutex_lock(&ioc->sas_device_info_mutex);
662 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
663 list) {
664 list_del(&sas_info->list);
665 kfree(sas_info);
666 }
667 mutex_unlock(&ioc->sas_device_info_mutex);
668}
669
Eric Moore547f9a22006-06-27 14:42:12 -0600670
671/*
672 * mptsas_setup_wide_ports
673 *
674 * Updates for new and existing narrow/wide port configuration
675 * in the sas_topology
676 */
Eric Moore376ac832006-06-29 17:36:26 -0600677static void
Eric Moore547f9a22006-06-27 14:42:12 -0600678mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
679{
680 struct mptsas_portinfo_details * port_details;
681 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
682 u64 sas_address;
683 int i, j;
684
685 mutex_lock(&ioc->sas_topology_mutex);
686
687 phy_info = port_info->phy_info;
688 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
689 if (phy_info->attached.handle)
690 continue;
691 port_details = phy_info->port_details;
692 if (!port_details)
693 continue;
694 if (port_details->num_phys < 2)
695 continue;
696 /*
697 * Removing a phy from a port, letting the last
698 * phy be removed by firmware events.
699 */
Eric Moore29dd3602007-09-14 18:46:51 -0600700 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
701 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700702 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600703 port_details->num_phys--;
704 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
705 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
706 sas_port_delete_phy(port_details->port, phy_info->phy);
707 phy_info->port_details = NULL;
708 }
709
710 /*
711 * Populate and refresh the tree
712 */
713 phy_info = port_info->phy_info;
714 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
715 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600716 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
717 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600718 if (!sas_address)
719 continue;
720 port_details = phy_info->port_details;
721 /*
722 * Forming a port
723 */
724 if (!port_details) {
725 port_details = kzalloc(sizeof(*port_details),
726 GFP_KERNEL);
727 if (!port_details)
728 goto out;
729 port_details->num_phys = 1;
730 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600731 if (phy_info->phy_id < 64 )
732 port_details->phy_bitmask |=
733 (1 << phy_info->phy_id);
734 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600735 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700736 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600737 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600738 phy_info->port_details = port_details;
739 }
740
741 if (i == port_info->num_phys - 1)
742 continue;
743 phy_info_cmp = &port_info->phy_info[i + 1];
744 for (j = i + 1 ; j < port_info->num_phys ; j++,
745 phy_info_cmp++) {
746 if (!phy_info_cmp->attached.sas_address)
747 continue;
748 if (sas_address != phy_info_cmp->attached.sas_address)
749 continue;
750 if (phy_info_cmp->port_details == port_details )
751 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600752 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700753 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600754 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700755 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600756 if (phy_info_cmp->port_details) {
757 port_details->rphy =
758 mptsas_get_rphy(phy_info_cmp);
759 port_details->port =
760 mptsas_get_port(phy_info_cmp);
761 port_details->starget =
762 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600763 port_details->num_phys =
764 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600765 if (!phy_info_cmp->port_details->num_phys)
766 kfree(phy_info_cmp->port_details);
767 } else
768 phy_info_cmp->sas_port_add_phy=1;
769 /*
770 * Adding a phy to a port
771 */
772 phy_info_cmp->port_details = port_details;
773 if (phy_info_cmp->phy_id < 64 )
774 port_details->phy_bitmask |=
775 (1 << phy_info_cmp->phy_id);
776 port_details->num_phys++;
777 }
778 }
779
780 out:
781
Eric Moore547f9a22006-06-27 14:42:12 -0600782 for (i = 0; i < port_info->num_phys; i++) {
783 port_details = port_info->phy_info[i].port_details;
784 if (!port_details)
785 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600786 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700787 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700788 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700789 port_details, i, port_details->num_phys,
790 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600791 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
792 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600793 }
Eric Moore29dd3602007-09-14 18:46:51 -0600794 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600795 mutex_unlock(&ioc->sas_topology_mutex);
796}
797
Eric Mooredf9e0622007-01-29 09:46:21 -0700798/**
799 * csmisas_find_vtarget
800 *
801 * @ioc
802 * @volume_id
803 * @volume_bus
804 *
805 **/
806static VirtTarget *
807mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600808{
Eric Mooredf9e0622007-01-29 09:46:21 -0700809 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600810 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700811 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600812
Eric Mooredf9e0622007-01-29 09:46:21 -0700813 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530814 vdevice = sdev->hostdata;
815 if ((vdevice == NULL) ||
816 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700817 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600818 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530819 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600820 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600821 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700822 return vtarget;
823}
824
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530825static void
826mptsas_queue_device_delete(MPT_ADAPTER *ioc,
827 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
828{
829 struct fw_event_work *fw_event;
830 int sz;
831
832 sz = offsetof(struct fw_event_work, event_data) +
833 sizeof(MpiEventDataSasDeviceStatusChange_t);
834 fw_event = kzalloc(sz, GFP_ATOMIC);
835 if (!fw_event) {
836 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
837 ioc->name, __func__, __LINE__);
838 return;
839 }
840 memcpy(fw_event->event_data, sas_event_data,
841 sizeof(MpiEventDataSasDeviceStatusChange_t));
842 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
843 fw_event->ioc = ioc;
844 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
845}
846
847
Eric Mooredf9e0622007-01-29 09:46:21 -0700848/**
849 * mptsas_target_reset
850 *
851 * Issues TARGET_RESET to end device using handshaking method
852 *
853 * @ioc
854 * @channel
855 * @id
856 *
857 * Returns (1) success
858 * (0) failure
859 *
860 **/
861static int
862mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
863{
864 MPT_FRAME_HDR *mf;
865 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530866 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
867 return 0;
868
Eric Mooredf9e0622007-01-29 09:46:21 -0700869
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530870 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
871 if (mf == NULL) {
872 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530873 "%s, no msg frames @%d!!\n", ioc->name,
874 __func__, __LINE__));
875 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -0700876 }
877
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530878 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
879 ioc->name, mf));
880
Eric Mooredf9e0622007-01-29 09:46:21 -0700881 /* Format the Request
882 */
883 pScsiTm = (SCSITaskMgmt_t *) mf;
884 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
885 pScsiTm->TargetID = id;
886 pScsiTm->Bus = channel;
887 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
888 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
889 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
890
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530891 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700892
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530893 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
894 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
895 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
896
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530897 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700898
899 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530900
901 out_fail:
902
903 mpt_clear_taskmgmt_in_progress_flag(ioc);
904 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -0700905}
906
907/**
908 * mptsas_target_reset_queue
909 *
910 * Receive request for TARGET_RESET after recieving an firmware
911 * event NOT_RESPONDING_EVENT, then put command in link list
912 * and queue if task_queue already in use.
913 *
914 * @ioc
915 * @sas_event_data
916 *
917 **/
918static void
919mptsas_target_reset_queue(MPT_ADAPTER *ioc,
920 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
921{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600922 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700923 VirtTarget *vtarget = NULL;
924 struct mptsas_target_reset_event *target_reset_list;
925 u8 id, channel;
926
927 id = sas_event_data->TargetID;
928 channel = sas_event_data->Bus;
929
930 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
931 return;
932
933 vtarget->deleted = 1; /* block IO */
934
935 target_reset_list = kzalloc(sizeof(*target_reset_list),
936 GFP_ATOMIC);
937 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530938 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
939 "%s, failed to allocate mem @%d..!!\n",
940 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -0700941 return;
942 }
943
944 memcpy(&target_reset_list->sas_event_data, sas_event_data,
945 sizeof(*sas_event_data));
946 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
947
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530948 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -0700949
950 if (mptsas_target_reset(ioc, channel, id)) {
951 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700952 }
953}
954
955/**
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530956 * mptsas_taskmgmt_complete - Completion for TARGET_RESET after
957 * NOT_RESPONDING_EVENT, enable work queue to finish off removing device
958 * from upper layers. then send next TARGET_RESET in the queue.
959 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -0700960 *
961 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530962static int
963mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -0700964{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600965 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700966 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -0700967 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530968 struct mptsas_target_reset_event *target_reset_list;
969 SCSITaskMgmtReply_t *pScsiTmReply;
970
971 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
972 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
973
974 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
975 if (pScsiTmReply) {
976 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
977 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
978 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
979 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
980 "term_cmnds = %d\n", ioc->name,
981 pScsiTmReply->Bus, pScsiTmReply->TargetID,
982 pScsiTmReply->TaskType,
983 le16_to_cpu(pScsiTmReply->IOCStatus),
984 le32_to_cpu(pScsiTmReply->IOCLogInfo),
985 pScsiTmReply->ResponseCode,
986 le32_to_cpu(pScsiTmReply->TerminationCount)));
987
988 if (pScsiTmReply->ResponseCode)
989 mptscsih_taskmgmt_response_code(ioc,
990 pScsiTmReply->ResponseCode);
991 }
992
993 if (pScsiTmReply && (pScsiTmReply->TaskType ==
994 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
995 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
996 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
997 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
998 memcpy(ioc->taskmgmt_cmds.reply, mr,
999 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1000 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1001 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1002 complete(&ioc->taskmgmt_cmds.done);
1003 return 1;
1004 }
1005 return 0;
1006 }
1007
1008 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001009
1010 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301011 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001012
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301013 target_reset_list = list_entry(head->next,
1014 struct mptsas_target_reset_event, list);
1015
1016 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1017 "TaskMgmt: completed (%d seconds)\n",
1018 ioc->name, jiffies_to_msecs(jiffies -
1019 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001020
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301021 id = pScsiTmReply->TargetID;
1022 channel = pScsiTmReply->Bus;
1023 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001024
1025 /*
1026 * retry target reset
1027 */
1028 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301029 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001030 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301031 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001032 }
1033
1034 /*
1035 * enable work queue to remove device from upper layers
1036 */
1037 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301038 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1039 mptsas_queue_device_delete(ioc,
1040 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301041
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301042
Eric Mooredf9e0622007-01-29 09:46:21 -07001043 /*
1044 * issue target reset to next device in the queue
1045 */
1046
1047 head = &hd->target_reset_list;
1048 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301049 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001050
1051 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1052 list);
1053
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301054 id = target_reset_list->sas_event_data.TargetID;
1055 channel = target_reset_list->sas_event_data.Bus;
1056 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001057
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301058 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001059 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001060
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301061 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001062}
1063
1064/**
1065 * mptscsih_ioc_reset
1066 *
1067 * @ioc
1068 * @reset_phase
1069 *
1070 **/
1071static int
1072mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1073{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001074 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001075 int rc;
1076
1077 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301078 if ((ioc->bus_type != SAS) || (!rc))
1079 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001080
Eric Mooree7eae9f2007-09-29 10:15:59 -06001081 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001082 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001083 goto out;
1084
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301085 switch (reset_phase) {
1086 case MPT_IOC_SETUP_RESET:
1087 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1088 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1089 mptsas_fw_event_off(ioc);
1090 break;
1091 case MPT_IOC_PRE_RESET:
1092 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1093 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1094 break;
1095 case MPT_IOC_POST_RESET:
1096 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1097 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1098 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1099 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1100 complete(&ioc->sas_mgmt.done);
1101 }
1102 mptsas_cleanup_fw_event_q(ioc);
1103 mptsas_fw_event_on(ioc);
1104 break;
1105 default:
1106 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001107 }
1108
1109 out:
1110 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001111}
1112
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301113
1114/**
1115 * enum device_state -
1116 * @DEVICE_RETRY: need to retry the TUR
1117 * @DEVICE_ERROR: TUR return error, don't add device
1118 * @DEVICE_READY: device can be added
1119 *
1120 */
1121enum device_state{
1122 DEVICE_RETRY,
1123 DEVICE_ERROR,
1124 DEVICE_READY,
1125};
1126
Christoph Hellwige3094442006-02-16 13:25:36 +01001127static int
Moore, Eric52435432006-03-14 09:14:15 -07001128mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001129 u32 form, u32 form_specific)
1130{
1131 ConfigExtendedPageHeader_t hdr;
1132 CONFIGPARMS cfg;
1133 SasEnclosurePage0_t *buffer;
1134 dma_addr_t dma_handle;
1135 int error;
1136 __le64 le_identifier;
1137
1138 memset(&hdr, 0, sizeof(hdr));
1139 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1140 hdr.PageNumber = 0;
1141 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1142 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1143
1144 cfg.cfghdr.ehdr = &hdr;
1145 cfg.physAddr = -1;
1146 cfg.pageAddr = form + form_specific;
1147 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1148 cfg.dir = 0; /* read */
1149 cfg.timeout = 10;
1150
1151 error = mpt_config(ioc, &cfg);
1152 if (error)
1153 goto out;
1154 if (!hdr.ExtPageLength) {
1155 error = -ENXIO;
1156 goto out;
1157 }
1158
1159 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1160 &dma_handle);
1161 if (!buffer) {
1162 error = -ENOMEM;
1163 goto out;
1164 }
1165
1166 cfg.physAddr = dma_handle;
1167 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1168
1169 error = mpt_config(ioc, &cfg);
1170 if (error)
1171 goto out_free_consistent;
1172
1173 /* save config data */
1174 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1175 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1176 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1177 enclosure->flags = le16_to_cpu(buffer->Flags);
1178 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1179 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1180 enclosure->start_id = buffer->StartTargetID;
1181 enclosure->start_channel = buffer->StartBus;
1182 enclosure->sep_id = buffer->SEPTargetID;
1183 enclosure->sep_channel = buffer->SEPBus;
1184
1185 out_free_consistent:
1186 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1187 buffer, dma_handle);
1188 out:
1189 return error;
1190}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001191
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301192/**
1193 * mptsas_add_end_device - report a new end device to sas transport layer
1194 * @ioc: Pointer to MPT_ADAPTER structure
1195 * @phy_info: decribes attached device
1196 *
1197 * return (0) success (1) failure
1198 *
1199 **/
1200static int
1201mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1202{
1203 struct sas_rphy *rphy;
1204 struct sas_port *port;
1205 struct sas_identify identify;
1206 char *ds = NULL;
1207 u8 fw_id;
1208
1209 if (!phy_info) {
1210 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1211 "%s: exit at line=%d\n", ioc->name,
1212 __func__, __LINE__));
1213 return 1;
1214 }
1215
1216 fw_id = phy_info->attached.id;
1217
1218 if (mptsas_get_rphy(phy_info)) {
1219 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1220 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1221 __func__, fw_id, __LINE__));
1222 return 2;
1223 }
1224
1225 port = mptsas_get_port(phy_info);
1226 if (!port) {
1227 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1228 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1229 __func__, fw_id, __LINE__));
1230 return 3;
1231 }
1232
1233 if (phy_info->attached.device_info &
1234 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1235 ds = "ssp";
1236 if (phy_info->attached.device_info &
1237 MPI_SAS_DEVICE_INFO_STP_TARGET)
1238 ds = "stp";
1239 if (phy_info->attached.device_info &
1240 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1241 ds = "sata";
1242
1243 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1244 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1245 phy_info->attached.channel, phy_info->attached.id,
1246 phy_info->attached.phy_id, (unsigned long long)
1247 phy_info->attached.sas_address);
1248
1249 mptsas_parse_device_info(&identify, &phy_info->attached);
1250 rphy = sas_end_device_alloc(port);
1251 if (!rphy) {
1252 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1253 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1254 __func__, fw_id, __LINE__));
1255 return 5; /* non-fatal: an rphy can be added later */
1256 }
1257
1258 rphy->identify = identify;
1259 if (sas_rphy_add(rphy)) {
1260 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1261 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1262 __func__, fw_id, __LINE__));
1263 sas_rphy_free(rphy);
1264 return 6;
1265 }
1266 mptsas_set_rphy(ioc, phy_info, rphy);
1267 return 0;
1268}
1269
1270/**
1271 * mptsas_del_end_device - report a deleted end device to sas transport
1272 * layer
1273 * @ioc: Pointer to MPT_ADAPTER structure
1274 * @phy_info: decribes attached device
1275 *
1276 **/
1277static void
1278mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1279{
1280 struct sas_rphy *rphy;
1281 struct sas_port *port;
1282 struct mptsas_portinfo *port_info;
1283 struct mptsas_phyinfo *phy_info_parent;
1284 int i;
1285 char *ds = NULL;
1286 u8 fw_id;
1287 u64 sas_address;
1288
1289 if (!phy_info)
1290 return;
1291
1292 fw_id = phy_info->attached.id;
1293 sas_address = phy_info->attached.sas_address;
1294
1295 if (!phy_info->port_details) {
1296 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1297 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1298 __func__, fw_id, __LINE__));
1299 return;
1300 }
1301 rphy = mptsas_get_rphy(phy_info);
1302 if (!rphy) {
1303 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1304 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1305 __func__, fw_id, __LINE__));
1306 return;
1307 }
1308
1309 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1310 || phy_info->attached.device_info
1311 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1312 || phy_info->attached.device_info
1313 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1314 ds = "initiator";
1315 if (phy_info->attached.device_info &
1316 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1317 ds = "ssp";
1318 if (phy_info->attached.device_info &
1319 MPI_SAS_DEVICE_INFO_STP_TARGET)
1320 ds = "stp";
1321 if (phy_info->attached.device_info &
1322 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1323 ds = "sata";
1324
1325 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1326 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1327 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1328 phy_info->attached.id, phy_info->attached.phy_id,
1329 (unsigned long long) sas_address);
1330
1331 port = mptsas_get_port(phy_info);
1332 if (!port) {
1333 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1334 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1335 __func__, fw_id, __LINE__));
1336 return;
1337 }
1338 port_info = phy_info->portinfo;
1339 phy_info_parent = port_info->phy_info;
1340 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1341 if (!phy_info_parent->phy)
1342 continue;
1343 if (phy_info_parent->attached.sas_address !=
1344 sas_address)
1345 continue;
1346 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1347 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1348 ioc->name, phy_info_parent->phy_id,
1349 phy_info_parent->phy);
1350 sas_port_delete_phy(port, phy_info_parent->phy);
1351 }
1352
1353 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1354 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1355 port->port_identifier, (unsigned long long)sas_address);
1356 sas_port_delete(port);
1357 mptsas_set_port(ioc, phy_info, NULL);
1358 mptsas_port_delete(ioc, phy_info->port_details);
1359}
1360
1361struct mptsas_phyinfo *
1362mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1363 struct mptsas_devinfo *sas_device)
1364{
1365 struct mptsas_phyinfo *phy_info;
1366 struct mptsas_portinfo *port_info;
1367 int i;
1368
1369 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1370 sas_device->sas_address);
1371 if (!phy_info)
1372 goto out;
1373 port_info = phy_info->portinfo;
1374 if (!port_info)
1375 goto out;
1376 mutex_lock(&ioc->sas_topology_mutex);
1377 for (i = 0; i < port_info->num_phys; i++) {
1378 if (port_info->phy_info[i].attached.sas_address !=
1379 sas_device->sas_address)
1380 continue;
1381 port_info->phy_info[i].attached.channel = sas_device->channel;
1382 port_info->phy_info[i].attached.id = sas_device->id;
1383 port_info->phy_info[i].attached.sas_address =
1384 sas_device->sas_address;
1385 port_info->phy_info[i].attached.handle = sas_device->handle;
1386 port_info->phy_info[i].attached.handle_parent =
1387 sas_device->handle_parent;
1388 port_info->phy_info[i].attached.handle_enclosure =
1389 sas_device->handle_enclosure;
1390 }
1391 mutex_unlock(&ioc->sas_topology_mutex);
1392 out:
1393 return phy_info;
1394}
1395
1396/**
1397 * mptsas_firmware_event_work - work thread for processing fw events
1398 * @work: work queue payload containing info describing the event
1399 * Context: user
1400 *
1401 */
1402static void
1403mptsas_firmware_event_work(struct work_struct *work)
1404{
1405 struct fw_event_work *fw_event =
1406 container_of(work, struct fw_event_work, work.work);
1407 MPT_ADAPTER *ioc = fw_event->ioc;
1408
1409
1410 /* events handling turned off during host reset */
1411 if (ioc->fw_events_off) {
1412 mptsas_free_fw_event(ioc, fw_event);
1413 return;
1414 }
1415
1416 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1417 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1418 (fw_event->event & 0xFF)));
1419
1420 switch (fw_event->event) {
1421 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1422 mptsas_send_sas_event(fw_event);
1423 break;
1424 case MPI_EVENT_INTEGRATED_RAID:
1425 mptsas_send_raid_event(fw_event);
1426 break;
1427 case MPI_EVENT_IR2:
1428 mptsas_send_ir2_event(fw_event);
1429 break;
1430 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1431 mptbase_sas_persist_operation(ioc,
1432 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1433 mptsas_free_fw_event(ioc, fw_event);
1434 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301435 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1436 mptsas_send_expander_event(fw_event);
1437 break;
1438 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1439 mptsas_send_link_status_event(fw_event);
1440 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301441 }
1442}
1443
1444
1445
James Bottomleyf013db32006-03-18 14:54:36 -06001446static int
1447mptsas_slave_configure(struct scsi_device *sdev)
1448{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301449 struct Scsi_Host *host = sdev->host;
1450 MPT_SCSI_HOST *hd = shost_priv(host);
1451 MPT_ADAPTER *ioc = hd->ioc;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001452
James Bottomleye8bf3942006-07-11 17:49:34 -04001453 if (sdev->channel == MPTSAS_RAID_CHANNEL)
1454 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -06001455
James Bottomleye8bf3942006-07-11 17:49:34 -04001456 sas_read_port_mode_page(sdev);
1457
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301458 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1459
James Bottomleye8bf3942006-07-11 17:49:34 -04001460 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001461 return mptscsih_slave_configure(sdev);
1462}
1463
Eric Moore547f9a22006-06-27 14:42:12 -06001464static int
1465mptsas_target_alloc(struct scsi_target *starget)
1466{
1467 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001468 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001469 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001470 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001471 struct sas_rphy *rphy;
1472 struct mptsas_portinfo *p;
1473 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001474 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001475
1476 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1477 if (!vtarget)
1478 return -ENOMEM;
1479
1480 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001481 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001482 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1483 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001484 channel = 0;
1485
Eric Moore793955f2007-01-29 09:42:20 -07001486 /*
1487 * RAID volumes placed beyond the last expected port.
1488 */
1489 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Eric Mooree80b0022007-09-14 18:49:03 -06001490 for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
1491 if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
1492 channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -06001493 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001494 }
Eric Moore547f9a22006-06-27 14:42:12 -06001495
1496 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001497 mutex_lock(&ioc->sas_topology_mutex);
1498 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001499 for (i = 0; i < p->num_phys; i++) {
1500 if (p->phy_info[i].attached.sas_address !=
1501 rphy->identify.sas_address)
1502 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001503 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001504 channel = p->phy_info[i].attached.channel;
1505 mptsas_set_starget(&p->phy_info[i], starget);
1506
1507 /*
1508 * Exposing hidden raid components
1509 */
Eric Mooree80b0022007-09-14 18:49:03 -06001510 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1511 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001512 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001513 vtarget->tflags |=
1514 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001515 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001516 }
Eric Mooree80b0022007-09-14 18:49:03 -06001517 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001518 goto out;
1519 }
1520 }
Eric Mooree80b0022007-09-14 18:49:03 -06001521 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001522
1523 kfree(vtarget);
1524 return -ENXIO;
1525
1526 out:
Eric Moore793955f2007-01-29 09:42:20 -07001527 vtarget->id = id;
1528 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001529 starget->hostdata = vtarget;
1530 return 0;
1531}
1532
1533static void
1534mptsas_target_destroy(struct scsi_target *starget)
1535{
1536 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001537 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001538 struct sas_rphy *rphy;
1539 struct mptsas_portinfo *p;
1540 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301541 MPT_ADAPTER *ioc = hd->ioc;
1542 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001543
1544 if (!starget->hostdata)
1545 return;
1546
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301547 vtarget = starget->hostdata;
1548
1549
James Bottomleye8bf3942006-07-11 17:49:34 -04001550 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001551 goto out;
1552
1553 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001554 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001555 for (i = 0; i < p->num_phys; i++) {
1556 if (p->phy_info[i].attached.sas_address !=
1557 rphy->identify.sas_address)
1558 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301559
1560 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1561 "delete device: fw_channel %d, fw_id %d, phy %d, "
1562 "sas_addr 0x%llx\n", ioc->name,
1563 p->phy_info[i].attached.channel,
1564 p->phy_info[i].attached.id,
1565 p->phy_info[i].attached.phy_id, (unsigned long long)
1566 p->phy_info[i].attached.sas_address);
1567
Eric Moore547f9a22006-06-27 14:42:12 -06001568 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001569 }
1570 }
1571
1572 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301573 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001574 kfree(starget->hostdata);
1575 starget->hostdata = NULL;
1576}
1577
1578
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001579static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001580mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001581{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001582 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001583 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001584 struct sas_rphy *rphy;
1585 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001586 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001587 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001588 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001589 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001590
Eric Moorea69de502007-09-14 18:48:19 -06001591 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1592 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001593 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001594 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001595 return -ENOMEM;
1596 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001597 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001598 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001599
James Bottomleye8bf3942006-07-11 17:49:34 -04001600 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001601 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001602
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001603 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001604 mutex_lock(&ioc->sas_topology_mutex);
1605 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001606 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001607 if (p->phy_info[i].attached.sas_address !=
1608 rphy->identify.sas_address)
1609 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001610 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001611 /*
1612 * Exposing hidden raid components
1613 */
Eric Mooree80b0022007-09-14 18:49:03 -06001614 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001615 p->phy_info[i].attached.channel,
1616 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001617 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001618 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001619 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001620 }
1621 }
Eric Mooree80b0022007-09-14 18:49:03 -06001622 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001623
Eric Moorea69de502007-09-14 18:48:19 -06001624 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001625 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001626
1627 out:
Eric Moorea69de502007-09-14 18:48:19 -06001628 vdevice->vtarget->num_luns++;
1629 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001630 return 0;
1631}
1632
Eric Moore547f9a22006-06-27 14:42:12 -06001633static int
1634mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001635{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301636 MPT_SCSI_HOST *hd;
1637 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001638 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001639
Eric Moorea69de502007-09-14 18:48:19 -06001640 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001641 SCpnt->result = DID_NO_CONNECT << 16;
1642 done(SCpnt);
1643 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001644 }
Eric Moore547f9a22006-06-27 14:42:12 -06001645
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301646 hd = shost_priv(SCpnt->device->host);
1647 ioc = hd->ioc;
1648
1649 if (ioc->sas_discovery_quiesce_io)
1650 return SCSI_MLQUEUE_HOST_BUSY;
1651
Eric Moore793955f2007-01-29 09:42:20 -07001652// scsi_print_command(SCpnt);
1653
Eric Moore547f9a22006-06-27 14:42:12 -06001654 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001655}
1656
Eric Moore547f9a22006-06-27 14:42:12 -06001657
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001658static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001659 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001660 .proc_name = "mptsas",
1661 .proc_info = mptscsih_proc_info,
1662 .name = "MPT SPI Host",
1663 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001664 .queuecommand = mptsas_qcmd,
1665 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001666 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001667 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001668 .target_destroy = mptsas_target_destroy,
1669 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001670 .change_queue_depth = mptscsih_change_queue_depth,
1671 .eh_abort_handler = mptscsih_abort,
1672 .eh_device_reset_handler = mptscsih_dev_reset,
1673 .eh_bus_reset_handler = mptscsih_bus_reset,
1674 .eh_host_reset_handler = mptscsih_host_reset,
1675 .bios_param = mptscsih_bios_param,
1676 .can_queue = MPT_FC_CAN_QUEUE,
1677 .this_id = -1,
1678 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1679 .max_sectors = 8192,
1680 .cmd_per_lun = 7,
1681 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301682 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001683};
1684
Christoph Hellwigb5141122005-10-28 22:07:41 +02001685static int mptsas_get_linkerrors(struct sas_phy *phy)
1686{
1687 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1688 ConfigExtendedPageHeader_t hdr;
1689 CONFIGPARMS cfg;
1690 SasPhyPage1_t *buffer;
1691 dma_addr_t dma_handle;
1692 int error;
1693
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001694 /* FIXME: only have link errors on local phys */
1695 if (!scsi_is_sas_phy_local(phy))
1696 return -EINVAL;
1697
Christoph Hellwigb5141122005-10-28 22:07:41 +02001698 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1699 hdr.ExtPageLength = 0;
1700 hdr.PageNumber = 1 /* page number 1*/;
1701 hdr.Reserved1 = 0;
1702 hdr.Reserved2 = 0;
1703 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1704 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1705
1706 cfg.cfghdr.ehdr = &hdr;
1707 cfg.physAddr = -1;
1708 cfg.pageAddr = phy->identify.phy_identifier;
1709 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1710 cfg.dir = 0; /* read */
1711 cfg.timeout = 10;
1712
1713 error = mpt_config(ioc, &cfg);
1714 if (error)
1715 return error;
1716 if (!hdr.ExtPageLength)
1717 return -ENXIO;
1718
1719 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1720 &dma_handle);
1721 if (!buffer)
1722 return -ENOMEM;
1723
1724 cfg.physAddr = dma_handle;
1725 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1726
1727 error = mpt_config(ioc, &cfg);
1728 if (error)
1729 goto out_free_consistent;
1730
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301731 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001732
1733 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1734 phy->running_disparity_error_count =
1735 le32_to_cpu(buffer->RunningDisparityErrorCount);
1736 phy->loss_of_dword_sync_count =
1737 le32_to_cpu(buffer->LossDwordSynchCount);
1738 phy->phy_reset_problem_count =
1739 le32_to_cpu(buffer->PhyResetProblemCount);
1740
1741 out_free_consistent:
1742 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1743 buffer, dma_handle);
1744 return error;
1745}
1746
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001747static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1748 MPT_FRAME_HDR *reply)
1749{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301750 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001751 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301752 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001753 memcpy(ioc->sas_mgmt.reply, reply,
1754 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1755 }
1756 complete(&ioc->sas_mgmt.done);
1757 return 1;
1758}
1759
1760static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1761{
1762 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1763 SasIoUnitControlRequest_t *req;
1764 SasIoUnitControlReply_t *reply;
1765 MPT_FRAME_HDR *mf;
1766 MPIHeader_t *hdr;
1767 unsigned long timeleft;
1768 int error = -ERESTARTSYS;
1769
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001770 /* FIXME: fusion doesn't allow non-local phy reset */
1771 if (!scsi_is_sas_phy_local(phy))
1772 return -EINVAL;
1773
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001774 /* not implemented for expanders */
1775 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1776 return -ENXIO;
1777
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001778 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001779 goto out;
1780
1781 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1782 if (!mf) {
1783 error = -ENOMEM;
1784 goto out_unlock;
1785 }
1786
1787 hdr = (MPIHeader_t *) mf;
1788 req = (SasIoUnitControlRequest_t *)mf;
1789 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1790 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1791 req->MsgContext = hdr->MsgContext;
1792 req->Operation = hard_reset ?
1793 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1794 req->PhyNum = phy->identify.phy_identifier;
1795
1796 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1797
1798 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1799 10 * HZ);
1800 if (!timeleft) {
1801 /* On timeout reset the board */
1802 mpt_free_msg_frame(ioc, mf);
1803 mpt_HardResetHandler(ioc, CAN_SLEEP);
1804 error = -ETIMEDOUT;
1805 goto out_unlock;
1806 }
1807
1808 /* a reply frame is expected */
1809 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301810 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001811 error = -ENXIO;
1812 goto out_unlock;
1813 }
1814
1815 /* process the completed Reply Message Frame */
1816 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1817 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001818 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001819 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001820 error = -ENXIO;
1821 goto out_unlock;
1822 }
1823
1824 error = 0;
1825
1826 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001827 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001828 out:
1829 return error;
1830}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001831
Christoph Hellwige3094442006-02-16 13:25:36 +01001832static int
1833mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1834{
1835 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1836 int i, error;
1837 struct mptsas_portinfo *p;
1838 struct mptsas_enclosure enclosure_info;
1839 u64 enclosure_handle;
1840
1841 mutex_lock(&ioc->sas_topology_mutex);
1842 list_for_each_entry(p, &ioc->sas_topology, list) {
1843 for (i = 0; i < p->num_phys; i++) {
1844 if (p->phy_info[i].attached.sas_address ==
1845 rphy->identify.sas_address) {
1846 enclosure_handle = p->phy_info[i].
1847 attached.handle_enclosure;
1848 goto found_info;
1849 }
1850 }
1851 }
1852 mutex_unlock(&ioc->sas_topology_mutex);
1853 return -ENXIO;
1854
1855 found_info:
1856 mutex_unlock(&ioc->sas_topology_mutex);
1857 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001858 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001859 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1860 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1861 if (!error)
1862 *identifier = enclosure_info.enclosure_logical_id;
1863 return error;
1864}
1865
1866static int
1867mptsas_get_bay_identifier(struct sas_rphy *rphy)
1868{
1869 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1870 struct mptsas_portinfo *p;
1871 int i, rc;
1872
1873 mutex_lock(&ioc->sas_topology_mutex);
1874 list_for_each_entry(p, &ioc->sas_topology, list) {
1875 for (i = 0; i < p->num_phys; i++) {
1876 if (p->phy_info[i].attached.sas_address ==
1877 rphy->identify.sas_address) {
1878 rc = p->phy_info[i].attached.slot;
1879 goto out;
1880 }
1881 }
1882 }
1883 rc = -ENXIO;
1884 out:
1885 mutex_unlock(&ioc->sas_topology_mutex);
1886 return rc;
1887}
1888
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001889static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1890 struct request *req)
1891{
1892 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1893 MPT_FRAME_HDR *mf;
1894 SmpPassthroughRequest_t *smpreq;
1895 struct request *rsp = req->next_rq;
1896 int ret;
1897 int flagsLength;
1898 unsigned long timeleft;
1899 char *psge;
1900 dma_addr_t dma_addr_in = 0;
1901 dma_addr_t dma_addr_out = 0;
1902 u64 sas_address = 0;
1903
1904 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06001905 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001906 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001907 return -EINVAL;
1908 }
1909
1910 /* do we need to support multiple segments? */
1911 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06001912 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001913 ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
Eric Moore29dd3602007-09-14 18:46:51 -06001914 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001915 return -EINVAL;
1916 }
1917
1918 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1919 if (ret)
1920 goto out;
1921
1922 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1923 if (!mf) {
1924 ret = -ENOMEM;
1925 goto out_unlock;
1926 }
1927
1928 smpreq = (SmpPassthroughRequest_t *)mf;
1929 memset(smpreq, 0, sizeof(*smpreq));
1930
1931 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1932 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1933
1934 if (rphy)
1935 sas_address = rphy->identify.sas_address;
1936 else {
1937 struct mptsas_portinfo *port_info;
1938
1939 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301940 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001941 if (port_info && port_info->phy_info)
1942 sas_address =
1943 port_info->phy_info[0].phy->identify.sas_address;
1944 mutex_unlock(&ioc->sas_topology_mutex);
1945 }
1946
1947 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1948
1949 psge = (char *)
1950 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1951
1952 /* request */
1953 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1954 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301955 MPI_SGE_FLAGS_DIRECTION)
1956 << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001957 flagsLength |= (req->data_len - 4);
1958
1959 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1960 req->data_len, PCI_DMA_BIDIRECTIONAL);
1961 if (!dma_addr_out)
1962 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301963 ioc->add_sge(psge, flagsLength, dma_addr_out);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001964 psge += (sizeof(u32) + sizeof(dma_addr_t));
1965
1966 /* response */
1967 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1968 flagsLength |= rsp->data_len + 4;
1969 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1970 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1971 if (!dma_addr_in)
1972 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301973 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001974
1975 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1976
1977 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1978 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001979 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001980 /* On timeout reset the board */
1981 mpt_HardResetHandler(ioc, CAN_SLEEP);
1982 ret = -ETIMEDOUT;
1983 goto unmap;
1984 }
1985 mf = NULL;
1986
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301987 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001988 SmpPassthroughReply_t *smprep;
1989
1990 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1991 memcpy(req->sense, smprep, sizeof(*smprep));
1992 req->sense_len = sizeof(*smprep);
FUJITA Tomonori38b31672007-12-30 19:34:52 +09001993 req->data_len = 0;
1994 rsp->data_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001995 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001996 printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001997 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001998 ret = -ENXIO;
1999 }
2000unmap:
2001 if (dma_addr_out)
2002 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
2003 PCI_DMA_BIDIRECTIONAL);
2004 if (dma_addr_in)
2005 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
2006 PCI_DMA_BIDIRECTIONAL);
2007put_mf:
2008 if (mf)
2009 mpt_free_msg_frame(ioc, mf);
2010out_unlock:
2011 mutex_unlock(&ioc->sas_mgmt.mutex);
2012out:
2013 return ret;
2014}
2015
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002016static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002017 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002018 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2019 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002020 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002021 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002022};
2023
2024static struct scsi_transport_template *mptsas_transport_template;
2025
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002026static int
2027mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2028{
2029 ConfigExtendedPageHeader_t hdr;
2030 CONFIGPARMS cfg;
2031 SasIOUnitPage0_t *buffer;
2032 dma_addr_t dma_handle;
2033 int error, i;
2034
2035 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2036 hdr.ExtPageLength = 0;
2037 hdr.PageNumber = 0;
2038 hdr.Reserved1 = 0;
2039 hdr.Reserved2 = 0;
2040 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2041 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2042
2043 cfg.cfghdr.ehdr = &hdr;
2044 cfg.physAddr = -1;
2045 cfg.pageAddr = 0;
2046 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2047 cfg.dir = 0; /* read */
2048 cfg.timeout = 10;
2049
2050 error = mpt_config(ioc, &cfg);
2051 if (error)
2052 goto out;
2053 if (!hdr.ExtPageLength) {
2054 error = -ENXIO;
2055 goto out;
2056 }
2057
2058 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2059 &dma_handle);
2060 if (!buffer) {
2061 error = -ENOMEM;
2062 goto out;
2063 }
2064
2065 cfg.physAddr = dma_handle;
2066 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2067
2068 error = mpt_config(ioc, &cfg);
2069 if (error)
2070 goto out_free_consistent;
2071
2072 port_info->num_phys = buffer->NumPhys;
2073 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06002074 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002075 if (!port_info->phy_info) {
2076 error = -ENOMEM;
2077 goto out_free_consistent;
2078 }
2079
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302080 ioc->nvdata_version_persistent =
2081 le16_to_cpu(buffer->NvdataVersionPersistent);
2082 ioc->nvdata_version_default =
2083 le16_to_cpu(buffer->NvdataVersionDefault);
2084
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002085 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302086 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002087 port_info->phy_info[i].phy_id = i;
2088 port_info->phy_info[i].port_id =
2089 buffer->PhyData[i].Port;
2090 port_info->phy_info[i].negotiated_link_rate =
2091 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002092 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002093 port_info->phy_info[i].handle =
2094 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002095 }
2096
2097 out_free_consistent:
2098 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2099 buffer, dma_handle);
2100 out:
2101 return error;
2102}
2103
2104static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302105mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2106{
2107 ConfigExtendedPageHeader_t hdr;
2108 CONFIGPARMS cfg;
2109 SasIOUnitPage1_t *buffer;
2110 dma_addr_t dma_handle;
2111 int error;
2112 u16 device_missing_delay;
2113
2114 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2115 memset(&cfg, 0, sizeof(CONFIGPARMS));
2116
2117 cfg.cfghdr.ehdr = &hdr;
2118 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2119 cfg.timeout = 10;
2120 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2121 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2122 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2123 cfg.cfghdr.ehdr->PageNumber = 1;
2124
2125 error = mpt_config(ioc, &cfg);
2126 if (error)
2127 goto out;
2128 if (!hdr.ExtPageLength) {
2129 error = -ENXIO;
2130 goto out;
2131 }
2132
2133 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2134 &dma_handle);
2135 if (!buffer) {
2136 error = -ENOMEM;
2137 goto out;
2138 }
2139
2140 cfg.physAddr = dma_handle;
2141 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2142
2143 error = mpt_config(ioc, &cfg);
2144 if (error)
2145 goto out_free_consistent;
2146
2147 ioc->io_missing_delay =
2148 le16_to_cpu(buffer->IODeviceMissingDelay);
2149 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2150 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2151 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2152 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2153
2154 out_free_consistent:
2155 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2156 buffer, dma_handle);
2157 out:
2158 return error;
2159}
2160
2161static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002162mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2163 u32 form, u32 form_specific)
2164{
2165 ConfigExtendedPageHeader_t hdr;
2166 CONFIGPARMS cfg;
2167 SasPhyPage0_t *buffer;
2168 dma_addr_t dma_handle;
2169 int error;
2170
2171 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2172 hdr.ExtPageLength = 0;
2173 hdr.PageNumber = 0;
2174 hdr.Reserved1 = 0;
2175 hdr.Reserved2 = 0;
2176 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2177 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2178
2179 cfg.cfghdr.ehdr = &hdr;
2180 cfg.dir = 0; /* read */
2181 cfg.timeout = 10;
2182
2183 /* Get Phy Pg 0 for each Phy. */
2184 cfg.physAddr = -1;
2185 cfg.pageAddr = form + form_specific;
2186 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2187
2188 error = mpt_config(ioc, &cfg);
2189 if (error)
2190 goto out;
2191
2192 if (!hdr.ExtPageLength) {
2193 error = -ENXIO;
2194 goto out;
2195 }
2196
2197 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2198 &dma_handle);
2199 if (!buffer) {
2200 error = -ENOMEM;
2201 goto out;
2202 }
2203
2204 cfg.physAddr = dma_handle;
2205 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2206
2207 error = mpt_config(ioc, &cfg);
2208 if (error)
2209 goto out_free_consistent;
2210
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302211 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002212
2213 phy_info->hw_link_rate = buffer->HwLinkRate;
2214 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2215 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2216 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2217
2218 out_free_consistent:
2219 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2220 buffer, dma_handle);
2221 out:
2222 return error;
2223}
2224
2225static int
2226mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2227 u32 form, u32 form_specific)
2228{
2229 ConfigExtendedPageHeader_t hdr;
2230 CONFIGPARMS cfg;
2231 SasDevicePage0_t *buffer;
2232 dma_addr_t dma_handle;
2233 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002234 int error=0;
2235
2236 if (ioc->sas_discovery_runtime &&
2237 mptsas_is_end_device(device_info))
2238 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002239
2240 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2241 hdr.ExtPageLength = 0;
2242 hdr.PageNumber = 0;
2243 hdr.Reserved1 = 0;
2244 hdr.Reserved2 = 0;
2245 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2246 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2247
2248 cfg.cfghdr.ehdr = &hdr;
2249 cfg.pageAddr = form + form_specific;
2250 cfg.physAddr = -1;
2251 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2252 cfg.dir = 0; /* read */
2253 cfg.timeout = 10;
2254
Moore, Ericdb9c9172006-03-14 09:14:18 -07002255 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002256 error = mpt_config(ioc, &cfg);
2257 if (error)
2258 goto out;
2259 if (!hdr.ExtPageLength) {
2260 error = -ENXIO;
2261 goto out;
2262 }
2263
2264 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2265 &dma_handle);
2266 if (!buffer) {
2267 error = -ENOMEM;
2268 goto out;
2269 }
2270
2271 cfg.physAddr = dma_handle;
2272 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2273
2274 error = mpt_config(ioc, &cfg);
2275 if (error)
2276 goto out_free_consistent;
2277
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302278 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002279
2280 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002281 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002282 device_info->handle_enclosure =
2283 le16_to_cpu(buffer->EnclosureHandle);
2284 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002285 device_info->phy_id = buffer->PhyNum;
2286 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002287 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002288 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002289 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002290 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2291 device_info->sas_address = le64_to_cpu(sas_address);
2292 device_info->device_info =
2293 le32_to_cpu(buffer->DeviceInfo);
2294
2295 out_free_consistent:
2296 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2297 buffer, dma_handle);
2298 out:
2299 return error;
2300}
2301
2302static int
2303mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2304 u32 form, u32 form_specific)
2305{
2306 ConfigExtendedPageHeader_t hdr;
2307 CONFIGPARMS cfg;
2308 SasExpanderPage0_t *buffer;
2309 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002310 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002311
2312 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2313 hdr.ExtPageLength = 0;
2314 hdr.PageNumber = 0;
2315 hdr.Reserved1 = 0;
2316 hdr.Reserved2 = 0;
2317 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2318 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2319
2320 cfg.cfghdr.ehdr = &hdr;
2321 cfg.physAddr = -1;
2322 cfg.pageAddr = form + form_specific;
2323 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2324 cfg.dir = 0; /* read */
2325 cfg.timeout = 10;
2326
Moore, Ericdb9c9172006-03-14 09:14:18 -07002327 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002328 error = mpt_config(ioc, &cfg);
2329 if (error)
2330 goto out;
2331
2332 if (!hdr.ExtPageLength) {
2333 error = -ENXIO;
2334 goto out;
2335 }
2336
2337 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2338 &dma_handle);
2339 if (!buffer) {
2340 error = -ENOMEM;
2341 goto out;
2342 }
2343
2344 cfg.physAddr = dma_handle;
2345 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2346
2347 error = mpt_config(ioc, &cfg);
2348 if (error)
2349 goto out_free_consistent;
2350
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002351 if (!buffer->NumPhys) {
2352 error = -ENODEV;
2353 goto out_free_consistent;
2354 }
2355
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002356 /* save config data */
2357 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002358 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06002359 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002360 if (!port_info->phy_info) {
2361 error = -ENOMEM;
2362 goto out_free_consistent;
2363 }
2364
Eric Moore2ecce492007-01-29 09:47:08 -07002365 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002366 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002367 port_info->phy_info[i].handle =
2368 le16_to_cpu(buffer->DevHandle);
2369 }
Eric Moore547f9a22006-06-27 14:42:12 -06002370
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002371 out_free_consistent:
2372 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2373 buffer, dma_handle);
2374 out:
2375 return error;
2376}
2377
2378static int
2379mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2380 u32 form, u32 form_specific)
2381{
2382 ConfigExtendedPageHeader_t hdr;
2383 CONFIGPARMS cfg;
2384 SasExpanderPage1_t *buffer;
2385 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002386 int error=0;
2387
2388 if (ioc->sas_discovery_runtime &&
2389 mptsas_is_end_device(&phy_info->attached))
2390 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002391
2392 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2393 hdr.ExtPageLength = 0;
2394 hdr.PageNumber = 1;
2395 hdr.Reserved1 = 0;
2396 hdr.Reserved2 = 0;
2397 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2398 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2399
2400 cfg.cfghdr.ehdr = &hdr;
2401 cfg.physAddr = -1;
2402 cfg.pageAddr = form + form_specific;
2403 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2404 cfg.dir = 0; /* read */
2405 cfg.timeout = 10;
2406
2407 error = mpt_config(ioc, &cfg);
2408 if (error)
2409 goto out;
2410
2411 if (!hdr.ExtPageLength) {
2412 error = -ENXIO;
2413 goto out;
2414 }
2415
2416 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2417 &dma_handle);
2418 if (!buffer) {
2419 error = -ENOMEM;
2420 goto out;
2421 }
2422
2423 cfg.physAddr = dma_handle;
2424 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2425
2426 error = mpt_config(ioc, &cfg);
2427 if (error)
2428 goto out_free_consistent;
2429
2430
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302431 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002432
2433 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002434 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002435 phy_info->port_id = buffer->PhysicalPort;
2436 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2437 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2438 phy_info->hw_link_rate = buffer->HwLinkRate;
2439 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2440 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2441
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002442 out_free_consistent:
2443 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2444 buffer, dma_handle);
2445 out:
2446 return error;
2447}
2448
2449static void
2450mptsas_parse_device_info(struct sas_identify *identify,
2451 struct mptsas_devinfo *device_info)
2452{
2453 u16 protocols;
2454
2455 identify->sas_address = device_info->sas_address;
2456 identify->phy_identifier = device_info->phy_id;
2457
2458 /*
2459 * Fill in Phy Initiator Port Protocol.
2460 * Bits 6:3, more than one bit can be set, fall through cases.
2461 */
2462 protocols = device_info->device_info & 0x78;
2463 identify->initiator_port_protocols = 0;
2464 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2465 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2466 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2467 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2468 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2469 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2470 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2471 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2472
2473 /*
2474 * Fill in Phy Target Port Protocol.
2475 * Bits 10:7, more than one bit can be set, fall through cases.
2476 */
2477 protocols = device_info->device_info & 0x780;
2478 identify->target_port_protocols = 0;
2479 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2480 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2481 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2482 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2483 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2484 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2485 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2486 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2487
2488 /*
2489 * Fill in Attached device type.
2490 */
2491 switch (device_info->device_info &
2492 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2493 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2494 identify->device_type = SAS_PHY_UNUSED;
2495 break;
2496 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2497 identify->device_type = SAS_END_DEVICE;
2498 break;
2499 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2500 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2501 break;
2502 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2503 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2504 break;
2505 }
2506}
2507
2508static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002509 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002510{
Moore, Erice6b2d762006-03-14 09:14:24 -07002511 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002512 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002513 struct sas_port *port;
2514 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002515
Eric Moore547f9a22006-06-27 14:42:12 -06002516 if (!dev) {
2517 error = -ENODEV;
2518 goto out;
2519 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002520
2521 if (!phy_info->phy) {
2522 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002523 if (!phy) {
2524 error = -ENOMEM;
2525 goto out;
2526 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002527 } else
2528 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002529
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002530 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002531
2532 /*
2533 * Set Negotiated link rate.
2534 */
2535 switch (phy_info->negotiated_link_rate) {
2536 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002537 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002538 break;
2539 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002540 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002541 break;
2542 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002543 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002544 break;
2545 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002546 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002547 break;
2548 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2549 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2550 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002551 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002552 break;
2553 }
2554
2555 /*
2556 * Set Max hardware link rate.
2557 */
2558 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2559 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002560 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002561 break;
2562 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002563 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002564 break;
2565 default:
2566 break;
2567 }
2568
2569 /*
2570 * Set Max programmed link rate.
2571 */
2572 switch (phy_info->programmed_link_rate &
2573 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2574 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002575 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002576 break;
2577 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002578 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002579 break;
2580 default:
2581 break;
2582 }
2583
2584 /*
2585 * Set Min hardware link rate.
2586 */
2587 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2588 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002589 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002590 break;
2591 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002592 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002593 break;
2594 default:
2595 break;
2596 }
2597
2598 /*
2599 * Set Min programmed link rate.
2600 */
2601 switch (phy_info->programmed_link_rate &
2602 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2603 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002604 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002605 break;
2606 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002607 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002608 break;
2609 default:
2610 break;
2611 }
2612
Moore, Erice6b2d762006-03-14 09:14:24 -07002613 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002614
Moore, Erice6b2d762006-03-14 09:14:24 -07002615 error = sas_phy_add(phy);
2616 if (error) {
2617 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002618 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002619 }
2620 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002621 }
2622
Eric Moore547f9a22006-06-27 14:42:12 -06002623 if (!phy_info->attached.handle ||
2624 !phy_info->port_details)
2625 goto out;
2626
2627 port = mptsas_get_port(phy_info);
2628 ioc = phy_to_ioc(phy_info->phy);
2629
2630 if (phy_info->sas_port_add_phy) {
2631
2632 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002633 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002634 if (!port) {
2635 error = -ENOMEM;
2636 goto out;
2637 }
2638 error = sas_port_add(port);
2639 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302640 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002641 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002642 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002643 goto out;
2644 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302645 mptsas_set_port(ioc, phy_info, port);
Eric Moore29dd3602007-09-14 18:46:51 -06002646 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooredc22f162006-07-06 11:23:14 -06002647 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002648 ioc->name, port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002649 }
Eric Moore29dd3602007-09-14 18:46:51 -06002650 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
2651 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002652 sas_port_add_phy(port, phy_info->phy);
2653 phy_info->sas_port_add_phy = 0;
2654 }
2655
2656 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002657
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002658 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002659 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002660 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002661
James Bottomley2686de22006-06-30 12:54:02 -05002662 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002663 /*
2664 * Let the hotplug_work thread handle processing
2665 * the adding/removing of devices that occur
2666 * after start of day.
2667 */
2668 if (ioc->sas_discovery_runtime &&
2669 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002670 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002671
James Bottomleyf013db32006-03-18 14:54:36 -06002672 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002673 if (scsi_is_host_device(parent)) {
2674 struct mptsas_portinfo *port_info;
2675 int i;
2676
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302677 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05002678
2679 for (i = 0; i < port_info->num_phys; i++)
2680 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002681 identify.sas_address) {
2682 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002683 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002684 }
James Bottomley2686de22006-06-30 12:54:02 -05002685
2686 } else if (scsi_is_sas_rphy(parent)) {
2687 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2688 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002689 parent_rphy->identify.sas_address) {
2690 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002691 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002692 }
James Bottomley2686de22006-06-30 12:54:02 -05002693 }
2694
James Bottomleyf013db32006-03-18 14:54:36 -06002695 switch (identify.device_type) {
2696 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002697 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002698 break;
2699 case SAS_EDGE_EXPANDER_DEVICE:
2700 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002701 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002702 break;
2703 default:
2704 rphy = NULL;
2705 break;
2706 }
Eric Moore547f9a22006-06-27 14:42:12 -06002707 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302708 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002709 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002710 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002711 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002712 }
2713
Eric Moore547f9a22006-06-27 14:42:12 -06002714 rphy->identify = identify;
2715 error = sas_rphy_add(rphy);
2716 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302717 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002718 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002719 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002720 sas_rphy_free(rphy);
2721 goto out;
2722 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302723 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002724 }
2725
Eric Moore547f9a22006-06-27 14:42:12 -06002726 out:
2727 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002728}
2729
2730static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002731mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002732{
Moore, Erice6b2d762006-03-14 09:14:24 -07002733 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002734 int error = -ENOMEM, i;
2735
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302736 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07002737 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002738 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002739
Moore, Erice6b2d762006-03-14 09:14:24 -07002740 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002741 if (error)
2742 goto out_free_port_info;
2743
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302744 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002745 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302746 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07002747 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302748 ioc->hba_port_info = port_info = hba;
2749 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07002750 list_add_tail(&port_info->list, &ioc->sas_topology);
2751 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002752 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002753 port_info->phy_info[i].negotiated_link_rate =
2754 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002755 port_info->phy_info[i].handle =
2756 hba->phy_info[i].handle;
2757 port_info->phy_info[i].port_id =
2758 hba->phy_info[i].port_id;
2759 }
Eric Moore547f9a22006-06-27 14:42:12 -06002760 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002761 kfree(hba);
2762 hba = NULL;
2763 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002764 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302765#if defined(CPQ_CIM)
2766 ioc->num_ports = port_info->num_phys;
2767#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002768 for (i = 0; i < port_info->num_phys; i++) {
2769 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2770 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2771 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302772 port_info->phy_info[i].identify.handle =
2773 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002774 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002775 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2776 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302777 port_info->phy_info[i].identify.handle);
2778 if (!ioc->hba_port_sas_addr)
2779 ioc->hba_port_sas_addr =
2780 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02002781 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002782 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002783 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002784 mptsas_sas_device_pg0(ioc,
2785 &port_info->phy_info[i].attached,
2786 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2787 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2788 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002789 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002790
Eric Moore547f9a22006-06-27 14:42:12 -06002791 mptsas_setup_wide_ports(ioc, port_info);
2792
2793 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002794 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002795 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002796
2797 return 0;
2798
2799 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002800 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002801 out:
2802 return error;
2803}
2804
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302805static void
2806mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002807{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302808 struct mptsas_portinfo *parent;
2809 struct device *parent_dev;
2810 struct sas_rphy *rphy;
2811 int i;
2812 u64 sas_address; /* expander sas address */
2813 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002814
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302815 handle = port_info->phy_info[0].handle;
2816 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002817 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002818 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302819 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2820 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002821
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302822 mptsas_sas_device_pg0(ioc,
2823 &port_info->phy_info[i].identify,
2824 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2825 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2826 port_info->phy_info[i].identify.handle);
2827 port_info->phy_info[i].identify.phy_id =
2828 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002829
2830 if (port_info->phy_info[i].attached.handle) {
2831 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302832 &port_info->phy_info[i].attached,
2833 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2834 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2835 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002836 port_info->phy_info[i].attached.phy_id =
2837 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002838 }
Eric Moore547f9a22006-06-27 14:42:12 -06002839 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002840
Moore, Erice6b2d762006-03-14 09:14:24 -07002841 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302842 parent = mptsas_find_portinfo_by_handle(ioc,
2843 port_info->phy_info[0].identify.handle_parent);
2844 if (!parent) {
2845 mutex_unlock(&ioc->sas_topology_mutex);
2846 return;
2847 }
2848 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
2849 i++) {
2850 if (parent->phy_info[i].attached.sas_address == sas_address) {
2851 rphy = mptsas_get_rphy(&parent->phy_info[i]);
2852 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07002853 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002854 }
2855 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302856
2857 mptsas_setup_wide_ports(ioc, port_info);
2858 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
2859 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
2860 ioc->sas_index, 0);
2861}
2862
2863static void
2864mptsas_expander_event_add(MPT_ADAPTER *ioc,
2865 MpiEventDataSasExpanderStatusChange_t *expander_data)
2866{
2867 struct mptsas_portinfo *port_info;
2868 int i;
2869 __le64 sas_address;
2870
2871 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
2872 if (!port_info)
2873 BUG();
2874 port_info->num_phys = (expander_data->NumPhys) ?
2875 expander_data->NumPhys : 1;
2876 port_info->phy_info = kcalloc(port_info->num_phys,
2877 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
2878 if (!port_info->phy_info)
2879 BUG();
2880 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
2881 for (i = 0; i < port_info->num_phys; i++) {
2882 port_info->phy_info[i].portinfo = port_info;
2883 port_info->phy_info[i].handle =
2884 le16_to_cpu(expander_data->DevHandle);
2885 port_info->phy_info[i].identify.sas_address =
2886 le64_to_cpu(sas_address);
2887 port_info->phy_info[i].identify.handle_parent =
2888 le16_to_cpu(expander_data->ParentDevHandle);
2889 }
2890
2891 mutex_lock(&ioc->sas_topology_mutex);
2892 list_add_tail(&port_info->list, &ioc->sas_topology);
2893 mutex_unlock(&ioc->sas_topology_mutex);
2894
2895 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
2896 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
2897 (unsigned long long)sas_address);
2898
2899 mptsas_expander_refresh(ioc, port_info);
2900}
2901
2902/**
2903 * mptsas_delete_expander_siblings - remove siblings attached to expander
2904 * @ioc: Pointer to MPT_ADAPTER structure
2905 * @parent: the parent port_info object
2906 * @expander: the expander port_info object
2907 **/
2908static void
2909mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
2910 *parent, struct mptsas_portinfo *expander)
2911{
2912 struct mptsas_phyinfo *phy_info;
2913 struct mptsas_portinfo *port_info;
2914 struct sas_rphy *rphy;
2915 int i;
2916
2917 phy_info = expander->phy_info;
2918 for (i = 0; i < expander->num_phys; i++, phy_info++) {
2919 rphy = mptsas_get_rphy(phy_info);
2920 if (!rphy)
2921 continue;
2922 if (rphy->identify.device_type == SAS_END_DEVICE)
2923 mptsas_del_end_device(ioc, phy_info);
2924 }
2925
2926 phy_info = expander->phy_info;
2927 for (i = 0; i < expander->num_phys; i++, phy_info++) {
2928 rphy = mptsas_get_rphy(phy_info);
2929 if (!rphy)
2930 continue;
2931 if (rphy->identify.device_type ==
2932 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
2933 rphy->identify.device_type ==
2934 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
2935 port_info = mptsas_find_portinfo_by_sas_address(ioc,
2936 rphy->identify.sas_address);
2937 if (!port_info)
2938 continue;
2939 if (port_info == parent) /* backlink rphy */
2940 continue;
2941 /*
2942 Delete this expander even if the expdevpage is exists
2943 because the parent expander is already deleted
2944 */
2945 mptsas_expander_delete(ioc, port_info, 1);
2946 }
2947 }
2948}
2949
2950
2951/**
2952 * mptsas_expander_delete - remove this expander
2953 * @ioc: Pointer to MPT_ADAPTER structure
2954 * @port_info: expander port_info struct
2955 * @force: Flag to forcefully delete the expander
2956 *
2957 **/
2958
2959static void mptsas_expander_delete(MPT_ADAPTER *ioc,
2960 struct mptsas_portinfo *port_info, u8 force)
2961{
2962
2963 struct mptsas_portinfo *parent;
2964 int i;
2965 u64 expander_sas_address;
2966 struct mptsas_phyinfo *phy_info;
2967 struct mptsas_portinfo buffer;
2968 struct mptsas_portinfo_details *port_details;
2969 struct sas_port *port;
2970
2971 if (!port_info)
2972 return;
2973
2974 /* see if expander is still there before deleting */
2975 mptsas_sas_expander_pg0(ioc, &buffer,
2976 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
2977 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2978 port_info->phy_info[0].identify.handle);
2979
2980 if (buffer.num_phys) {
2981 kfree(buffer.phy_info);
2982 if (!force)
2983 return;
2984 }
2985
2986
2987 /*
2988 * Obtain the port_info instance to the parent port
2989 */
2990 port_details = NULL;
2991 expander_sas_address =
2992 port_info->phy_info[0].identify.sas_address;
2993 parent = mptsas_find_portinfo_by_handle(ioc,
2994 port_info->phy_info[0].identify.handle_parent);
2995 mptsas_delete_expander_siblings(ioc, parent, port_info);
2996 if (!parent)
2997 goto out;
2998
2999 /*
3000 * Delete rphys in the parent that point
3001 * to this expander.
3002 */
3003 phy_info = parent->phy_info;
3004 port = NULL;
3005 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3006 if (!phy_info->phy)
3007 continue;
3008 if (phy_info->attached.sas_address !=
3009 expander_sas_address)
3010 continue;
3011 if (!port) {
3012 port = mptsas_get_port(phy_info);
3013 port_details = phy_info->port_details;
3014 }
3015 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3016 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3017 phy_info->phy_id, phy_info->phy);
3018 sas_port_delete_phy(port, phy_info->phy);
3019 }
3020 if (port) {
3021 dev_printk(KERN_DEBUG, &port->dev,
3022 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3023 ioc->name, port->port_identifier,
3024 (unsigned long long)expander_sas_address);
3025 sas_port_delete(port);
3026 mptsas_port_delete(ioc, port_details);
3027 }
3028 out:
3029
3030 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3031 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3032 (unsigned long long)expander_sas_address);
3033
3034 /*
3035 * free link
3036 */
3037 list_del(&port_info->list);
3038 kfree(port_info->phy_info);
3039 kfree(port_info);
3040}
3041
3042
3043/**
3044 * mptsas_send_expander_event - expanders events
3045 * @ioc: Pointer to MPT_ADAPTER structure
3046 * @expander_data: event data
3047 *
3048 *
3049 * This function handles adding, removing, and refreshing
3050 * device handles within the expander objects.
3051 */
3052static void
3053mptsas_send_expander_event(struct fw_event_work *fw_event)
3054{
3055 MPT_ADAPTER *ioc;
3056 MpiEventDataSasExpanderStatusChange_t *expander_data;
3057 struct mptsas_portinfo *port_info;
3058 __le64 sas_address;
3059 int i;
3060
3061 ioc = fw_event->ioc;
3062 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3063 fw_event->event_data;
3064 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3065 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3066
3067 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3068 if (port_info) {
3069 for (i = 0; i < port_info->num_phys; i++) {
3070 port_info->phy_info[i].portinfo = port_info;
3071 port_info->phy_info[i].handle =
3072 le16_to_cpu(expander_data->DevHandle);
3073 port_info->phy_info[i].identify.sas_address =
3074 le64_to_cpu(sas_address);
3075 port_info->phy_info[i].identify.handle_parent =
3076 le16_to_cpu(expander_data->ParentDevHandle);
3077 }
3078 mptsas_expander_refresh(ioc, port_info);
3079 } else if (!port_info && expander_data->NumPhys)
3080 mptsas_expander_event_add(ioc, expander_data);
3081 } else if (expander_data->ReasonCode ==
3082 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3083 mptsas_expander_delete(ioc, port_info, 0);
3084
3085 mptsas_free_fw_event(ioc, fw_event);
3086}
3087
3088
3089/**
3090 * mptsas_expander_add -
3091 * @ioc: Pointer to MPT_ADAPTER structure
3092 * @handle:
3093 *
3094 */
3095struct mptsas_portinfo *
3096mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3097{
3098 struct mptsas_portinfo buffer, *port_info;
3099 int i;
3100
3101 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3102 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3103 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3104 return NULL;
3105
3106 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3107 if (!port_info) {
3108 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3109 "%s: exit at line=%d\n", ioc->name,
3110 __func__, __LINE__));
3111 return NULL;
3112 }
3113 port_info->num_phys = buffer.num_phys;
3114 port_info->phy_info = buffer.phy_info;
3115 for (i = 0; i < port_info->num_phys; i++)
3116 port_info->phy_info[i].portinfo = port_info;
3117 mutex_lock(&ioc->sas_topology_mutex);
3118 list_add_tail(&port_info->list, &ioc->sas_topology);
3119 mutex_unlock(&ioc->sas_topology_mutex);
3120 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3121 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3122 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3123 mptsas_expander_refresh(ioc, port_info);
3124 return port_info;
3125}
3126
3127static void
3128mptsas_send_link_status_event(struct fw_event_work *fw_event)
3129{
3130 MPT_ADAPTER *ioc;
3131 MpiEventDataSasPhyLinkStatus_t *link_data;
3132 struct mptsas_portinfo *port_info;
3133 struct mptsas_phyinfo *phy_info = NULL;
3134 __le64 sas_address;
3135 u8 phy_num;
3136 u8 link_rate;
3137
3138 ioc = fw_event->ioc;
3139 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3140
3141 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3142 sas_address = le64_to_cpu(sas_address);
3143 link_rate = link_data->LinkRates >> 4;
3144 phy_num = link_data->PhyNum;
3145
3146 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3147 if (port_info) {
3148 phy_info = &port_info->phy_info[phy_num];
3149 if (phy_info)
3150 phy_info->negotiated_link_rate = link_rate;
3151 }
3152
3153 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3154 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3155
3156 if (!port_info)
3157 goto out;
3158
3159 if (port_info == ioc->hba_port_info)
3160 mptsas_probe_hba_phys(ioc);
3161 else
3162 mptsas_expander_refresh(ioc, port_info);
3163 } else if (phy_info && phy_info->phy) {
3164 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3165 phy_info->phy->negotiated_linkrate =
3166 SAS_PHY_DISABLED;
3167 else if (link_rate ==
3168 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3169 phy_info->phy->negotiated_linkrate =
3170 SAS_LINK_RATE_FAILED;
3171 else
3172 phy_info->phy->negotiated_linkrate =
3173 SAS_LINK_RATE_UNKNOWN;
3174 }
3175 out:
3176 mptsas_free_fw_event(ioc, fw_event);
3177}
3178
3179/**
3180 * mptsas_probe_expanders - adding expanders
3181 * @ioc: Pointer to MPT_ADAPTER structure
3182 *
3183 **/
3184static void
3185mptsas_probe_expanders(MPT_ADAPTER *ioc)
3186{
3187 struct mptsas_portinfo buffer, *port_info;
3188 u32 handle;
3189 int i;
3190
3191 handle = 0xFFFF;
3192 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3193 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3194 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3195
3196 handle = buffer.phy_info[0].handle;
3197 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3198 buffer.phy_info[0].identify.sas_address);
3199
3200 if (port_info) {
3201 /* refreshing handles */
3202 for (i = 0; i < buffer.num_phys; i++) {
3203 port_info->phy_info[i].handle = handle;
3204 port_info->phy_info[i].identify.handle_parent =
3205 buffer.phy_info[0].identify.handle_parent;
3206 }
3207 mptsas_expander_refresh(ioc, port_info);
3208 kfree(buffer.phy_info);
3209 continue;
3210 }
3211
3212 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3213 if (!port_info) {
3214 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3215 "%s: exit at line=%d\n", ioc->name,
3216 __func__, __LINE__));
3217 return;
3218 }
3219 port_info->num_phys = buffer.num_phys;
3220 port_info->phy_info = buffer.phy_info;
3221 for (i = 0; i < port_info->num_phys; i++)
3222 port_info->phy_info[i].portinfo = port_info;
3223 mutex_lock(&ioc->sas_topology_mutex);
3224 list_add_tail(&port_info->list, &ioc->sas_topology);
3225 mutex_unlock(&ioc->sas_topology_mutex);
3226 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3227 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3228 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3229 mptsas_expander_refresh(ioc, port_info);
3230 }
3231}
3232
3233static void
3234mptsas_probe_devices(MPT_ADAPTER *ioc)
3235{
3236 u16 handle;
3237 struct mptsas_devinfo sas_device;
3238 struct mptsas_phyinfo *phy_info;
3239
3240 handle = 0xFFFF;
3241 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3242 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3243
3244 handle = sas_device.handle;
3245
3246 if ((sas_device.device_info &
3247 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3248 MPI_SAS_DEVICE_INFO_STP_TARGET |
3249 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3250 continue;
3251
3252 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3253 if (!phy_info)
3254 continue;
3255
3256 if (mptsas_get_rphy(phy_info))
3257 continue;
3258
3259 mptsas_add_end_device(ioc, phy_info);
3260 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003261}
3262
3263/*
3264 * Start of day discovery
3265 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003266static void
3267mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3268{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303269 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003270 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003271
Moore, Erice6b2d762006-03-14 09:14:24 -07003272 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303273 mptsas_probe_expanders(ioc);
3274 mptsas_probe_devices(ioc);
3275
Moore, Ericf44e5462006-03-14 09:14:21 -07003276 /*
3277 Reporting RAID volumes.
3278 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303279 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3280 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3281 return;
Eric Moore793955f2007-01-29 09:42:20 -07003282 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303283 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3284 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3285 if (sdev) {
3286 scsi_device_put(sdev);
3287 continue;
3288 }
3289 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3290 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3291 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003292 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003293 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3294 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003295}
3296
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003297static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003298mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003299{
3300 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003301 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003302 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003303
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003304 mutex_lock(&ioc->sas_topology_mutex);
3305 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3306 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003307 if (!mptsas_is_end_device(
3308 &port_info->phy_info[i].attached))
3309 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003310 if (port_info->phy_info[i].attached.sas_address
3311 != sas_address)
3312 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003313 phy_info = &port_info->phy_info[i];
3314 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003315 }
3316 }
3317 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003318 return phy_info;
3319}
3320
Eric Mooreb506ade2007-01-29 09:45:37 -07003321
3322static struct mptsas_phyinfo *
3323mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
3324{
3325 struct mptsas_portinfo *port_info;
3326 struct mptsas_phyinfo *phy_info = NULL;
3327 int i;
3328
3329 mutex_lock(&ioc->sas_topology_mutex);
3330 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3331 for (i = 0; i < port_info->num_phys; i++) {
3332 if (!mptsas_is_end_device(
3333 &port_info->phy_info[i].attached))
3334 continue;
3335 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
3336 continue;
3337 if (port_info->phy_info[i].attached.phys_disk_num != id)
3338 continue;
3339 if (port_info->phy_info[i].attached.channel != channel)
3340 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003341 phy_info = &port_info->phy_info[i];
3342 break;
3343 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003344 }
3345 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003346 return phy_info;
3347}
3348
3349static void
Moore, Ericf44e5462006-03-14 09:14:21 -07003350mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
3351{
Eric Mooref99be432007-01-04 20:46:54 -07003352 int rc;
3353
Moore, Ericf44e5462006-03-14 09:14:21 -07003354 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07003355 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07003356}
3357
3358static void
3359mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
3360{
3361 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
3362 mptsas_reprobe_lun);
3363}
3364
Eric Mooreb506ade2007-01-29 09:45:37 -07003365static void
3366mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
3367{
3368 CONFIGPARMS cfg;
3369 ConfigPageHeader_t hdr;
3370 dma_addr_t dma_handle;
3371 pRaidVolumePage0_t buffer = NULL;
3372 RaidPhysDiskPage0_t phys_disk;
3373 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303374 struct mptsas_phyinfo *phy_info;
3375 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07003376
3377 memset(&cfg, 0 , sizeof(CONFIGPARMS));
3378 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
3379 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
3380 cfg.pageAddr = (channel << 8) + id;
3381 cfg.cfghdr.hdr = &hdr;
3382 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3383
3384 if (mpt_config(ioc, &cfg) != 0)
3385 goto out;
3386
3387 if (!hdr.PageLength)
3388 goto out;
3389
3390 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
3391 &dma_handle);
3392
3393 if (!buffer)
3394 goto out;
3395
3396 cfg.physAddr = dma_handle;
3397 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3398
3399 if (mpt_config(ioc, &cfg) != 0)
3400 goto out;
3401
3402 if (!(buffer->VolumeStatus.Flags &
3403 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
3404 goto out;
3405
3406 if (!buffer->NumPhysDisks)
3407 goto out;
3408
3409 for (i = 0; i < buffer->NumPhysDisks; i++) {
3410
3411 if (mpt_raid_phys_disk_pg0(ioc,
3412 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
3413 continue;
3414
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303415 if (mptsas_sas_device_pg0(ioc, &sas_device,
3416 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3417 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3418 (phys_disk.PhysDiskBus << 8) +
3419 phys_disk.PhysDiskID))
3420 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003421
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303422 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3423 sas_device.sas_address);
3424 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07003425 }
3426
3427 out:
3428 if (buffer)
3429 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
3430 dma_handle);
3431}
Moore, Erice6b2d762006-03-14 09:14:24 -07003432/*
3433 * Work queue thread to handle SAS hotplug events
3434 */
Moore, Ericf44e5462006-03-14 09:14:21 -07003435static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303436mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
3437 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003438{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003439 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06003440 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003441 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07003442 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303443 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06003444
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303445 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003446
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303447 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07003448
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303449 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07003450 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003451
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303452 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
3453 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
3454 hot_plug_info->id) {
3455 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
3456 "to add hidden disk - target_id matchs "
3457 "volume_id\n", ioc->name);
3458 mptsas_free_fw_event(ioc, fw_event);
3459 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07003460 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003461 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303462 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003463
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003464 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303465 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
3466 mptsas_sas_device_pg0(ioc, &sas_device,
3467 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3468 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3469 (hot_plug_info->channel << 8) +
3470 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003471
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303472 if (!sas_device.handle)
3473 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06003474
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303475 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3476 if (!phy_info)
3477 break;
3478
3479 if (mptsas_get_rphy(phy_info))
3480 break;
3481
3482 mptsas_add_end_device(ioc, phy_info);
3483 break;
3484
3485 case MPTSAS_DEL_DEVICE:
3486 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3487 hot_plug_info->sas_address);
3488 mptsas_del_end_device(ioc, phy_info);
3489 break;
3490
3491 case MPTSAS_DEL_PHYSDISK:
3492
3493 mpt_findImVolumes(ioc);
3494
3495 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
3496 ioc, hot_plug_info->channel,
3497 hot_plug_info->phys_disk_num);
3498 mptsas_del_end_device(ioc, phy_info);
3499 break;
3500
3501 case MPTSAS_ADD_PHYSDISK_REPROBE:
3502
Christoph Hellwige3094442006-02-16 13:25:36 +01003503 if (mptsas_sas_device_pg0(ioc, &sas_device,
3504 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07003505 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303506 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
3507 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3508 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3509 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01003510 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07003511 }
3512
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303513 phy_info = mptsas_find_phyinfo_by_sas_address(
3514 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07003515
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303516 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303517 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303518 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3519 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003520 break;
3521 }
3522
3523 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303524 if (!starget) {
3525 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3526 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3527 __func__, hot_plug_info->id, __LINE__));
3528 break;
3529 }
Eric Mooreb506ade2007-01-29 09:45:37 -07003530
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303531 vtarget = starget->hostdata;
3532 if (!vtarget) {
3533 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3534 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3535 __func__, hot_plug_info->id, __LINE__));
3536 break;
3537 }
Eric Moore547f9a22006-06-27 14:42:12 -06003538
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303539 mpt_findImVolumes(ioc);
3540
3541 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
3542 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
3543 ioc->name, hot_plug_info->channel, hot_plug_info->id,
3544 hot_plug_info->phys_disk_num, (unsigned long long)
3545 sas_device.sas_address);
3546
3547 vtarget->id = hot_plug_info->phys_disk_num;
3548 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
3549 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
3550 mptsas_reprobe_target(starget, 1);
3551 break;
3552
3553 case MPTSAS_DEL_PHYSDISK_REPROBE:
3554
3555 if (mptsas_sas_device_pg0(ioc, &sas_device,
3556 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3557 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3558 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303559 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303560 "%s: fw_id=%d exit at line=%d\n",
3561 ioc->name, __func__,
3562 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003563 break;
3564 }
3565
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303566 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3567 sas_device.sas_address);
3568 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303569 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303570 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3571 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003572 break;
Eric Moore547f9a22006-06-27 14:42:12 -06003573 }
Eric Mooreb506ade2007-01-29 09:45:37 -07003574
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303575 starget = mptsas_get_starget(phy_info);
3576 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303577 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303578 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3579 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003580 break;
3581 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003582
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303583 vtarget = starget->hostdata;
3584 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303585 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303586 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3587 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003588 break;
3589 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303590
3591 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
3592 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3593 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3594 __func__, hot_plug_info->id, __LINE__));
3595 break;
3596 }
3597
3598 mpt_findImVolumes(ioc);
3599
3600 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
3601 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
3602 ioc->name, hot_plug_info->channel, hot_plug_info->id,
3603 hot_plug_info->phys_disk_num, (unsigned long long)
3604 sas_device.sas_address);
3605
3606 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
3607 vtarget->id = hot_plug_info->id;
3608 phy_info->attached.phys_disk_num = ~0;
3609 mptsas_reprobe_target(starget, 0);
3610 mptsas_add_device_component_by_fw(ioc,
3611 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003612 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303613
Moore, Ericc73787ee2006-01-26 16:20:06 -07003614 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303615
Moore, Ericc73787ee2006-01-26 16:20:06 -07003616 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303617 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3618 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3619 hot_plug_info->id);
3620 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
3621 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003622 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303623
Moore, Ericc73787ee2006-01-26 16:20:06 -07003624 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303625
Moore, Ericc73787ee2006-01-26 16:20:06 -07003626 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303627 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
3628 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3629 hot_plug_info->id);
3630 scsi_remove_device(hot_plug_info->sdev);
3631 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003632 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303633
Eric Mooreb506ade2007-01-29 09:45:37 -07003634 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303635
3636 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07003637 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303638 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07003639 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303640
Moore, Ericbd23e942006-04-17 12:43:04 -06003641 default:
3642 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003643 }
3644
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303645 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003646}
3647
3648static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303649mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003650{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303651 MPT_ADAPTER *ioc;
3652 struct mptsas_hotplug_event hot_plug_info;
3653 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
3654 u32 device_info;
3655 u64 sas_address;
3656
3657 ioc = fw_event->ioc;
3658 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
3659 fw_event->event_data;
3660 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003661
3662 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303663 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3664 MPI_SAS_DEVICE_INFO_STP_TARGET |
3665 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
3666 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003667 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303668 }
3669
3670 if (sas_event_data->ReasonCode ==
3671 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
3672 mptbase_sas_persist_operation(ioc,
3673 MPI_SAS_OP_CLEAR_NOT_PRESENT);
3674 mptsas_free_fw_event(ioc, fw_event);
3675 return;
3676 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003677
Moore, Eric4b766472006-03-14 09:14:12 -07003678 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07003679 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07003680 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303681 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
3682 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
3683 hot_plug_info.channel = sas_event_data->Bus;
3684 hot_plug_info.id = sas_event_data->TargetID;
3685 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07003686 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303687 sizeof(u64));
3688 hot_plug_info.sas_address = le64_to_cpu(sas_address);
3689 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07003690 if (sas_event_data->ReasonCode &
3691 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303692 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07003693 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303694 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
3695 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07003696 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303697
Moore, Eric4b766472006-03-14 09:14:12 -07003698 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303699 mptbase_sas_persist_operation(ioc,
3700 MPI_SAS_OP_CLEAR_NOT_PRESENT);
3701 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07003702 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303703
Moore, Eric4b766472006-03-14 09:14:12 -07003704 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303705 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07003706 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303707 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07003708 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303709 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07003710 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003711 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003712}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303713
Moore, Ericc73787ee2006-01-26 16:20:06 -07003714static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303715mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003716{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303717 MPT_ADAPTER *ioc;
3718 EVENT_DATA_RAID *raid_event_data;
3719 struct mptsas_hotplug_event hot_plug_info;
3720 int status;
3721 int state;
3722 struct scsi_device *sdev = NULL;
3723 VirtDevice *vdevice = NULL;
3724 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003725
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303726 ioc = fw_event->ioc;
3727 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
3728 status = le32_to_cpu(raid_event_data->SettingsStatus);
3729 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003730
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303731 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
3732 hot_plug_info.id = raid_event_data->VolumeID;
3733 hot_plug_info.channel = raid_event_data->VolumeBus;
3734 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
3735
3736 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
3737 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
3738 raid_event_data->ReasonCode ==
3739 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
3740 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3741 hot_plug_info.id, 0);
3742 hot_plug_info.sdev = sdev;
3743 if (sdev)
3744 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003745 }
3746
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303747 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
3748 "ReasonCode=%02x\n", ioc->name, __func__,
3749 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07003750
3751 switch (raid_event_data->ReasonCode) {
3752 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303753 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003754 break;
3755 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303756 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003757 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06003758 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
3759 switch (state) {
3760 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07003761 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303762 mpt_raid_phys_disk_pg0(ioc,
3763 raid_event_data->PhysDiskNum, &phys_disk);
3764 hot_plug_info.id = phys_disk.PhysDiskID;
3765 hot_plug_info.channel = phys_disk.PhysDiskBus;
3766 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06003767 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303768 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06003769 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06003770 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
3771 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
3772 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303773 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06003774 break;
3775 default:
3776 break;
3777 }
3778 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003779 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303780 if (!sdev)
3781 break;
3782 vdevice->vtarget->deleted = 1; /* block IO */
3783 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003784 break;
3785 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303786 if (sdev) {
3787 scsi_device_put(sdev);
3788 break;
3789 }
3790 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003791 break;
3792 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303793 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
3794 if (!sdev)
3795 break;
3796 vdevice->vtarget->deleted = 1; /* block IO */
3797 hot_plug_info.event_type = MPTSAS_DEL_RAID;
3798 break;
3799 }
Moore, Ericbd23e942006-04-17 12:43:04 -06003800 switch (state) {
3801 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
3802 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303803 if (!sdev)
3804 break;
3805 vdevice->vtarget->deleted = 1; /* block IO */
3806 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06003807 break;
3808 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
3809 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303810 if (sdev) {
3811 scsi_device_put(sdev);
3812 break;
3813 }
3814 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06003815 break;
3816 default:
3817 break;
3818 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003819 break;
3820 default:
3821 break;
3822 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303823
3824 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
3825 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
3826 else
3827 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003828}
3829
Eric Mooreb506ade2007-01-29 09:45:37 -07003830/*
3831 * mptsas_send_ir2_event - handle exposing hidden disk when
3832 * an inactive raid volume is added
3833 *
3834 * @ioc: Pointer to MPT_ADAPTER structure
3835 * @ir2_data
3836 *
3837 */
3838static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303839mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07003840{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303841 MPT_ADAPTER *ioc;
3842 struct mptsas_hotplug_event hot_plug_info;
3843 MPI_EVENT_DATA_IR2 *ir2_data;
3844 u8 reasonCode;
Eric Mooreb506ade2007-01-29 09:45:37 -07003845
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303846 ioc = fw_event->ioc;
3847 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
3848 reasonCode = ir2_data->ReasonCode;
3849
3850 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
3851 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
3852
3853 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
3854 hot_plug_info.id = ir2_data->TargetID;
3855 hot_plug_info.channel = ir2_data->Bus;
3856 switch (reasonCode) {
3857 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
3858 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3859 break;
3860 default:
3861 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07003862 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303863 }
3864 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
3865}
Moore, Erice6b2d762006-03-14 09:14:24 -07003866
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003867static int
3868mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3869{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303870 u32 event = le32_to_cpu(reply->Event);
3871 int sz, event_data_sz;
3872 struct fw_event_work *fw_event;
3873 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003874
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303875 /* events turned off due to host reset or driver unloading */
3876 if (ioc->fw_events_off)
3877 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003878
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303879 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003880 switch (event) {
3881 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303882 {
3883 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
3884 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
3885
3886 if (sas_event_data->ReasonCode ==
3887 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
3888 mptsas_target_reset_queue(ioc, sas_event_data);
3889 return 0;
3890 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003891 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303892 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303893 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
3894 {
3895 MpiEventDataSasExpanderStatusChange_t *expander_data =
3896 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
3897
3898
3899 if (expander_data->ReasonCode ==
3900 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
3901 ioc->device_missing_delay)
3902 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07003903 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303904 }
3905 case MPI_EVENT_SAS_DISCOVERY:
3906 {
3907 u32 discovery_status;
3908 EventDataSasDiscovery_t *discovery_data =
3909 (EventDataSasDiscovery_t *)reply->Data;
3910
3911 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
3912 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
3913 return 0;
3914 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303915 case MPI_EVENT_INTEGRATED_RAID:
3916 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07003917 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303918 case MPI_EVENT_SAS_PHY_LINK_STATUS:
3919 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07003920 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003921 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303922 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003923 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003924
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303925 event_data_sz = ((reply->MsgLength * 4) -
3926 offsetof(EventNotificationReply_t, Data));
3927 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
3928 fw_event = kzalloc(sz, GFP_ATOMIC);
3929 if (!fw_event) {
3930 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
3931 __func__, __LINE__);
3932 return 0;
3933 }
3934 memcpy(fw_event->event_data, reply->Data, event_data_sz);
3935 fw_event->event = event;
3936 fw_event->ioc = ioc;
3937 mptsas_add_fw_event(ioc, fw_event, delay);
3938 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003939}
3940
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003941static int
3942mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3943{
3944 struct Scsi_Host *sh;
3945 MPT_SCSI_HOST *hd;
3946 MPT_ADAPTER *ioc;
3947 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003948 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003949 int numSGE = 0;
3950 int scale;
3951 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003952 int error=0;
3953 int r;
3954
3955 r = mpt_attach(pdev,id);
3956 if (r)
3957 return r;
3958
3959 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303960 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003961 ioc->DoneCtx = mptsasDoneCtx;
3962 ioc->TaskCtx = mptsasTaskCtx;
3963 ioc->InternalCtx = mptsasInternalCtx;
3964
3965 /* Added sanity check on readiness of the MPT adapter.
3966 */
3967 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3968 printk(MYIOC_s_WARN_FMT
3969 "Skipping because it's not operational!\n",
3970 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003971 error = -ENODEV;
3972 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003973 }
3974
3975 if (!ioc->active) {
3976 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3977 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003978 error = -ENODEV;
3979 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003980 }
3981
3982 /* Sanity check - ensure at least 1 port is INITIATOR capable
3983 */
3984 ioc_cap = 0;
3985 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3986 if (ioc->pfacts[ii].ProtocolFlags &
3987 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3988 ioc_cap++;
3989 }
3990
3991 if (!ioc_cap) {
3992 printk(MYIOC_s_WARN_FMT
3993 "Skipping ioc=%p because SCSI Initiator mode "
3994 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003995 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003996 }
3997
3998 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3999 if (!sh) {
4000 printk(MYIOC_s_WARN_FMT
4001 "Unable to register controller with SCSI subsystem\n",
4002 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004003 error = -1;
4004 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004005 }
4006
4007 spin_lock_irqsave(&ioc->FreeQlock, flags);
4008
4009 /* Attach the SCSI Host to the IOC structure
4010 */
4011 ioc->sh = sh;
4012
4013 sh->io_port = 0;
4014 sh->n_io_port = 0;
4015 sh->irq = 0;
4016
4017 /* set 16 byte cdb's */
4018 sh->max_cmd_len = 16;
4019
Eric Moore793955f2007-01-29 09:42:20 -07004020 sh->max_id = ioc->pfacts[0].PortSCSIID;
4021 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004022
4023 sh->transportt = mptsas_transport_template;
4024
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004025 /* Required entry.
4026 */
4027 sh->unique_id = ioc->id;
4028
4029 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004030 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004031 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004032 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004033 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004034
4035 /* Verify that we won't exceed the maximum
4036 * number of chain buffers
4037 * We can optimize: ZZ = req_sz/sizeof(SGE)
4038 * For 32bit SGE's:
4039 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4040 * + (req_sz - 64)/sizeof(SGE)
4041 * A slightly different algorithm is required for
4042 * 64bit SGEs.
4043 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304044 scale = ioc->req_sz/ioc->SGE_size;
4045 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004046 numSGE = (scale - 1) *
4047 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304048 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004049 } else {
4050 numSGE = 1 + (scale - 1) *
4051 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304052 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004053 }
4054
4055 if (numSGE < sh->sg_tablesize) {
4056 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304057 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004058 "Resetting sg_tablesize to %d from %d\n",
4059 ioc->name, numSGE, sh->sg_tablesize));
4060 sh->sg_tablesize = numSGE;
4061 }
4062
Eric Mooree7eae9f2007-09-29 10:15:59 -06004063 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004064 hd->ioc = ioc;
4065
4066 /* SCSI needs scsi_cmnd lookup table!
4067 * (with size equal to req_depth*PtrSz!)
4068 */
Eric Mooree8206382007-09-29 10:16:53 -06004069 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
4070 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004071 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06004072 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004073 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004074 }
Eric Mooree8206382007-09-29 10:16:53 -06004075 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004076
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304077 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06004078 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004079
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004080 /* Clear the TM flags
4081 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004082 hd->abortSCpnt = NULL;
4083
4084 /* Clear the pointer used to store
4085 * single-threaded commands, i.e., those
4086 * issued during a bus scan, dv and
4087 * configuration pages.
4088 */
4089 hd->cmdPtr = NULL;
4090
4091 /* Initialize this SCSI Hosts' timers
4092 * To use, set the timer expires field
4093 * and add_timer
4094 */
4095 init_timer(&hd->timer);
4096 hd->timer.data = (unsigned long) hd;
4097 hd->timer.function = mptscsih_timer_expired;
4098
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004099 ioc->sas_data.ptClear = mpt_pt_clear;
4100
Eric Mooredf9e0622007-01-29 09:46:21 -07004101 hd->last_queue_full = 0;
4102 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304103 INIT_LIST_HEAD(&ioc->sas_device_info_list);
4104 mutex_init(&ioc->sas_device_info_mutex);
4105
Eric Mooredf9e0622007-01-29 09:46:21 -07004106 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4107
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004108 if (ioc->sas_data.ptClear==1) {
4109 mptbase_sas_persist_operation(
4110 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
4111 }
4112
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004113 error = scsi_add_host(sh, &ioc->pcidev->dev);
4114 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06004115 dprintk(ioc, printk(MYIOC_s_ERR_FMT
4116 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004117 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004118 }
4119
4120 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304121 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004122 return 0;
4123
Eric Moore547f9a22006-06-27 14:42:12 -06004124 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004125
4126 mptscsih_remove(pdev);
4127 return error;
4128}
4129
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304130void
4131mptsas_shutdown(struct pci_dev *pdev)
4132{
4133 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4134
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304135 mptsas_fw_event_off(ioc);
4136 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304137}
4138
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004139static void __devexit mptsas_remove(struct pci_dev *pdev)
4140{
4141 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4142 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06004143 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004144
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304145 mptsas_shutdown(pdev);
4146
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304147 mptsas_del_device_components(ioc);
4148
Eric Mooreb506ade2007-01-29 09:45:37 -07004149 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004150 sas_remove_host(ioc->sh);
4151
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004152 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004153 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
4154 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06004155 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304156 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304157
Eric Moore547f9a22006-06-27 14:42:12 -06004158 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004159 kfree(p);
4160 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004161 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304162 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004163 mptscsih_remove(pdev);
4164}
4165
4166static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06004167 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004168 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004169 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004170 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004171 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004172 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004173 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004174 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004175 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004176 PCI_ANY_ID, PCI_ANY_ID },
4177 {0} /* Terminating entry */
4178};
4179MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
4180
4181
4182static struct pci_driver mptsas_driver = {
4183 .name = "mptsas",
4184 .id_table = mptsas_pci_table,
4185 .probe = mptsas_probe,
4186 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304187 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004188#ifdef CONFIG_PM
4189 .suspend = mptscsih_suspend,
4190 .resume = mptscsih_resume,
4191#endif
4192};
4193
4194static int __init
4195mptsas_init(void)
4196{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304197 int error;
4198
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004199 show_mptmod_ver(my_NAME, my_VERSION);
4200
4201 mptsas_transport_template =
4202 sas_attach_transport(&mptsas_transport_functions);
4203 if (!mptsas_transport_template)
4204 return -ENODEV;
4205
4206 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304207 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004208 mptsasInternalCtx =
4209 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004210 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304211 mptsasDeviceResetCtx =
4212 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004213
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304214 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
4215 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004216
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304217 error = pci_register_driver(&mptsas_driver);
4218 if (error)
4219 sas_release_transport(mptsas_transport_template);
4220
4221 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004222}
4223
4224static void __exit
4225mptsas_exit(void)
4226{
4227 pci_unregister_driver(&mptsas_driver);
4228 sas_release_transport(mptsas_transport_template);
4229
4230 mpt_reset_deregister(mptsasDoneCtx);
4231 mpt_event_deregister(mptsasDoneCtx);
4232
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004233 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004234 mpt_deregister(mptsasInternalCtx);
4235 mpt_deregister(mptsasTaskCtx);
4236 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304237 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004238}
4239
4240module_init(mptsas_init);
4241module_exit(mptsas_exit);