blob: f77b329f6923baab6e4b23742981b97b58393046 [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, Sathyaf36789e2007-08-14 16:22:54 +05306 * Copyright (c) 1999-2007 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;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020096
Eric Mooreb506ade2007-01-29 09:45:37 -070097static void mptsas_hotplug_work(struct work_struct *work);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020098
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +053099static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
100 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200101{
Eric Moore29dd3602007-09-14 18:46:51 -0600102 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
103 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
104 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
105 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
106 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
107 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
108 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
109 ioc->name, phy_data->Port));
110 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
111 ioc->name, phy_data->PortFlags));
112 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
113 ioc->name, phy_data->PhyFlags));
114 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
115 ioc->name, phy_data->NegotiatedLinkRate));
116 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
117 "Controller PHY Device Info=0x%X\n", ioc->name,
118 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
119 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
120 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200121}
122
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530123static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200124{
125 __le64 sas_address;
126
127 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
128
Eric Moore29dd3602007-09-14 18:46:51 -0600129 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
130 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
131 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
132 "Attached Device Handle=0x%X\n", ioc->name,
133 le16_to_cpu(pg0->AttachedDevHandle)));
134 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
135 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
136 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
137 "Attached PHY Identifier=0x%X\n", ioc->name,
138 pg0->AttachedPhyIdentifier));
139 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
140 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
141 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
142 ioc->name, pg0->ProgrammedLinkRate));
143 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
144 ioc->name, pg0->ChangeCount));
145 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
146 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200147}
148
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530149static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200150{
Eric Moore29dd3602007-09-14 18:46:51 -0600151 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
152 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
153 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
154 ioc->name, pg1->InvalidDwordCount));
155 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
156 "Running Disparity Error Count=0x%x\n", ioc->name,
157 pg1->RunningDisparityErrorCount));
158 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
159 "Loss Dword Synch Count=0x%x\n", ioc->name,
160 pg1->LossDwordSynchCount));
161 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
162 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
163 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200164}
165
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530166static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200167{
168 __le64 sas_address;
169
170 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
171
Eric Moore29dd3602007-09-14 18:46:51 -0600172 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
173 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
174 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
175 ioc->name, le16_to_cpu(pg0->DevHandle)));
176 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
177 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
178 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
179 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
180 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
181 ioc->name, le16_to_cpu(pg0->Slot)));
182 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
183 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
184 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
185 ioc->name, pg0->TargetID));
186 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
187 ioc->name, pg0->Bus));
188 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
189 ioc->name, pg0->PhyNum));
190 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
191 ioc->name, le16_to_cpu(pg0->AccessStatus)));
192 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
193 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
194 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
195 ioc->name, le16_to_cpu(pg0->Flags)));
196 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
197 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200198}
199
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530200static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200201{
Eric Moore29dd3602007-09-14 18:46:51 -0600202 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
203 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
204 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
205 ioc->name, pg1->PhysicalPort));
206 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
207 ioc->name, pg1->PhyIdentifier));
208 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
209 ioc->name, pg1->NegotiatedLinkRate));
210 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
211 ioc->name, pg1->ProgrammedLinkRate));
212 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
213 ioc->name, pg1->HwLinkRate));
214 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
215 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
216 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
217 "Attached Device Handle=0x%X\n\n", ioc->name,
218 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200219}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200220
Christoph Hellwige3094442006-02-16 13:25:36 +0100221static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
222{
223 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
224 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
225}
226
227static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
228{
229 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
230 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
231}
232
Moore, Erice6b2d762006-03-14 09:14:24 -0700233/*
234 * mptsas_find_portinfo_by_handle
235 *
236 * This function should be called with the sas_topology_mutex already held
237 */
238static struct mptsas_portinfo *
239mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
240{
241 struct mptsas_portinfo *port_info, *rc=NULL;
242 int i;
243
244 list_for_each_entry(port_info, &ioc->sas_topology, list)
245 for (i = 0; i < port_info->num_phys; i++)
246 if (port_info->phy_info[i].identify.handle == handle) {
247 rc = port_info;
248 goto out;
249 }
250 out:
251 return rc;
252}
253
Moore, Ericbd23e942006-04-17 12:43:04 -0600254/*
255 * Returns true if there is a scsi end device
256 */
257static inline int
258mptsas_is_end_device(struct mptsas_devinfo * attached)
259{
Eric Moore547f9a22006-06-27 14:42:12 -0600260 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600261 (attached->device_info &
262 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
263 ((attached->device_info &
264 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
265 (attached->device_info &
266 MPI_SAS_DEVICE_INFO_STP_TARGET) |
267 (attached->device_info &
268 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
269 return 1;
270 else
271 return 0;
272}
273
Eric Moore547f9a22006-06-27 14:42:12 -0600274/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600275static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530276mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600277{
278 struct mptsas_portinfo *port_info;
279 struct mptsas_phyinfo *phy_info;
280 u8 i;
281
282 if (!port_details)
283 return;
284
285 port_info = port_details->port_info;
286 phy_info = port_info->phy_info;
287
Eric Moore29dd3602007-09-14 18:46:51 -0600288 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
289 "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700290 port_details->num_phys, (unsigned long long)
291 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600292
293 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
294 if(phy_info->port_details != port_details)
295 continue;
296 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
297 phy_info->port_details = NULL;
298 }
299 kfree(port_details);
300}
301
302static inline struct sas_rphy *
303mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
304{
305 if (phy_info->port_details)
306 return phy_info->port_details->rphy;
307 else
308 return NULL;
309}
310
311static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530312mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600313{
314 if (phy_info->port_details) {
315 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600316 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
317 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600318 }
319
Eric Moore547f9a22006-06-27 14:42:12 -0600320 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600321 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
322 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600323 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
324 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600325 }
Eric Moore547f9a22006-06-27 14:42:12 -0600326}
327
328static inline struct sas_port *
329mptsas_get_port(struct mptsas_phyinfo *phy_info)
330{
331 if (phy_info->port_details)
332 return phy_info->port_details->port;
333 else
334 return NULL;
335}
336
337static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530338mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600339{
340 if (phy_info->port_details)
341 phy_info->port_details->port = port;
342
Eric Moore547f9a22006-06-27 14:42:12 -0600343 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600344 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
345 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600346 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
347 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600348 }
Eric Moore547f9a22006-06-27 14:42:12 -0600349}
350
351static inline struct scsi_target *
352mptsas_get_starget(struct mptsas_phyinfo *phy_info)
353{
354 if (phy_info->port_details)
355 return phy_info->port_details->starget;
356 else
357 return NULL;
358}
359
360static inline void
361mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
362starget)
363{
364 if (phy_info->port_details)
365 phy_info->port_details->starget = starget;
366}
367
368
369/*
370 * mptsas_setup_wide_ports
371 *
372 * Updates for new and existing narrow/wide port configuration
373 * in the sas_topology
374 */
Eric Moore376ac832006-06-29 17:36:26 -0600375static void
Eric Moore547f9a22006-06-27 14:42:12 -0600376mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
377{
378 struct mptsas_portinfo_details * port_details;
379 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
380 u64 sas_address;
381 int i, j;
382
383 mutex_lock(&ioc->sas_topology_mutex);
384
385 phy_info = port_info->phy_info;
386 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
387 if (phy_info->attached.handle)
388 continue;
389 port_details = phy_info->port_details;
390 if (!port_details)
391 continue;
392 if (port_details->num_phys < 2)
393 continue;
394 /*
395 * Removing a phy from a port, letting the last
396 * phy be removed by firmware events.
397 */
Eric Moore29dd3602007-09-14 18:46:51 -0600398 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
399 "%s: [%p]: deleting phy = %d\n",
400 ioc->name, __FUNCTION__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600401 port_details->num_phys--;
402 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
403 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
404 sas_port_delete_phy(port_details->port, phy_info->phy);
405 phy_info->port_details = NULL;
406 }
407
408 /*
409 * Populate and refresh the tree
410 */
411 phy_info = port_info->phy_info;
412 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
413 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600414 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
415 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600416 if (!sas_address)
417 continue;
418 port_details = phy_info->port_details;
419 /*
420 * Forming a port
421 */
422 if (!port_details) {
423 port_details = kzalloc(sizeof(*port_details),
424 GFP_KERNEL);
425 if (!port_details)
426 goto out;
427 port_details->num_phys = 1;
428 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600429 if (phy_info->phy_id < 64 )
430 port_details->phy_bitmask |=
431 (1 << phy_info->phy_id);
432 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600433 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700434 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600435 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600436 phy_info->port_details = port_details;
437 }
438
439 if (i == port_info->num_phys - 1)
440 continue;
441 phy_info_cmp = &port_info->phy_info[i + 1];
442 for (j = i + 1 ; j < port_info->num_phys ; j++,
443 phy_info_cmp++) {
444 if (!phy_info_cmp->attached.sas_address)
445 continue;
446 if (sas_address != phy_info_cmp->attached.sas_address)
447 continue;
448 if (phy_info_cmp->port_details == port_details )
449 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600450 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700451 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600452 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700453 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600454 if (phy_info_cmp->port_details) {
455 port_details->rphy =
456 mptsas_get_rphy(phy_info_cmp);
457 port_details->port =
458 mptsas_get_port(phy_info_cmp);
459 port_details->starget =
460 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600461 port_details->num_phys =
462 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600463 if (!phy_info_cmp->port_details->num_phys)
464 kfree(phy_info_cmp->port_details);
465 } else
466 phy_info_cmp->sas_port_add_phy=1;
467 /*
468 * Adding a phy to a port
469 */
470 phy_info_cmp->port_details = port_details;
471 if (phy_info_cmp->phy_id < 64 )
472 port_details->phy_bitmask |=
473 (1 << phy_info_cmp->phy_id);
474 port_details->num_phys++;
475 }
476 }
477
478 out:
479
Eric Moore547f9a22006-06-27 14:42:12 -0600480 for (i = 0; i < port_info->num_phys; i++) {
481 port_details = port_info->phy_info[i].port_details;
482 if (!port_details)
483 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600484 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700485 "%s: [%p]: phy_id=%02d num_phys=%02d "
Eric Moore29dd3602007-09-14 18:46:51 -0600486 "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
Eric Mooref99be432007-01-04 20:46:54 -0700487 port_details, i, port_details->num_phys,
488 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600489 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
490 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600491 }
Eric Moore29dd3602007-09-14 18:46:51 -0600492 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600493 mutex_unlock(&ioc->sas_topology_mutex);
494}
495
Eric Mooredf9e0622007-01-29 09:46:21 -0700496/**
497 * csmisas_find_vtarget
498 *
499 * @ioc
500 * @volume_id
501 * @volume_bus
502 *
503 **/
504static VirtTarget *
505mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600506{
Eric Mooredf9e0622007-01-29 09:46:21 -0700507 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600508 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700509 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600510
Eric Mooredf9e0622007-01-29 09:46:21 -0700511 shost_for_each_device(sdev, ioc->sh) {
Eric Moorea69de502007-09-14 18:48:19 -0600512 if ((vdevice = sdev->hostdata) == NULL)
Eric Mooredf9e0622007-01-29 09:46:21 -0700513 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600514 if (vdevice->vtarget->id == id &&
515 vdevice->vtarget->channel == channel)
516 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600517 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700518 return vtarget;
519}
520
521/**
522 * mptsas_target_reset
523 *
524 * Issues TARGET_RESET to end device using handshaking method
525 *
526 * @ioc
527 * @channel
528 * @id
529 *
530 * Returns (1) success
531 * (0) failure
532 *
533 **/
534static int
535mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
536{
537 MPT_FRAME_HDR *mf;
538 SCSITaskMgmt_t *pScsiTm;
539
540 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530541 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700542 ioc->name,__FUNCTION__, __LINE__));
543 return 0;
544 }
545
546 /* Format the Request
547 */
548 pScsiTm = (SCSITaskMgmt_t *) mf;
549 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
550 pScsiTm->TargetID = id;
551 pScsiTm->Bus = channel;
552 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
553 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
554 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
555
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530556 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700557
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530558 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700559
560 return 1;
561}
562
563/**
564 * mptsas_target_reset_queue
565 *
566 * Receive request for TARGET_RESET after recieving an firmware
567 * event NOT_RESPONDING_EVENT, then put command in link list
568 * and queue if task_queue already in use.
569 *
570 * @ioc
571 * @sas_event_data
572 *
573 **/
574static void
575mptsas_target_reset_queue(MPT_ADAPTER *ioc,
576 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
577{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600578 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700579 VirtTarget *vtarget = NULL;
580 struct mptsas_target_reset_event *target_reset_list;
581 u8 id, channel;
582
583 id = sas_event_data->TargetID;
584 channel = sas_event_data->Bus;
585
586 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
587 return;
588
589 vtarget->deleted = 1; /* block IO */
590
591 target_reset_list = kzalloc(sizeof(*target_reset_list),
592 GFP_ATOMIC);
593 if (!target_reset_list) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530594 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700595 ioc->name,__FUNCTION__, __LINE__));
596 return;
597 }
598
599 memcpy(&target_reset_list->sas_event_data, sas_event_data,
600 sizeof(*sas_event_data));
601 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
602
603 if (hd->resetPending)
604 return;
605
606 if (mptsas_target_reset(ioc, channel, id)) {
607 target_reset_list->target_reset_issued = 1;
608 hd->resetPending = 1;
609 }
610}
611
612/**
613 * mptsas_dev_reset_complete
614 *
615 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
616 * enable work queue to finish off removing device from upper layers.
617 * then send next TARGET_RESET in the queue.
618 *
619 * @ioc
620 *
621 **/
622static void
623mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
624{
Eric Mooree7eae9f2007-09-29 10:15:59 -0600625 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -0700626 struct list_head *head = &hd->target_reset_list;
627 struct mptsas_target_reset_event *target_reset_list;
628 struct mptsas_hotplug_event *ev;
629 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
630 u8 id, channel;
631 __le64 sas_address;
632
633 if (list_empty(head))
634 return;
635
636 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
637
638 sas_event_data = &target_reset_list->sas_event_data;
639 id = sas_event_data->TargetID;
640 channel = sas_event_data->Bus;
641 hd->resetPending = 0;
642
643 /*
644 * retry target reset
645 */
646 if (!target_reset_list->target_reset_issued) {
647 if (mptsas_target_reset(ioc, channel, id)) {
648 target_reset_list->target_reset_issued = 1;
649 hd->resetPending = 1;
650 }
651 return;
652 }
653
654 /*
655 * enable work queue to remove device from upper layers
656 */
657 list_del(&target_reset_list->list);
658
659 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
660 if (!ev) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530661 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700662 ioc->name,__FUNCTION__, __LINE__));
663 return;
664 }
665
666 INIT_WORK(&ev->work, mptsas_hotplug_work);
667 ev->ioc = ioc;
668 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
669 ev->parent_handle =
670 le16_to_cpu(sas_event_data->ParentDevHandle);
671 ev->channel = channel;
672 ev->id =id;
673 ev->phy_id = sas_event_data->PhyNum;
674 memcpy(&sas_address, &sas_event_data->SASAddress,
675 sizeof(__le64));
676 ev->sas_address = le64_to_cpu(sas_address);
677 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
678 ev->event_type = MPTSAS_DEL_DEVICE;
679 schedule_work(&ev->work);
680 kfree(target_reset_list);
681
682 /*
683 * issue target reset to next device in the queue
684 */
685
686 head = &hd->target_reset_list;
687 if (list_empty(head))
688 return;
689
690 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
691 list);
692
693 sas_event_data = &target_reset_list->sas_event_data;
694 id = sas_event_data->TargetID;
695 channel = sas_event_data->Bus;
696
697 if (mptsas_target_reset(ioc, channel, id)) {
698 target_reset_list->target_reset_issued = 1;
699 hd->resetPending = 1;
700 }
701}
702
703/**
704 * mptsas_taskmgmt_complete
705 *
706 * @ioc
707 * @mf
708 * @mr
709 *
710 **/
711static int
712mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
713{
714 mptsas_dev_reset_complete(ioc);
715 return mptscsih_taskmgmt_complete(ioc, mf, mr);
716}
717
718/**
719 * mptscsih_ioc_reset
720 *
721 * @ioc
722 * @reset_phase
723 *
724 **/
725static int
726mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
727{
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800728 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -0700729 struct mptsas_target_reset_event *target_reset_list, *n;
730 int rc;
731
732 rc = mptscsih_ioc_reset(ioc, reset_phase);
733
734 if (ioc->bus_type != SAS)
735 goto out;
736
737 if (reset_phase != MPT_IOC_POST_RESET)
738 goto out;
739
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800740 if (!ioc->sh || !ioc->sh->hostdata)
741 goto out;
Eric Mooree7eae9f2007-09-29 10:15:59 -0600742 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800743 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -0700744 goto out;
745
746 if (list_empty(&hd->target_reset_list))
747 goto out;
748
749 /* flush the target_reset_list */
750 list_for_each_entry_safe(target_reset_list, n,
751 &hd->target_reset_list, list) {
752 list_del(&target_reset_list->list);
753 kfree(target_reset_list);
754 }
755
756 out:
757 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -0600758}
759
Christoph Hellwige3094442006-02-16 13:25:36 +0100760static int
Moore, Eric52435432006-03-14 09:14:15 -0700761mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100762 u32 form, u32 form_specific)
763{
764 ConfigExtendedPageHeader_t hdr;
765 CONFIGPARMS cfg;
766 SasEnclosurePage0_t *buffer;
767 dma_addr_t dma_handle;
768 int error;
769 __le64 le_identifier;
770
771 memset(&hdr, 0, sizeof(hdr));
772 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
773 hdr.PageNumber = 0;
774 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
775 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
776
777 cfg.cfghdr.ehdr = &hdr;
778 cfg.physAddr = -1;
779 cfg.pageAddr = form + form_specific;
780 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
781 cfg.dir = 0; /* read */
782 cfg.timeout = 10;
783
784 error = mpt_config(ioc, &cfg);
785 if (error)
786 goto out;
787 if (!hdr.ExtPageLength) {
788 error = -ENXIO;
789 goto out;
790 }
791
792 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
793 &dma_handle);
794 if (!buffer) {
795 error = -ENOMEM;
796 goto out;
797 }
798
799 cfg.physAddr = dma_handle;
800 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
801
802 error = mpt_config(ioc, &cfg);
803 if (error)
804 goto out_free_consistent;
805
806 /* save config data */
807 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
808 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
809 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
810 enclosure->flags = le16_to_cpu(buffer->Flags);
811 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
812 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
813 enclosure->start_id = buffer->StartTargetID;
814 enclosure->start_channel = buffer->StartBus;
815 enclosure->sep_id = buffer->SEPTargetID;
816 enclosure->sep_channel = buffer->SEPBus;
817
818 out_free_consistent:
819 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
820 buffer, dma_handle);
821 out:
822 return error;
823}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200824
James Bottomleyf013db32006-03-18 14:54:36 -0600825static int
826mptsas_slave_configure(struct scsi_device *sdev)
827{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600828
James Bottomleye8bf3942006-07-11 17:49:34 -0400829 if (sdev->channel == MPTSAS_RAID_CHANNEL)
830 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600831
James Bottomleye8bf3942006-07-11 17:49:34 -0400832 sas_read_port_mode_page(sdev);
833
834 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600835 return mptscsih_slave_configure(sdev);
836}
837
Eric Moore547f9a22006-06-27 14:42:12 -0600838static int
839mptsas_target_alloc(struct scsi_target *starget)
840{
841 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -0600842 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -0600843 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700844 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600845 struct sas_rphy *rphy;
846 struct mptsas_portinfo *p;
847 int i;
Eric Mooree80b0022007-09-14 18:49:03 -0600848 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -0600849
850 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
851 if (!vtarget)
852 return -ENOMEM;
853
854 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -0600855 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -0700856 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
857 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -0600858 channel = 0;
859
Eric Moore793955f2007-01-29 09:42:20 -0700860 /*
861 * RAID volumes placed beyond the last expected port.
862 */
863 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Eric Mooree80b0022007-09-14 18:49:03 -0600864 for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
865 if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
866 channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
Eric Moore547f9a22006-06-27 14:42:12 -0600867 goto out;
Eric Moore793955f2007-01-29 09:42:20 -0700868 }
Eric Moore547f9a22006-06-27 14:42:12 -0600869
870 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -0600871 mutex_lock(&ioc->sas_topology_mutex);
872 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -0600873 for (i = 0; i < p->num_phys; i++) {
874 if (p->phy_info[i].attached.sas_address !=
875 rphy->identify.sas_address)
876 continue;
Eric Moore793955f2007-01-29 09:42:20 -0700877 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -0600878 channel = p->phy_info[i].attached.channel;
879 mptsas_set_starget(&p->phy_info[i], starget);
880
881 /*
882 * Exposing hidden raid components
883 */
Eric Mooree80b0022007-09-14 18:49:03 -0600884 if (mptscsih_is_phys_disk(ioc, channel, id)) {
885 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -0700886 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -0600887 vtarget->tflags |=
888 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -0700889 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -0600890 }
Eric Mooree80b0022007-09-14 18:49:03 -0600891 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -0600892 goto out;
893 }
894 }
Eric Mooree80b0022007-09-14 18:49:03 -0600895 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -0600896
897 kfree(vtarget);
898 return -ENXIO;
899
900 out:
Eric Moore793955f2007-01-29 09:42:20 -0700901 vtarget->id = id;
902 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600903 starget->hostdata = vtarget;
904 return 0;
905}
906
907static void
908mptsas_target_destroy(struct scsi_target *starget)
909{
910 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -0600911 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -0600912 struct sas_rphy *rphy;
913 struct mptsas_portinfo *p;
914 int i;
Eric Mooree80b0022007-09-14 18:49:03 -0600915 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -0600916
917 if (!starget->hostdata)
918 return;
919
James Bottomleye8bf3942006-07-11 17:49:34 -0400920 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -0600921 goto out;
922
923 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -0600924 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -0600925 for (i = 0; i < p->num_phys; i++) {
926 if (p->phy_info[i].attached.sas_address !=
927 rphy->identify.sas_address)
928 continue;
929 mptsas_set_starget(&p->phy_info[i], NULL);
930 goto out;
931 }
932 }
933
934 out:
935 kfree(starget->hostdata);
936 starget->hostdata = NULL;
937}
938
939
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200940static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700941mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200942{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700943 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -0600944 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200945 struct sas_rphy *rphy;
946 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -0600947 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700948 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -0600949 int i;
Eric Mooree80b0022007-09-14 18:49:03 -0600950 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200951
Eric Moorea69de502007-09-14 18:48:19 -0600952 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
953 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -0600954 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -0600955 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200956 return -ENOMEM;
957 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700958 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -0600959 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200960
James Bottomleye8bf3942006-07-11 17:49:34 -0400961 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -0700962 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -0700963
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700964 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -0600965 mutex_lock(&ioc->sas_topology_mutex);
966 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200967 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -0600968 if (p->phy_info[i].attached.sas_address !=
969 rphy->identify.sas_address)
970 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600971 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -0600972 /*
973 * Exposing hidden raid components
974 */
Eric Mooree80b0022007-09-14 18:49:03 -0600975 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -0700976 p->phy_info[i].attached.channel,
977 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -0600978 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -0600979 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -0600980 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200981 }
982 }
Eric Mooree80b0022007-09-14 18:49:03 -0600983 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200984
Eric Moorea69de502007-09-14 18:48:19 -0600985 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +0100986 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200987
988 out:
Eric Moorea69de502007-09-14 18:48:19 -0600989 vdevice->vtarget->num_luns++;
990 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200991 return 0;
992}
993
Eric Moore547f9a22006-06-27 14:42:12 -0600994static int
995mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +0100996{
Eric Moorea69de502007-09-14 18:48:19 -0600997 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +0100998
Eric Moorea69de502007-09-14 18:48:19 -0600999 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001000 SCpnt->result = DID_NO_CONNECT << 16;
1001 done(SCpnt);
1002 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001003 }
Eric Moore547f9a22006-06-27 14:42:12 -06001004
Eric Moore793955f2007-01-29 09:42:20 -07001005// scsi_print_command(SCpnt);
1006
Eric Moore547f9a22006-06-27 14:42:12 -06001007 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001008}
1009
Eric Moore547f9a22006-06-27 14:42:12 -06001010
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001011static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001012 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001013 .proc_name = "mptsas",
1014 .proc_info = mptscsih_proc_info,
1015 .name = "MPT SPI Host",
1016 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001017 .queuecommand = mptsas_qcmd,
1018 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001019 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001020 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001021 .target_destroy = mptsas_target_destroy,
1022 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001023 .change_queue_depth = mptscsih_change_queue_depth,
1024 .eh_abort_handler = mptscsih_abort,
1025 .eh_device_reset_handler = mptscsih_dev_reset,
1026 .eh_bus_reset_handler = mptscsih_bus_reset,
1027 .eh_host_reset_handler = mptscsih_host_reset,
1028 .bios_param = mptscsih_bios_param,
1029 .can_queue = MPT_FC_CAN_QUEUE,
1030 .this_id = -1,
1031 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1032 .max_sectors = 8192,
1033 .cmd_per_lun = 7,
1034 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301035 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001036};
1037
Christoph Hellwigb5141122005-10-28 22:07:41 +02001038static int mptsas_get_linkerrors(struct sas_phy *phy)
1039{
1040 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1041 ConfigExtendedPageHeader_t hdr;
1042 CONFIGPARMS cfg;
1043 SasPhyPage1_t *buffer;
1044 dma_addr_t dma_handle;
1045 int error;
1046
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001047 /* FIXME: only have link errors on local phys */
1048 if (!scsi_is_sas_phy_local(phy))
1049 return -EINVAL;
1050
Christoph Hellwigb5141122005-10-28 22:07:41 +02001051 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1052 hdr.ExtPageLength = 0;
1053 hdr.PageNumber = 1 /* page number 1*/;
1054 hdr.Reserved1 = 0;
1055 hdr.Reserved2 = 0;
1056 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1057 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1058
1059 cfg.cfghdr.ehdr = &hdr;
1060 cfg.physAddr = -1;
1061 cfg.pageAddr = phy->identify.phy_identifier;
1062 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1063 cfg.dir = 0; /* read */
1064 cfg.timeout = 10;
1065
1066 error = mpt_config(ioc, &cfg);
1067 if (error)
1068 return error;
1069 if (!hdr.ExtPageLength)
1070 return -ENXIO;
1071
1072 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1073 &dma_handle);
1074 if (!buffer)
1075 return -ENOMEM;
1076
1077 cfg.physAddr = dma_handle;
1078 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1079
1080 error = mpt_config(ioc, &cfg);
1081 if (error)
1082 goto out_free_consistent;
1083
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301084 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001085
1086 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1087 phy->running_disparity_error_count =
1088 le32_to_cpu(buffer->RunningDisparityErrorCount);
1089 phy->loss_of_dword_sync_count =
1090 le32_to_cpu(buffer->LossDwordSynchCount);
1091 phy->phy_reset_problem_count =
1092 le32_to_cpu(buffer->PhyResetProblemCount);
1093
1094 out_free_consistent:
1095 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1096 buffer, dma_handle);
1097 return error;
1098}
1099
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001100static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1101 MPT_FRAME_HDR *reply)
1102{
1103 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
1104 if (reply != NULL) {
1105 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
1106 memcpy(ioc->sas_mgmt.reply, reply,
1107 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1108 }
1109 complete(&ioc->sas_mgmt.done);
1110 return 1;
1111}
1112
1113static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1114{
1115 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1116 SasIoUnitControlRequest_t *req;
1117 SasIoUnitControlReply_t *reply;
1118 MPT_FRAME_HDR *mf;
1119 MPIHeader_t *hdr;
1120 unsigned long timeleft;
1121 int error = -ERESTARTSYS;
1122
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001123 /* FIXME: fusion doesn't allow non-local phy reset */
1124 if (!scsi_is_sas_phy_local(phy))
1125 return -EINVAL;
1126
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001127 /* not implemented for expanders */
1128 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1129 return -ENXIO;
1130
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001131 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001132 goto out;
1133
1134 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1135 if (!mf) {
1136 error = -ENOMEM;
1137 goto out_unlock;
1138 }
1139
1140 hdr = (MPIHeader_t *) mf;
1141 req = (SasIoUnitControlRequest_t *)mf;
1142 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1143 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1144 req->MsgContext = hdr->MsgContext;
1145 req->Operation = hard_reset ?
1146 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1147 req->PhyNum = phy->identify.phy_identifier;
1148
1149 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1150
1151 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1152 10 * HZ);
1153 if (!timeleft) {
1154 /* On timeout reset the board */
1155 mpt_free_msg_frame(ioc, mf);
1156 mpt_HardResetHandler(ioc, CAN_SLEEP);
1157 error = -ETIMEDOUT;
1158 goto out_unlock;
1159 }
1160
1161 /* a reply frame is expected */
1162 if ((ioc->sas_mgmt.status &
1163 MPT_IOCTL_STATUS_RF_VALID) == 0) {
1164 error = -ENXIO;
1165 goto out_unlock;
1166 }
1167
1168 /* process the completed Reply Message Frame */
1169 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1170 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001171 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
1172 ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001173 error = -ENXIO;
1174 goto out_unlock;
1175 }
1176
1177 error = 0;
1178
1179 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001180 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001181 out:
1182 return error;
1183}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001184
Christoph Hellwige3094442006-02-16 13:25:36 +01001185static int
1186mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1187{
1188 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1189 int i, error;
1190 struct mptsas_portinfo *p;
1191 struct mptsas_enclosure enclosure_info;
1192 u64 enclosure_handle;
1193
1194 mutex_lock(&ioc->sas_topology_mutex);
1195 list_for_each_entry(p, &ioc->sas_topology, list) {
1196 for (i = 0; i < p->num_phys; i++) {
1197 if (p->phy_info[i].attached.sas_address ==
1198 rphy->identify.sas_address) {
1199 enclosure_handle = p->phy_info[i].
1200 attached.handle_enclosure;
1201 goto found_info;
1202 }
1203 }
1204 }
1205 mutex_unlock(&ioc->sas_topology_mutex);
1206 return -ENXIO;
1207
1208 found_info:
1209 mutex_unlock(&ioc->sas_topology_mutex);
1210 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001211 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001212 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1213 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1214 if (!error)
1215 *identifier = enclosure_info.enclosure_logical_id;
1216 return error;
1217}
1218
1219static int
1220mptsas_get_bay_identifier(struct sas_rphy *rphy)
1221{
1222 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1223 struct mptsas_portinfo *p;
1224 int i, rc;
1225
1226 mutex_lock(&ioc->sas_topology_mutex);
1227 list_for_each_entry(p, &ioc->sas_topology, list) {
1228 for (i = 0; i < p->num_phys; i++) {
1229 if (p->phy_info[i].attached.sas_address ==
1230 rphy->identify.sas_address) {
1231 rc = p->phy_info[i].attached.slot;
1232 goto out;
1233 }
1234 }
1235 }
1236 rc = -ENXIO;
1237 out:
1238 mutex_unlock(&ioc->sas_topology_mutex);
1239 return rc;
1240}
1241
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001242static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1243 struct request *req)
1244{
1245 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1246 MPT_FRAME_HDR *mf;
1247 SmpPassthroughRequest_t *smpreq;
1248 struct request *rsp = req->next_rq;
1249 int ret;
1250 int flagsLength;
1251 unsigned long timeleft;
1252 char *psge;
1253 dma_addr_t dma_addr_in = 0;
1254 dma_addr_t dma_addr_out = 0;
1255 u64 sas_address = 0;
1256
1257 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06001258 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
1259 ioc->name, __FUNCTION__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001260 return -EINVAL;
1261 }
1262
1263 /* do we need to support multiple segments? */
1264 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06001265 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
1266 ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len,
1267 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001268 return -EINVAL;
1269 }
1270
1271 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1272 if (ret)
1273 goto out;
1274
1275 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1276 if (!mf) {
1277 ret = -ENOMEM;
1278 goto out_unlock;
1279 }
1280
1281 smpreq = (SmpPassthroughRequest_t *)mf;
1282 memset(smpreq, 0, sizeof(*smpreq));
1283
1284 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1285 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1286
1287 if (rphy)
1288 sas_address = rphy->identify.sas_address;
1289 else {
1290 struct mptsas_portinfo *port_info;
1291
1292 mutex_lock(&ioc->sas_topology_mutex);
1293 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
1294 if (port_info && port_info->phy_info)
1295 sas_address =
1296 port_info->phy_info[0].phy->identify.sas_address;
1297 mutex_unlock(&ioc->sas_topology_mutex);
1298 }
1299
1300 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1301
1302 psge = (char *)
1303 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1304
1305 /* request */
1306 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1307 MPI_SGE_FLAGS_END_OF_BUFFER |
1308 MPI_SGE_FLAGS_DIRECTION |
1309 mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
1310 flagsLength |= (req->data_len - 4);
1311
1312 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1313 req->data_len, PCI_DMA_BIDIRECTIONAL);
1314 if (!dma_addr_out)
1315 goto put_mf;
1316 mpt_add_sge(psge, flagsLength, dma_addr_out);
1317 psge += (sizeof(u32) + sizeof(dma_addr_t));
1318
1319 /* response */
1320 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1321 flagsLength |= rsp->data_len + 4;
1322 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1323 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1324 if (!dma_addr_in)
1325 goto unmap;
1326 mpt_add_sge(psge, flagsLength, dma_addr_in);
1327
1328 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1329
1330 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1331 if (!timeleft) {
Eric Moore29dd3602007-09-14 18:46:51 -06001332 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001333 /* On timeout reset the board */
1334 mpt_HardResetHandler(ioc, CAN_SLEEP);
1335 ret = -ETIMEDOUT;
1336 goto unmap;
1337 }
1338 mf = NULL;
1339
1340 if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
1341 SmpPassthroughReply_t *smprep;
1342
1343 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1344 memcpy(req->sense, smprep, sizeof(*smprep));
1345 req->sense_len = sizeof(*smprep);
FUJITA Tomonori38b31672007-12-30 19:34:52 +09001346 req->data_len = 0;
1347 rsp->data_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001348 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001349 printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
1350 ioc->name, __FUNCTION__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001351 ret = -ENXIO;
1352 }
1353unmap:
1354 if (dma_addr_out)
1355 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1356 PCI_DMA_BIDIRECTIONAL);
1357 if (dma_addr_in)
1358 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1359 PCI_DMA_BIDIRECTIONAL);
1360put_mf:
1361 if (mf)
1362 mpt_free_msg_frame(ioc, mf);
1363out_unlock:
1364 mutex_unlock(&ioc->sas_mgmt.mutex);
1365out:
1366 return ret;
1367}
1368
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001369static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001370 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001371 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1372 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001373 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001374 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001375};
1376
1377static struct scsi_transport_template *mptsas_transport_template;
1378
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001379static int
1380mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1381{
1382 ConfigExtendedPageHeader_t hdr;
1383 CONFIGPARMS cfg;
1384 SasIOUnitPage0_t *buffer;
1385 dma_addr_t dma_handle;
1386 int error, i;
1387
1388 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1389 hdr.ExtPageLength = 0;
1390 hdr.PageNumber = 0;
1391 hdr.Reserved1 = 0;
1392 hdr.Reserved2 = 0;
1393 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1394 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1395
1396 cfg.cfghdr.ehdr = &hdr;
1397 cfg.physAddr = -1;
1398 cfg.pageAddr = 0;
1399 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1400 cfg.dir = 0; /* read */
1401 cfg.timeout = 10;
1402
1403 error = mpt_config(ioc, &cfg);
1404 if (error)
1405 goto out;
1406 if (!hdr.ExtPageLength) {
1407 error = -ENXIO;
1408 goto out;
1409 }
1410
1411 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1412 &dma_handle);
1413 if (!buffer) {
1414 error = -ENOMEM;
1415 goto out;
1416 }
1417
1418 cfg.physAddr = dma_handle;
1419 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1420
1421 error = mpt_config(ioc, &cfg);
1422 if (error)
1423 goto out_free_consistent;
1424
1425 port_info->num_phys = buffer->NumPhys;
1426 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001427 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001428 if (!port_info->phy_info) {
1429 error = -ENOMEM;
1430 goto out_free_consistent;
1431 }
1432
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301433 ioc->nvdata_version_persistent =
1434 le16_to_cpu(buffer->NvdataVersionPersistent);
1435 ioc->nvdata_version_default =
1436 le16_to_cpu(buffer->NvdataVersionDefault);
1437
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001438 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301439 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001440 port_info->phy_info[i].phy_id = i;
1441 port_info->phy_info[i].port_id =
1442 buffer->PhyData[i].Port;
1443 port_info->phy_info[i].negotiated_link_rate =
1444 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001445 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001446 port_info->phy_info[i].handle =
1447 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001448 }
1449
1450 out_free_consistent:
1451 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1452 buffer, dma_handle);
1453 out:
1454 return error;
1455}
1456
1457static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301458mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1459{
1460 ConfigExtendedPageHeader_t hdr;
1461 CONFIGPARMS cfg;
1462 SasIOUnitPage1_t *buffer;
1463 dma_addr_t dma_handle;
1464 int error;
1465 u16 device_missing_delay;
1466
1467 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1468 memset(&cfg, 0, sizeof(CONFIGPARMS));
1469
1470 cfg.cfghdr.ehdr = &hdr;
1471 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1472 cfg.timeout = 10;
1473 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1474 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1475 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1476 cfg.cfghdr.ehdr->PageNumber = 1;
1477
1478 error = mpt_config(ioc, &cfg);
1479 if (error)
1480 goto out;
1481 if (!hdr.ExtPageLength) {
1482 error = -ENXIO;
1483 goto out;
1484 }
1485
1486 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1487 &dma_handle);
1488 if (!buffer) {
1489 error = -ENOMEM;
1490 goto out;
1491 }
1492
1493 cfg.physAddr = dma_handle;
1494 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1495
1496 error = mpt_config(ioc, &cfg);
1497 if (error)
1498 goto out_free_consistent;
1499
1500 ioc->io_missing_delay =
1501 le16_to_cpu(buffer->IODeviceMissingDelay);
1502 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1503 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1504 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1505 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1506
1507 out_free_consistent:
1508 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1509 buffer, dma_handle);
1510 out:
1511 return error;
1512}
1513
1514static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001515mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1516 u32 form, u32 form_specific)
1517{
1518 ConfigExtendedPageHeader_t hdr;
1519 CONFIGPARMS cfg;
1520 SasPhyPage0_t *buffer;
1521 dma_addr_t dma_handle;
1522 int error;
1523
1524 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1525 hdr.ExtPageLength = 0;
1526 hdr.PageNumber = 0;
1527 hdr.Reserved1 = 0;
1528 hdr.Reserved2 = 0;
1529 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1530 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1531
1532 cfg.cfghdr.ehdr = &hdr;
1533 cfg.dir = 0; /* read */
1534 cfg.timeout = 10;
1535
1536 /* Get Phy Pg 0 for each Phy. */
1537 cfg.physAddr = -1;
1538 cfg.pageAddr = form + form_specific;
1539 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1540
1541 error = mpt_config(ioc, &cfg);
1542 if (error)
1543 goto out;
1544
1545 if (!hdr.ExtPageLength) {
1546 error = -ENXIO;
1547 goto out;
1548 }
1549
1550 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1551 &dma_handle);
1552 if (!buffer) {
1553 error = -ENOMEM;
1554 goto out;
1555 }
1556
1557 cfg.physAddr = dma_handle;
1558 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1559
1560 error = mpt_config(ioc, &cfg);
1561 if (error)
1562 goto out_free_consistent;
1563
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301564 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001565
1566 phy_info->hw_link_rate = buffer->HwLinkRate;
1567 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1568 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1569 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1570
1571 out_free_consistent:
1572 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1573 buffer, dma_handle);
1574 out:
1575 return error;
1576}
1577
1578static int
1579mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1580 u32 form, u32 form_specific)
1581{
1582 ConfigExtendedPageHeader_t hdr;
1583 CONFIGPARMS cfg;
1584 SasDevicePage0_t *buffer;
1585 dma_addr_t dma_handle;
1586 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001587 int error=0;
1588
1589 if (ioc->sas_discovery_runtime &&
1590 mptsas_is_end_device(device_info))
1591 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001592
1593 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1594 hdr.ExtPageLength = 0;
1595 hdr.PageNumber = 0;
1596 hdr.Reserved1 = 0;
1597 hdr.Reserved2 = 0;
1598 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1599 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1600
1601 cfg.cfghdr.ehdr = &hdr;
1602 cfg.pageAddr = form + form_specific;
1603 cfg.physAddr = -1;
1604 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1605 cfg.dir = 0; /* read */
1606 cfg.timeout = 10;
1607
Moore, Ericdb9c9172006-03-14 09:14:18 -07001608 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001609 error = mpt_config(ioc, &cfg);
1610 if (error)
1611 goto out;
1612 if (!hdr.ExtPageLength) {
1613 error = -ENXIO;
1614 goto out;
1615 }
1616
1617 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1618 &dma_handle);
1619 if (!buffer) {
1620 error = -ENOMEM;
1621 goto out;
1622 }
1623
1624 cfg.physAddr = dma_handle;
1625 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1626
1627 error = mpt_config(ioc, &cfg);
1628 if (error)
1629 goto out_free_consistent;
1630
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301631 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001632
1633 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001634 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001635 device_info->handle_enclosure =
1636 le16_to_cpu(buffer->EnclosureHandle);
1637 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001638 device_info->phy_id = buffer->PhyNum;
1639 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001640 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001641 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001642 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001643 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1644 device_info->sas_address = le64_to_cpu(sas_address);
1645 device_info->device_info =
1646 le32_to_cpu(buffer->DeviceInfo);
1647
1648 out_free_consistent:
1649 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1650 buffer, dma_handle);
1651 out:
1652 return error;
1653}
1654
1655static int
1656mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1657 u32 form, u32 form_specific)
1658{
1659 ConfigExtendedPageHeader_t hdr;
1660 CONFIGPARMS cfg;
1661 SasExpanderPage0_t *buffer;
1662 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001663 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001664
1665 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1666 hdr.ExtPageLength = 0;
1667 hdr.PageNumber = 0;
1668 hdr.Reserved1 = 0;
1669 hdr.Reserved2 = 0;
1670 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1671 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1672
1673 cfg.cfghdr.ehdr = &hdr;
1674 cfg.physAddr = -1;
1675 cfg.pageAddr = form + form_specific;
1676 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1677 cfg.dir = 0; /* read */
1678 cfg.timeout = 10;
1679
Moore, Ericdb9c9172006-03-14 09:14:18 -07001680 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001681 error = mpt_config(ioc, &cfg);
1682 if (error)
1683 goto out;
1684
1685 if (!hdr.ExtPageLength) {
1686 error = -ENXIO;
1687 goto out;
1688 }
1689
1690 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1691 &dma_handle);
1692 if (!buffer) {
1693 error = -ENOMEM;
1694 goto out;
1695 }
1696
1697 cfg.physAddr = dma_handle;
1698 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1699
1700 error = mpt_config(ioc, &cfg);
1701 if (error)
1702 goto out_free_consistent;
1703
1704 /* save config data */
1705 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001706 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001707 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001708 if (!port_info->phy_info) {
1709 error = -ENOMEM;
1710 goto out_free_consistent;
1711 }
1712
Eric Moore2ecce492007-01-29 09:47:08 -07001713 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001714 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001715 port_info->phy_info[i].handle =
1716 le16_to_cpu(buffer->DevHandle);
1717 }
Eric Moore547f9a22006-06-27 14:42:12 -06001718
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001719 out_free_consistent:
1720 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1721 buffer, dma_handle);
1722 out:
1723 return error;
1724}
1725
1726static int
1727mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1728 u32 form, u32 form_specific)
1729{
1730 ConfigExtendedPageHeader_t hdr;
1731 CONFIGPARMS cfg;
1732 SasExpanderPage1_t *buffer;
1733 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001734 int error=0;
1735
1736 if (ioc->sas_discovery_runtime &&
1737 mptsas_is_end_device(&phy_info->attached))
1738 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001739
1740 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1741 hdr.ExtPageLength = 0;
1742 hdr.PageNumber = 1;
1743 hdr.Reserved1 = 0;
1744 hdr.Reserved2 = 0;
1745 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1746 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1747
1748 cfg.cfghdr.ehdr = &hdr;
1749 cfg.physAddr = -1;
1750 cfg.pageAddr = form + form_specific;
1751 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1752 cfg.dir = 0; /* read */
1753 cfg.timeout = 10;
1754
1755 error = mpt_config(ioc, &cfg);
1756 if (error)
1757 goto out;
1758
1759 if (!hdr.ExtPageLength) {
1760 error = -ENXIO;
1761 goto out;
1762 }
1763
1764 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1765 &dma_handle);
1766 if (!buffer) {
1767 error = -ENOMEM;
1768 goto out;
1769 }
1770
1771 cfg.physAddr = dma_handle;
1772 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1773
1774 error = mpt_config(ioc, &cfg);
1775 if (error)
1776 goto out_free_consistent;
1777
1778
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301779 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001780
1781 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001782 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001783 phy_info->port_id = buffer->PhysicalPort;
1784 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1785 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1786 phy_info->hw_link_rate = buffer->HwLinkRate;
1787 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1788 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1789
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001790 out_free_consistent:
1791 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1792 buffer, dma_handle);
1793 out:
1794 return error;
1795}
1796
1797static void
1798mptsas_parse_device_info(struct sas_identify *identify,
1799 struct mptsas_devinfo *device_info)
1800{
1801 u16 protocols;
1802
1803 identify->sas_address = device_info->sas_address;
1804 identify->phy_identifier = device_info->phy_id;
1805
1806 /*
1807 * Fill in Phy Initiator Port Protocol.
1808 * Bits 6:3, more than one bit can be set, fall through cases.
1809 */
1810 protocols = device_info->device_info & 0x78;
1811 identify->initiator_port_protocols = 0;
1812 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1813 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1814 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1815 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1816 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1817 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1818 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1819 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1820
1821 /*
1822 * Fill in Phy Target Port Protocol.
1823 * Bits 10:7, more than one bit can be set, fall through cases.
1824 */
1825 protocols = device_info->device_info & 0x780;
1826 identify->target_port_protocols = 0;
1827 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1828 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1829 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1830 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1831 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1832 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1833 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1834 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1835
1836 /*
1837 * Fill in Attached device type.
1838 */
1839 switch (device_info->device_info &
1840 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1841 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1842 identify->device_type = SAS_PHY_UNUSED;
1843 break;
1844 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1845 identify->device_type = SAS_END_DEVICE;
1846 break;
1847 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1848 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1849 break;
1850 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1851 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1852 break;
1853 }
1854}
1855
1856static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001857 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001858{
Moore, Erice6b2d762006-03-14 09:14:24 -07001859 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001860 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001861 struct sas_port *port;
1862 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001863
Eric Moore547f9a22006-06-27 14:42:12 -06001864 if (!dev) {
1865 error = -ENODEV;
1866 goto out;
1867 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001868
1869 if (!phy_info->phy) {
1870 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001871 if (!phy) {
1872 error = -ENOMEM;
1873 goto out;
1874 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001875 } else
1876 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001877
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001878 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001879
1880 /*
1881 * Set Negotiated link rate.
1882 */
1883 switch (phy_info->negotiated_link_rate) {
1884 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001885 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001886 break;
1887 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001888 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001889 break;
1890 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001891 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001892 break;
1893 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001894 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001895 break;
1896 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1897 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1898 default:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001899 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001900 break;
1901 }
1902
1903 /*
1904 * Set Max hardware link rate.
1905 */
1906 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1907 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001908 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001909 break;
1910 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001911 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001912 break;
1913 default:
1914 break;
1915 }
1916
1917 /*
1918 * Set Max programmed link rate.
1919 */
1920 switch (phy_info->programmed_link_rate &
1921 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1922 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001923 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001924 break;
1925 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001926 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001927 break;
1928 default:
1929 break;
1930 }
1931
1932 /*
1933 * Set Min hardware link rate.
1934 */
1935 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1936 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001937 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001938 break;
1939 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001940 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001941 break;
1942 default:
1943 break;
1944 }
1945
1946 /*
1947 * Set Min programmed link rate.
1948 */
1949 switch (phy_info->programmed_link_rate &
1950 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1951 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001952 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001953 break;
1954 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001955 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001956 break;
1957 default:
1958 break;
1959 }
1960
Moore, Erice6b2d762006-03-14 09:14:24 -07001961 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001962
Moore, Erice6b2d762006-03-14 09:14:24 -07001963 error = sas_phy_add(phy);
1964 if (error) {
1965 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001966 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001967 }
1968 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001969 }
1970
Eric Moore547f9a22006-06-27 14:42:12 -06001971 if (!phy_info->attached.handle ||
1972 !phy_info->port_details)
1973 goto out;
1974
1975 port = mptsas_get_port(phy_info);
1976 ioc = phy_to_ioc(phy_info->phy);
1977
1978 if (phy_info->sas_port_add_phy) {
1979
1980 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001981 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001982 if (!port) {
1983 error = -ENOMEM;
1984 goto out;
1985 }
1986 error = sas_port_add(port);
1987 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301988 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06001989 "%s: exit at line=%d\n", ioc->name,
1990 __FUNCTION__, __LINE__));
1991 goto out;
1992 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301993 mptsas_set_port(ioc, phy_info, port);
Eric Moore29dd3602007-09-14 18:46:51 -06001994 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooredc22f162006-07-06 11:23:14 -06001995 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001996 ioc->name, port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06001997 }
Eric Moore29dd3602007-09-14 18:46:51 -06001998 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
1999 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002000 sas_port_add_phy(port, phy_info->phy);
2001 phy_info->sas_port_add_phy = 0;
2002 }
2003
2004 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002005
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002006 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002007 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002008 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002009
James Bottomley2686de22006-06-30 12:54:02 -05002010 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002011 /*
2012 * Let the hotplug_work thread handle processing
2013 * the adding/removing of devices that occur
2014 * after start of day.
2015 */
2016 if (ioc->sas_discovery_runtime &&
2017 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002018 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002019
James Bottomleyf013db32006-03-18 14:54:36 -06002020 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002021 if (scsi_is_host_device(parent)) {
2022 struct mptsas_portinfo *port_info;
2023 int i;
2024
2025 mutex_lock(&ioc->sas_topology_mutex);
2026 port_info = mptsas_find_portinfo_by_handle(ioc,
2027 ioc->handle);
2028 mutex_unlock(&ioc->sas_topology_mutex);
2029
2030 for (i = 0; i < port_info->num_phys; i++)
2031 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002032 identify.sas_address) {
2033 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002034 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002035 }
James Bottomley2686de22006-06-30 12:54:02 -05002036
2037 } else if (scsi_is_sas_rphy(parent)) {
2038 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2039 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002040 parent_rphy->identify.sas_address) {
2041 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002042 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002043 }
James Bottomley2686de22006-06-30 12:54:02 -05002044 }
2045
James Bottomleyf013db32006-03-18 14:54:36 -06002046 switch (identify.device_type) {
2047 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002048 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002049 break;
2050 case SAS_EDGE_EXPANDER_DEVICE:
2051 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002052 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002053 break;
2054 default:
2055 rphy = NULL;
2056 break;
2057 }
Eric Moore547f9a22006-06-27 14:42:12 -06002058 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302059 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002060 "%s: exit at line=%d\n", ioc->name,
2061 __FUNCTION__, __LINE__));
2062 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002063 }
2064
Eric Moore547f9a22006-06-27 14:42:12 -06002065 rphy->identify = identify;
2066 error = sas_rphy_add(rphy);
2067 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302068 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002069 "%s: exit at line=%d\n", ioc->name,
2070 __FUNCTION__, __LINE__));
2071 sas_rphy_free(rphy);
2072 goto out;
2073 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302074 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002075 }
2076
Eric Moore547f9a22006-06-27 14:42:12 -06002077 out:
2078 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002079}
2080
2081static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002082mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002083{
Moore, Erice6b2d762006-03-14 09:14:24 -07002084 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002085 int error = -ENOMEM, i;
2086
Moore, Erice6b2d762006-03-14 09:14:24 -07002087 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2088 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002089 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002090
Moore, Erice6b2d762006-03-14 09:14:24 -07002091 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002092 if (error)
2093 goto out_free_port_info;
2094
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302095 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002096 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07002097 ioc->handle = hba->phy_info[0].handle;
2098 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07002099 if (!port_info) {
2100 port_info = hba;
2101 list_add_tail(&port_info->list, &ioc->sas_topology);
2102 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002103 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002104 port_info->phy_info[i].negotiated_link_rate =
2105 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002106 port_info->phy_info[i].handle =
2107 hba->phy_info[i].handle;
2108 port_info->phy_info[i].port_id =
2109 hba->phy_info[i].port_id;
2110 }
Eric Moore547f9a22006-06-27 14:42:12 -06002111 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002112 kfree(hba);
2113 hba = NULL;
2114 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002115 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002116 for (i = 0; i < port_info->num_phys; i++) {
2117 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2118 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2119 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2120
2121 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002122 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2123 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2124 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002125 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002126 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002127 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002128 mptsas_sas_device_pg0(ioc,
2129 &port_info->phy_info[i].attached,
2130 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2131 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2132 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002133 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002134
Eric Moore547f9a22006-06-27 14:42:12 -06002135 mptsas_setup_wide_ports(ioc, port_info);
2136
2137 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002138 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002139 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002140
2141 return 0;
2142
2143 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002144 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002145 out:
2146 return error;
2147}
2148
2149static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002150mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002151{
Moore, Erice6b2d762006-03-14 09:14:24 -07002152 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002153 struct device *parent;
2154 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002155 int error = -ENOMEM, i, j;
2156
Moore, Erice6b2d762006-03-14 09:14:24 -07002157 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2158 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002159 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002160
Moore, Erice6b2d762006-03-14 09:14:24 -07002161 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002162 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2163 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002164 if (error)
2165 goto out_free_port_info;
2166
Eric Moore2ecce492007-01-29 09:47:08 -07002167 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002168
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002169 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002170 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2171 if (!port_info) {
2172 port_info = ex;
2173 list_add_tail(&port_info->list, &ioc->sas_topology);
2174 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002175 for (i = 0; i < ex->num_phys; i++) {
2176 port_info->phy_info[i].handle =
2177 ex->phy_info[i].handle;
2178 port_info->phy_info[i].port_id =
2179 ex->phy_info[i].port_id;
2180 }
Eric Moore547f9a22006-06-27 14:42:12 -06002181 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002182 kfree(ex);
2183 ex = NULL;
2184 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002185 mutex_unlock(&ioc->sas_topology_mutex);
2186
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002187 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002188 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2189 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2190 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2191
2192 if (port_info->phy_info[i].identify.handle) {
2193 mptsas_sas_device_pg0(ioc,
2194 &port_info->phy_info[i].identify,
2195 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2196 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2197 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002198 port_info->phy_info[i].identify.phy_id =
2199 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002200 }
2201
2202 if (port_info->phy_info[i].attached.handle) {
2203 mptsas_sas_device_pg0(ioc,
2204 &port_info->phy_info[i].attached,
2205 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2206 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2207 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002208 port_info->phy_info[i].attached.phy_id =
2209 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002210 }
Eric Moore547f9a22006-06-27 14:42:12 -06002211 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002212
Eric Moore547f9a22006-06-27 14:42:12 -06002213 parent = &ioc->sh->shost_gendev;
2214 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002215 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002216 list_for_each_entry(p, &ioc->sas_topology, list) {
2217 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002218 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002219 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002220 continue;
2221 rphy = mptsas_get_rphy(&p->phy_info[j]);
2222 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002223 }
2224 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002225 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002226 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002227
Eric Moore547f9a22006-06-27 14:42:12 -06002228 mptsas_setup_wide_ports(ioc, port_info);
2229
2230 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002231 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002232 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002233
2234 return 0;
2235
2236 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002237 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002238 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002239 kfree(ex);
2240 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002241 out:
2242 return error;
2243}
2244
Moore, Erice6b2d762006-03-14 09:14:24 -07002245/*
2246 * mptsas_delete_expander_phys
2247 *
2248 *
2249 * This will traverse topology, and remove expanders
2250 * that are no longer present
2251 */
2252static void
2253mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2254{
2255 struct mptsas_portinfo buffer;
2256 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002257 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002258 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002259 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002260 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002261
2262 mutex_lock(&ioc->sas_topology_mutex);
2263 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2264
2265 if (port_info->phy_info &&
2266 (!(port_info->phy_info[0].identify.device_info &
2267 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2268 continue;
2269
2270 if (mptsas_sas_expander_pg0(ioc, &buffer,
2271 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002272 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2273 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002274
2275 /*
2276 * Obtain the port_info instance to the parent port
2277 */
2278 parent = mptsas_find_portinfo_by_handle(ioc,
2279 port_info->phy_info[0].identify.handle_parent);
2280
2281 if (!parent)
2282 goto next_port;
2283
Eric Moore547f9a22006-06-27 14:42:12 -06002284 expander_sas_address =
2285 port_info->phy_info[0].identify.sas_address;
2286
Moore, Erice6b2d762006-03-14 09:14:24 -07002287 /*
2288 * Delete rphys in the parent that point
2289 * to this expander. The transport layer will
2290 * cleanup all the children.
2291 */
Eric Moore547f9a22006-06-27 14:42:12 -06002292 phy_info = parent->phy_info;
2293 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2294 port = mptsas_get_port(phy_info);
2295 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002296 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002297 if (phy_info->attached.sas_address !=
2298 expander_sas_address)
2299 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302300 dsaswideprintk(ioc,
Eric Moorec51d0be2007-09-29 10:17:21 -06002301 dev_printk(KERN_DEBUG, &port->dev,
2302 MYIOC_s_FMT "delete port (%d)\n", ioc->name,
2303 port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002304 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302305 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002306 }
2307 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002308
2309 phy_info = port_info->phy_info;
2310 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302311 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002312
Moore, Erice6b2d762006-03-14 09:14:24 -07002313 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002314 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002315 kfree(port_info);
2316 }
2317 /*
2318 * Free this memory allocated from inside
2319 * mptsas_sas_expander_pg0
2320 */
Eric Moore547f9a22006-06-27 14:42:12 -06002321 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002322 }
2323 mutex_unlock(&ioc->sas_topology_mutex);
2324}
2325
2326/*
2327 * Start of day discovery
2328 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002329static void
2330mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2331{
2332 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002333 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002334
Moore, Erice6b2d762006-03-14 09:14:24 -07002335 mutex_lock(&ioc->sas_discovery_mutex);
2336 mptsas_probe_hba_phys(ioc);
2337 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002338 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002339 /*
2340 Reporting RAID volumes.
2341 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002342 if (!ioc->ir_firmware)
2343 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002344 if (!ioc->raid_data.pIocPg2)
2345 goto out;
2346 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2347 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002348 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002349 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002350 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2351 }
2352 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002353 mutex_unlock(&ioc->sas_discovery_mutex);
2354}
2355
2356/*
2357 * Work queue thread to handle Runtime discovery
2358 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002359 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002360 */
2361static void
Eric Moore547f9a22006-06-27 14:42:12 -06002362__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002363{
Moore, Erice6b2d762006-03-14 09:14:24 -07002364 u32 handle = 0xFFFF;
2365
Moore, Erice6b2d762006-03-14 09:14:24 -07002366 ioc->sas_discovery_runtime=1;
2367 mptsas_delete_expander_phys(ioc);
2368 mptsas_probe_hba_phys(ioc);
2369 while (!mptsas_probe_expander_phys(ioc, &handle))
2370 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002371 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002372}
2373
2374/*
2375 * Work queue thread to handle Runtime discovery
2376 * Mere purpose is the hot add/delete of expanders
2377 *(Mutex LOCKED)
2378 */
2379static void
David Howellsc4028952006-11-22 14:57:56 +00002380mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002381{
David Howellsc4028952006-11-22 14:57:56 +00002382 struct mptsas_discovery_event *ev =
2383 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002384 MPT_ADAPTER *ioc = ev->ioc;
2385
2386 mutex_lock(&ioc->sas_discovery_mutex);
2387 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002388 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002389 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002390}
2391
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002392static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002393mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002394{
2395 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002396 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002397 int i;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002398
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002399 mutex_lock(&ioc->sas_topology_mutex);
2400 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2401 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002402 if (!mptsas_is_end_device(
2403 &port_info->phy_info[i].attached))
2404 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002405 if (port_info->phy_info[i].attached.sas_address
2406 != sas_address)
2407 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002408 phy_info = &port_info->phy_info[i];
2409 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002410 }
2411 }
2412 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002413 return phy_info;
2414}
2415
2416static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002417mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002418{
2419 struct mptsas_portinfo *port_info;
2420 struct mptsas_phyinfo *phy_info = NULL;
2421 int i;
2422
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002423 mutex_lock(&ioc->sas_topology_mutex);
2424 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002425 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002426 if (!mptsas_is_end_device(
2427 &port_info->phy_info[i].attached))
2428 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002429 if (port_info->phy_info[i].attached.id != id)
2430 continue;
2431 if (port_info->phy_info[i].attached.channel != channel)
2432 continue;
2433 phy_info = &port_info->phy_info[i];
2434 break;
2435 }
2436 }
2437 mutex_unlock(&ioc->sas_topology_mutex);
2438 return phy_info;
2439}
2440
2441static struct mptsas_phyinfo *
2442mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2443{
2444 struct mptsas_portinfo *port_info;
2445 struct mptsas_phyinfo *phy_info = NULL;
2446 int i;
2447
2448 mutex_lock(&ioc->sas_topology_mutex);
2449 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2450 for (i = 0; i < port_info->num_phys; i++) {
2451 if (!mptsas_is_end_device(
2452 &port_info->phy_info[i].attached))
2453 continue;
2454 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2455 continue;
2456 if (port_info->phy_info[i].attached.phys_disk_num != id)
2457 continue;
2458 if (port_info->phy_info[i].attached.channel != channel)
2459 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002460 phy_info = &port_info->phy_info[i];
2461 break;
2462 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002463 }
2464 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002465 return phy_info;
2466}
2467
Moore, Eric4b766472006-03-14 09:14:12 -07002468/*
2469 * Work queue thread to clear the persitency table
2470 */
2471static void
David Howellsc4028952006-11-22 14:57:56 +00002472mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002473{
David Howellsc4028952006-11-22 14:57:56 +00002474 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002475
2476 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2477}
2478
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002479static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002480mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2481{
Eric Mooref99be432007-01-04 20:46:54 -07002482 int rc;
2483
Moore, Ericf44e5462006-03-14 09:14:21 -07002484 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002485 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002486}
2487
2488static void
2489mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2490{
2491 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2492 mptsas_reprobe_lun);
2493}
2494
Eric Mooreb506ade2007-01-29 09:45:37 -07002495static void
2496mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2497{
2498 CONFIGPARMS cfg;
2499 ConfigPageHeader_t hdr;
2500 dma_addr_t dma_handle;
2501 pRaidVolumePage0_t buffer = NULL;
2502 RaidPhysDiskPage0_t phys_disk;
2503 int i;
2504 struct mptsas_hotplug_event *ev;
2505
2506 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2507 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2508 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2509 cfg.pageAddr = (channel << 8) + id;
2510 cfg.cfghdr.hdr = &hdr;
2511 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2512
2513 if (mpt_config(ioc, &cfg) != 0)
2514 goto out;
2515
2516 if (!hdr.PageLength)
2517 goto out;
2518
2519 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2520 &dma_handle);
2521
2522 if (!buffer)
2523 goto out;
2524
2525 cfg.physAddr = dma_handle;
2526 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2527
2528 if (mpt_config(ioc, &cfg) != 0)
2529 goto out;
2530
2531 if (!(buffer->VolumeStatus.Flags &
2532 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2533 goto out;
2534
2535 if (!buffer->NumPhysDisks)
2536 goto out;
2537
2538 for (i = 0; i < buffer->NumPhysDisks; i++) {
2539
2540 if (mpt_raid_phys_disk_pg0(ioc,
2541 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2542 continue;
2543
2544 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2545 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002546 printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
Eric Mooreb506ade2007-01-29 09:45:37 -07002547 goto out;
2548 }
2549
2550 INIT_WORK(&ev->work, mptsas_hotplug_work);
2551 ev->ioc = ioc;
2552 ev->id = phys_disk.PhysDiskID;
2553 ev->channel = phys_disk.PhysDiskBus;
2554 ev->phys_disk_num_valid = 1;
2555 ev->phys_disk_num = phys_disk.PhysDiskNum;
2556 ev->event_type = MPTSAS_ADD_DEVICE;
2557 schedule_work(&ev->work);
2558 }
2559
2560 out:
2561 if (buffer)
2562 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2563 dma_handle);
2564}
Moore, Erice6b2d762006-03-14 09:14:24 -07002565/*
2566 * Work queue thread to handle SAS hotplug events
2567 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002568static void
David Howellsc4028952006-11-22 14:57:56 +00002569mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002570{
David Howellsc4028952006-11-22 14:57:56 +00002571 struct mptsas_hotplug_event *ev =
2572 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002573
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002574 MPT_ADAPTER *ioc = ev->ioc;
2575 struct mptsas_phyinfo *phy_info;
2576 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002577 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002578 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002579 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002580 struct sas_identify identify;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002581 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002582 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002583 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002584 VirtDevice *vdevice;
2585
Moore, Erice6b2d762006-03-14 09:14:24 -07002586 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002587 switch (ev->event_type) {
2588 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002589
Eric Mooreb506ade2007-01-29 09:45:37 -07002590 phy_info = NULL;
2591 if (ev->phys_disk_num_valid) {
2592 if (ev->hidden_raid_component){
2593 if (mptsas_sas_device_pg0(ioc, &sas_device,
2594 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2595 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2596 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302597 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002598 "%s: exit at line=%d\n", ioc->name,
2599 __FUNCTION__, __LINE__));
2600 break;
2601 }
2602 phy_info = mptsas_find_phyinfo_by_sas_address(
2603 ioc, sas_device.sas_address);
2604 }else
2605 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2606 ioc, ev->channel, ev->phys_disk_num);
2607 }
2608
2609 if (!phy_info)
2610 phy_info = mptsas_find_phyinfo_by_target(ioc,
2611 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002612
Moore, Ericf44e5462006-03-14 09:14:21 -07002613 /*
2614 * Sanity checks, for non-existing phys and remote rphys.
2615 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002616 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302617 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002618 "%s: exit at line=%d\n", ioc->name,
2619 __FUNCTION__, __LINE__));
2620 break;
2621 }
2622 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302623 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002624 "%s: exit at line=%d\n", ioc->name,
2625 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002626 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002627 }
2628 rphy = mptsas_get_rphy(phy_info);
2629 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302630 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002631 "%s: exit at line=%d\n", ioc->name,
2632 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002633 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002634 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002635
Eric Moore547f9a22006-06-27 14:42:12 -06002636 port = mptsas_get_port(phy_info);
2637 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302638 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002639 "%s: exit at line=%d\n", ioc->name,
2640 __FUNCTION__, __LINE__));
2641 break;
2642 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002643
Eric Moore547f9a22006-06-27 14:42:12 -06002644 starget = mptsas_get_starget(phy_info);
2645 if (starget) {
2646 vtarget = starget->hostdata;
2647
2648 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302649 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002650 "%s: exit at line=%d\n", ioc->name,
2651 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002652 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002653 }
2654
Moore, Ericf44e5462006-03-14 09:14:21 -07002655 /*
2656 * Handling RAID components
2657 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002658 if (ev->phys_disk_num_valid &&
2659 ev->hidden_raid_component) {
2660 printk(MYIOC_s_INFO_FMT
2661 "RAID Hidding: channel=%d, id=%d, "
2662 "physdsk %d \n", ioc->name, ev->channel,
2663 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002664 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002665 vtarget->tflags |=
2666 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002667 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002668 phy_info->attached.phys_disk_num =
2669 ev->phys_disk_num;
2670 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002671 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002672 }
2673
Eric Mooreb506ade2007-01-29 09:45:37 -07002674 if (phy_info->attached.device_info &
2675 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002676 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002677 if (phy_info->attached.device_info &
2678 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002679 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002680 if (phy_info->attached.device_info &
2681 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002682 ds = "sata";
2683
2684 printk(MYIOC_s_INFO_FMT
2685 "removing %s device, channel %d, id %d, phy %d\n",
2686 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moorec51d0be2007-09-29 10:17:21 -06002687 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002688 "delete port (%d)\n", ioc->name, port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002689 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302690 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002691 break;
2692 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002693
Moore, Ericbd23e942006-04-17 12:43:04 -06002694 if (ev->phys_disk_num_valid)
2695 mpt_findImVolumes(ioc);
2696
Moore, Ericc73787ee2006-01-26 16:20:06 -07002697 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002698 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002699 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002700 if (mptsas_sas_device_pg0(ioc, &sas_device,
2701 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002702 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2703 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302704 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002705 "%s: exit at line=%d\n", ioc->name,
2706 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002707 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002708 }
2709
Eric Moore547f9a22006-06-27 14:42:12 -06002710 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002711
Eric Moore547f9a22006-06-27 14:42:12 -06002712 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2713 sas_device.sas_address);
2714
2715 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302716 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002717 "%s: exit at line=%d\n", ioc->name,
2718 __FUNCTION__, __LINE__));
2719 break;
2720 }
2721
2722 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002723 if (starget && (!ev->hidden_raid_component)){
2724
Eric Moore547f9a22006-06-27 14:42:12 -06002725 vtarget = starget->hostdata;
2726
2727 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302728 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002729 "%s: exit at line=%d\n", ioc->name,
2730 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002731 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002732 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002733 /*
2734 * Handling RAID components
2735 */
2736 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002737 printk(MYIOC_s_INFO_FMT
2738 "RAID Exposing: channel=%d, id=%d, "
2739 "physdsk %d \n", ioc->name, ev->channel,
2740 ev->id, ev->phys_disk_num);
2741 vtarget->tflags &=
2742 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002743 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002744 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002745 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002746 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002747 break;
2748 }
2749
Eric Moore547f9a22006-06-27 14:42:12 -06002750 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302751 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002752 "%s: exit at line=%d\n", ioc->name,
2753 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002754 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002755 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002756 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002757
Eric Moore547f9a22006-06-27 14:42:12 -06002758 port = mptsas_get_port(phy_info);
2759 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302760 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002761 "%s: exit at line=%d\n", ioc->name,
2762 __FUNCTION__, __LINE__));
2763 break;
2764 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002765 memcpy(&phy_info->attached, &sas_device,
2766 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002767
Eric Mooreb506ade2007-01-29 09:45:37 -07002768 if (phy_info->attached.device_info &
2769 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002770 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002771 if (phy_info->attached.device_info &
2772 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002773 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002774 if (phy_info->attached.device_info &
2775 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002776 ds = "sata";
2777
2778 printk(MYIOC_s_INFO_FMT
2779 "attaching %s device, channel %d, id %d, phy %d\n",
2780 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2781
James Bottomleyf013db32006-03-18 14:54:36 -06002782 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002783 rphy = sas_end_device_alloc(port);
2784 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302785 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002786 "%s: exit at line=%d\n", ioc->name,
2787 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002788 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002789 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002790
James Bottomleyf013db32006-03-18 14:54:36 -06002791 rphy->identify = identify;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002792 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302793 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002794 "%s: exit at line=%d\n", ioc->name,
2795 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002796 sas_rphy_free(rphy);
2797 break;
2798 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302799 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002800 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002801 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002802 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2803 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002804 if (sdev) {
2805 scsi_device_put(sdev);
2806 break;
2807 }
2808 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002809 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002810 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2811 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002812 mpt_findImVolumes(ioc);
2813 break;
2814 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002815 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002816 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002817 if (!sdev)
2818 break;
2819 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002820 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002821 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002822 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002823 scsi_remove_device(sdev);
2824 scsi_device_put(sdev);
2825 mpt_findImVolumes(ioc);
2826 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002827 case MPTSAS_ADD_INACTIVE_VOLUME:
2828 mptsas_adding_inactive_raid_components(ioc,
2829 ev->channel, ev->id);
2830 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002831 case MPTSAS_IGNORE_EVENT:
2832 default:
2833 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002834 }
2835
Moore, Erice6b2d762006-03-14 09:14:24 -07002836 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002837 kfree(ev);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002838}
2839
2840static void
Eric Moore547f9a22006-06-27 14:42:12 -06002841mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002842 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2843{
2844 struct mptsas_hotplug_event *ev;
2845 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2846 __le64 sas_address;
2847
2848 if ((device_info &
2849 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2850 MPI_SAS_DEVICE_INFO_STP_TARGET |
2851 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2852 return;
2853
Moore, Eric4b766472006-03-14 09:14:12 -07002854 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002855 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002856
2857 mptsas_target_reset_queue(ioc, sas_event_data);
2858 break;
2859
2860 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002861 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002862 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002863 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Eric4b766472006-03-14 09:14:12 -07002864 break;
2865 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002866
David Howellsc4028952006-11-22 14:57:56 +00002867 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002868 ev->ioc = ioc;
2869 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2870 ev->parent_handle =
2871 le16_to_cpu(sas_event_data->ParentDevHandle);
2872 ev->channel = sas_event_data->Bus;
2873 ev->id = sas_event_data->TargetID;
2874 ev->phy_id = sas_event_data->PhyNum;
2875 memcpy(&sas_address, &sas_event_data->SASAddress,
2876 sizeof(__le64));
2877 ev->sas_address = le64_to_cpu(sas_address);
2878 ev->device_info = device_info;
2879
2880 if (sas_event_data->ReasonCode &
2881 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2882 ev->event_type = MPTSAS_ADD_DEVICE;
2883 else
2884 ev->event_type = MPTSAS_DEL_DEVICE;
2885 schedule_work(&ev->work);
2886 break;
2887 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2888 /*
2889 * Persistent table is full.
2890 */
Eric Moore547f9a22006-06-27 14:42:12 -06002891 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002892 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002893 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002894 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002895 /*
2896 * TODO, handle other events
2897 */
Moore, Eric4b766472006-03-14 09:14:12 -07002898 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002899 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002900 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002901 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2902 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2903 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2904 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002905 default:
2906 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002907 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002908}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002909static void
Eric Moore547f9a22006-06-27 14:42:12 -06002910mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002911 EVENT_DATA_RAID *raid_event_data)
2912{
2913 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002914 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2915 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002916
2917 if (ioc->bus_type != SAS)
2918 return;
2919
Eric Moore547f9a22006-06-27 14:42:12 -06002920 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002921 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002922 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002923 return;
2924 }
2925
David Howellsc4028952006-11-22 14:57:56 +00002926 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002927 ev->ioc = ioc;
2928 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002929 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002930 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002931
2932 switch (raid_event_data->ReasonCode) {
2933 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002934 ev->phys_disk_num_valid = 1;
2935 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002936 ev->event_type = MPTSAS_ADD_DEVICE;
2937 break;
2938 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002939 ev->phys_disk_num_valid = 1;
2940 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002941 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002942 ev->event_type = MPTSAS_DEL_DEVICE;
2943 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002944 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2945 switch (state) {
2946 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002947 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002948 ev->phys_disk_num_valid = 1;
2949 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002950 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002951 ev->event_type = MPTSAS_ADD_DEVICE;
2952 break;
2953 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002954 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2955 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2956 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002957 ev->phys_disk_num_valid = 1;
2958 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002959 ev->event_type = MPTSAS_DEL_DEVICE;
2960 break;
2961 default:
2962 break;
2963 }
2964 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002965 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2966 ev->event_type = MPTSAS_DEL_RAID;
2967 break;
2968 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2969 ev->event_type = MPTSAS_ADD_RAID;
2970 break;
2971 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002972 switch (state) {
2973 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2974 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2975 ev->event_type = MPTSAS_DEL_RAID;
2976 break;
2977 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2978 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2979 ev->event_type = MPTSAS_ADD_RAID;
2980 break;
2981 default:
2982 break;
2983 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002984 break;
2985 default:
2986 break;
2987 }
2988 schedule_work(&ev->work);
2989}
2990
Moore, Erice6b2d762006-03-14 09:14:24 -07002991static void
Eric Moore547f9a22006-06-27 14:42:12 -06002992mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002993 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2994{
2995 struct mptsas_discovery_event *ev;
2996
2997 /*
2998 * DiscoveryStatus
2999 *
3000 * This flag will be non-zero when firmware
3001 * kicks off discovery, and return to zero
3002 * once its completed.
3003 */
3004 if (discovery_data->DiscoveryStatus)
3005 return;
3006
Eric Moore547f9a22006-06-27 14:42:12 -06003007 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07003008 if (!ev)
3009 return;
David Howellsc4028952006-11-22 14:57:56 +00003010 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07003011 ev->ioc = ioc;
3012 schedule_work(&ev->work);
3013};
3014
Eric Mooreb506ade2007-01-29 09:45:37 -07003015/*
3016 * mptsas_send_ir2_event - handle exposing hidden disk when
3017 * an inactive raid volume is added
3018 *
3019 * @ioc: Pointer to MPT_ADAPTER structure
3020 * @ir2_data
3021 *
3022 */
3023static void
3024mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
3025{
3026 struct mptsas_hotplug_event *ev;
3027
3028 if (ir2_data->ReasonCode !=
3029 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
3030 return;
3031
3032 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
3033 if (!ev)
3034 return;
3035
3036 INIT_WORK(&ev->work, mptsas_hotplug_work);
3037 ev->ioc = ioc;
3038 ev->id = ir2_data->TargetID;
3039 ev->channel = ir2_data->Bus;
3040 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3041
3042 schedule_work(&ev->work);
3043};
Moore, Erice6b2d762006-03-14 09:14:24 -07003044
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003045static int
3046mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3047{
Moore, Ericc73787ee2006-01-26 16:20:06 -07003048 int rc=1;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003049 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3050
3051 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003052 goto out;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003053
Moore, Erice6b2d762006-03-14 09:14:24 -07003054 /*
3055 * sas_discovery_ignore_events
3056 *
3057 * This flag is to prevent anymore processing of
3058 * sas events once mptsas_remove function is called.
3059 */
3060 if (ioc->sas_discovery_ignore_events) {
3061 rc = mptscsih_event_process(ioc, reply);
3062 goto out;
3063 }
3064
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003065 switch (event) {
3066 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003067 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003068 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003069 break;
3070 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003071 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003072 (EVENT_DATA_RAID *)reply->Data);
3073 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003074 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003075 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003076 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003077 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003078 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003079 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003080 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003081 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3082 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003083 case MPI_EVENT_IR2:
3084 mptsas_send_ir2_event(ioc,
3085 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3086 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003087 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003088 rc = mptscsih_event_process(ioc, reply);
3089 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003090 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003091 out:
3092
3093 return rc;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003094}
3095
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003096static int
3097mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3098{
3099 struct Scsi_Host *sh;
3100 MPT_SCSI_HOST *hd;
3101 MPT_ADAPTER *ioc;
3102 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003103 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003104 int numSGE = 0;
3105 int scale;
3106 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003107 int error=0;
3108 int r;
3109
3110 r = mpt_attach(pdev,id);
3111 if (r)
3112 return r;
3113
3114 ioc = pci_get_drvdata(pdev);
3115 ioc->DoneCtx = mptsasDoneCtx;
3116 ioc->TaskCtx = mptsasTaskCtx;
3117 ioc->InternalCtx = mptsasInternalCtx;
3118
3119 /* Added sanity check on readiness of the MPT adapter.
3120 */
3121 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3122 printk(MYIOC_s_WARN_FMT
3123 "Skipping because it's not operational!\n",
3124 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003125 error = -ENODEV;
3126 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003127 }
3128
3129 if (!ioc->active) {
3130 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3131 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003132 error = -ENODEV;
3133 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003134 }
3135
3136 /* Sanity check - ensure at least 1 port is INITIATOR capable
3137 */
3138 ioc_cap = 0;
3139 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3140 if (ioc->pfacts[ii].ProtocolFlags &
3141 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3142 ioc_cap++;
3143 }
3144
3145 if (!ioc_cap) {
3146 printk(MYIOC_s_WARN_FMT
3147 "Skipping ioc=%p because SCSI Initiator mode "
3148 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003149 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003150 }
3151
3152 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3153 if (!sh) {
3154 printk(MYIOC_s_WARN_FMT
3155 "Unable to register controller with SCSI subsystem\n",
3156 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003157 error = -1;
3158 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003159 }
3160
3161 spin_lock_irqsave(&ioc->FreeQlock, flags);
3162
3163 /* Attach the SCSI Host to the IOC structure
3164 */
3165 ioc->sh = sh;
3166
3167 sh->io_port = 0;
3168 sh->n_io_port = 0;
3169 sh->irq = 0;
3170
3171 /* set 16 byte cdb's */
3172 sh->max_cmd_len = 16;
3173
Eric Moore793955f2007-01-29 09:42:20 -07003174 sh->max_id = ioc->pfacts[0].PortSCSIID;
3175 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003176
3177 sh->transportt = mptsas_transport_template;
3178
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003179 sh->this_id = ioc->pfacts[0].PortSCSIID;
3180
3181 /* Required entry.
3182 */
3183 sh->unique_id = ioc->id;
3184
3185 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003186 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003187 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003188 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003189 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003190
3191 /* Verify that we won't exceed the maximum
3192 * number of chain buffers
3193 * We can optimize: ZZ = req_sz/sizeof(SGE)
3194 * For 32bit SGE's:
3195 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3196 * + (req_sz - 64)/sizeof(SGE)
3197 * A slightly different algorithm is required for
3198 * 64bit SGEs.
3199 */
3200 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3201 if (sizeof(dma_addr_t) == sizeof(u64)) {
3202 numSGE = (scale - 1) *
3203 (ioc->facts.MaxChainDepth-1) + scale +
3204 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3205 sizeof(u32));
3206 } else {
3207 numSGE = 1 + (scale - 1) *
3208 (ioc->facts.MaxChainDepth-1) + scale +
3209 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3210 sizeof(u32));
3211 }
3212
3213 if (numSGE < sh->sg_tablesize) {
3214 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303215 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003216 "Resetting sg_tablesize to %d from %d\n",
3217 ioc->name, numSGE, sh->sg_tablesize));
3218 sh->sg_tablesize = numSGE;
3219 }
3220
Eric Mooree7eae9f2007-09-29 10:15:59 -06003221 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003222 hd->ioc = ioc;
3223
3224 /* SCSI needs scsi_cmnd lookup table!
3225 * (with size equal to req_depth*PtrSz!)
3226 */
Eric Mooree8206382007-09-29 10:16:53 -06003227 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3228 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003229 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06003230 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003231 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003232 }
Eric Mooree8206382007-09-29 10:16:53 -06003233 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003234
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303235 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06003236 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003237
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003238 /* Clear the TM flags
3239 */
3240 hd->tmPending = 0;
3241 hd->tmState = TM_STATE_NONE;
3242 hd->resetPending = 0;
3243 hd->abortSCpnt = NULL;
3244
3245 /* Clear the pointer used to store
3246 * single-threaded commands, i.e., those
3247 * issued during a bus scan, dv and
3248 * configuration pages.
3249 */
3250 hd->cmdPtr = NULL;
3251
3252 /* Initialize this SCSI Hosts' timers
3253 * To use, set the timer expires field
3254 * and add_timer
3255 */
3256 init_timer(&hd->timer);
3257 hd->timer.data = (unsigned long) hd;
3258 hd->timer.function = mptscsih_timer_expired;
3259
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003260 ioc->sas_data.ptClear = mpt_pt_clear;
3261
Eric Mooredf9e0622007-01-29 09:46:21 -07003262 init_waitqueue_head(&hd->scandv_waitq);
3263 hd->scandv_wait_done = 0;
3264 hd->last_queue_full = 0;
3265 INIT_LIST_HEAD(&hd->target_reset_list);
3266 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3267
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003268 if (ioc->sas_data.ptClear==1) {
3269 mptbase_sas_persist_operation(
3270 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3271 }
3272
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003273 error = scsi_add_host(sh, &ioc->pcidev->dev);
3274 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06003275 dprintk(ioc, printk(MYIOC_s_ERR_FMT
3276 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003277 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003278 }
3279
3280 mptsas_scan_sas_topology(ioc);
3281
3282 return 0;
3283
Eric Moore547f9a22006-06-27 14:42:12 -06003284 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003285
3286 mptscsih_remove(pdev);
3287 return error;
3288}
3289
3290static void __devexit mptsas_remove(struct pci_dev *pdev)
3291{
3292 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3293 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003294 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003295
Eric Mooreb506ade2007-01-29 09:45:37 -07003296 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003297 sas_remove_host(ioc->sh);
3298
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003299 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003300 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3301 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003302 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303303 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003304 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003305 kfree(p);
3306 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003307 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003308
3309 mptscsih_remove(pdev);
3310}
3311
3312static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003313 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003314 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003315 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003316 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003317 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003318 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003319 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003320 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003321 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003322 PCI_ANY_ID, PCI_ANY_ID },
3323 {0} /* Terminating entry */
3324};
3325MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3326
3327
3328static struct pci_driver mptsas_driver = {
3329 .name = "mptsas",
3330 .id_table = mptsas_pci_table,
3331 .probe = mptsas_probe,
3332 .remove = __devexit_p(mptsas_remove),
3333 .shutdown = mptscsih_shutdown,
3334#ifdef CONFIG_PM
3335 .suspend = mptscsih_suspend,
3336 .resume = mptscsih_resume,
3337#endif
3338};
3339
3340static int __init
3341mptsas_init(void)
3342{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303343 int error;
3344
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003345 show_mptmod_ver(my_NAME, my_VERSION);
3346
3347 mptsas_transport_template =
3348 sas_attach_transport(&mptsas_transport_functions);
3349 if (!mptsas_transport_template)
3350 return -ENODEV;
3351
3352 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003353 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003354 mptsasInternalCtx =
3355 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003356 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003357
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303358 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3359 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003360
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303361 error = pci_register_driver(&mptsas_driver);
3362 if (error)
3363 sas_release_transport(mptsas_transport_template);
3364
3365 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003366}
3367
3368static void __exit
3369mptsas_exit(void)
3370{
3371 pci_unregister_driver(&mptsas_driver);
3372 sas_release_transport(mptsas_transport_template);
3373
3374 mpt_reset_deregister(mptsasDoneCtx);
3375 mpt_event_deregister(mptsasDoneCtx);
3376
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003377 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003378 mpt_deregister(mptsasInternalCtx);
3379 mpt_deregister(mptsasTaskCtx);
3380 mpt_deregister(mptsasDoneCtx);
3381}
3382
3383module_init(mptsas_init);
3384module_exit(mptsas_exit);