blob: 3efa728fc59054eca81b51799eca5543e24540ba [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
Eric Mooreb506ade2007-01-29 09:45:37 -070098static void mptsas_hotplug_work(struct work_struct *work);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020099
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530100static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
101 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200102{
Eric Moore29dd3602007-09-14 18:46:51 -0600103 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
104 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
105 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
106 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
107 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
108 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
109 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
110 ioc->name, phy_data->Port));
111 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
112 ioc->name, phy_data->PortFlags));
113 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
114 ioc->name, phy_data->PhyFlags));
115 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
116 ioc->name, phy_data->NegotiatedLinkRate));
117 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
118 "Controller PHY Device Info=0x%X\n", ioc->name,
119 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
120 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
121 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200122}
123
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530124static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200125{
126 __le64 sas_address;
127
128 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
129
Eric Moore29dd3602007-09-14 18:46:51 -0600130 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
131 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
132 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
133 "Attached Device Handle=0x%X\n", ioc->name,
134 le16_to_cpu(pg0->AttachedDevHandle)));
135 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
136 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
137 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
138 "Attached PHY Identifier=0x%X\n", ioc->name,
139 pg0->AttachedPhyIdentifier));
140 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
141 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
142 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
143 ioc->name, pg0->ProgrammedLinkRate));
144 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
145 ioc->name, pg0->ChangeCount));
146 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
147 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200148}
149
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530150static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200151{
Eric Moore29dd3602007-09-14 18:46:51 -0600152 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
153 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
154 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
155 ioc->name, pg1->InvalidDwordCount));
156 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
157 "Running Disparity Error Count=0x%x\n", ioc->name,
158 pg1->RunningDisparityErrorCount));
159 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
160 "Loss Dword Synch Count=0x%x\n", ioc->name,
161 pg1->LossDwordSynchCount));
162 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
163 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
164 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200165}
166
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530167static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200168{
169 __le64 sas_address;
170
171 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
172
Eric Moore29dd3602007-09-14 18:46:51 -0600173 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
174 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
175 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
176 ioc->name, le16_to_cpu(pg0->DevHandle)));
177 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
178 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
179 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
180 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
181 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
182 ioc->name, le16_to_cpu(pg0->Slot)));
183 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
184 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
185 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
186 ioc->name, pg0->TargetID));
187 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
188 ioc->name, pg0->Bus));
189 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
190 ioc->name, pg0->PhyNum));
191 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
192 ioc->name, le16_to_cpu(pg0->AccessStatus)));
193 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
194 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
195 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
196 ioc->name, le16_to_cpu(pg0->Flags)));
197 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
198 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200199}
200
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530201static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200202{
Eric Moore29dd3602007-09-14 18:46:51 -0600203 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
204 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
205 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
206 ioc->name, pg1->PhysicalPort));
207 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
208 ioc->name, pg1->PhyIdentifier));
209 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
210 ioc->name, pg1->NegotiatedLinkRate));
211 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
212 ioc->name, pg1->ProgrammedLinkRate));
213 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
214 ioc->name, pg1->HwLinkRate));
215 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
216 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
217 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
218 "Attached Device Handle=0x%X\n\n", ioc->name,
219 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200220}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200221
Christoph Hellwige3094442006-02-16 13:25:36 +0100222static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
223{
224 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
225 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
226}
227
228static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
229{
230 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
231 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
232}
233
Michael Reed77483692008-03-20 17:32:05 -0500234static struct mptsas_portinfo *
235mptsas_get_hba_portinfo(MPT_ADAPTER *ioc)
236{
237 struct list_head *head = &ioc->sas_topology;
238 struct mptsas_portinfo *pi = NULL;
239
240 /* always the first entry on sas_topology list */
241
242 if (!list_empty(head))
243 pi = list_entry(head->next, struct mptsas_portinfo, list);
244
245 return pi;
246}
247
Moore, Erice6b2d762006-03-14 09:14:24 -0700248/*
249 * mptsas_find_portinfo_by_handle
250 *
251 * This function should be called with the sas_topology_mutex already held
252 */
253static struct mptsas_portinfo *
254mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
255{
256 struct mptsas_portinfo *port_info, *rc=NULL;
257 int i;
258
259 list_for_each_entry(port_info, &ioc->sas_topology, list)
260 for (i = 0; i < port_info->num_phys; i++)
261 if (port_info->phy_info[i].identify.handle == handle) {
262 rc = port_info;
263 goto out;
264 }
265 out:
266 return rc;
267}
268
Moore, Ericbd23e942006-04-17 12:43:04 -0600269/*
270 * Returns true if there is a scsi end device
271 */
272static inline int
273mptsas_is_end_device(struct mptsas_devinfo * attached)
274{
Eric Moore547f9a22006-06-27 14:42:12 -0600275 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600276 (attached->device_info &
277 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
278 ((attached->device_info &
279 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
280 (attached->device_info &
281 MPI_SAS_DEVICE_INFO_STP_TARGET) |
282 (attached->device_info &
283 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
284 return 1;
285 else
286 return 0;
287}
288
Eric Moore547f9a22006-06-27 14:42:12 -0600289/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600290static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530291mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600292{
293 struct mptsas_portinfo *port_info;
294 struct mptsas_phyinfo *phy_info;
295 u8 i;
296
297 if (!port_details)
298 return;
299
300 port_info = port_details->port_info;
301 phy_info = port_info->phy_info;
302
Eric Moore29dd3602007-09-14 18:46:51 -0600303 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700304 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700305 port_details->num_phys, (unsigned long long)
306 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600307
308 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
309 if(phy_info->port_details != port_details)
310 continue;
311 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
312 phy_info->port_details = NULL;
313 }
314 kfree(port_details);
315}
316
317static inline struct sas_rphy *
318mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
319{
320 if (phy_info->port_details)
321 return phy_info->port_details->rphy;
322 else
323 return NULL;
324}
325
326static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530327mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600328{
329 if (phy_info->port_details) {
330 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600331 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
332 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600333 }
334
Eric Moore547f9a22006-06-27 14:42:12 -0600335 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600336 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
337 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600338 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
339 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600340 }
Eric Moore547f9a22006-06-27 14:42:12 -0600341}
342
343static inline struct sas_port *
344mptsas_get_port(struct mptsas_phyinfo *phy_info)
345{
346 if (phy_info->port_details)
347 return phy_info->port_details->port;
348 else
349 return NULL;
350}
351
352static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530353mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600354{
355 if (phy_info->port_details)
356 phy_info->port_details->port = port;
357
Eric Moore547f9a22006-06-27 14:42:12 -0600358 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600359 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
360 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600361 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
362 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600363 }
Eric Moore547f9a22006-06-27 14:42:12 -0600364}
365
366static inline struct scsi_target *
367mptsas_get_starget(struct mptsas_phyinfo *phy_info)
368{
369 if (phy_info->port_details)
370 return phy_info->port_details->starget;
371 else
372 return NULL;
373}
374
375static inline void
376mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
377starget)
378{
379 if (phy_info->port_details)
380 phy_info->port_details->starget = starget;
381}
382
383
384/*
385 * mptsas_setup_wide_ports
386 *
387 * Updates for new and existing narrow/wide port configuration
388 * in the sas_topology
389 */
Eric Moore376ac832006-06-29 17:36:26 -0600390static void
Eric Moore547f9a22006-06-27 14:42:12 -0600391mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
392{
393 struct mptsas_portinfo_details * port_details;
394 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
395 u64 sas_address;
396 int i, j;
397
398 mutex_lock(&ioc->sas_topology_mutex);
399
400 phy_info = port_info->phy_info;
401 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
402 if (phy_info->attached.handle)
403 continue;
404 port_details = phy_info->port_details;
405 if (!port_details)
406 continue;
407 if (port_details->num_phys < 2)
408 continue;
409 /*
410 * Removing a phy from a port, letting the last
411 * phy be removed by firmware events.
412 */
Eric Moore29dd3602007-09-14 18:46:51 -0600413 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
414 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700415 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600416 port_details->num_phys--;
417 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
418 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
419 sas_port_delete_phy(port_details->port, phy_info->phy);
420 phy_info->port_details = NULL;
421 }
422
423 /*
424 * Populate and refresh the tree
425 */
426 phy_info = port_info->phy_info;
427 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
428 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600429 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
430 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600431 if (!sas_address)
432 continue;
433 port_details = phy_info->port_details;
434 /*
435 * Forming a port
436 */
437 if (!port_details) {
438 port_details = kzalloc(sizeof(*port_details),
439 GFP_KERNEL);
440 if (!port_details)
441 goto out;
442 port_details->num_phys = 1;
443 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600444 if (phy_info->phy_id < 64 )
445 port_details->phy_bitmask |=
446 (1 << phy_info->phy_id);
447 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600448 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700449 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600450 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600451 phy_info->port_details = port_details;
452 }
453
454 if (i == port_info->num_phys - 1)
455 continue;
456 phy_info_cmp = &port_info->phy_info[i + 1];
457 for (j = i + 1 ; j < port_info->num_phys ; j++,
458 phy_info_cmp++) {
459 if (!phy_info_cmp->attached.sas_address)
460 continue;
461 if (sas_address != phy_info_cmp->attached.sas_address)
462 continue;
463 if (phy_info_cmp->port_details == port_details )
464 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600465 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700466 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600467 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700468 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600469 if (phy_info_cmp->port_details) {
470 port_details->rphy =
471 mptsas_get_rphy(phy_info_cmp);
472 port_details->port =
473 mptsas_get_port(phy_info_cmp);
474 port_details->starget =
475 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600476 port_details->num_phys =
477 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600478 if (!phy_info_cmp->port_details->num_phys)
479 kfree(phy_info_cmp->port_details);
480 } else
481 phy_info_cmp->sas_port_add_phy=1;
482 /*
483 * Adding a phy to a port
484 */
485 phy_info_cmp->port_details = port_details;
486 if (phy_info_cmp->phy_id < 64 )
487 port_details->phy_bitmask |=
488 (1 << phy_info_cmp->phy_id);
489 port_details->num_phys++;
490 }
491 }
492
493 out:
494
Eric Moore547f9a22006-06-27 14:42:12 -0600495 for (i = 0; i < port_info->num_phys; i++) {
496 port_details = port_info->phy_info[i].port_details;
497 if (!port_details)
498 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600499 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700500 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700501 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700502 port_details, i, port_details->num_phys,
503 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600504 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
505 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600506 }
Eric Moore29dd3602007-09-14 18:46:51 -0600507 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600508 mutex_unlock(&ioc->sas_topology_mutex);
509}
510
Eric Mooredf9e0622007-01-29 09:46:21 -0700511/**
512 * csmisas_find_vtarget
513 *
514 * @ioc
515 * @volume_id
516 * @volume_bus
517 *
518 **/
519static VirtTarget *
520mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600521{
Eric Mooredf9e0622007-01-29 09:46:21 -0700522 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600523 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700524 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600525
Eric Mooredf9e0622007-01-29 09:46:21 -0700526 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530527 vdevice = sdev->hostdata;
528 if ((vdevice == NULL) ||
529 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700530 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600531 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530532 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600533 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600534 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700535 return vtarget;
536}
537
538/**
539 * mptsas_target_reset
540 *
541 * Issues TARGET_RESET to end device using handshaking method
542 *
543 * @ioc
544 * @channel
545 * @id
546 *
547 * Returns (1) success
548 * (0) failure
549 *
550 **/
551static int
552mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
553{
554 MPT_FRAME_HDR *mf;
555 SCSITaskMgmt_t *pScsiTm;
556
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530557 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
558 if (mf == NULL) {
559 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
560 "%s, no msg frames @%d!!\n",
561 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -0700562 return 0;
563 }
564
565 /* Format the Request
566 */
567 pScsiTm = (SCSITaskMgmt_t *) mf;
568 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
569 pScsiTm->TargetID = id;
570 pScsiTm->Bus = channel;
571 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
572 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
573 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
574
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530575 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700576
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530577 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700578
579 return 1;
580}
581
582/**
583 * mptsas_target_reset_queue
584 *
585 * Receive request for TARGET_RESET after recieving an firmware
586 * event NOT_RESPONDING_EVENT, then put command in link list
587 * and queue if task_queue already in use.
588 *
589 * @ioc
590 * @sas_event_data
591 *
592 **/
593static void
594mptsas_target_reset_queue(MPT_ADAPTER *ioc,
595 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
596{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600597 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700598 VirtTarget *vtarget = NULL;
599 struct mptsas_target_reset_event *target_reset_list;
600 u8 id, channel;
601
602 id = sas_event_data->TargetID;
603 channel = sas_event_data->Bus;
604
605 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
606 return;
607
608 vtarget->deleted = 1; /* block IO */
609
610 target_reset_list = kzalloc(sizeof(*target_reset_list),
611 GFP_ATOMIC);
612 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530613 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
614 "%s, failed to allocate mem @%d..!!\n",
615 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -0700616 return;
617 }
618
619 memcpy(&target_reset_list->sas_event_data, sas_event_data,
620 sizeof(*sas_event_data));
621 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
622
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530623 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -0700624
625 if (mptsas_target_reset(ioc, channel, id)) {
626 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700627 }
628}
629
630/**
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530631 * mptsas_taskmgmt_complete - Completion for TARGET_RESET after
632 * NOT_RESPONDING_EVENT, enable work queue to finish off removing device
633 * from upper layers. then send next TARGET_RESET in the queue.
634 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -0700635 *
636 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530637static int
638mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -0700639{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600640 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700641 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -0700642 struct mptsas_hotplug_event *ev;
643 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
644 u8 id, channel;
645 __le64 sas_address;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530646 struct mptsas_target_reset_event *target_reset_list;
647 SCSITaskMgmtReply_t *pScsiTmReply;
648
649 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
650 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
651
652 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
653 if (pScsiTmReply) {
654 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
655 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
656 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
657 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
658 "term_cmnds = %d\n", ioc->name,
659 pScsiTmReply->Bus, pScsiTmReply->TargetID,
660 pScsiTmReply->TaskType,
661 le16_to_cpu(pScsiTmReply->IOCStatus),
662 le32_to_cpu(pScsiTmReply->IOCLogInfo),
663 pScsiTmReply->ResponseCode,
664 le32_to_cpu(pScsiTmReply->TerminationCount)));
665
666 if (pScsiTmReply->ResponseCode)
667 mptscsih_taskmgmt_response_code(ioc,
668 pScsiTmReply->ResponseCode);
669 }
670
671 if (pScsiTmReply && (pScsiTmReply->TaskType ==
672 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
673 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
674 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
675 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
676 memcpy(ioc->taskmgmt_cmds.reply, mr,
677 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
678 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
679 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
680 complete(&ioc->taskmgmt_cmds.done);
681 return 1;
682 }
683 return 0;
684 }
685
686 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -0700687
688 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530689 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700690
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530691 target_reset_list = list_entry(head->next,
692 struct mptsas_target_reset_event, list);
693
694 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
695 "TaskMgmt: completed (%d seconds)\n",
696 ioc->name, jiffies_to_msecs(jiffies -
697 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -0700698
699 sas_event_data = &target_reset_list->sas_event_data;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530700 id = pScsiTmReply->TargetID;
701 channel = pScsiTmReply->Bus;
702 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -0700703
704 /*
705 * retry target reset
706 */
707 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530708 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -0700709 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530710 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700711 }
712
713 /*
714 * enable work queue to remove device from upper layers
715 */
716 list_del(&target_reset_list->list);
717
718 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
719 if (!ev) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530720 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700721 ioc->name,__func__, __LINE__));
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530722 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -0700723 }
724
725 INIT_WORK(&ev->work, mptsas_hotplug_work);
726 ev->ioc = ioc;
727 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
728 ev->parent_handle =
729 le16_to_cpu(sas_event_data->ParentDevHandle);
730 ev->channel = channel;
731 ev->id =id;
732 ev->phy_id = sas_event_data->PhyNum;
733 memcpy(&sas_address, &sas_event_data->SASAddress,
734 sizeof(__le64));
735 ev->sas_address = le64_to_cpu(sas_address);
736 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
737 ev->event_type = MPTSAS_DEL_DEVICE;
738 schedule_work(&ev->work);
739 kfree(target_reset_list);
740
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530741
Eric Mooredf9e0622007-01-29 09:46:21 -0700742 /*
743 * issue target reset to next device in the queue
744 */
745
746 head = &hd->target_reset_list;
747 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530748 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700749
750 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
751 list);
752
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530753 id = target_reset_list->sas_event_data.TargetID;
754 channel = target_reset_list->sas_event_data.Bus;
755 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -0700756
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530757 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -0700758 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700759
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530760 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700761}
762
763/**
764 * mptscsih_ioc_reset
765 *
766 * @ioc
767 * @reset_phase
768 *
769 **/
770static int
771mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
772{
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800773 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -0700774 struct mptsas_target_reset_event *target_reset_list, *n;
775 int rc;
776
777 rc = mptscsih_ioc_reset(ioc, reset_phase);
778
779 if (ioc->bus_type != SAS)
780 goto out;
781
782 if (reset_phase != MPT_IOC_POST_RESET)
783 goto out;
784
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800785 if (!ioc->sh || !ioc->sh->hostdata)
786 goto out;
Eric Mooree7eae9f2007-09-29 10:15:59 -0600787 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800788 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -0700789 goto out;
790
791 if (list_empty(&hd->target_reset_list))
792 goto out;
793
794 /* flush the target_reset_list */
795 list_for_each_entry_safe(target_reset_list, n,
796 &hd->target_reset_list, list) {
797 list_del(&target_reset_list->list);
798 kfree(target_reset_list);
799 }
800
801 out:
802 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -0600803}
804
Christoph Hellwige3094442006-02-16 13:25:36 +0100805static int
Moore, Eric52435432006-03-14 09:14:15 -0700806mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100807 u32 form, u32 form_specific)
808{
809 ConfigExtendedPageHeader_t hdr;
810 CONFIGPARMS cfg;
811 SasEnclosurePage0_t *buffer;
812 dma_addr_t dma_handle;
813 int error;
814 __le64 le_identifier;
815
816 memset(&hdr, 0, sizeof(hdr));
817 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
818 hdr.PageNumber = 0;
819 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
820 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
821
822 cfg.cfghdr.ehdr = &hdr;
823 cfg.physAddr = -1;
824 cfg.pageAddr = form + form_specific;
825 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
826 cfg.dir = 0; /* read */
827 cfg.timeout = 10;
828
829 error = mpt_config(ioc, &cfg);
830 if (error)
831 goto out;
832 if (!hdr.ExtPageLength) {
833 error = -ENXIO;
834 goto out;
835 }
836
837 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
838 &dma_handle);
839 if (!buffer) {
840 error = -ENOMEM;
841 goto out;
842 }
843
844 cfg.physAddr = dma_handle;
845 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
846
847 error = mpt_config(ioc, &cfg);
848 if (error)
849 goto out_free_consistent;
850
851 /* save config data */
852 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
853 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
854 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
855 enclosure->flags = le16_to_cpu(buffer->Flags);
856 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
857 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
858 enclosure->start_id = buffer->StartTargetID;
859 enclosure->start_channel = buffer->StartBus;
860 enclosure->sep_id = buffer->SEPTargetID;
861 enclosure->sep_channel = buffer->SEPBus;
862
863 out_free_consistent:
864 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
865 buffer, dma_handle);
866 out:
867 return error;
868}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200869
James Bottomleyf013db32006-03-18 14:54:36 -0600870static int
871mptsas_slave_configure(struct scsi_device *sdev)
872{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600873
James Bottomleye8bf3942006-07-11 17:49:34 -0400874 if (sdev->channel == MPTSAS_RAID_CHANNEL)
875 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600876
James Bottomleye8bf3942006-07-11 17:49:34 -0400877 sas_read_port_mode_page(sdev);
878
879 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600880 return mptscsih_slave_configure(sdev);
881}
882
Eric Moore547f9a22006-06-27 14:42:12 -0600883static int
884mptsas_target_alloc(struct scsi_target *starget)
885{
886 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -0600887 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -0600888 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700889 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600890 struct sas_rphy *rphy;
891 struct mptsas_portinfo *p;
892 int i;
Eric Mooree80b0022007-09-14 18:49:03 -0600893 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -0600894
895 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
896 if (!vtarget)
897 return -ENOMEM;
898
899 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -0600900 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -0700901 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
902 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600903 channel = 0;
904
Eric Moore793955f2007-01-29 09:42:20 -0700905 /*
906 * RAID volumes placed beyond the last expected port.
907 */
908 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Eric Mooree80b0022007-09-14 18:49:03 -0600909 for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
910 if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
911 channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600912 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700913 }
Eric Moore547f9a22006-06-27 14:42:12 -0600914
915 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -0600916 mutex_lock(&ioc->sas_topology_mutex);
917 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -0600918 for (i = 0; i < p->num_phys; i++) {
919 if (p->phy_info[i].attached.sas_address !=
920 rphy->identify.sas_address)
921 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700922 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600923 channel = p->phy_info[i].attached.channel;
924 mptsas_set_starget(&p->phy_info[i], starget);
925
926 /*
927 * Exposing hidden raid components
928 */
Eric Mooree80b0022007-09-14 18:49:03 -0600929 if (mptscsih_is_phys_disk(ioc, channel, id)) {
930 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -0700931 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600932 vtarget->tflags |=
933 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700934 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600935 }
Eric Mooree80b0022007-09-14 18:49:03 -0600936 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -0600937 goto out;
938 }
939 }
Eric Mooree80b0022007-09-14 18:49:03 -0600940 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -0600941
942 kfree(vtarget);
943 return -ENXIO;
944
945 out:
Eric Moore793955f2007-01-29 09:42:20 -0700946 vtarget->id = id;
947 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600948 starget->hostdata = vtarget;
949 return 0;
950}
951
952static void
953mptsas_target_destroy(struct scsi_target *starget)
954{
955 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -0600956 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -0600957 struct sas_rphy *rphy;
958 struct mptsas_portinfo *p;
959 int i;
Eric Mooree80b0022007-09-14 18:49:03 -0600960 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -0600961
962 if (!starget->hostdata)
963 return;
964
James Bottomleye8bf3942006-07-11 17:49:34 -0400965 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -0600966 goto out;
967
968 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -0600969 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -0600970 for (i = 0; i < p->num_phys; i++) {
971 if (p->phy_info[i].attached.sas_address !=
972 rphy->identify.sas_address)
973 continue;
974 mptsas_set_starget(&p->phy_info[i], NULL);
975 goto out;
976 }
977 }
978
979 out:
980 kfree(starget->hostdata);
981 starget->hostdata = NULL;
982}
983
984
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200985static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700986mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200987{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700988 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -0600989 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200990 struct sas_rphy *rphy;
991 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -0600992 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700993 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -0600994 int i;
Eric Mooree80b0022007-09-14 18:49:03 -0600995 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200996
Eric Moorea69de502007-09-14 18:48:19 -0600997 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
998 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -0600999 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001000 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001001 return -ENOMEM;
1002 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001003 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001004 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001005
James Bottomleye8bf3942006-07-11 17:49:34 -04001006 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001007 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001008
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001009 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001010 mutex_lock(&ioc->sas_topology_mutex);
1011 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001012 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001013 if (p->phy_info[i].attached.sas_address !=
1014 rphy->identify.sas_address)
1015 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001016 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001017 /*
1018 * Exposing hidden raid components
1019 */
Eric Mooree80b0022007-09-14 18:49:03 -06001020 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001021 p->phy_info[i].attached.channel,
1022 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001023 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001024 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001025 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001026 }
1027 }
Eric Mooree80b0022007-09-14 18:49:03 -06001028 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001029
Eric Moorea69de502007-09-14 18:48:19 -06001030 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001031 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001032
1033 out:
Eric Moorea69de502007-09-14 18:48:19 -06001034 vdevice->vtarget->num_luns++;
1035 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001036 return 0;
1037}
1038
Eric Moore547f9a22006-06-27 14:42:12 -06001039static int
1040mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001041{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301042 MPT_SCSI_HOST *hd;
1043 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001044 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001045
Eric Moorea69de502007-09-14 18:48:19 -06001046 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001047 SCpnt->result = DID_NO_CONNECT << 16;
1048 done(SCpnt);
1049 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001050 }
Eric Moore547f9a22006-06-27 14:42:12 -06001051
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301052 hd = shost_priv(SCpnt->device->host);
1053 ioc = hd->ioc;
1054
1055 if (ioc->sas_discovery_quiesce_io)
1056 return SCSI_MLQUEUE_HOST_BUSY;
1057
Eric Moore793955f2007-01-29 09:42:20 -07001058// scsi_print_command(SCpnt);
1059
Eric Moore547f9a22006-06-27 14:42:12 -06001060 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001061}
1062
Eric Moore547f9a22006-06-27 14:42:12 -06001063
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001064static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001065 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001066 .proc_name = "mptsas",
1067 .proc_info = mptscsih_proc_info,
1068 .name = "MPT SPI Host",
1069 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001070 .queuecommand = mptsas_qcmd,
1071 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001072 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001073 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001074 .target_destroy = mptsas_target_destroy,
1075 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001076 .change_queue_depth = mptscsih_change_queue_depth,
1077 .eh_abort_handler = mptscsih_abort,
1078 .eh_device_reset_handler = mptscsih_dev_reset,
1079 .eh_bus_reset_handler = mptscsih_bus_reset,
1080 .eh_host_reset_handler = mptscsih_host_reset,
1081 .bios_param = mptscsih_bios_param,
1082 .can_queue = MPT_FC_CAN_QUEUE,
1083 .this_id = -1,
1084 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1085 .max_sectors = 8192,
1086 .cmd_per_lun = 7,
1087 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301088 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001089};
1090
Christoph Hellwigb5141122005-10-28 22:07:41 +02001091static int mptsas_get_linkerrors(struct sas_phy *phy)
1092{
1093 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1094 ConfigExtendedPageHeader_t hdr;
1095 CONFIGPARMS cfg;
1096 SasPhyPage1_t *buffer;
1097 dma_addr_t dma_handle;
1098 int error;
1099
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001100 /* FIXME: only have link errors on local phys */
1101 if (!scsi_is_sas_phy_local(phy))
1102 return -EINVAL;
1103
Christoph Hellwigb5141122005-10-28 22:07:41 +02001104 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1105 hdr.ExtPageLength = 0;
1106 hdr.PageNumber = 1 /* page number 1*/;
1107 hdr.Reserved1 = 0;
1108 hdr.Reserved2 = 0;
1109 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1110 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1111
1112 cfg.cfghdr.ehdr = &hdr;
1113 cfg.physAddr = -1;
1114 cfg.pageAddr = phy->identify.phy_identifier;
1115 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1116 cfg.dir = 0; /* read */
1117 cfg.timeout = 10;
1118
1119 error = mpt_config(ioc, &cfg);
1120 if (error)
1121 return error;
1122 if (!hdr.ExtPageLength)
1123 return -ENXIO;
1124
1125 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1126 &dma_handle);
1127 if (!buffer)
1128 return -ENOMEM;
1129
1130 cfg.physAddr = dma_handle;
1131 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1132
1133 error = mpt_config(ioc, &cfg);
1134 if (error)
1135 goto out_free_consistent;
1136
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301137 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001138
1139 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1140 phy->running_disparity_error_count =
1141 le32_to_cpu(buffer->RunningDisparityErrorCount);
1142 phy->loss_of_dword_sync_count =
1143 le32_to_cpu(buffer->LossDwordSynchCount);
1144 phy->phy_reset_problem_count =
1145 le32_to_cpu(buffer->PhyResetProblemCount);
1146
1147 out_free_consistent:
1148 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1149 buffer, dma_handle);
1150 return error;
1151}
1152
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001153static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1154 MPT_FRAME_HDR *reply)
1155{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301156 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001157 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301158 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001159 memcpy(ioc->sas_mgmt.reply, reply,
1160 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1161 }
1162 complete(&ioc->sas_mgmt.done);
1163 return 1;
1164}
1165
1166static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1167{
1168 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1169 SasIoUnitControlRequest_t *req;
1170 SasIoUnitControlReply_t *reply;
1171 MPT_FRAME_HDR *mf;
1172 MPIHeader_t *hdr;
1173 unsigned long timeleft;
1174 int error = -ERESTARTSYS;
1175
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001176 /* FIXME: fusion doesn't allow non-local phy reset */
1177 if (!scsi_is_sas_phy_local(phy))
1178 return -EINVAL;
1179
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001180 /* not implemented for expanders */
1181 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1182 return -ENXIO;
1183
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001184 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001185 goto out;
1186
1187 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1188 if (!mf) {
1189 error = -ENOMEM;
1190 goto out_unlock;
1191 }
1192
1193 hdr = (MPIHeader_t *) mf;
1194 req = (SasIoUnitControlRequest_t *)mf;
1195 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1196 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1197 req->MsgContext = hdr->MsgContext;
1198 req->Operation = hard_reset ?
1199 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1200 req->PhyNum = phy->identify.phy_identifier;
1201
1202 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1203
1204 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1205 10 * HZ);
1206 if (!timeleft) {
1207 /* On timeout reset the board */
1208 mpt_free_msg_frame(ioc, mf);
1209 mpt_HardResetHandler(ioc, CAN_SLEEP);
1210 error = -ETIMEDOUT;
1211 goto out_unlock;
1212 }
1213
1214 /* a reply frame is expected */
1215 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301216 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001217 error = -ENXIO;
1218 goto out_unlock;
1219 }
1220
1221 /* process the completed Reply Message Frame */
1222 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1223 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001224 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001225 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001226 error = -ENXIO;
1227 goto out_unlock;
1228 }
1229
1230 error = 0;
1231
1232 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001233 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001234 out:
1235 return error;
1236}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001237
Christoph Hellwige3094442006-02-16 13:25:36 +01001238static int
1239mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1240{
1241 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1242 int i, error;
1243 struct mptsas_portinfo *p;
1244 struct mptsas_enclosure enclosure_info;
1245 u64 enclosure_handle;
1246
1247 mutex_lock(&ioc->sas_topology_mutex);
1248 list_for_each_entry(p, &ioc->sas_topology, list) {
1249 for (i = 0; i < p->num_phys; i++) {
1250 if (p->phy_info[i].attached.sas_address ==
1251 rphy->identify.sas_address) {
1252 enclosure_handle = p->phy_info[i].
1253 attached.handle_enclosure;
1254 goto found_info;
1255 }
1256 }
1257 }
1258 mutex_unlock(&ioc->sas_topology_mutex);
1259 return -ENXIO;
1260
1261 found_info:
1262 mutex_unlock(&ioc->sas_topology_mutex);
1263 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001264 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001265 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1266 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1267 if (!error)
1268 *identifier = enclosure_info.enclosure_logical_id;
1269 return error;
1270}
1271
1272static int
1273mptsas_get_bay_identifier(struct sas_rphy *rphy)
1274{
1275 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1276 struct mptsas_portinfo *p;
1277 int i, rc;
1278
1279 mutex_lock(&ioc->sas_topology_mutex);
1280 list_for_each_entry(p, &ioc->sas_topology, list) {
1281 for (i = 0; i < p->num_phys; i++) {
1282 if (p->phy_info[i].attached.sas_address ==
1283 rphy->identify.sas_address) {
1284 rc = p->phy_info[i].attached.slot;
1285 goto out;
1286 }
1287 }
1288 }
1289 rc = -ENXIO;
1290 out:
1291 mutex_unlock(&ioc->sas_topology_mutex);
1292 return rc;
1293}
1294
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001295static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1296 struct request *req)
1297{
1298 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1299 MPT_FRAME_HDR *mf;
1300 SmpPassthroughRequest_t *smpreq;
1301 struct request *rsp = req->next_rq;
1302 int ret;
1303 int flagsLength;
1304 unsigned long timeleft;
1305 char *psge;
1306 dma_addr_t dma_addr_in = 0;
1307 dma_addr_t dma_addr_out = 0;
1308 u64 sas_address = 0;
1309
1310 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06001311 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001312 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001313 return -EINVAL;
1314 }
1315
1316 /* do we need to support multiple segments? */
1317 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06001318 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001319 ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
Eric Moore29dd3602007-09-14 18:46:51 -06001320 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001321 return -EINVAL;
1322 }
1323
1324 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1325 if (ret)
1326 goto out;
1327
1328 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1329 if (!mf) {
1330 ret = -ENOMEM;
1331 goto out_unlock;
1332 }
1333
1334 smpreq = (SmpPassthroughRequest_t *)mf;
1335 memset(smpreq, 0, sizeof(*smpreq));
1336
1337 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1338 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1339
1340 if (rphy)
1341 sas_address = rphy->identify.sas_address;
1342 else {
1343 struct mptsas_portinfo *port_info;
1344
1345 mutex_lock(&ioc->sas_topology_mutex);
Michael Reed77483692008-03-20 17:32:05 -05001346 port_info = mptsas_get_hba_portinfo(ioc);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001347 if (port_info && port_info->phy_info)
1348 sas_address =
1349 port_info->phy_info[0].phy->identify.sas_address;
1350 mutex_unlock(&ioc->sas_topology_mutex);
1351 }
1352
1353 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1354
1355 psge = (char *)
1356 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1357
1358 /* request */
1359 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1360 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301361 MPI_SGE_FLAGS_DIRECTION)
1362 << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001363 flagsLength |= (req->data_len - 4);
1364
1365 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1366 req->data_len, PCI_DMA_BIDIRECTIONAL);
1367 if (!dma_addr_out)
1368 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301369 ioc->add_sge(psge, flagsLength, dma_addr_out);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001370 psge += (sizeof(u32) + sizeof(dma_addr_t));
1371
1372 /* response */
1373 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1374 flagsLength |= rsp->data_len + 4;
1375 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1376 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1377 if (!dma_addr_in)
1378 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301379 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001380
1381 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1382
1383 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1384 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001385 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001386 /* On timeout reset the board */
1387 mpt_HardResetHandler(ioc, CAN_SLEEP);
1388 ret = -ETIMEDOUT;
1389 goto unmap;
1390 }
1391 mf = NULL;
1392
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301393 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001394 SmpPassthroughReply_t *smprep;
1395
1396 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1397 memcpy(req->sense, smprep, sizeof(*smprep));
1398 req->sense_len = sizeof(*smprep);
FUJITA Tomonori38b31672007-12-30 19:34:52 +09001399 req->data_len = 0;
1400 rsp->data_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001401 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001402 printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001403 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001404 ret = -ENXIO;
1405 }
1406unmap:
1407 if (dma_addr_out)
1408 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1409 PCI_DMA_BIDIRECTIONAL);
1410 if (dma_addr_in)
1411 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1412 PCI_DMA_BIDIRECTIONAL);
1413put_mf:
1414 if (mf)
1415 mpt_free_msg_frame(ioc, mf);
1416out_unlock:
1417 mutex_unlock(&ioc->sas_mgmt.mutex);
1418out:
1419 return ret;
1420}
1421
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001422static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001423 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001424 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1425 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001426 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001427 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001428};
1429
1430static struct scsi_transport_template *mptsas_transport_template;
1431
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001432static int
1433mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1434{
1435 ConfigExtendedPageHeader_t hdr;
1436 CONFIGPARMS cfg;
1437 SasIOUnitPage0_t *buffer;
1438 dma_addr_t dma_handle;
1439 int error, i;
1440
1441 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1442 hdr.ExtPageLength = 0;
1443 hdr.PageNumber = 0;
1444 hdr.Reserved1 = 0;
1445 hdr.Reserved2 = 0;
1446 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1447 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1448
1449 cfg.cfghdr.ehdr = &hdr;
1450 cfg.physAddr = -1;
1451 cfg.pageAddr = 0;
1452 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1453 cfg.dir = 0; /* read */
1454 cfg.timeout = 10;
1455
1456 error = mpt_config(ioc, &cfg);
1457 if (error)
1458 goto out;
1459 if (!hdr.ExtPageLength) {
1460 error = -ENXIO;
1461 goto out;
1462 }
1463
1464 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1465 &dma_handle);
1466 if (!buffer) {
1467 error = -ENOMEM;
1468 goto out;
1469 }
1470
1471 cfg.physAddr = dma_handle;
1472 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1473
1474 error = mpt_config(ioc, &cfg);
1475 if (error)
1476 goto out_free_consistent;
1477
1478 port_info->num_phys = buffer->NumPhys;
1479 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001480 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001481 if (!port_info->phy_info) {
1482 error = -ENOMEM;
1483 goto out_free_consistent;
1484 }
1485
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301486 ioc->nvdata_version_persistent =
1487 le16_to_cpu(buffer->NvdataVersionPersistent);
1488 ioc->nvdata_version_default =
1489 le16_to_cpu(buffer->NvdataVersionDefault);
1490
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001491 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301492 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001493 port_info->phy_info[i].phy_id = i;
1494 port_info->phy_info[i].port_id =
1495 buffer->PhyData[i].Port;
1496 port_info->phy_info[i].negotiated_link_rate =
1497 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001498 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001499 port_info->phy_info[i].handle =
1500 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001501 }
1502
1503 out_free_consistent:
1504 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1505 buffer, dma_handle);
1506 out:
1507 return error;
1508}
1509
1510static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301511mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1512{
1513 ConfigExtendedPageHeader_t hdr;
1514 CONFIGPARMS cfg;
1515 SasIOUnitPage1_t *buffer;
1516 dma_addr_t dma_handle;
1517 int error;
1518 u16 device_missing_delay;
1519
1520 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1521 memset(&cfg, 0, sizeof(CONFIGPARMS));
1522
1523 cfg.cfghdr.ehdr = &hdr;
1524 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1525 cfg.timeout = 10;
1526 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1527 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1528 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1529 cfg.cfghdr.ehdr->PageNumber = 1;
1530
1531 error = mpt_config(ioc, &cfg);
1532 if (error)
1533 goto out;
1534 if (!hdr.ExtPageLength) {
1535 error = -ENXIO;
1536 goto out;
1537 }
1538
1539 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1540 &dma_handle);
1541 if (!buffer) {
1542 error = -ENOMEM;
1543 goto out;
1544 }
1545
1546 cfg.physAddr = dma_handle;
1547 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1548
1549 error = mpt_config(ioc, &cfg);
1550 if (error)
1551 goto out_free_consistent;
1552
1553 ioc->io_missing_delay =
1554 le16_to_cpu(buffer->IODeviceMissingDelay);
1555 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1556 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1557 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1558 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1559
1560 out_free_consistent:
1561 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1562 buffer, dma_handle);
1563 out:
1564 return error;
1565}
1566
1567static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001568mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1569 u32 form, u32 form_specific)
1570{
1571 ConfigExtendedPageHeader_t hdr;
1572 CONFIGPARMS cfg;
1573 SasPhyPage0_t *buffer;
1574 dma_addr_t dma_handle;
1575 int error;
1576
1577 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1578 hdr.ExtPageLength = 0;
1579 hdr.PageNumber = 0;
1580 hdr.Reserved1 = 0;
1581 hdr.Reserved2 = 0;
1582 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1583 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1584
1585 cfg.cfghdr.ehdr = &hdr;
1586 cfg.dir = 0; /* read */
1587 cfg.timeout = 10;
1588
1589 /* Get Phy Pg 0 for each Phy. */
1590 cfg.physAddr = -1;
1591 cfg.pageAddr = form + form_specific;
1592 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1593
1594 error = mpt_config(ioc, &cfg);
1595 if (error)
1596 goto out;
1597
1598 if (!hdr.ExtPageLength) {
1599 error = -ENXIO;
1600 goto out;
1601 }
1602
1603 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1604 &dma_handle);
1605 if (!buffer) {
1606 error = -ENOMEM;
1607 goto out;
1608 }
1609
1610 cfg.physAddr = dma_handle;
1611 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1612
1613 error = mpt_config(ioc, &cfg);
1614 if (error)
1615 goto out_free_consistent;
1616
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301617 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001618
1619 phy_info->hw_link_rate = buffer->HwLinkRate;
1620 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1621 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1622 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1623
1624 out_free_consistent:
1625 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1626 buffer, dma_handle);
1627 out:
1628 return error;
1629}
1630
1631static int
1632mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1633 u32 form, u32 form_specific)
1634{
1635 ConfigExtendedPageHeader_t hdr;
1636 CONFIGPARMS cfg;
1637 SasDevicePage0_t *buffer;
1638 dma_addr_t dma_handle;
1639 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001640 int error=0;
1641
1642 if (ioc->sas_discovery_runtime &&
1643 mptsas_is_end_device(device_info))
1644 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001645
1646 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1647 hdr.ExtPageLength = 0;
1648 hdr.PageNumber = 0;
1649 hdr.Reserved1 = 0;
1650 hdr.Reserved2 = 0;
1651 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1652 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1653
1654 cfg.cfghdr.ehdr = &hdr;
1655 cfg.pageAddr = form + form_specific;
1656 cfg.physAddr = -1;
1657 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1658 cfg.dir = 0; /* read */
1659 cfg.timeout = 10;
1660
Moore, Ericdb9c9172006-03-14 09:14:18 -07001661 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001662 error = mpt_config(ioc, &cfg);
1663 if (error)
1664 goto out;
1665 if (!hdr.ExtPageLength) {
1666 error = -ENXIO;
1667 goto out;
1668 }
1669
1670 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1671 &dma_handle);
1672 if (!buffer) {
1673 error = -ENOMEM;
1674 goto out;
1675 }
1676
1677 cfg.physAddr = dma_handle;
1678 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1679
1680 error = mpt_config(ioc, &cfg);
1681 if (error)
1682 goto out_free_consistent;
1683
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301684 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001685
1686 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001687 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001688 device_info->handle_enclosure =
1689 le16_to_cpu(buffer->EnclosureHandle);
1690 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001691 device_info->phy_id = buffer->PhyNum;
1692 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001693 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001694 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001695 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001696 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1697 device_info->sas_address = le64_to_cpu(sas_address);
1698 device_info->device_info =
1699 le32_to_cpu(buffer->DeviceInfo);
1700
1701 out_free_consistent:
1702 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1703 buffer, dma_handle);
1704 out:
1705 return error;
1706}
1707
1708static int
1709mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1710 u32 form, u32 form_specific)
1711{
1712 ConfigExtendedPageHeader_t hdr;
1713 CONFIGPARMS cfg;
1714 SasExpanderPage0_t *buffer;
1715 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001716 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001717
1718 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1719 hdr.ExtPageLength = 0;
1720 hdr.PageNumber = 0;
1721 hdr.Reserved1 = 0;
1722 hdr.Reserved2 = 0;
1723 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1724 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1725
1726 cfg.cfghdr.ehdr = &hdr;
1727 cfg.physAddr = -1;
1728 cfg.pageAddr = form + form_specific;
1729 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1730 cfg.dir = 0; /* read */
1731 cfg.timeout = 10;
1732
Moore, Ericdb9c9172006-03-14 09:14:18 -07001733 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001734 error = mpt_config(ioc, &cfg);
1735 if (error)
1736 goto out;
1737
1738 if (!hdr.ExtPageLength) {
1739 error = -ENXIO;
1740 goto out;
1741 }
1742
1743 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1744 &dma_handle);
1745 if (!buffer) {
1746 error = -ENOMEM;
1747 goto out;
1748 }
1749
1750 cfg.physAddr = dma_handle;
1751 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1752
1753 error = mpt_config(ioc, &cfg);
1754 if (error)
1755 goto out_free_consistent;
1756
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08001757 if (!buffer->NumPhys) {
1758 error = -ENODEV;
1759 goto out_free_consistent;
1760 }
1761
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001762 /* save config data */
1763 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001764 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001765 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001766 if (!port_info->phy_info) {
1767 error = -ENOMEM;
1768 goto out_free_consistent;
1769 }
1770
Eric Moore2ecce492007-01-29 09:47:08 -07001771 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001772 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001773 port_info->phy_info[i].handle =
1774 le16_to_cpu(buffer->DevHandle);
1775 }
Eric Moore547f9a22006-06-27 14:42:12 -06001776
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001777 out_free_consistent:
1778 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1779 buffer, dma_handle);
1780 out:
1781 return error;
1782}
1783
1784static int
1785mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1786 u32 form, u32 form_specific)
1787{
1788 ConfigExtendedPageHeader_t hdr;
1789 CONFIGPARMS cfg;
1790 SasExpanderPage1_t *buffer;
1791 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001792 int error=0;
1793
1794 if (ioc->sas_discovery_runtime &&
1795 mptsas_is_end_device(&phy_info->attached))
1796 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001797
1798 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1799 hdr.ExtPageLength = 0;
1800 hdr.PageNumber = 1;
1801 hdr.Reserved1 = 0;
1802 hdr.Reserved2 = 0;
1803 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1804 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1805
1806 cfg.cfghdr.ehdr = &hdr;
1807 cfg.physAddr = -1;
1808 cfg.pageAddr = form + form_specific;
1809 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1810 cfg.dir = 0; /* read */
1811 cfg.timeout = 10;
1812
1813 error = mpt_config(ioc, &cfg);
1814 if (error)
1815 goto out;
1816
1817 if (!hdr.ExtPageLength) {
1818 error = -ENXIO;
1819 goto out;
1820 }
1821
1822 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1823 &dma_handle);
1824 if (!buffer) {
1825 error = -ENOMEM;
1826 goto out;
1827 }
1828
1829 cfg.physAddr = dma_handle;
1830 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1831
1832 error = mpt_config(ioc, &cfg);
1833 if (error)
1834 goto out_free_consistent;
1835
1836
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301837 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001838
1839 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001840 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001841 phy_info->port_id = buffer->PhysicalPort;
1842 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1843 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1844 phy_info->hw_link_rate = buffer->HwLinkRate;
1845 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1846 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1847
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001848 out_free_consistent:
1849 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1850 buffer, dma_handle);
1851 out:
1852 return error;
1853}
1854
1855static void
1856mptsas_parse_device_info(struct sas_identify *identify,
1857 struct mptsas_devinfo *device_info)
1858{
1859 u16 protocols;
1860
1861 identify->sas_address = device_info->sas_address;
1862 identify->phy_identifier = device_info->phy_id;
1863
1864 /*
1865 * Fill in Phy Initiator Port Protocol.
1866 * Bits 6:3, more than one bit can be set, fall through cases.
1867 */
1868 protocols = device_info->device_info & 0x78;
1869 identify->initiator_port_protocols = 0;
1870 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1871 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1872 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1873 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1874 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1875 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1876 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1877 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1878
1879 /*
1880 * Fill in Phy Target Port Protocol.
1881 * Bits 10:7, more than one bit can be set, fall through cases.
1882 */
1883 protocols = device_info->device_info & 0x780;
1884 identify->target_port_protocols = 0;
1885 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1886 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1887 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1888 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1889 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1890 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1891 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1892 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1893
1894 /*
1895 * Fill in Attached device type.
1896 */
1897 switch (device_info->device_info &
1898 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1899 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1900 identify->device_type = SAS_PHY_UNUSED;
1901 break;
1902 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1903 identify->device_type = SAS_END_DEVICE;
1904 break;
1905 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1906 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1907 break;
1908 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1909 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1910 break;
1911 }
1912}
1913
1914static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001915 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001916{
Moore, Erice6b2d762006-03-14 09:14:24 -07001917 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001918 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001919 struct sas_port *port;
1920 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001921
Eric Moore547f9a22006-06-27 14:42:12 -06001922 if (!dev) {
1923 error = -ENODEV;
1924 goto out;
1925 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001926
1927 if (!phy_info->phy) {
1928 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001929 if (!phy) {
1930 error = -ENOMEM;
1931 goto out;
1932 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001933 } else
1934 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001935
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001936 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001937
1938 /*
1939 * Set Negotiated link rate.
1940 */
1941 switch (phy_info->negotiated_link_rate) {
1942 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001943 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001944 break;
1945 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001946 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001947 break;
1948 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001949 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001950 break;
1951 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001952 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001953 break;
1954 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1955 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1956 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001957 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001958 break;
1959 }
1960
1961 /*
1962 * Set Max hardware link rate.
1963 */
1964 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1965 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001966 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001967 break;
1968 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001969 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001970 break;
1971 default:
1972 break;
1973 }
1974
1975 /*
1976 * Set Max programmed link rate.
1977 */
1978 switch (phy_info->programmed_link_rate &
1979 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1980 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001981 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001982 break;
1983 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001984 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001985 break;
1986 default:
1987 break;
1988 }
1989
1990 /*
1991 * Set Min hardware link rate.
1992 */
1993 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1994 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001995 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001996 break;
1997 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001998 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001999 break;
2000 default:
2001 break;
2002 }
2003
2004 /*
2005 * Set Min programmed link rate.
2006 */
2007 switch (phy_info->programmed_link_rate &
2008 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2009 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002010 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002011 break;
2012 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002013 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002014 break;
2015 default:
2016 break;
2017 }
2018
Moore, Erice6b2d762006-03-14 09:14:24 -07002019 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002020
Moore, Erice6b2d762006-03-14 09:14:24 -07002021 error = sas_phy_add(phy);
2022 if (error) {
2023 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002024 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002025 }
2026 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002027 }
2028
Eric Moore547f9a22006-06-27 14:42:12 -06002029 if (!phy_info->attached.handle ||
2030 !phy_info->port_details)
2031 goto out;
2032
2033 port = mptsas_get_port(phy_info);
2034 ioc = phy_to_ioc(phy_info->phy);
2035
2036 if (phy_info->sas_port_add_phy) {
2037
2038 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002039 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002040 if (!port) {
2041 error = -ENOMEM;
2042 goto out;
2043 }
2044 error = sas_port_add(port);
2045 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302046 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002047 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002048 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002049 goto out;
2050 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302051 mptsas_set_port(ioc, phy_info, port);
Eric Moore29dd3602007-09-14 18:46:51 -06002052 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooredc22f162006-07-06 11:23:14 -06002053 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002054 ioc->name, port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002055 }
Eric Moore29dd3602007-09-14 18:46:51 -06002056 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
2057 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002058 sas_port_add_phy(port, phy_info->phy);
2059 phy_info->sas_port_add_phy = 0;
2060 }
2061
2062 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002063
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002064 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002065 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002066 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002067
James Bottomley2686de22006-06-30 12:54:02 -05002068 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002069 /*
2070 * Let the hotplug_work thread handle processing
2071 * the adding/removing of devices that occur
2072 * after start of day.
2073 */
2074 if (ioc->sas_discovery_runtime &&
2075 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002076 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002077
James Bottomleyf013db32006-03-18 14:54:36 -06002078 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002079 if (scsi_is_host_device(parent)) {
2080 struct mptsas_portinfo *port_info;
2081 int i;
2082
2083 mutex_lock(&ioc->sas_topology_mutex);
Michael Reed77483692008-03-20 17:32:05 -05002084 port_info = mptsas_get_hba_portinfo(ioc);
James Bottomley2686de22006-06-30 12:54:02 -05002085 mutex_unlock(&ioc->sas_topology_mutex);
2086
2087 for (i = 0; i < port_info->num_phys; i++)
2088 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002089 identify.sas_address) {
2090 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002091 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002092 }
James Bottomley2686de22006-06-30 12:54:02 -05002093
2094 } else if (scsi_is_sas_rphy(parent)) {
2095 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2096 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002097 parent_rphy->identify.sas_address) {
2098 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002099 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002100 }
James Bottomley2686de22006-06-30 12:54:02 -05002101 }
2102
James Bottomleyf013db32006-03-18 14:54:36 -06002103 switch (identify.device_type) {
2104 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002105 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002106 break;
2107 case SAS_EDGE_EXPANDER_DEVICE:
2108 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002109 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002110 break;
2111 default:
2112 rphy = NULL;
2113 break;
2114 }
Eric Moore547f9a22006-06-27 14:42:12 -06002115 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302116 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002117 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002118 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002119 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002120 }
2121
Eric Moore547f9a22006-06-27 14:42:12 -06002122 rphy->identify = identify;
2123 error = sas_rphy_add(rphy);
2124 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302125 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002126 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002127 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002128 sas_rphy_free(rphy);
2129 goto out;
2130 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302131 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002132 }
2133
Eric Moore547f9a22006-06-27 14:42:12 -06002134 out:
2135 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002136}
2137
2138static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002139mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002140{
Moore, Erice6b2d762006-03-14 09:14:24 -07002141 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002142 int error = -ENOMEM, i;
2143
Moore, Erice6b2d762006-03-14 09:14:24 -07002144 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2145 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002146 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002147
Moore, Erice6b2d762006-03-14 09:14:24 -07002148 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002149 if (error)
2150 goto out_free_port_info;
2151
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302152 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002153 mutex_lock(&ioc->sas_topology_mutex);
Michael Reed77483692008-03-20 17:32:05 -05002154 port_info = mptsas_get_hba_portinfo(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002155 if (!port_info) {
2156 port_info = hba;
2157 list_add_tail(&port_info->list, &ioc->sas_topology);
2158 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002159 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002160 port_info->phy_info[i].negotiated_link_rate =
2161 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002162 port_info->phy_info[i].handle =
2163 hba->phy_info[i].handle;
2164 port_info->phy_info[i].port_id =
2165 hba->phy_info[i].port_id;
2166 }
Eric Moore547f9a22006-06-27 14:42:12 -06002167 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002168 kfree(hba);
2169 hba = NULL;
2170 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002171 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002172 for (i = 0; i < port_info->num_phys; i++) {
2173 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2174 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2175 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2176
2177 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002178 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2179 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2180 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002181 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002182 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002183 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002184 mptsas_sas_device_pg0(ioc,
2185 &port_info->phy_info[i].attached,
2186 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2187 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2188 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002189 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002190
Eric Moore547f9a22006-06-27 14:42:12 -06002191 mptsas_setup_wide_ports(ioc, port_info);
2192
2193 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002194 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002195 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002196
2197 return 0;
2198
2199 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002200 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002201 out:
2202 return error;
2203}
2204
2205static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002206mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002207{
Moore, Erice6b2d762006-03-14 09:14:24 -07002208 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002209 struct device *parent;
2210 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002211 int error = -ENOMEM, i, j;
2212
Moore, Erice6b2d762006-03-14 09:14:24 -07002213 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2214 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002215 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002216
Moore, Erice6b2d762006-03-14 09:14:24 -07002217 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002218 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2219 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002220 if (error)
2221 goto out_free_port_info;
2222
Eric Moore2ecce492007-01-29 09:47:08 -07002223 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002224
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002225 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002226 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2227 if (!port_info) {
2228 port_info = ex;
2229 list_add_tail(&port_info->list, &ioc->sas_topology);
2230 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002231 for (i = 0; i < ex->num_phys; i++) {
2232 port_info->phy_info[i].handle =
2233 ex->phy_info[i].handle;
2234 port_info->phy_info[i].port_id =
2235 ex->phy_info[i].port_id;
2236 }
Eric Moore547f9a22006-06-27 14:42:12 -06002237 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002238 kfree(ex);
2239 ex = NULL;
2240 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002241 mutex_unlock(&ioc->sas_topology_mutex);
2242
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002243 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002244 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2245 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2246 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2247
2248 if (port_info->phy_info[i].identify.handle) {
2249 mptsas_sas_device_pg0(ioc,
2250 &port_info->phy_info[i].identify,
2251 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2252 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2253 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002254 port_info->phy_info[i].identify.phy_id =
2255 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002256 }
2257
2258 if (port_info->phy_info[i].attached.handle) {
2259 mptsas_sas_device_pg0(ioc,
2260 &port_info->phy_info[i].attached,
2261 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2262 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2263 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002264 port_info->phy_info[i].attached.phy_id =
2265 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002266 }
Eric Moore547f9a22006-06-27 14:42:12 -06002267 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002268
Eric Moore547f9a22006-06-27 14:42:12 -06002269 parent = &ioc->sh->shost_gendev;
2270 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002271 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002272 list_for_each_entry(p, &ioc->sas_topology, list) {
2273 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002274 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002275 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002276 continue;
2277 rphy = mptsas_get_rphy(&p->phy_info[j]);
2278 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002279 }
2280 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002281 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002282 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002283
Eric Moore547f9a22006-06-27 14:42:12 -06002284 mptsas_setup_wide_ports(ioc, port_info);
2285
2286 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002287 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002288 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002289
2290 return 0;
2291
2292 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002293 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002294 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002295 kfree(ex);
2296 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002297 out:
2298 return error;
2299}
2300
Moore, Erice6b2d762006-03-14 09:14:24 -07002301/*
2302 * mptsas_delete_expander_phys
2303 *
2304 *
2305 * This will traverse topology, and remove expanders
2306 * that are no longer present
2307 */
2308static void
2309mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2310{
2311 struct mptsas_portinfo buffer;
2312 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002313 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002314 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002315 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002316 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002317
2318 mutex_lock(&ioc->sas_topology_mutex);
2319 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2320
Alan Coxd58069a2009-04-01 15:00:29 +01002321 if (!(port_info->phy_info[0].identify.device_info &
2322 MPI_SAS_DEVICE_INFO_SMP_TARGET))
Moore, Erice6b2d762006-03-14 09:14:24 -07002323 continue;
2324
2325 if (mptsas_sas_expander_pg0(ioc, &buffer,
2326 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002327 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2328 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002329
2330 /*
2331 * Obtain the port_info instance to the parent port
2332 */
2333 parent = mptsas_find_portinfo_by_handle(ioc,
2334 port_info->phy_info[0].identify.handle_parent);
2335
2336 if (!parent)
2337 goto next_port;
2338
Eric Moore547f9a22006-06-27 14:42:12 -06002339 expander_sas_address =
2340 port_info->phy_info[0].identify.sas_address;
2341
Moore, Erice6b2d762006-03-14 09:14:24 -07002342 /*
2343 * Delete rphys in the parent that point
2344 * to this expander. The transport layer will
2345 * cleanup all the children.
2346 */
Eric Moore547f9a22006-06-27 14:42:12 -06002347 phy_info = parent->phy_info;
2348 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2349 port = mptsas_get_port(phy_info);
2350 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002351 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002352 if (phy_info->attached.sas_address !=
2353 expander_sas_address)
2354 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302355 dsaswideprintk(ioc,
Eric Moorec51d0be2007-09-29 10:17:21 -06002356 dev_printk(KERN_DEBUG, &port->dev,
2357 MYIOC_s_FMT "delete port (%d)\n", ioc->name,
2358 port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002359 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302360 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002361 }
2362 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002363
2364 phy_info = port_info->phy_info;
2365 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302366 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002367
Moore, Erice6b2d762006-03-14 09:14:24 -07002368 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002369 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002370 kfree(port_info);
2371 }
2372 /*
2373 * Free this memory allocated from inside
2374 * mptsas_sas_expander_pg0
2375 */
Eric Moore547f9a22006-06-27 14:42:12 -06002376 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002377 }
2378 mutex_unlock(&ioc->sas_topology_mutex);
2379}
2380
2381/*
2382 * Start of day discovery
2383 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002384static void
2385mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2386{
2387 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002388 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002389
Moore, Erice6b2d762006-03-14 09:14:24 -07002390 mutex_lock(&ioc->sas_discovery_mutex);
2391 mptsas_probe_hba_phys(ioc);
2392 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002393 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002394 /*
2395 Reporting RAID volumes.
2396 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002397 if (!ioc->ir_firmware)
2398 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002399 if (!ioc->raid_data.pIocPg2)
2400 goto out;
2401 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2402 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002403 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002404 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002405 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2406 }
2407 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002408 mutex_unlock(&ioc->sas_discovery_mutex);
2409}
2410
2411/*
2412 * Work queue thread to handle Runtime discovery
2413 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002414 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002415 */
2416static void
Eric Moore547f9a22006-06-27 14:42:12 -06002417__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002418{
Moore, Erice6b2d762006-03-14 09:14:24 -07002419 u32 handle = 0xFFFF;
2420
Moore, Erice6b2d762006-03-14 09:14:24 -07002421 ioc->sas_discovery_runtime=1;
2422 mptsas_delete_expander_phys(ioc);
2423 mptsas_probe_hba_phys(ioc);
2424 while (!mptsas_probe_expander_phys(ioc, &handle))
2425 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002426 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002427}
2428
2429/*
2430 * Work queue thread to handle Runtime discovery
2431 * Mere purpose is the hot add/delete of expanders
2432 *(Mutex LOCKED)
2433 */
2434static void
David Howellsc4028952006-11-22 14:57:56 +00002435mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002436{
David Howellsc4028952006-11-22 14:57:56 +00002437 struct mptsas_discovery_event *ev =
2438 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002439 MPT_ADAPTER *ioc = ev->ioc;
2440
2441 mutex_lock(&ioc->sas_discovery_mutex);
2442 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002443 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002444 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002445}
2446
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002447static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002448mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002449{
2450 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002451 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002452 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002453
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002454 mutex_lock(&ioc->sas_topology_mutex);
2455 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2456 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002457 if (!mptsas_is_end_device(
2458 &port_info->phy_info[i].attached))
2459 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002460 if (port_info->phy_info[i].attached.sas_address
2461 != sas_address)
2462 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002463 phy_info = &port_info->phy_info[i];
2464 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002465 }
2466 }
2467 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002468 return phy_info;
2469}
2470
2471static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002472mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002473{
2474 struct mptsas_portinfo *port_info;
2475 struct mptsas_phyinfo *phy_info = NULL;
2476 int i;
2477
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002478 mutex_lock(&ioc->sas_topology_mutex);
2479 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002480 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002481 if (!mptsas_is_end_device(
2482 &port_info->phy_info[i].attached))
2483 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002484 if (port_info->phy_info[i].attached.id != id)
2485 continue;
2486 if (port_info->phy_info[i].attached.channel != channel)
2487 continue;
2488 phy_info = &port_info->phy_info[i];
2489 break;
2490 }
2491 }
2492 mutex_unlock(&ioc->sas_topology_mutex);
2493 return phy_info;
2494}
2495
2496static struct mptsas_phyinfo *
2497mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2498{
2499 struct mptsas_portinfo *port_info;
2500 struct mptsas_phyinfo *phy_info = NULL;
2501 int i;
2502
2503 mutex_lock(&ioc->sas_topology_mutex);
2504 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2505 for (i = 0; i < port_info->num_phys; i++) {
2506 if (!mptsas_is_end_device(
2507 &port_info->phy_info[i].attached))
2508 continue;
2509 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2510 continue;
2511 if (port_info->phy_info[i].attached.phys_disk_num != id)
2512 continue;
2513 if (port_info->phy_info[i].attached.channel != channel)
2514 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002515 phy_info = &port_info->phy_info[i];
2516 break;
2517 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002518 }
2519 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002520 return phy_info;
2521}
2522
Moore, Eric4b766472006-03-14 09:14:12 -07002523/*
2524 * Work queue thread to clear the persitency table
2525 */
2526static void
David Howellsc4028952006-11-22 14:57:56 +00002527mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002528{
David Howellsc4028952006-11-22 14:57:56 +00002529 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002530
2531 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2532}
2533
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002534static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002535mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2536{
Eric Mooref99be432007-01-04 20:46:54 -07002537 int rc;
2538
Moore, Ericf44e5462006-03-14 09:14:21 -07002539 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002540 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002541}
2542
2543static void
2544mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2545{
2546 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2547 mptsas_reprobe_lun);
2548}
2549
Eric Mooreb506ade2007-01-29 09:45:37 -07002550static void
2551mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2552{
2553 CONFIGPARMS cfg;
2554 ConfigPageHeader_t hdr;
2555 dma_addr_t dma_handle;
2556 pRaidVolumePage0_t buffer = NULL;
2557 RaidPhysDiskPage0_t phys_disk;
2558 int i;
2559 struct mptsas_hotplug_event *ev;
2560
2561 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2562 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2563 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2564 cfg.pageAddr = (channel << 8) + id;
2565 cfg.cfghdr.hdr = &hdr;
2566 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2567
2568 if (mpt_config(ioc, &cfg) != 0)
2569 goto out;
2570
2571 if (!hdr.PageLength)
2572 goto out;
2573
2574 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2575 &dma_handle);
2576
2577 if (!buffer)
2578 goto out;
2579
2580 cfg.physAddr = dma_handle;
2581 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2582
2583 if (mpt_config(ioc, &cfg) != 0)
2584 goto out;
2585
2586 if (!(buffer->VolumeStatus.Flags &
2587 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2588 goto out;
2589
2590 if (!buffer->NumPhysDisks)
2591 goto out;
2592
2593 for (i = 0; i < buffer->NumPhysDisks; i++) {
2594
2595 if (mpt_raid_phys_disk_pg0(ioc,
2596 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2597 continue;
2598
2599 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2600 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002601 printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
Eric Mooreb506ade2007-01-29 09:45:37 -07002602 goto out;
2603 }
2604
2605 INIT_WORK(&ev->work, mptsas_hotplug_work);
2606 ev->ioc = ioc;
2607 ev->id = phys_disk.PhysDiskID;
2608 ev->channel = phys_disk.PhysDiskBus;
2609 ev->phys_disk_num_valid = 1;
2610 ev->phys_disk_num = phys_disk.PhysDiskNum;
2611 ev->event_type = MPTSAS_ADD_DEVICE;
2612 schedule_work(&ev->work);
2613 }
2614
2615 out:
2616 if (buffer)
2617 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2618 dma_handle);
2619}
Moore, Erice6b2d762006-03-14 09:14:24 -07002620/*
2621 * Work queue thread to handle SAS hotplug events
2622 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002623static void
David Howellsc4028952006-11-22 14:57:56 +00002624mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002625{
David Howellsc4028952006-11-22 14:57:56 +00002626 struct mptsas_hotplug_event *ev =
2627 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002628
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002629 MPT_ADAPTER *ioc = ev->ioc;
2630 struct mptsas_phyinfo *phy_info;
2631 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002632 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002633 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002634 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002635 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002636 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002637 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002638 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002639 VirtDevice *vdevice;
2640
Moore, Erice6b2d762006-03-14 09:14:24 -07002641 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002642 switch (ev->event_type) {
2643 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002644
Eric Mooreb506ade2007-01-29 09:45:37 -07002645 phy_info = NULL;
2646 if (ev->phys_disk_num_valid) {
2647 if (ev->hidden_raid_component){
2648 if (mptsas_sas_device_pg0(ioc, &sas_device,
2649 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2650 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2651 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302652 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002653 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002654 __func__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002655 break;
2656 }
2657 phy_info = mptsas_find_phyinfo_by_sas_address(
2658 ioc, sas_device.sas_address);
2659 }else
2660 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2661 ioc, ev->channel, ev->phys_disk_num);
2662 }
2663
2664 if (!phy_info)
2665 phy_info = mptsas_find_phyinfo_by_target(ioc,
2666 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002667
Moore, Ericf44e5462006-03-14 09:14:21 -07002668 /*
2669 * Sanity checks, for non-existing phys and remote rphys.
2670 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002671 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302672 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002673 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002674 __func__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002675 break;
2676 }
2677 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302678 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002679 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002680 __func__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002681 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002682 }
2683 rphy = mptsas_get_rphy(phy_info);
2684 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302685 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002686 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002687 __func__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002688 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002689 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002690
Eric Moore547f9a22006-06-27 14:42:12 -06002691 port = mptsas_get_port(phy_info);
2692 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302693 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002694 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002695 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002696 break;
2697 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002698
Eric Moore547f9a22006-06-27 14:42:12 -06002699 starget = mptsas_get_starget(phy_info);
2700 if (starget) {
2701 vtarget = starget->hostdata;
2702
2703 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302704 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002705 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002706 __func__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002707 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002708 }
2709
Moore, Ericf44e5462006-03-14 09:14:21 -07002710 /*
2711 * Handling RAID components
2712 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002713 if (ev->phys_disk_num_valid &&
2714 ev->hidden_raid_component) {
2715 printk(MYIOC_s_INFO_FMT
2716 "RAID Hidding: channel=%d, id=%d, "
2717 "physdsk %d \n", ioc->name, ev->channel,
2718 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002719 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002720 vtarget->tflags |=
2721 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002722 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002723 phy_info->attached.phys_disk_num =
2724 ev->phys_disk_num;
2725 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002726 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002727 }
2728
Eric Mooreb506ade2007-01-29 09:45:37 -07002729 if (phy_info->attached.device_info &
2730 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002731 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002732 if (phy_info->attached.device_info &
2733 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002734 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002735 if (phy_info->attached.device_info &
2736 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002737 ds = "sata";
2738
2739 printk(MYIOC_s_INFO_FMT
2740 "removing %s device, channel %d, id %d, phy %d\n",
2741 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moorec51d0be2007-09-29 10:17:21 -06002742 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002743 "delete port (%d)\n", ioc->name, port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002744 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302745 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002746 break;
2747 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002748
Moore, Ericbd23e942006-04-17 12:43:04 -06002749 if (ev->phys_disk_num_valid)
2750 mpt_findImVolumes(ioc);
2751
Moore, Ericc73787ee2006-01-26 16:20:06 -07002752 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002753 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002754 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002755 if (mptsas_sas_device_pg0(ioc, &sas_device,
2756 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002757 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2758 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302759 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002760 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002761 __func__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002762 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002763 }
2764
Eric Moore547f9a22006-06-27 14:42:12 -06002765 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002766
Eric Moore547f9a22006-06-27 14:42:12 -06002767 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2768 sas_device.sas_address);
2769
2770 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302771 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002772 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002773 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002774 break;
2775 }
2776
2777 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002778 if (starget && (!ev->hidden_raid_component)){
2779
Eric Moore547f9a22006-06-27 14:42:12 -06002780 vtarget = starget->hostdata;
2781
2782 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302783 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002784 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002785 __func__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002786 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002787 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002788 /*
2789 * Handling RAID components
2790 */
2791 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002792 printk(MYIOC_s_INFO_FMT
2793 "RAID Exposing: channel=%d, id=%d, "
2794 "physdsk %d \n", ioc->name, ev->channel,
2795 ev->id, ev->phys_disk_num);
2796 vtarget->tflags &=
2797 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002798 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002799 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002800 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002801 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002802 break;
2803 }
2804
Eric Moore547f9a22006-06-27 14:42:12 -06002805 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302806 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002807 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002808 __func__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002809 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002810 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002811 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002812
Eric Moore547f9a22006-06-27 14:42:12 -06002813 port = mptsas_get_port(phy_info);
2814 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302815 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002816 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002817 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002818 break;
2819 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002820 memcpy(&phy_info->attached, &sas_device,
2821 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002822
Eric Mooreb506ade2007-01-29 09:45:37 -07002823 if (phy_info->attached.device_info &
2824 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002825 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002826 if (phy_info->attached.device_info &
2827 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002828 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002829 if (phy_info->attached.device_info &
2830 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002831 ds = "sata";
2832
2833 printk(MYIOC_s_INFO_FMT
2834 "attaching %s device, channel %d, id %d, phy %d\n",
2835 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2836
James Bottomleyf013db32006-03-18 14:54:36 -06002837 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002838 rphy = sas_end_device_alloc(port);
2839 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302840 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002841 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002842 __func__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002843 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002844 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002845
James Bottomleyf013db32006-03-18 14:54:36 -06002846 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002847 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302848 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002849 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002850 __func__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002851 sas_rphy_free(rphy);
2852 break;
2853 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302854 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002855 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002856 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002857 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2858 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002859 if (sdev) {
2860 scsi_device_put(sdev);
2861 break;
2862 }
2863 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002864 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002865 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2866 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002867 mpt_findImVolumes(ioc);
2868 break;
2869 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002870 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002871 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002872 if (!sdev)
2873 break;
2874 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002875 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002876 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002877 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002878 scsi_remove_device(sdev);
2879 scsi_device_put(sdev);
2880 mpt_findImVolumes(ioc);
2881 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002882 case MPTSAS_ADD_INACTIVE_VOLUME:
2883 mptsas_adding_inactive_raid_components(ioc,
2884 ev->channel, ev->id);
2885 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002886 case MPTSAS_IGNORE_EVENT:
2887 default:
2888 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002889 }
2890
Moore, Erice6b2d762006-03-14 09:14:24 -07002891 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002892 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002893}
2894
2895static void
Eric Moore547f9a22006-06-27 14:42:12 -06002896mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002897 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2898{
2899 struct mptsas_hotplug_event *ev;
2900 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2901 __le64 sas_address;
2902
2903 if ((device_info &
2904 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2905 MPI_SAS_DEVICE_INFO_STP_TARGET |
2906 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2907 return;
2908
Moore, Eric4b766472006-03-14 09:14:12 -07002909 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002910 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002911
2912 mptsas_target_reset_queue(ioc, sas_event_data);
2913 break;
2914
2915 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002916 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002917 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002918 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Eric4b766472006-03-14 09:14:12 -07002919 break;
2920 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002921
David Howellsc4028952006-11-22 14:57:56 +00002922 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002923 ev->ioc = ioc;
2924 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2925 ev->parent_handle =
2926 le16_to_cpu(sas_event_data->ParentDevHandle);
2927 ev->channel = sas_event_data->Bus;
2928 ev->id = sas_event_data->TargetID;
2929 ev->phy_id = sas_event_data->PhyNum;
2930 memcpy(&sas_address, &sas_event_data->SASAddress,
2931 sizeof(__le64));
2932 ev->sas_address = le64_to_cpu(sas_address);
2933 ev->device_info = device_info;
2934
2935 if (sas_event_data->ReasonCode &
2936 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2937 ev->event_type = MPTSAS_ADD_DEVICE;
2938 else
2939 ev->event_type = MPTSAS_DEL_DEVICE;
2940 schedule_work(&ev->work);
2941 break;
2942 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2943 /*
2944 * Persistent table is full.
2945 */
Eric Moore547f9a22006-06-27 14:42:12 -06002946 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002947 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002948 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002949 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002950 /*
2951 * TODO, handle other events
2952 */
Moore, Eric4b766472006-03-14 09:14:12 -07002953 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002954 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002955 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002956 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2957 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2958 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2959 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002960 default:
2961 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002962 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002963}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002964static void
Eric Moore547f9a22006-06-27 14:42:12 -06002965mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002966 EVENT_DATA_RAID *raid_event_data)
2967{
2968 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002969 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2970 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002971
2972 if (ioc->bus_type != SAS)
2973 return;
2974
Eric Moore547f9a22006-06-27 14:42:12 -06002975 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002976 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002977 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002978 return;
2979 }
2980
David Howellsc4028952006-11-22 14:57:56 +00002981 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002982 ev->ioc = ioc;
2983 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002984 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002985 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002986
2987 switch (raid_event_data->ReasonCode) {
2988 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002989 ev->phys_disk_num_valid = 1;
2990 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002991 ev->event_type = MPTSAS_ADD_DEVICE;
2992 break;
2993 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002994 ev->phys_disk_num_valid = 1;
2995 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002996 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002997 ev->event_type = MPTSAS_DEL_DEVICE;
2998 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002999 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
3000 switch (state) {
3001 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07003002 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06003003 ev->phys_disk_num_valid = 1;
3004 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07003005 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06003006 ev->event_type = MPTSAS_ADD_DEVICE;
3007 break;
3008 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06003009 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
3010 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
3011 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07003012 ev->phys_disk_num_valid = 1;
3013 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06003014 ev->event_type = MPTSAS_DEL_DEVICE;
3015 break;
3016 default:
3017 break;
3018 }
3019 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003020 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
3021 ev->event_type = MPTSAS_DEL_RAID;
3022 break;
3023 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
3024 ev->event_type = MPTSAS_ADD_RAID;
3025 break;
3026 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06003027 switch (state) {
3028 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
3029 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
3030 ev->event_type = MPTSAS_DEL_RAID;
3031 break;
3032 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
3033 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
3034 ev->event_type = MPTSAS_ADD_RAID;
3035 break;
3036 default:
3037 break;
3038 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003039 break;
3040 default:
3041 break;
3042 }
3043 schedule_work(&ev->work);
3044}
3045
Moore, Erice6b2d762006-03-14 09:14:24 -07003046static void
Eric Moore547f9a22006-06-27 14:42:12 -06003047mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003048 EVENT_DATA_SAS_DISCOVERY *discovery_data)
3049{
3050 struct mptsas_discovery_event *ev;
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303051 u32 discovery_status;
Moore, Erice6b2d762006-03-14 09:14:24 -07003052
3053 /*
3054 * DiscoveryStatus
3055 *
3056 * This flag will be non-zero when firmware
3057 * kicks off discovery, and return to zero
3058 * once its completed.
3059 */
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303060 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
3061 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
3062 if (discovery_status)
Moore, Erice6b2d762006-03-14 09:14:24 -07003063 return;
3064
Eric Moore547f9a22006-06-27 14:42:12 -06003065 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07003066 if (!ev)
3067 return;
David Howellsc4028952006-11-22 14:57:56 +00003068 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07003069 ev->ioc = ioc;
3070 schedule_work(&ev->work);
3071};
3072
Eric Mooreb506ade2007-01-29 09:45:37 -07003073/*
3074 * mptsas_send_ir2_event - handle exposing hidden disk when
3075 * an inactive raid volume is added
3076 *
3077 * @ioc: Pointer to MPT_ADAPTER structure
3078 * @ir2_data
3079 *
3080 */
3081static void
3082mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
3083{
3084 struct mptsas_hotplug_event *ev;
3085
3086 if (ir2_data->ReasonCode !=
3087 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
3088 return;
3089
3090 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
3091 if (!ev)
3092 return;
3093
3094 INIT_WORK(&ev->work, mptsas_hotplug_work);
3095 ev->ioc = ioc;
3096 ev->id = ir2_data->TargetID;
3097 ev->channel = ir2_data->Bus;
3098 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3099
3100 schedule_work(&ev->work);
3101};
Moore, Erice6b2d762006-03-14 09:14:24 -07003102
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003103static int
3104mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3105{
Moore, Ericc73787ee2006-01-26 16:20:06 -07003106 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003107 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3108
3109 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003110 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003111
Moore, Erice6b2d762006-03-14 09:14:24 -07003112 /*
3113 * sas_discovery_ignore_events
3114 *
3115 * This flag is to prevent anymore processing of
3116 * sas events once mptsas_remove function is called.
3117 */
3118 if (ioc->sas_discovery_ignore_events) {
3119 rc = mptscsih_event_process(ioc, reply);
3120 goto out;
3121 }
3122
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003123 switch (event) {
3124 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003125 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003126 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003127 break;
3128 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003129 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003130 (EVENT_DATA_RAID *)reply->Data);
3131 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003132 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003133 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003134 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003135 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003136 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003137 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003138 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003139 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3140 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003141 case MPI_EVENT_IR2:
3142 mptsas_send_ir2_event(ioc,
3143 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3144 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003145 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003146 rc = mptscsih_event_process(ioc, reply);
3147 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003148 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003149 out:
3150
3151 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003152}
3153
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003154static int
3155mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3156{
3157 struct Scsi_Host *sh;
3158 MPT_SCSI_HOST *hd;
3159 MPT_ADAPTER *ioc;
3160 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003161 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003162 int numSGE = 0;
3163 int scale;
3164 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003165 int error=0;
3166 int r;
3167
3168 r = mpt_attach(pdev,id);
3169 if (r)
3170 return r;
3171
3172 ioc = pci_get_drvdata(pdev);
3173 ioc->DoneCtx = mptsasDoneCtx;
3174 ioc->TaskCtx = mptsasTaskCtx;
3175 ioc->InternalCtx = mptsasInternalCtx;
3176
3177 /* Added sanity check on readiness of the MPT adapter.
3178 */
3179 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3180 printk(MYIOC_s_WARN_FMT
3181 "Skipping because it's not operational!\n",
3182 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003183 error = -ENODEV;
3184 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003185 }
3186
3187 if (!ioc->active) {
3188 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3189 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003190 error = -ENODEV;
3191 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003192 }
3193
3194 /* Sanity check - ensure at least 1 port is INITIATOR capable
3195 */
3196 ioc_cap = 0;
3197 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3198 if (ioc->pfacts[ii].ProtocolFlags &
3199 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3200 ioc_cap++;
3201 }
3202
3203 if (!ioc_cap) {
3204 printk(MYIOC_s_WARN_FMT
3205 "Skipping ioc=%p because SCSI Initiator mode "
3206 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003207 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003208 }
3209
3210 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3211 if (!sh) {
3212 printk(MYIOC_s_WARN_FMT
3213 "Unable to register controller with SCSI subsystem\n",
3214 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003215 error = -1;
3216 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003217 }
3218
3219 spin_lock_irqsave(&ioc->FreeQlock, flags);
3220
3221 /* Attach the SCSI Host to the IOC structure
3222 */
3223 ioc->sh = sh;
3224
3225 sh->io_port = 0;
3226 sh->n_io_port = 0;
3227 sh->irq = 0;
3228
3229 /* set 16 byte cdb's */
3230 sh->max_cmd_len = 16;
3231
Eric Moore793955f2007-01-29 09:42:20 -07003232 sh->max_id = ioc->pfacts[0].PortSCSIID;
3233 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003234
3235 sh->transportt = mptsas_transport_template;
3236
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003237 /* Required entry.
3238 */
3239 sh->unique_id = ioc->id;
3240
3241 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003242 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003243 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003244 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003245 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003246
3247 /* Verify that we won't exceed the maximum
3248 * number of chain buffers
3249 * We can optimize: ZZ = req_sz/sizeof(SGE)
3250 * For 32bit SGE's:
3251 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3252 * + (req_sz - 64)/sizeof(SGE)
3253 * A slightly different algorithm is required for
3254 * 64bit SGEs.
3255 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303256 scale = ioc->req_sz/ioc->SGE_size;
3257 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003258 numSGE = (scale - 1) *
3259 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303260 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003261 } else {
3262 numSGE = 1 + (scale - 1) *
3263 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303264 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003265 }
3266
3267 if (numSGE < sh->sg_tablesize) {
3268 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303269 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003270 "Resetting sg_tablesize to %d from %d\n",
3271 ioc->name, numSGE, sh->sg_tablesize));
3272 sh->sg_tablesize = numSGE;
3273 }
3274
Eric Mooree7eae9f2007-09-29 10:15:59 -06003275 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003276 hd->ioc = ioc;
3277
3278 /* SCSI needs scsi_cmnd lookup table!
3279 * (with size equal to req_depth*PtrSz!)
3280 */
Eric Mooree8206382007-09-29 10:16:53 -06003281 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3282 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003283 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06003284 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003285 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003286 }
Eric Mooree8206382007-09-29 10:16:53 -06003287 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003288
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303289 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06003290 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003291
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003292 /* Clear the TM flags
3293 */
3294 hd->tmPending = 0;
3295 hd->tmState = TM_STATE_NONE;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003296 hd->abortSCpnt = NULL;
3297
3298 /* Clear the pointer used to store
3299 * single-threaded commands, i.e., those
3300 * issued during a bus scan, dv and
3301 * configuration pages.
3302 */
3303 hd->cmdPtr = NULL;
3304
3305 /* Initialize this SCSI Hosts' timers
3306 * To use, set the timer expires field
3307 * and add_timer
3308 */
3309 init_timer(&hd->timer);
3310 hd->timer.data = (unsigned long) hd;
3311 hd->timer.function = mptscsih_timer_expired;
3312
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003313 ioc->sas_data.ptClear = mpt_pt_clear;
3314
Eric Mooredf9e0622007-01-29 09:46:21 -07003315 hd->last_queue_full = 0;
3316 INIT_LIST_HEAD(&hd->target_reset_list);
3317 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3318
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003319 if (ioc->sas_data.ptClear==1) {
3320 mptbase_sas_persist_operation(
3321 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3322 }
3323
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003324 error = scsi_add_host(sh, &ioc->pcidev->dev);
3325 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06003326 dprintk(ioc, printk(MYIOC_s_ERR_FMT
3327 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003328 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003329 }
3330
3331 mptsas_scan_sas_topology(ioc);
3332
3333 return 0;
3334
Eric Moore547f9a22006-06-27 14:42:12 -06003335 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003336
3337 mptscsih_remove(pdev);
3338 return error;
3339}
3340
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303341void
3342mptsas_shutdown(struct pci_dev *pdev)
3343{
3344 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3345
3346 ioc->sas_discovery_quiesce_io = 0;
3347}
3348
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003349static void __devexit mptsas_remove(struct pci_dev *pdev)
3350{
3351 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3352 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003353 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003354
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303355 mptsas_shutdown(pdev);
3356
Eric Mooreb506ade2007-01-29 09:45:37 -07003357 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003358 sas_remove_host(ioc->sh);
3359
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003360 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003361 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3362 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003363 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303364 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003365 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003366 kfree(p);
3367 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003368 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003369
3370 mptscsih_remove(pdev);
3371}
3372
3373static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003374 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003375 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003376 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003377 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003378 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003379 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003380 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003381 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003382 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003383 PCI_ANY_ID, PCI_ANY_ID },
3384 {0} /* Terminating entry */
3385};
3386MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3387
3388
3389static struct pci_driver mptsas_driver = {
3390 .name = "mptsas",
3391 .id_table = mptsas_pci_table,
3392 .probe = mptsas_probe,
3393 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303394 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003395#ifdef CONFIG_PM
3396 .suspend = mptscsih_suspend,
3397 .resume = mptscsih_resume,
3398#endif
3399};
3400
3401static int __init
3402mptsas_init(void)
3403{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303404 int error;
3405
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003406 show_mptmod_ver(my_NAME, my_VERSION);
3407
3408 mptsas_transport_template =
3409 sas_attach_transport(&mptsas_transport_functions);
3410 if (!mptsas_transport_template)
3411 return -ENODEV;
3412
3413 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05303414 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003415 mptsasInternalCtx =
3416 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003417 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05303418 mptsasDeviceResetCtx =
3419 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003420
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303421 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3422 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003423
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303424 error = pci_register_driver(&mptsas_driver);
3425 if (error)
3426 sas_release_transport(mptsas_transport_template);
3427
3428 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003429}
3430
3431static void __exit
3432mptsas_exit(void)
3433{
3434 pci_unregister_driver(&mptsas_driver);
3435 sas_release_transport(mptsas_transport_template);
3436
3437 mpt_reset_deregister(mptsasDoneCtx);
3438 mpt_event_deregister(mptsasDoneCtx);
3439
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003440 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003441 mpt_deregister(mptsasInternalCtx);
3442 mpt_deregister(mptsasTaskCtx);
3443 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05303444 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003445}
3446
3447module_init(mptsas_init);
3448module_exit(mptsas_exit);