blob: eb6b10eb11d2b705761f15ce6df7d0cfb20612f6 [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;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530556 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
557 return 0;
558
Eric Mooredf9e0622007-01-29 09:46:21 -0700559
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530560 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
561 if (mf == NULL) {
562 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530563 "%s, no msg frames @%d!!\n", ioc->name,
564 __func__, __LINE__));
565 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -0700566 }
567
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530568 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
569 ioc->name, mf));
570
Eric Mooredf9e0622007-01-29 09:46:21 -0700571 /* Format the Request
572 */
573 pScsiTm = (SCSITaskMgmt_t *) mf;
574 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
575 pScsiTm->TargetID = id;
576 pScsiTm->Bus = channel;
577 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
578 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
579 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
580
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530581 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700582
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530583 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
584 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
585 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
586
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530587 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700588
589 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530590
591 out_fail:
592
593 mpt_clear_taskmgmt_in_progress_flag(ioc);
594 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -0700595}
596
597/**
598 * mptsas_target_reset_queue
599 *
600 * Receive request for TARGET_RESET after recieving an firmware
601 * event NOT_RESPONDING_EVENT, then put command in link list
602 * and queue if task_queue already in use.
603 *
604 * @ioc
605 * @sas_event_data
606 *
607 **/
608static void
609mptsas_target_reset_queue(MPT_ADAPTER *ioc,
610 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
611{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600612 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700613 VirtTarget *vtarget = NULL;
614 struct mptsas_target_reset_event *target_reset_list;
615 u8 id, channel;
616
617 id = sas_event_data->TargetID;
618 channel = sas_event_data->Bus;
619
620 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
621 return;
622
623 vtarget->deleted = 1; /* block IO */
624
625 target_reset_list = kzalloc(sizeof(*target_reset_list),
626 GFP_ATOMIC);
627 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530628 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
629 "%s, failed to allocate mem @%d..!!\n",
630 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -0700631 return;
632 }
633
634 memcpy(&target_reset_list->sas_event_data, sas_event_data,
635 sizeof(*sas_event_data));
636 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
637
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530638 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -0700639
640 if (mptsas_target_reset(ioc, channel, id)) {
641 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700642 }
643}
644
645/**
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530646 * mptsas_taskmgmt_complete - Completion for TARGET_RESET after
647 * NOT_RESPONDING_EVENT, enable work queue to finish off removing device
648 * from upper layers. then send next TARGET_RESET in the queue.
649 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -0700650 *
651 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530652static int
653mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -0700654{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600655 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700656 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -0700657 struct mptsas_hotplug_event *ev;
658 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
659 u8 id, channel;
660 __le64 sas_address;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530661 struct mptsas_target_reset_event *target_reset_list;
662 SCSITaskMgmtReply_t *pScsiTmReply;
663
664 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
665 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
666
667 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
668 if (pScsiTmReply) {
669 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
670 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
671 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
672 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
673 "term_cmnds = %d\n", ioc->name,
674 pScsiTmReply->Bus, pScsiTmReply->TargetID,
675 pScsiTmReply->TaskType,
676 le16_to_cpu(pScsiTmReply->IOCStatus),
677 le32_to_cpu(pScsiTmReply->IOCLogInfo),
678 pScsiTmReply->ResponseCode,
679 le32_to_cpu(pScsiTmReply->TerminationCount)));
680
681 if (pScsiTmReply->ResponseCode)
682 mptscsih_taskmgmt_response_code(ioc,
683 pScsiTmReply->ResponseCode);
684 }
685
686 if (pScsiTmReply && (pScsiTmReply->TaskType ==
687 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
688 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
689 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
690 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
691 memcpy(ioc->taskmgmt_cmds.reply, mr,
692 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
693 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
694 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
695 complete(&ioc->taskmgmt_cmds.done);
696 return 1;
697 }
698 return 0;
699 }
700
701 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -0700702
703 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530704 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700705
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530706 target_reset_list = list_entry(head->next,
707 struct mptsas_target_reset_event, list);
708
709 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
710 "TaskMgmt: completed (%d seconds)\n",
711 ioc->name, jiffies_to_msecs(jiffies -
712 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -0700713
714 sas_event_data = &target_reset_list->sas_event_data;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530715 id = pScsiTmReply->TargetID;
716 channel = pScsiTmReply->Bus;
717 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -0700718
719 /*
720 * retry target reset
721 */
722 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530723 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -0700724 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530725 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700726 }
727
728 /*
729 * enable work queue to remove device from upper layers
730 */
731 list_del(&target_reset_list->list);
732
733 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
734 if (!ev) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530735 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700736 ioc->name,__func__, __LINE__));
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530737 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -0700738 }
739
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530740 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
741 ioc->name, mf));
742
Eric Mooredf9e0622007-01-29 09:46:21 -0700743 INIT_WORK(&ev->work, mptsas_hotplug_work);
744 ev->ioc = ioc;
745 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
746 ev->parent_handle =
747 le16_to_cpu(sas_event_data->ParentDevHandle);
748 ev->channel = channel;
749 ev->id =id;
750 ev->phy_id = sas_event_data->PhyNum;
751 memcpy(&sas_address, &sas_event_data->SASAddress,
752 sizeof(__le64));
753 ev->sas_address = le64_to_cpu(sas_address);
754 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530755 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
756 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
757 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
758
Eric Mooredf9e0622007-01-29 09:46:21 -0700759 ev->event_type = MPTSAS_DEL_DEVICE;
760 schedule_work(&ev->work);
761 kfree(target_reset_list);
762
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530763 out_fail:
764
765 mpt_clear_taskmgmt_in_progress_flag(ioc);
766 return 0;
767
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530768
Eric Mooredf9e0622007-01-29 09:46:21 -0700769 /*
770 * issue target reset to next device in the queue
771 */
772
773 head = &hd->target_reset_list;
774 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530775 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700776
777 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
778 list);
779
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530780 id = target_reset_list->sas_event_data.TargetID;
781 channel = target_reset_list->sas_event_data.Bus;
782 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -0700783
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530784 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -0700785 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700786
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530787 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -0700788}
789
790/**
791 * mptscsih_ioc_reset
792 *
793 * @ioc
794 * @reset_phase
795 *
796 **/
797static int
798mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
799{
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800800 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -0700801 struct mptsas_target_reset_event *target_reset_list, *n;
802 int rc;
803
804 rc = mptscsih_ioc_reset(ioc, reset_phase);
805
806 if (ioc->bus_type != SAS)
807 goto out;
808
809 if (reset_phase != MPT_IOC_POST_RESET)
810 goto out;
811
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800812 if (!ioc->sh || !ioc->sh->hostdata)
813 goto out;
Eric Mooree7eae9f2007-09-29 10:15:59 -0600814 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800815 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -0700816 goto out;
817
818 if (list_empty(&hd->target_reset_list))
819 goto out;
820
821 /* flush the target_reset_list */
822 list_for_each_entry_safe(target_reset_list, n,
823 &hd->target_reset_list, list) {
824 list_del(&target_reset_list->list);
825 kfree(target_reset_list);
826 }
827
828 out:
829 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -0600830}
831
Christoph Hellwige3094442006-02-16 13:25:36 +0100832static int
Moore, Eric52435432006-03-14 09:14:15 -0700833mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100834 u32 form, u32 form_specific)
835{
836 ConfigExtendedPageHeader_t hdr;
837 CONFIGPARMS cfg;
838 SasEnclosurePage0_t *buffer;
839 dma_addr_t dma_handle;
840 int error;
841 __le64 le_identifier;
842
843 memset(&hdr, 0, sizeof(hdr));
844 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
845 hdr.PageNumber = 0;
846 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
847 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
848
849 cfg.cfghdr.ehdr = &hdr;
850 cfg.physAddr = -1;
851 cfg.pageAddr = form + form_specific;
852 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
853 cfg.dir = 0; /* read */
854 cfg.timeout = 10;
855
856 error = mpt_config(ioc, &cfg);
857 if (error)
858 goto out;
859 if (!hdr.ExtPageLength) {
860 error = -ENXIO;
861 goto out;
862 }
863
864 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
865 &dma_handle);
866 if (!buffer) {
867 error = -ENOMEM;
868 goto out;
869 }
870
871 cfg.physAddr = dma_handle;
872 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
873
874 error = mpt_config(ioc, &cfg);
875 if (error)
876 goto out_free_consistent;
877
878 /* save config data */
879 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
880 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
881 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
882 enclosure->flags = le16_to_cpu(buffer->Flags);
883 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
884 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
885 enclosure->start_id = buffer->StartTargetID;
886 enclosure->start_channel = buffer->StartBus;
887 enclosure->sep_id = buffer->SEPTargetID;
888 enclosure->sep_channel = buffer->SEPBus;
889
890 out_free_consistent:
891 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
892 buffer, dma_handle);
893 out:
894 return error;
895}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200896
James Bottomleyf013db32006-03-18 14:54:36 -0600897static int
898mptsas_slave_configure(struct scsi_device *sdev)
899{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600900
James Bottomleye8bf3942006-07-11 17:49:34 -0400901 if (sdev->channel == MPTSAS_RAID_CHANNEL)
902 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600903
James Bottomleye8bf3942006-07-11 17:49:34 -0400904 sas_read_port_mode_page(sdev);
905
906 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600907 return mptscsih_slave_configure(sdev);
908}
909
Eric Moore547f9a22006-06-27 14:42:12 -0600910static int
911mptsas_target_alloc(struct scsi_target *starget)
912{
913 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -0600914 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -0600915 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700916 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600917 struct sas_rphy *rphy;
918 struct mptsas_portinfo *p;
919 int i;
Eric Mooree80b0022007-09-14 18:49:03 -0600920 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -0600921
922 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
923 if (!vtarget)
924 return -ENOMEM;
925
926 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -0600927 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -0700928 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
929 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600930 channel = 0;
931
Eric Moore793955f2007-01-29 09:42:20 -0700932 /*
933 * RAID volumes placed beyond the last expected port.
934 */
935 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Eric Mooree80b0022007-09-14 18:49:03 -0600936 for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
937 if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
938 channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600939 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700940 }
Eric Moore547f9a22006-06-27 14:42:12 -0600941
942 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -0600943 mutex_lock(&ioc->sas_topology_mutex);
944 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -0600945 for (i = 0; i < p->num_phys; i++) {
946 if (p->phy_info[i].attached.sas_address !=
947 rphy->identify.sas_address)
948 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700949 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600950 channel = p->phy_info[i].attached.channel;
951 mptsas_set_starget(&p->phy_info[i], starget);
952
953 /*
954 * Exposing hidden raid components
955 */
Eric Mooree80b0022007-09-14 18:49:03 -0600956 if (mptscsih_is_phys_disk(ioc, channel, id)) {
957 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -0700958 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600959 vtarget->tflags |=
960 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700961 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600962 }
Eric Mooree80b0022007-09-14 18:49:03 -0600963 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -0600964 goto out;
965 }
966 }
Eric Mooree80b0022007-09-14 18:49:03 -0600967 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -0600968
969 kfree(vtarget);
970 return -ENXIO;
971
972 out:
Eric Moore793955f2007-01-29 09:42:20 -0700973 vtarget->id = id;
974 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600975 starget->hostdata = vtarget;
976 return 0;
977}
978
979static void
980mptsas_target_destroy(struct scsi_target *starget)
981{
982 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -0600983 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -0600984 struct sas_rphy *rphy;
985 struct mptsas_portinfo *p;
986 int i;
Eric Mooree80b0022007-09-14 18:49:03 -0600987 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -0600988
989 if (!starget->hostdata)
990 return;
991
James Bottomleye8bf3942006-07-11 17:49:34 -0400992 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -0600993 goto out;
994
995 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -0600996 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -0600997 for (i = 0; i < p->num_phys; i++) {
998 if (p->phy_info[i].attached.sas_address !=
999 rphy->identify.sas_address)
1000 continue;
1001 mptsas_set_starget(&p->phy_info[i], NULL);
1002 goto out;
1003 }
1004 }
1005
1006 out:
1007 kfree(starget->hostdata);
1008 starget->hostdata = NULL;
1009}
1010
1011
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001012static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001013mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001014{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001015 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001016 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001017 struct sas_rphy *rphy;
1018 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001019 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001020 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001021 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001022 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001023
Eric Moorea69de502007-09-14 18:48:19 -06001024 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1025 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001026 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001027 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001028 return -ENOMEM;
1029 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001030 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001031 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001032
James Bottomleye8bf3942006-07-11 17:49:34 -04001033 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001034 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001035
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001036 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001037 mutex_lock(&ioc->sas_topology_mutex);
1038 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001039 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001040 if (p->phy_info[i].attached.sas_address !=
1041 rphy->identify.sas_address)
1042 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001043 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001044 /*
1045 * Exposing hidden raid components
1046 */
Eric Mooree80b0022007-09-14 18:49:03 -06001047 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001048 p->phy_info[i].attached.channel,
1049 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001050 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001051 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001052 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001053 }
1054 }
Eric Mooree80b0022007-09-14 18:49:03 -06001055 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001056
Eric Moorea69de502007-09-14 18:48:19 -06001057 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001058 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001059
1060 out:
Eric Moorea69de502007-09-14 18:48:19 -06001061 vdevice->vtarget->num_luns++;
1062 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001063 return 0;
1064}
1065
Eric Moore547f9a22006-06-27 14:42:12 -06001066static int
1067mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001068{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301069 MPT_SCSI_HOST *hd;
1070 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001071 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001072
Eric Moorea69de502007-09-14 18:48:19 -06001073 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001074 SCpnt->result = DID_NO_CONNECT << 16;
1075 done(SCpnt);
1076 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001077 }
Eric Moore547f9a22006-06-27 14:42:12 -06001078
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301079 hd = shost_priv(SCpnt->device->host);
1080 ioc = hd->ioc;
1081
1082 if (ioc->sas_discovery_quiesce_io)
1083 return SCSI_MLQUEUE_HOST_BUSY;
1084
Eric Moore793955f2007-01-29 09:42:20 -07001085// scsi_print_command(SCpnt);
1086
Eric Moore547f9a22006-06-27 14:42:12 -06001087 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001088}
1089
Eric Moore547f9a22006-06-27 14:42:12 -06001090
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001091static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001092 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001093 .proc_name = "mptsas",
1094 .proc_info = mptscsih_proc_info,
1095 .name = "MPT SPI Host",
1096 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001097 .queuecommand = mptsas_qcmd,
1098 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001099 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001100 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001101 .target_destroy = mptsas_target_destroy,
1102 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001103 .change_queue_depth = mptscsih_change_queue_depth,
1104 .eh_abort_handler = mptscsih_abort,
1105 .eh_device_reset_handler = mptscsih_dev_reset,
1106 .eh_bus_reset_handler = mptscsih_bus_reset,
1107 .eh_host_reset_handler = mptscsih_host_reset,
1108 .bios_param = mptscsih_bios_param,
1109 .can_queue = MPT_FC_CAN_QUEUE,
1110 .this_id = -1,
1111 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1112 .max_sectors = 8192,
1113 .cmd_per_lun = 7,
1114 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301115 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001116};
1117
Christoph Hellwigb5141122005-10-28 22:07:41 +02001118static int mptsas_get_linkerrors(struct sas_phy *phy)
1119{
1120 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1121 ConfigExtendedPageHeader_t hdr;
1122 CONFIGPARMS cfg;
1123 SasPhyPage1_t *buffer;
1124 dma_addr_t dma_handle;
1125 int error;
1126
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001127 /* FIXME: only have link errors on local phys */
1128 if (!scsi_is_sas_phy_local(phy))
1129 return -EINVAL;
1130
Christoph Hellwigb5141122005-10-28 22:07:41 +02001131 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1132 hdr.ExtPageLength = 0;
1133 hdr.PageNumber = 1 /* page number 1*/;
1134 hdr.Reserved1 = 0;
1135 hdr.Reserved2 = 0;
1136 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1137 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1138
1139 cfg.cfghdr.ehdr = &hdr;
1140 cfg.physAddr = -1;
1141 cfg.pageAddr = phy->identify.phy_identifier;
1142 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1143 cfg.dir = 0; /* read */
1144 cfg.timeout = 10;
1145
1146 error = mpt_config(ioc, &cfg);
1147 if (error)
1148 return error;
1149 if (!hdr.ExtPageLength)
1150 return -ENXIO;
1151
1152 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1153 &dma_handle);
1154 if (!buffer)
1155 return -ENOMEM;
1156
1157 cfg.physAddr = dma_handle;
1158 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1159
1160 error = mpt_config(ioc, &cfg);
1161 if (error)
1162 goto out_free_consistent;
1163
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301164 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001165
1166 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1167 phy->running_disparity_error_count =
1168 le32_to_cpu(buffer->RunningDisparityErrorCount);
1169 phy->loss_of_dword_sync_count =
1170 le32_to_cpu(buffer->LossDwordSynchCount);
1171 phy->phy_reset_problem_count =
1172 le32_to_cpu(buffer->PhyResetProblemCount);
1173
1174 out_free_consistent:
1175 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1176 buffer, dma_handle);
1177 return error;
1178}
1179
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001180static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1181 MPT_FRAME_HDR *reply)
1182{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301183 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001184 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301185 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001186 memcpy(ioc->sas_mgmt.reply, reply,
1187 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1188 }
1189 complete(&ioc->sas_mgmt.done);
1190 return 1;
1191}
1192
1193static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1194{
1195 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1196 SasIoUnitControlRequest_t *req;
1197 SasIoUnitControlReply_t *reply;
1198 MPT_FRAME_HDR *mf;
1199 MPIHeader_t *hdr;
1200 unsigned long timeleft;
1201 int error = -ERESTARTSYS;
1202
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001203 /* FIXME: fusion doesn't allow non-local phy reset */
1204 if (!scsi_is_sas_phy_local(phy))
1205 return -EINVAL;
1206
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001207 /* not implemented for expanders */
1208 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1209 return -ENXIO;
1210
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001211 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001212 goto out;
1213
1214 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1215 if (!mf) {
1216 error = -ENOMEM;
1217 goto out_unlock;
1218 }
1219
1220 hdr = (MPIHeader_t *) mf;
1221 req = (SasIoUnitControlRequest_t *)mf;
1222 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1223 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1224 req->MsgContext = hdr->MsgContext;
1225 req->Operation = hard_reset ?
1226 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1227 req->PhyNum = phy->identify.phy_identifier;
1228
1229 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1230
1231 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1232 10 * HZ);
1233 if (!timeleft) {
1234 /* On timeout reset the board */
1235 mpt_free_msg_frame(ioc, mf);
1236 mpt_HardResetHandler(ioc, CAN_SLEEP);
1237 error = -ETIMEDOUT;
1238 goto out_unlock;
1239 }
1240
1241 /* a reply frame is expected */
1242 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301243 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001244 error = -ENXIO;
1245 goto out_unlock;
1246 }
1247
1248 /* process the completed Reply Message Frame */
1249 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1250 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001251 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001252 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001253 error = -ENXIO;
1254 goto out_unlock;
1255 }
1256
1257 error = 0;
1258
1259 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001260 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001261 out:
1262 return error;
1263}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001264
Christoph Hellwige3094442006-02-16 13:25:36 +01001265static int
1266mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1267{
1268 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1269 int i, error;
1270 struct mptsas_portinfo *p;
1271 struct mptsas_enclosure enclosure_info;
1272 u64 enclosure_handle;
1273
1274 mutex_lock(&ioc->sas_topology_mutex);
1275 list_for_each_entry(p, &ioc->sas_topology, list) {
1276 for (i = 0; i < p->num_phys; i++) {
1277 if (p->phy_info[i].attached.sas_address ==
1278 rphy->identify.sas_address) {
1279 enclosure_handle = p->phy_info[i].
1280 attached.handle_enclosure;
1281 goto found_info;
1282 }
1283 }
1284 }
1285 mutex_unlock(&ioc->sas_topology_mutex);
1286 return -ENXIO;
1287
1288 found_info:
1289 mutex_unlock(&ioc->sas_topology_mutex);
1290 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001291 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001292 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1293 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1294 if (!error)
1295 *identifier = enclosure_info.enclosure_logical_id;
1296 return error;
1297}
1298
1299static int
1300mptsas_get_bay_identifier(struct sas_rphy *rphy)
1301{
1302 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1303 struct mptsas_portinfo *p;
1304 int i, rc;
1305
1306 mutex_lock(&ioc->sas_topology_mutex);
1307 list_for_each_entry(p, &ioc->sas_topology, list) {
1308 for (i = 0; i < p->num_phys; i++) {
1309 if (p->phy_info[i].attached.sas_address ==
1310 rphy->identify.sas_address) {
1311 rc = p->phy_info[i].attached.slot;
1312 goto out;
1313 }
1314 }
1315 }
1316 rc = -ENXIO;
1317 out:
1318 mutex_unlock(&ioc->sas_topology_mutex);
1319 return rc;
1320}
1321
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001322static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1323 struct request *req)
1324{
1325 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1326 MPT_FRAME_HDR *mf;
1327 SmpPassthroughRequest_t *smpreq;
1328 struct request *rsp = req->next_rq;
1329 int ret;
1330 int flagsLength;
1331 unsigned long timeleft;
1332 char *psge;
1333 dma_addr_t dma_addr_in = 0;
1334 dma_addr_t dma_addr_out = 0;
1335 u64 sas_address = 0;
1336
1337 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06001338 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001339 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001340 return -EINVAL;
1341 }
1342
1343 /* do we need to support multiple segments? */
1344 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06001345 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001346 ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
Eric Moore29dd3602007-09-14 18:46:51 -06001347 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001348 return -EINVAL;
1349 }
1350
1351 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1352 if (ret)
1353 goto out;
1354
1355 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1356 if (!mf) {
1357 ret = -ENOMEM;
1358 goto out_unlock;
1359 }
1360
1361 smpreq = (SmpPassthroughRequest_t *)mf;
1362 memset(smpreq, 0, sizeof(*smpreq));
1363
1364 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1365 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1366
1367 if (rphy)
1368 sas_address = rphy->identify.sas_address;
1369 else {
1370 struct mptsas_portinfo *port_info;
1371
1372 mutex_lock(&ioc->sas_topology_mutex);
Michael Reed77483692008-03-20 17:32:05 -05001373 port_info = mptsas_get_hba_portinfo(ioc);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001374 if (port_info && port_info->phy_info)
1375 sas_address =
1376 port_info->phy_info[0].phy->identify.sas_address;
1377 mutex_unlock(&ioc->sas_topology_mutex);
1378 }
1379
1380 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1381
1382 psge = (char *)
1383 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1384
1385 /* request */
1386 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1387 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301388 MPI_SGE_FLAGS_DIRECTION)
1389 << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001390 flagsLength |= (req->data_len - 4);
1391
1392 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1393 req->data_len, PCI_DMA_BIDIRECTIONAL);
1394 if (!dma_addr_out)
1395 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301396 ioc->add_sge(psge, flagsLength, dma_addr_out);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001397 psge += (sizeof(u32) + sizeof(dma_addr_t));
1398
1399 /* response */
1400 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1401 flagsLength |= rsp->data_len + 4;
1402 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1403 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1404 if (!dma_addr_in)
1405 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05301406 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001407
1408 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1409
1410 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1411 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001412 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001413 /* On timeout reset the board */
1414 mpt_HardResetHandler(ioc, CAN_SLEEP);
1415 ret = -ETIMEDOUT;
1416 goto unmap;
1417 }
1418 mf = NULL;
1419
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301420 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001421 SmpPassthroughReply_t *smprep;
1422
1423 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1424 memcpy(req->sense, smprep, sizeof(*smprep));
1425 req->sense_len = sizeof(*smprep);
FUJITA Tomonori38b31672007-12-30 19:34:52 +09001426 req->data_len = 0;
1427 rsp->data_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001428 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001429 printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001430 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001431 ret = -ENXIO;
1432 }
1433unmap:
1434 if (dma_addr_out)
1435 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1436 PCI_DMA_BIDIRECTIONAL);
1437 if (dma_addr_in)
1438 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1439 PCI_DMA_BIDIRECTIONAL);
1440put_mf:
1441 if (mf)
1442 mpt_free_msg_frame(ioc, mf);
1443out_unlock:
1444 mutex_unlock(&ioc->sas_mgmt.mutex);
1445out:
1446 return ret;
1447}
1448
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001449static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001450 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001451 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1452 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001453 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001454 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001455};
1456
1457static struct scsi_transport_template *mptsas_transport_template;
1458
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001459static int
1460mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1461{
1462 ConfigExtendedPageHeader_t hdr;
1463 CONFIGPARMS cfg;
1464 SasIOUnitPage0_t *buffer;
1465 dma_addr_t dma_handle;
1466 int error, i;
1467
1468 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1469 hdr.ExtPageLength = 0;
1470 hdr.PageNumber = 0;
1471 hdr.Reserved1 = 0;
1472 hdr.Reserved2 = 0;
1473 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1474 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1475
1476 cfg.cfghdr.ehdr = &hdr;
1477 cfg.physAddr = -1;
1478 cfg.pageAddr = 0;
1479 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1480 cfg.dir = 0; /* read */
1481 cfg.timeout = 10;
1482
1483 error = mpt_config(ioc, &cfg);
1484 if (error)
1485 goto out;
1486 if (!hdr.ExtPageLength) {
1487 error = -ENXIO;
1488 goto out;
1489 }
1490
1491 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1492 &dma_handle);
1493 if (!buffer) {
1494 error = -ENOMEM;
1495 goto out;
1496 }
1497
1498 cfg.physAddr = dma_handle;
1499 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1500
1501 error = mpt_config(ioc, &cfg);
1502 if (error)
1503 goto out_free_consistent;
1504
1505 port_info->num_phys = buffer->NumPhys;
1506 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001507 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001508 if (!port_info->phy_info) {
1509 error = -ENOMEM;
1510 goto out_free_consistent;
1511 }
1512
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301513 ioc->nvdata_version_persistent =
1514 le16_to_cpu(buffer->NvdataVersionPersistent);
1515 ioc->nvdata_version_default =
1516 le16_to_cpu(buffer->NvdataVersionDefault);
1517
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001518 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301519 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001520 port_info->phy_info[i].phy_id = i;
1521 port_info->phy_info[i].port_id =
1522 buffer->PhyData[i].Port;
1523 port_info->phy_info[i].negotiated_link_rate =
1524 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001525 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001526 port_info->phy_info[i].handle =
1527 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001528 }
1529
1530 out_free_consistent:
1531 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1532 buffer, dma_handle);
1533 out:
1534 return error;
1535}
1536
1537static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301538mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1539{
1540 ConfigExtendedPageHeader_t hdr;
1541 CONFIGPARMS cfg;
1542 SasIOUnitPage1_t *buffer;
1543 dma_addr_t dma_handle;
1544 int error;
1545 u16 device_missing_delay;
1546
1547 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1548 memset(&cfg, 0, sizeof(CONFIGPARMS));
1549
1550 cfg.cfghdr.ehdr = &hdr;
1551 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1552 cfg.timeout = 10;
1553 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1554 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1555 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1556 cfg.cfghdr.ehdr->PageNumber = 1;
1557
1558 error = mpt_config(ioc, &cfg);
1559 if (error)
1560 goto out;
1561 if (!hdr.ExtPageLength) {
1562 error = -ENXIO;
1563 goto out;
1564 }
1565
1566 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1567 &dma_handle);
1568 if (!buffer) {
1569 error = -ENOMEM;
1570 goto out;
1571 }
1572
1573 cfg.physAddr = dma_handle;
1574 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1575
1576 error = mpt_config(ioc, &cfg);
1577 if (error)
1578 goto out_free_consistent;
1579
1580 ioc->io_missing_delay =
1581 le16_to_cpu(buffer->IODeviceMissingDelay);
1582 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1583 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1584 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1585 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1586
1587 out_free_consistent:
1588 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1589 buffer, dma_handle);
1590 out:
1591 return error;
1592}
1593
1594static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001595mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1596 u32 form, u32 form_specific)
1597{
1598 ConfigExtendedPageHeader_t hdr;
1599 CONFIGPARMS cfg;
1600 SasPhyPage0_t *buffer;
1601 dma_addr_t dma_handle;
1602 int error;
1603
1604 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1605 hdr.ExtPageLength = 0;
1606 hdr.PageNumber = 0;
1607 hdr.Reserved1 = 0;
1608 hdr.Reserved2 = 0;
1609 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1610 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1611
1612 cfg.cfghdr.ehdr = &hdr;
1613 cfg.dir = 0; /* read */
1614 cfg.timeout = 10;
1615
1616 /* Get Phy Pg 0 for each Phy. */
1617 cfg.physAddr = -1;
1618 cfg.pageAddr = form + form_specific;
1619 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1620
1621 error = mpt_config(ioc, &cfg);
1622 if (error)
1623 goto out;
1624
1625 if (!hdr.ExtPageLength) {
1626 error = -ENXIO;
1627 goto out;
1628 }
1629
1630 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1631 &dma_handle);
1632 if (!buffer) {
1633 error = -ENOMEM;
1634 goto out;
1635 }
1636
1637 cfg.physAddr = dma_handle;
1638 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1639
1640 error = mpt_config(ioc, &cfg);
1641 if (error)
1642 goto out_free_consistent;
1643
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301644 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001645
1646 phy_info->hw_link_rate = buffer->HwLinkRate;
1647 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1648 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1649 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1650
1651 out_free_consistent:
1652 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1653 buffer, dma_handle);
1654 out:
1655 return error;
1656}
1657
1658static int
1659mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1660 u32 form, u32 form_specific)
1661{
1662 ConfigExtendedPageHeader_t hdr;
1663 CONFIGPARMS cfg;
1664 SasDevicePage0_t *buffer;
1665 dma_addr_t dma_handle;
1666 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001667 int error=0;
1668
1669 if (ioc->sas_discovery_runtime &&
1670 mptsas_is_end_device(device_info))
1671 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001672
1673 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1674 hdr.ExtPageLength = 0;
1675 hdr.PageNumber = 0;
1676 hdr.Reserved1 = 0;
1677 hdr.Reserved2 = 0;
1678 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1679 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1680
1681 cfg.cfghdr.ehdr = &hdr;
1682 cfg.pageAddr = form + form_specific;
1683 cfg.physAddr = -1;
1684 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1685 cfg.dir = 0; /* read */
1686 cfg.timeout = 10;
1687
Moore, Ericdb9c9172006-03-14 09:14:18 -07001688 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001689 error = mpt_config(ioc, &cfg);
1690 if (error)
1691 goto out;
1692 if (!hdr.ExtPageLength) {
1693 error = -ENXIO;
1694 goto out;
1695 }
1696
1697 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1698 &dma_handle);
1699 if (!buffer) {
1700 error = -ENOMEM;
1701 goto out;
1702 }
1703
1704 cfg.physAddr = dma_handle;
1705 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1706
1707 error = mpt_config(ioc, &cfg);
1708 if (error)
1709 goto out_free_consistent;
1710
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301711 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001712
1713 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001714 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001715 device_info->handle_enclosure =
1716 le16_to_cpu(buffer->EnclosureHandle);
1717 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001718 device_info->phy_id = buffer->PhyNum;
1719 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001720 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001721 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001722 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001723 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1724 device_info->sas_address = le64_to_cpu(sas_address);
1725 device_info->device_info =
1726 le32_to_cpu(buffer->DeviceInfo);
1727
1728 out_free_consistent:
1729 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1730 buffer, dma_handle);
1731 out:
1732 return error;
1733}
1734
1735static int
1736mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1737 u32 form, u32 form_specific)
1738{
1739 ConfigExtendedPageHeader_t hdr;
1740 CONFIGPARMS cfg;
1741 SasExpanderPage0_t *buffer;
1742 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001743 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001744
1745 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1746 hdr.ExtPageLength = 0;
1747 hdr.PageNumber = 0;
1748 hdr.Reserved1 = 0;
1749 hdr.Reserved2 = 0;
1750 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1751 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1752
1753 cfg.cfghdr.ehdr = &hdr;
1754 cfg.physAddr = -1;
1755 cfg.pageAddr = form + form_specific;
1756 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1757 cfg.dir = 0; /* read */
1758 cfg.timeout = 10;
1759
Moore, Ericdb9c9172006-03-14 09:14:18 -07001760 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001761 error = mpt_config(ioc, &cfg);
1762 if (error)
1763 goto out;
1764
1765 if (!hdr.ExtPageLength) {
1766 error = -ENXIO;
1767 goto out;
1768 }
1769
1770 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1771 &dma_handle);
1772 if (!buffer) {
1773 error = -ENOMEM;
1774 goto out;
1775 }
1776
1777 cfg.physAddr = dma_handle;
1778 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1779
1780 error = mpt_config(ioc, &cfg);
1781 if (error)
1782 goto out_free_consistent;
1783
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08001784 if (!buffer->NumPhys) {
1785 error = -ENODEV;
1786 goto out_free_consistent;
1787 }
1788
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001789 /* save config data */
1790 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001791 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001792 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001793 if (!port_info->phy_info) {
1794 error = -ENOMEM;
1795 goto out_free_consistent;
1796 }
1797
Eric Moore2ecce492007-01-29 09:47:08 -07001798 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001799 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001800 port_info->phy_info[i].handle =
1801 le16_to_cpu(buffer->DevHandle);
1802 }
Eric Moore547f9a22006-06-27 14:42:12 -06001803
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001804 out_free_consistent:
1805 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1806 buffer, dma_handle);
1807 out:
1808 return error;
1809}
1810
1811static int
1812mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1813 u32 form, u32 form_specific)
1814{
1815 ConfigExtendedPageHeader_t hdr;
1816 CONFIGPARMS cfg;
1817 SasExpanderPage1_t *buffer;
1818 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001819 int error=0;
1820
1821 if (ioc->sas_discovery_runtime &&
1822 mptsas_is_end_device(&phy_info->attached))
1823 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001824
1825 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1826 hdr.ExtPageLength = 0;
1827 hdr.PageNumber = 1;
1828 hdr.Reserved1 = 0;
1829 hdr.Reserved2 = 0;
1830 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1831 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1832
1833 cfg.cfghdr.ehdr = &hdr;
1834 cfg.physAddr = -1;
1835 cfg.pageAddr = form + form_specific;
1836 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1837 cfg.dir = 0; /* read */
1838 cfg.timeout = 10;
1839
1840 error = mpt_config(ioc, &cfg);
1841 if (error)
1842 goto out;
1843
1844 if (!hdr.ExtPageLength) {
1845 error = -ENXIO;
1846 goto out;
1847 }
1848
1849 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1850 &dma_handle);
1851 if (!buffer) {
1852 error = -ENOMEM;
1853 goto out;
1854 }
1855
1856 cfg.physAddr = dma_handle;
1857 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1858
1859 error = mpt_config(ioc, &cfg);
1860 if (error)
1861 goto out_free_consistent;
1862
1863
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301864 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001865
1866 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001867 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001868 phy_info->port_id = buffer->PhysicalPort;
1869 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1870 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1871 phy_info->hw_link_rate = buffer->HwLinkRate;
1872 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1873 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1874
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001875 out_free_consistent:
1876 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1877 buffer, dma_handle);
1878 out:
1879 return error;
1880}
1881
1882static void
1883mptsas_parse_device_info(struct sas_identify *identify,
1884 struct mptsas_devinfo *device_info)
1885{
1886 u16 protocols;
1887
1888 identify->sas_address = device_info->sas_address;
1889 identify->phy_identifier = device_info->phy_id;
1890
1891 /*
1892 * Fill in Phy Initiator Port Protocol.
1893 * Bits 6:3, more than one bit can be set, fall through cases.
1894 */
1895 protocols = device_info->device_info & 0x78;
1896 identify->initiator_port_protocols = 0;
1897 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1898 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1899 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1900 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1901 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1902 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1903 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1904 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1905
1906 /*
1907 * Fill in Phy Target Port Protocol.
1908 * Bits 10:7, more than one bit can be set, fall through cases.
1909 */
1910 protocols = device_info->device_info & 0x780;
1911 identify->target_port_protocols = 0;
1912 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1913 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1914 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1915 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1916 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1917 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1918 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1919 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1920
1921 /*
1922 * Fill in Attached device type.
1923 */
1924 switch (device_info->device_info &
1925 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1926 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1927 identify->device_type = SAS_PHY_UNUSED;
1928 break;
1929 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1930 identify->device_type = SAS_END_DEVICE;
1931 break;
1932 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1933 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1934 break;
1935 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1936 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1937 break;
1938 }
1939}
1940
1941static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001942 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001943{
Moore, Erice6b2d762006-03-14 09:14:24 -07001944 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001945 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001946 struct sas_port *port;
1947 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001948
Eric Moore547f9a22006-06-27 14:42:12 -06001949 if (!dev) {
1950 error = -ENODEV;
1951 goto out;
1952 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001953
1954 if (!phy_info->phy) {
1955 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001956 if (!phy) {
1957 error = -ENOMEM;
1958 goto out;
1959 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001960 } else
1961 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001962
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001963 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001964
1965 /*
1966 * Set Negotiated link rate.
1967 */
1968 switch (phy_info->negotiated_link_rate) {
1969 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001970 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001971 break;
1972 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001973 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001974 break;
1975 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001976 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001977 break;
1978 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001979 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001980 break;
1981 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1982 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1983 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001984 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001985 break;
1986 }
1987
1988 /*
1989 * Set Max hardware link rate.
1990 */
1991 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1992 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001993 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001994 break;
1995 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001996 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001997 break;
1998 default:
1999 break;
2000 }
2001
2002 /*
2003 * Set Max programmed link rate.
2004 */
2005 switch (phy_info->programmed_link_rate &
2006 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2007 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002008 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002009 break;
2010 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002011 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002012 break;
2013 default:
2014 break;
2015 }
2016
2017 /*
2018 * Set Min hardware link rate.
2019 */
2020 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2021 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002022 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002023 break;
2024 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002025 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002026 break;
2027 default:
2028 break;
2029 }
2030
2031 /*
2032 * Set Min programmed link rate.
2033 */
2034 switch (phy_info->programmed_link_rate &
2035 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2036 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002037 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002038 break;
2039 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002040 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002041 break;
2042 default:
2043 break;
2044 }
2045
Moore, Erice6b2d762006-03-14 09:14:24 -07002046 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002047
Moore, Erice6b2d762006-03-14 09:14:24 -07002048 error = sas_phy_add(phy);
2049 if (error) {
2050 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002051 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002052 }
2053 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002054 }
2055
Eric Moore547f9a22006-06-27 14:42:12 -06002056 if (!phy_info->attached.handle ||
2057 !phy_info->port_details)
2058 goto out;
2059
2060 port = mptsas_get_port(phy_info);
2061 ioc = phy_to_ioc(phy_info->phy);
2062
2063 if (phy_info->sas_port_add_phy) {
2064
2065 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002066 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002067 if (!port) {
2068 error = -ENOMEM;
2069 goto out;
2070 }
2071 error = sas_port_add(port);
2072 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302073 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002074 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002075 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002076 goto out;
2077 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302078 mptsas_set_port(ioc, phy_info, port);
Eric Moore29dd3602007-09-14 18:46:51 -06002079 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooredc22f162006-07-06 11:23:14 -06002080 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002081 ioc->name, port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002082 }
Eric Moore29dd3602007-09-14 18:46:51 -06002083 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
2084 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002085 sas_port_add_phy(port, phy_info->phy);
2086 phy_info->sas_port_add_phy = 0;
2087 }
2088
2089 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002090
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002091 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002092 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002093 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002094
James Bottomley2686de22006-06-30 12:54:02 -05002095 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002096 /*
2097 * Let the hotplug_work thread handle processing
2098 * the adding/removing of devices that occur
2099 * after start of day.
2100 */
2101 if (ioc->sas_discovery_runtime &&
2102 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002103 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002104
James Bottomleyf013db32006-03-18 14:54:36 -06002105 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002106 if (scsi_is_host_device(parent)) {
2107 struct mptsas_portinfo *port_info;
2108 int i;
2109
2110 mutex_lock(&ioc->sas_topology_mutex);
Michael Reed77483692008-03-20 17:32:05 -05002111 port_info = mptsas_get_hba_portinfo(ioc);
James Bottomley2686de22006-06-30 12:54:02 -05002112 mutex_unlock(&ioc->sas_topology_mutex);
2113
2114 for (i = 0; i < port_info->num_phys; i++)
2115 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002116 identify.sas_address) {
2117 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002118 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002119 }
James Bottomley2686de22006-06-30 12:54:02 -05002120
2121 } else if (scsi_is_sas_rphy(parent)) {
2122 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2123 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002124 parent_rphy->identify.sas_address) {
2125 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002126 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002127 }
James Bottomley2686de22006-06-30 12:54:02 -05002128 }
2129
James Bottomleyf013db32006-03-18 14:54:36 -06002130 switch (identify.device_type) {
2131 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002132 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002133 break;
2134 case SAS_EDGE_EXPANDER_DEVICE:
2135 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002136 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002137 break;
2138 default:
2139 rphy = NULL;
2140 break;
2141 }
Eric Moore547f9a22006-06-27 14:42:12 -06002142 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302143 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002144 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002145 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002146 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002147 }
2148
Eric Moore547f9a22006-06-27 14:42:12 -06002149 rphy->identify = identify;
2150 error = sas_rphy_add(rphy);
2151 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302152 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002153 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002154 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002155 sas_rphy_free(rphy);
2156 goto out;
2157 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302158 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002159 }
2160
Eric Moore547f9a22006-06-27 14:42:12 -06002161 out:
2162 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002163}
2164
2165static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002166mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002167{
Moore, Erice6b2d762006-03-14 09:14:24 -07002168 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002169 int error = -ENOMEM, i;
2170
Moore, Erice6b2d762006-03-14 09:14:24 -07002171 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2172 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002173 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002174
Moore, Erice6b2d762006-03-14 09:14:24 -07002175 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002176 if (error)
2177 goto out_free_port_info;
2178
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302179 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002180 mutex_lock(&ioc->sas_topology_mutex);
Michael Reed77483692008-03-20 17:32:05 -05002181 port_info = mptsas_get_hba_portinfo(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002182 if (!port_info) {
2183 port_info = hba;
2184 list_add_tail(&port_info->list, &ioc->sas_topology);
2185 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002186 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002187 port_info->phy_info[i].negotiated_link_rate =
2188 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002189 port_info->phy_info[i].handle =
2190 hba->phy_info[i].handle;
2191 port_info->phy_info[i].port_id =
2192 hba->phy_info[i].port_id;
2193 }
Eric Moore547f9a22006-06-27 14:42:12 -06002194 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002195 kfree(hba);
2196 hba = NULL;
2197 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002198 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002199 for (i = 0; i < port_info->num_phys; i++) {
2200 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2201 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2202 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2203
2204 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002205 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2206 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2207 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002208 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002209 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002210 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002211 mptsas_sas_device_pg0(ioc,
2212 &port_info->phy_info[i].attached,
2213 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2214 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2215 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002216 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002217
Eric Moore547f9a22006-06-27 14:42:12 -06002218 mptsas_setup_wide_ports(ioc, port_info);
2219
2220 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002221 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002222 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002223
2224 return 0;
2225
2226 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002227 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002228 out:
2229 return error;
2230}
2231
2232static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002233mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002234{
Moore, Erice6b2d762006-03-14 09:14:24 -07002235 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002236 struct device *parent;
2237 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002238 int error = -ENOMEM, i, j;
2239
Moore, Erice6b2d762006-03-14 09:14:24 -07002240 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2241 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002242 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002243
Moore, Erice6b2d762006-03-14 09:14:24 -07002244 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002245 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2246 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002247 if (error)
2248 goto out_free_port_info;
2249
Eric Moore2ecce492007-01-29 09:47:08 -07002250 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002251
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002252 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002253 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2254 if (!port_info) {
2255 port_info = ex;
2256 list_add_tail(&port_info->list, &ioc->sas_topology);
2257 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002258 for (i = 0; i < ex->num_phys; i++) {
2259 port_info->phy_info[i].handle =
2260 ex->phy_info[i].handle;
2261 port_info->phy_info[i].port_id =
2262 ex->phy_info[i].port_id;
2263 }
Eric Moore547f9a22006-06-27 14:42:12 -06002264 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002265 kfree(ex);
2266 ex = NULL;
2267 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002268 mutex_unlock(&ioc->sas_topology_mutex);
2269
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002270 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002271 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2272 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2273 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2274
2275 if (port_info->phy_info[i].identify.handle) {
2276 mptsas_sas_device_pg0(ioc,
2277 &port_info->phy_info[i].identify,
2278 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2279 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2280 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002281 port_info->phy_info[i].identify.phy_id =
2282 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002283 }
2284
2285 if (port_info->phy_info[i].attached.handle) {
2286 mptsas_sas_device_pg0(ioc,
2287 &port_info->phy_info[i].attached,
2288 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2289 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2290 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002291 port_info->phy_info[i].attached.phy_id =
2292 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002293 }
Eric Moore547f9a22006-06-27 14:42:12 -06002294 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002295
Eric Moore547f9a22006-06-27 14:42:12 -06002296 parent = &ioc->sh->shost_gendev;
2297 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002298 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002299 list_for_each_entry(p, &ioc->sas_topology, list) {
2300 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002301 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002302 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002303 continue;
2304 rphy = mptsas_get_rphy(&p->phy_info[j]);
2305 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002306 }
2307 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002308 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002309 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002310
Eric Moore547f9a22006-06-27 14:42:12 -06002311 mptsas_setup_wide_ports(ioc, port_info);
2312
2313 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002314 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002315 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002316
2317 return 0;
2318
2319 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002320 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002321 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002322 kfree(ex);
2323 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002324 out:
2325 return error;
2326}
2327
Moore, Erice6b2d762006-03-14 09:14:24 -07002328/*
2329 * mptsas_delete_expander_phys
2330 *
2331 *
2332 * This will traverse topology, and remove expanders
2333 * that are no longer present
2334 */
2335static void
2336mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2337{
2338 struct mptsas_portinfo buffer;
2339 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002340 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002341 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002342 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002343 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002344
2345 mutex_lock(&ioc->sas_topology_mutex);
2346 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2347
Alan Coxd58069a2009-04-01 15:00:29 +01002348 if (!(port_info->phy_info[0].identify.device_info &
2349 MPI_SAS_DEVICE_INFO_SMP_TARGET))
Moore, Erice6b2d762006-03-14 09:14:24 -07002350 continue;
2351
2352 if (mptsas_sas_expander_pg0(ioc, &buffer,
2353 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002354 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2355 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002356
2357 /*
2358 * Obtain the port_info instance to the parent port
2359 */
2360 parent = mptsas_find_portinfo_by_handle(ioc,
2361 port_info->phy_info[0].identify.handle_parent);
2362
2363 if (!parent)
2364 goto next_port;
2365
Eric Moore547f9a22006-06-27 14:42:12 -06002366 expander_sas_address =
2367 port_info->phy_info[0].identify.sas_address;
2368
Moore, Erice6b2d762006-03-14 09:14:24 -07002369 /*
2370 * Delete rphys in the parent that point
2371 * to this expander. The transport layer will
2372 * cleanup all the children.
2373 */
Eric Moore547f9a22006-06-27 14:42:12 -06002374 phy_info = parent->phy_info;
2375 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2376 port = mptsas_get_port(phy_info);
2377 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002378 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002379 if (phy_info->attached.sas_address !=
2380 expander_sas_address)
2381 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302382 dsaswideprintk(ioc,
Eric Moorec51d0be2007-09-29 10:17:21 -06002383 dev_printk(KERN_DEBUG, &port->dev,
2384 MYIOC_s_FMT "delete port (%d)\n", ioc->name,
2385 port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002386 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302387 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002388 }
2389 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002390
2391 phy_info = port_info->phy_info;
2392 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302393 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002394
Moore, Erice6b2d762006-03-14 09:14:24 -07002395 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002396 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002397 kfree(port_info);
2398 }
2399 /*
2400 * Free this memory allocated from inside
2401 * mptsas_sas_expander_pg0
2402 */
Eric Moore547f9a22006-06-27 14:42:12 -06002403 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002404 }
2405 mutex_unlock(&ioc->sas_topology_mutex);
2406}
2407
2408/*
2409 * Start of day discovery
2410 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002411static void
2412mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2413{
2414 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002415 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002416
Moore, Erice6b2d762006-03-14 09:14:24 -07002417 mutex_lock(&ioc->sas_discovery_mutex);
2418 mptsas_probe_hba_phys(ioc);
2419 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002420 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002421 /*
2422 Reporting RAID volumes.
2423 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002424 if (!ioc->ir_firmware)
2425 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002426 if (!ioc->raid_data.pIocPg2)
2427 goto out;
2428 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2429 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002430 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002431 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002432 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2433 }
2434 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002435 mutex_unlock(&ioc->sas_discovery_mutex);
2436}
2437
2438/*
2439 * Work queue thread to handle Runtime discovery
2440 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002441 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002442 */
2443static void
Eric Moore547f9a22006-06-27 14:42:12 -06002444__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002445{
Moore, Erice6b2d762006-03-14 09:14:24 -07002446 u32 handle = 0xFFFF;
2447
Moore, Erice6b2d762006-03-14 09:14:24 -07002448 ioc->sas_discovery_runtime=1;
2449 mptsas_delete_expander_phys(ioc);
2450 mptsas_probe_hba_phys(ioc);
2451 while (!mptsas_probe_expander_phys(ioc, &handle))
2452 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002453 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002454}
2455
2456/*
2457 * Work queue thread to handle Runtime discovery
2458 * Mere purpose is the hot add/delete of expanders
2459 *(Mutex LOCKED)
2460 */
2461static void
David Howellsc4028952006-11-22 14:57:56 +00002462mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002463{
David Howellsc4028952006-11-22 14:57:56 +00002464 struct mptsas_discovery_event *ev =
2465 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002466 MPT_ADAPTER *ioc = ev->ioc;
2467
2468 mutex_lock(&ioc->sas_discovery_mutex);
2469 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002470 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002471 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002472}
2473
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002474static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002475mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002476{
2477 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002478 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002479 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002480
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002481 mutex_lock(&ioc->sas_topology_mutex);
2482 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2483 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002484 if (!mptsas_is_end_device(
2485 &port_info->phy_info[i].attached))
2486 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002487 if (port_info->phy_info[i].attached.sas_address
2488 != sas_address)
2489 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002490 phy_info = &port_info->phy_info[i];
2491 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002492 }
2493 }
2494 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002495 return phy_info;
2496}
2497
2498static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002499mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002500{
2501 struct mptsas_portinfo *port_info;
2502 struct mptsas_phyinfo *phy_info = NULL;
2503 int i;
2504
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002505 mutex_lock(&ioc->sas_topology_mutex);
2506 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002507 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002508 if (!mptsas_is_end_device(
2509 &port_info->phy_info[i].attached))
2510 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002511 if (port_info->phy_info[i].attached.id != id)
2512 continue;
2513 if (port_info->phy_info[i].attached.channel != channel)
2514 continue;
2515 phy_info = &port_info->phy_info[i];
2516 break;
2517 }
2518 }
2519 mutex_unlock(&ioc->sas_topology_mutex);
2520 return phy_info;
2521}
2522
2523static struct mptsas_phyinfo *
2524mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2525{
2526 struct mptsas_portinfo *port_info;
2527 struct mptsas_phyinfo *phy_info = NULL;
2528 int i;
2529
2530 mutex_lock(&ioc->sas_topology_mutex);
2531 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2532 for (i = 0; i < port_info->num_phys; i++) {
2533 if (!mptsas_is_end_device(
2534 &port_info->phy_info[i].attached))
2535 continue;
2536 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2537 continue;
2538 if (port_info->phy_info[i].attached.phys_disk_num != id)
2539 continue;
2540 if (port_info->phy_info[i].attached.channel != channel)
2541 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002542 phy_info = &port_info->phy_info[i];
2543 break;
2544 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002545 }
2546 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002547 return phy_info;
2548}
2549
Moore, Eric4b766472006-03-14 09:14:12 -07002550/*
2551 * Work queue thread to clear the persitency table
2552 */
2553static void
David Howellsc4028952006-11-22 14:57:56 +00002554mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002555{
David Howellsc4028952006-11-22 14:57:56 +00002556 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002557
2558 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2559}
2560
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002561static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002562mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2563{
Eric Mooref99be432007-01-04 20:46:54 -07002564 int rc;
2565
Moore, Ericf44e5462006-03-14 09:14:21 -07002566 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002567 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002568}
2569
2570static void
2571mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2572{
2573 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2574 mptsas_reprobe_lun);
2575}
2576
Eric Mooreb506ade2007-01-29 09:45:37 -07002577static void
2578mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2579{
2580 CONFIGPARMS cfg;
2581 ConfigPageHeader_t hdr;
2582 dma_addr_t dma_handle;
2583 pRaidVolumePage0_t buffer = NULL;
2584 RaidPhysDiskPage0_t phys_disk;
2585 int i;
2586 struct mptsas_hotplug_event *ev;
2587
2588 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2589 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2590 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2591 cfg.pageAddr = (channel << 8) + id;
2592 cfg.cfghdr.hdr = &hdr;
2593 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2594
2595 if (mpt_config(ioc, &cfg) != 0)
2596 goto out;
2597
2598 if (!hdr.PageLength)
2599 goto out;
2600
2601 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2602 &dma_handle);
2603
2604 if (!buffer)
2605 goto out;
2606
2607 cfg.physAddr = dma_handle;
2608 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2609
2610 if (mpt_config(ioc, &cfg) != 0)
2611 goto out;
2612
2613 if (!(buffer->VolumeStatus.Flags &
2614 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2615 goto out;
2616
2617 if (!buffer->NumPhysDisks)
2618 goto out;
2619
2620 for (i = 0; i < buffer->NumPhysDisks; i++) {
2621
2622 if (mpt_raid_phys_disk_pg0(ioc,
2623 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2624 continue;
2625
2626 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2627 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002628 printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
Eric Mooreb506ade2007-01-29 09:45:37 -07002629 goto out;
2630 }
2631
2632 INIT_WORK(&ev->work, mptsas_hotplug_work);
2633 ev->ioc = ioc;
2634 ev->id = phys_disk.PhysDiskID;
2635 ev->channel = phys_disk.PhysDiskBus;
2636 ev->phys_disk_num_valid = 1;
2637 ev->phys_disk_num = phys_disk.PhysDiskNum;
2638 ev->event_type = MPTSAS_ADD_DEVICE;
2639 schedule_work(&ev->work);
2640 }
2641
2642 out:
2643 if (buffer)
2644 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2645 dma_handle);
2646}
Moore, Erice6b2d762006-03-14 09:14:24 -07002647/*
2648 * Work queue thread to handle SAS hotplug events
2649 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002650static void
David Howellsc4028952006-11-22 14:57:56 +00002651mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002652{
David Howellsc4028952006-11-22 14:57:56 +00002653 struct mptsas_hotplug_event *ev =
2654 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002655
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002656 MPT_ADAPTER *ioc = ev->ioc;
2657 struct mptsas_phyinfo *phy_info;
2658 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002659 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002660 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002661 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002662 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002663 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002664 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002665 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002666 VirtDevice *vdevice;
2667
Moore, Erice6b2d762006-03-14 09:14:24 -07002668 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002669 switch (ev->event_type) {
2670 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002671
Eric Mooreb506ade2007-01-29 09:45:37 -07002672 phy_info = NULL;
2673 if (ev->phys_disk_num_valid) {
2674 if (ev->hidden_raid_component){
2675 if (mptsas_sas_device_pg0(ioc, &sas_device,
2676 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2677 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2678 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302679 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002680 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002681 __func__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002682 break;
2683 }
2684 phy_info = mptsas_find_phyinfo_by_sas_address(
2685 ioc, sas_device.sas_address);
2686 }else
2687 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2688 ioc, ev->channel, ev->phys_disk_num);
2689 }
2690
2691 if (!phy_info)
2692 phy_info = mptsas_find_phyinfo_by_target(ioc,
2693 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002694
Moore, Ericf44e5462006-03-14 09:14:21 -07002695 /*
2696 * Sanity checks, for non-existing phys and remote rphys.
2697 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002698 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302699 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002700 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002701 __func__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002702 break;
2703 }
2704 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302705 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002706 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002707 __func__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002708 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002709 }
2710 rphy = mptsas_get_rphy(phy_info);
2711 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302712 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002713 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002714 __func__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002715 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002716 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002717
Eric Moore547f9a22006-06-27 14:42:12 -06002718 port = mptsas_get_port(phy_info);
2719 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302720 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002721 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002722 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002723 break;
2724 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002725
Eric Moore547f9a22006-06-27 14:42:12 -06002726 starget = mptsas_get_starget(phy_info);
2727 if (starget) {
2728 vtarget = starget->hostdata;
2729
2730 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302731 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002732 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002733 __func__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002734 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002735 }
2736
Moore, Ericf44e5462006-03-14 09:14:21 -07002737 /*
2738 * Handling RAID components
2739 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002740 if (ev->phys_disk_num_valid &&
2741 ev->hidden_raid_component) {
2742 printk(MYIOC_s_INFO_FMT
2743 "RAID Hidding: channel=%d, id=%d, "
2744 "physdsk %d \n", ioc->name, ev->channel,
2745 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002746 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002747 vtarget->tflags |=
2748 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002749 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002750 phy_info->attached.phys_disk_num =
2751 ev->phys_disk_num;
2752 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002753 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002754 }
2755
Eric Mooreb506ade2007-01-29 09:45:37 -07002756 if (phy_info->attached.device_info &
2757 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002758 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002759 if (phy_info->attached.device_info &
2760 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002761 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002762 if (phy_info->attached.device_info &
2763 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002764 ds = "sata";
2765
2766 printk(MYIOC_s_INFO_FMT
2767 "removing %s device, channel %d, id %d, phy %d\n",
2768 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moorec51d0be2007-09-29 10:17:21 -06002769 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002770 "delete port (%d)\n", ioc->name, port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002771 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302772 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002773 break;
2774 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002775
Moore, Ericbd23e942006-04-17 12:43:04 -06002776 if (ev->phys_disk_num_valid)
2777 mpt_findImVolumes(ioc);
2778
Moore, Ericc73787ee2006-01-26 16:20:06 -07002779 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002780 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002781 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002782 if (mptsas_sas_device_pg0(ioc, &sas_device,
2783 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002784 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2785 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302786 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002787 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002788 __func__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002789 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002790 }
2791
Eric Moore547f9a22006-06-27 14:42:12 -06002792 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002793
Eric Moore547f9a22006-06-27 14:42:12 -06002794 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2795 sas_device.sas_address);
2796
2797 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302798 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002799 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002800 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002801 break;
2802 }
2803
2804 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002805 if (starget && (!ev->hidden_raid_component)){
2806
Eric Moore547f9a22006-06-27 14:42:12 -06002807 vtarget = starget->hostdata;
2808
2809 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302810 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002811 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002812 __func__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002813 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002814 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002815 /*
2816 * Handling RAID components
2817 */
2818 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002819 printk(MYIOC_s_INFO_FMT
2820 "RAID Exposing: channel=%d, id=%d, "
2821 "physdsk %d \n", ioc->name, ev->channel,
2822 ev->id, ev->phys_disk_num);
2823 vtarget->tflags &=
2824 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002825 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002826 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002827 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002828 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002829 break;
2830 }
2831
Eric Moore547f9a22006-06-27 14:42:12 -06002832 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302833 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002834 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002835 __func__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002836 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002837 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002838 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002839
Eric Moore547f9a22006-06-27 14:42:12 -06002840 port = mptsas_get_port(phy_info);
2841 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302842 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002843 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002844 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002845 break;
2846 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002847 memcpy(&phy_info->attached, &sas_device,
2848 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002849
Eric Mooreb506ade2007-01-29 09:45:37 -07002850 if (phy_info->attached.device_info &
2851 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002852 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002853 if (phy_info->attached.device_info &
2854 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002855 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002856 if (phy_info->attached.device_info &
2857 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002858 ds = "sata";
2859
2860 printk(MYIOC_s_INFO_FMT
2861 "attaching %s device, channel %d, id %d, phy %d\n",
2862 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2863
James Bottomleyf013db32006-03-18 14:54:36 -06002864 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002865 rphy = sas_end_device_alloc(port);
2866 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302867 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002868 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002869 __func__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002870 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002871 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002872
James Bottomleyf013db32006-03-18 14:54:36 -06002873 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002874 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302875 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002876 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002877 __func__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002878 sas_rphy_free(rphy);
2879 break;
2880 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302881 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002882 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002883 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002884 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2885 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002886 if (sdev) {
2887 scsi_device_put(sdev);
2888 break;
2889 }
2890 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002891 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002892 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2893 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002894 mpt_findImVolumes(ioc);
2895 break;
2896 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002897 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002898 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002899 if (!sdev)
2900 break;
2901 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002902 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002903 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002904 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002905 scsi_remove_device(sdev);
2906 scsi_device_put(sdev);
2907 mpt_findImVolumes(ioc);
2908 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002909 case MPTSAS_ADD_INACTIVE_VOLUME:
2910 mptsas_adding_inactive_raid_components(ioc,
2911 ev->channel, ev->id);
2912 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002913 case MPTSAS_IGNORE_EVENT:
2914 default:
2915 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002916 }
2917
Moore, Erice6b2d762006-03-14 09:14:24 -07002918 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002919 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002920}
2921
2922static void
Eric Moore547f9a22006-06-27 14:42:12 -06002923mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002924 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2925{
2926 struct mptsas_hotplug_event *ev;
2927 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2928 __le64 sas_address;
2929
2930 if ((device_info &
2931 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2932 MPI_SAS_DEVICE_INFO_STP_TARGET |
2933 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2934 return;
2935
Moore, Eric4b766472006-03-14 09:14:12 -07002936 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002937 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002938
2939 mptsas_target_reset_queue(ioc, sas_event_data);
2940 break;
2941
2942 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002943 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002944 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002945 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Eric4b766472006-03-14 09:14:12 -07002946 break;
2947 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002948
David Howellsc4028952006-11-22 14:57:56 +00002949 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002950 ev->ioc = ioc;
2951 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2952 ev->parent_handle =
2953 le16_to_cpu(sas_event_data->ParentDevHandle);
2954 ev->channel = sas_event_data->Bus;
2955 ev->id = sas_event_data->TargetID;
2956 ev->phy_id = sas_event_data->PhyNum;
2957 memcpy(&sas_address, &sas_event_data->SASAddress,
2958 sizeof(__le64));
2959 ev->sas_address = le64_to_cpu(sas_address);
2960 ev->device_info = device_info;
2961
2962 if (sas_event_data->ReasonCode &
2963 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2964 ev->event_type = MPTSAS_ADD_DEVICE;
2965 else
2966 ev->event_type = MPTSAS_DEL_DEVICE;
2967 schedule_work(&ev->work);
2968 break;
2969 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2970 /*
2971 * Persistent table is full.
2972 */
Eric Moore547f9a22006-06-27 14:42:12 -06002973 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002974 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002975 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002976 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002977 /*
2978 * TODO, handle other events
2979 */
Moore, Eric4b766472006-03-14 09:14:12 -07002980 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002981 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002982 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002983 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2984 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2985 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2986 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002987 default:
2988 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002989 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002990}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002991static void
Eric Moore547f9a22006-06-27 14:42:12 -06002992mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002993 EVENT_DATA_RAID *raid_event_data)
2994{
2995 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002996 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2997 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002998
2999 if (ioc->bus_type != SAS)
3000 return;
3001
Eric Moore547f9a22006-06-27 14:42:12 -06003002 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003003 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06003004 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003005 return;
3006 }
3007
David Howellsc4028952006-11-22 14:57:56 +00003008 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003009 ev->ioc = ioc;
3010 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07003011 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06003012 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003013
3014 switch (raid_event_data->ReasonCode) {
3015 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07003016 ev->phys_disk_num_valid = 1;
3017 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003018 ev->event_type = MPTSAS_ADD_DEVICE;
3019 break;
3020 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07003021 ev->phys_disk_num_valid = 1;
3022 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07003023 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003024 ev->event_type = MPTSAS_DEL_DEVICE;
3025 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06003026 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
3027 switch (state) {
3028 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07003029 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06003030 ev->phys_disk_num_valid = 1;
3031 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07003032 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06003033 ev->event_type = MPTSAS_ADD_DEVICE;
3034 break;
3035 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06003036 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
3037 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
3038 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07003039 ev->phys_disk_num_valid = 1;
3040 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06003041 ev->event_type = MPTSAS_DEL_DEVICE;
3042 break;
3043 default:
3044 break;
3045 }
3046 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003047 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
3048 ev->event_type = MPTSAS_DEL_RAID;
3049 break;
3050 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
3051 ev->event_type = MPTSAS_ADD_RAID;
3052 break;
3053 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06003054 switch (state) {
3055 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
3056 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
3057 ev->event_type = MPTSAS_DEL_RAID;
3058 break;
3059 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
3060 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
3061 ev->event_type = MPTSAS_ADD_RAID;
3062 break;
3063 default:
3064 break;
3065 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003066 break;
3067 default:
3068 break;
3069 }
3070 schedule_work(&ev->work);
3071}
3072
Moore, Erice6b2d762006-03-14 09:14:24 -07003073static void
Eric Moore547f9a22006-06-27 14:42:12 -06003074mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003075 EVENT_DATA_SAS_DISCOVERY *discovery_data)
3076{
3077 struct mptsas_discovery_event *ev;
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303078 u32 discovery_status;
Moore, Erice6b2d762006-03-14 09:14:24 -07003079
3080 /*
3081 * DiscoveryStatus
3082 *
3083 * This flag will be non-zero when firmware
3084 * kicks off discovery, and return to zero
3085 * once its completed.
3086 */
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303087 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
3088 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
3089 if (discovery_status)
Moore, Erice6b2d762006-03-14 09:14:24 -07003090 return;
3091
Eric Moore547f9a22006-06-27 14:42:12 -06003092 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07003093 if (!ev)
3094 return;
David Howellsc4028952006-11-22 14:57:56 +00003095 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07003096 ev->ioc = ioc;
3097 schedule_work(&ev->work);
3098};
3099
Eric Mooreb506ade2007-01-29 09:45:37 -07003100/*
3101 * mptsas_send_ir2_event - handle exposing hidden disk when
3102 * an inactive raid volume is added
3103 *
3104 * @ioc: Pointer to MPT_ADAPTER structure
3105 * @ir2_data
3106 *
3107 */
3108static void
3109mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
3110{
3111 struct mptsas_hotplug_event *ev;
3112
3113 if (ir2_data->ReasonCode !=
3114 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
3115 return;
3116
3117 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
3118 if (!ev)
3119 return;
3120
3121 INIT_WORK(&ev->work, mptsas_hotplug_work);
3122 ev->ioc = ioc;
3123 ev->id = ir2_data->TargetID;
3124 ev->channel = ir2_data->Bus;
3125 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3126
3127 schedule_work(&ev->work);
3128};
Moore, Erice6b2d762006-03-14 09:14:24 -07003129
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003130static int
3131mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3132{
Moore, Ericc73787ee2006-01-26 16:20:06 -07003133 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003134 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3135
3136 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003137 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003138
Moore, Erice6b2d762006-03-14 09:14:24 -07003139 /*
3140 * sas_discovery_ignore_events
3141 *
3142 * This flag is to prevent anymore processing of
3143 * sas events once mptsas_remove function is called.
3144 */
3145 if (ioc->sas_discovery_ignore_events) {
3146 rc = mptscsih_event_process(ioc, reply);
3147 goto out;
3148 }
3149
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003150 switch (event) {
3151 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003152 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003153 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003154 break;
3155 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003156 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003157 (EVENT_DATA_RAID *)reply->Data);
3158 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003159 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003160 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003161 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003162 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003163 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003164 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003165 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003166 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3167 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003168 case MPI_EVENT_IR2:
3169 mptsas_send_ir2_event(ioc,
3170 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3171 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003172 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003173 rc = mptscsih_event_process(ioc, reply);
3174 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003175 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003176 out:
3177
3178 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003179}
3180
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003181static int
3182mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3183{
3184 struct Scsi_Host *sh;
3185 MPT_SCSI_HOST *hd;
3186 MPT_ADAPTER *ioc;
3187 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003188 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003189 int numSGE = 0;
3190 int scale;
3191 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003192 int error=0;
3193 int r;
3194
3195 r = mpt_attach(pdev,id);
3196 if (r)
3197 return r;
3198
3199 ioc = pci_get_drvdata(pdev);
3200 ioc->DoneCtx = mptsasDoneCtx;
3201 ioc->TaskCtx = mptsasTaskCtx;
3202 ioc->InternalCtx = mptsasInternalCtx;
3203
3204 /* Added sanity check on readiness of the MPT adapter.
3205 */
3206 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3207 printk(MYIOC_s_WARN_FMT
3208 "Skipping because it's not operational!\n",
3209 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003210 error = -ENODEV;
3211 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003212 }
3213
3214 if (!ioc->active) {
3215 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3216 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003217 error = -ENODEV;
3218 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003219 }
3220
3221 /* Sanity check - ensure at least 1 port is INITIATOR capable
3222 */
3223 ioc_cap = 0;
3224 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3225 if (ioc->pfacts[ii].ProtocolFlags &
3226 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3227 ioc_cap++;
3228 }
3229
3230 if (!ioc_cap) {
3231 printk(MYIOC_s_WARN_FMT
3232 "Skipping ioc=%p because SCSI Initiator mode "
3233 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003234 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003235 }
3236
3237 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3238 if (!sh) {
3239 printk(MYIOC_s_WARN_FMT
3240 "Unable to register controller with SCSI subsystem\n",
3241 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003242 error = -1;
3243 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003244 }
3245
3246 spin_lock_irqsave(&ioc->FreeQlock, flags);
3247
3248 /* Attach the SCSI Host to the IOC structure
3249 */
3250 ioc->sh = sh;
3251
3252 sh->io_port = 0;
3253 sh->n_io_port = 0;
3254 sh->irq = 0;
3255
3256 /* set 16 byte cdb's */
3257 sh->max_cmd_len = 16;
3258
Eric Moore793955f2007-01-29 09:42:20 -07003259 sh->max_id = ioc->pfacts[0].PortSCSIID;
3260 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003261
3262 sh->transportt = mptsas_transport_template;
3263
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003264 /* Required entry.
3265 */
3266 sh->unique_id = ioc->id;
3267
3268 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003269 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003270 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003271 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003272 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003273
3274 /* Verify that we won't exceed the maximum
3275 * number of chain buffers
3276 * We can optimize: ZZ = req_sz/sizeof(SGE)
3277 * For 32bit SGE's:
3278 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3279 * + (req_sz - 64)/sizeof(SGE)
3280 * A slightly different algorithm is required for
3281 * 64bit SGEs.
3282 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303283 scale = ioc->req_sz/ioc->SGE_size;
3284 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003285 numSGE = (scale - 1) *
3286 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303287 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003288 } else {
3289 numSGE = 1 + (scale - 1) *
3290 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05303291 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003292 }
3293
3294 if (numSGE < sh->sg_tablesize) {
3295 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303296 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003297 "Resetting sg_tablesize to %d from %d\n",
3298 ioc->name, numSGE, sh->sg_tablesize));
3299 sh->sg_tablesize = numSGE;
3300 }
3301
Eric Mooree7eae9f2007-09-29 10:15:59 -06003302 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003303 hd->ioc = ioc;
3304
3305 /* SCSI needs scsi_cmnd lookup table!
3306 * (with size equal to req_depth*PtrSz!)
3307 */
Eric Mooree8206382007-09-29 10:16:53 -06003308 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3309 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003310 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06003311 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003312 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003313 }
Eric Mooree8206382007-09-29 10:16:53 -06003314 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003315
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303316 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06003317 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003318
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003319 /* Clear the TM flags
3320 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003321 hd->abortSCpnt = NULL;
3322
3323 /* Clear the pointer used to store
3324 * single-threaded commands, i.e., those
3325 * issued during a bus scan, dv and
3326 * configuration pages.
3327 */
3328 hd->cmdPtr = NULL;
3329
3330 /* Initialize this SCSI Hosts' timers
3331 * To use, set the timer expires field
3332 * and add_timer
3333 */
3334 init_timer(&hd->timer);
3335 hd->timer.data = (unsigned long) hd;
3336 hd->timer.function = mptscsih_timer_expired;
3337
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003338 ioc->sas_data.ptClear = mpt_pt_clear;
3339
Eric Mooredf9e0622007-01-29 09:46:21 -07003340 hd->last_queue_full = 0;
3341 INIT_LIST_HEAD(&hd->target_reset_list);
3342 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3343
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003344 if (ioc->sas_data.ptClear==1) {
3345 mptbase_sas_persist_operation(
3346 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3347 }
3348
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003349 error = scsi_add_host(sh, &ioc->pcidev->dev);
3350 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06003351 dprintk(ioc, printk(MYIOC_s_ERR_FMT
3352 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003353 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003354 }
3355
3356 mptsas_scan_sas_topology(ioc);
3357
3358 return 0;
3359
Eric Moore547f9a22006-06-27 14:42:12 -06003360 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003361
3362 mptscsih_remove(pdev);
3363 return error;
3364}
3365
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303366void
3367mptsas_shutdown(struct pci_dev *pdev)
3368{
3369 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3370
3371 ioc->sas_discovery_quiesce_io = 0;
3372}
3373
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003374static void __devexit mptsas_remove(struct pci_dev *pdev)
3375{
3376 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3377 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003378 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003379
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303380 mptsas_shutdown(pdev);
3381
Eric Mooreb506ade2007-01-29 09:45:37 -07003382 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003383 sas_remove_host(ioc->sh);
3384
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003385 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003386 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3387 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003388 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303389 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003390 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003391 kfree(p);
3392 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003393 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003394
3395 mptscsih_remove(pdev);
3396}
3397
3398static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003399 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003400 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003401 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003402 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003403 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003404 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003405 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003406 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003407 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003408 PCI_ANY_ID, PCI_ANY_ID },
3409 {0} /* Terminating entry */
3410};
3411MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3412
3413
3414static struct pci_driver mptsas_driver = {
3415 .name = "mptsas",
3416 .id_table = mptsas_pci_table,
3417 .probe = mptsas_probe,
3418 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05303419 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003420#ifdef CONFIG_PM
3421 .suspend = mptscsih_suspend,
3422 .resume = mptscsih_resume,
3423#endif
3424};
3425
3426static int __init
3427mptsas_init(void)
3428{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303429 int error;
3430
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003431 show_mptmod_ver(my_NAME, my_VERSION);
3432
3433 mptsas_transport_template =
3434 sas_attach_transport(&mptsas_transport_functions);
3435 if (!mptsas_transport_template)
3436 return -ENODEV;
3437
3438 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05303439 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003440 mptsasInternalCtx =
3441 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003442 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05303443 mptsasDeviceResetCtx =
3444 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003445
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303446 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3447 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003448
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303449 error = pci_register_driver(&mptsas_driver);
3450 if (error)
3451 sas_release_transport(mptsas_transport_template);
3452
3453 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003454}
3455
3456static void __exit
3457mptsas_exit(void)
3458{
3459 pci_unregister_driver(&mptsas_driver);
3460 sas_release_transport(mptsas_transport_template);
3461
3462 mpt_reset_deregister(mptsasDoneCtx);
3463 mpt_event_deregister(mptsasDoneCtx);
3464
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003465 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003466 mpt_deregister(mptsasInternalCtx);
3467 mpt_deregister(mptsasTaskCtx);
3468 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05303469 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003470}
3471
3472module_init(mptsas_init);
3473module_exit(mptsas_exit);