blob: 78734e25edd515bcc863fbcae3216c6447e045eb [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 Hellwig9a28f492006-01-13 18:04:41 +0100996{
Eric Moorea69de502007-09-14 18:48:19 -0600997 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08001704 if (!buffer->NumPhys) {
1705 error = -ENODEV;
1706 goto out_free_consistent;
1707 }
1708
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001709 /* save config data */
1710 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001711 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001712 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001713 if (!port_info->phy_info) {
1714 error = -ENOMEM;
1715 goto out_free_consistent;
1716 }
1717
Eric Moore2ecce492007-01-29 09:47:08 -07001718 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001719 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001720 port_info->phy_info[i].handle =
1721 le16_to_cpu(buffer->DevHandle);
1722 }
Eric Moore547f9a22006-06-27 14:42:12 -06001723
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001724 out_free_consistent:
1725 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1726 buffer, dma_handle);
1727 out:
1728 return error;
1729}
1730
1731static int
1732mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1733 u32 form, u32 form_specific)
1734{
1735 ConfigExtendedPageHeader_t hdr;
1736 CONFIGPARMS cfg;
1737 SasExpanderPage1_t *buffer;
1738 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001739 int error=0;
1740
1741 if (ioc->sas_discovery_runtime &&
1742 mptsas_is_end_device(&phy_info->attached))
1743 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001744
1745 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1746 hdr.ExtPageLength = 0;
1747 hdr.PageNumber = 1;
1748 hdr.Reserved1 = 0;
1749 hdr.Reserved2 = 0;
1750 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1751 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1752
1753 cfg.cfghdr.ehdr = &hdr;
1754 cfg.physAddr = -1;
1755 cfg.pageAddr = form + form_specific;
1756 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1757 cfg.dir = 0; /* read */
1758 cfg.timeout = 10;
1759
1760 error = mpt_config(ioc, &cfg);
1761 if (error)
1762 goto out;
1763
1764 if (!hdr.ExtPageLength) {
1765 error = -ENXIO;
1766 goto out;
1767 }
1768
1769 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1770 &dma_handle);
1771 if (!buffer) {
1772 error = -ENOMEM;
1773 goto out;
1774 }
1775
1776 cfg.physAddr = dma_handle;
1777 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1778
1779 error = mpt_config(ioc, &cfg);
1780 if (error)
1781 goto out_free_consistent;
1782
1783
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301784 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001785
1786 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001787 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001788 phy_info->port_id = buffer->PhysicalPort;
1789 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1790 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1791 phy_info->hw_link_rate = buffer->HwLinkRate;
1792 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1793 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1794
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001795 out_free_consistent:
1796 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1797 buffer, dma_handle);
1798 out:
1799 return error;
1800}
1801
1802static void
1803mptsas_parse_device_info(struct sas_identify *identify,
1804 struct mptsas_devinfo *device_info)
1805{
1806 u16 protocols;
1807
1808 identify->sas_address = device_info->sas_address;
1809 identify->phy_identifier = device_info->phy_id;
1810
1811 /*
1812 * Fill in Phy Initiator Port Protocol.
1813 * Bits 6:3, more than one bit can be set, fall through cases.
1814 */
1815 protocols = device_info->device_info & 0x78;
1816 identify->initiator_port_protocols = 0;
1817 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1818 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1819 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1820 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1821 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1822 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1823 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1824 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1825
1826 /*
1827 * Fill in Phy Target Port Protocol.
1828 * Bits 10:7, more than one bit can be set, fall through cases.
1829 */
1830 protocols = device_info->device_info & 0x780;
1831 identify->target_port_protocols = 0;
1832 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1833 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1834 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1835 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1836 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1837 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1838 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1839 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1840
1841 /*
1842 * Fill in Attached device type.
1843 */
1844 switch (device_info->device_info &
1845 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1846 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1847 identify->device_type = SAS_PHY_UNUSED;
1848 break;
1849 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1850 identify->device_type = SAS_END_DEVICE;
1851 break;
1852 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1853 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1854 break;
1855 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1856 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1857 break;
1858 }
1859}
1860
1861static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001862 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001863{
Moore, Erice6b2d762006-03-14 09:14:24 -07001864 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001865 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001866 struct sas_port *port;
1867 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001868
Eric Moore547f9a22006-06-27 14:42:12 -06001869 if (!dev) {
1870 error = -ENODEV;
1871 goto out;
1872 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001873
1874 if (!phy_info->phy) {
1875 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001876 if (!phy) {
1877 error = -ENOMEM;
1878 goto out;
1879 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001880 } else
1881 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001882
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001883 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001884
1885 /*
1886 * Set Negotiated link rate.
1887 */
1888 switch (phy_info->negotiated_link_rate) {
1889 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001890 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001891 break;
1892 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001893 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001894 break;
1895 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001896 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001897 break;
1898 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001899 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001900 break;
1901 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1902 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1903 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001904 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001905 break;
1906 }
1907
1908 /*
1909 * Set Max hardware link rate.
1910 */
1911 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1912 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001913 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001914 break;
1915 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001916 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001917 break;
1918 default:
1919 break;
1920 }
1921
1922 /*
1923 * Set Max programmed link rate.
1924 */
1925 switch (phy_info->programmed_link_rate &
1926 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1927 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001928 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001929 break;
1930 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001931 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001932 break;
1933 default:
1934 break;
1935 }
1936
1937 /*
1938 * Set Min hardware link rate.
1939 */
1940 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1941 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001942 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001943 break;
1944 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001945 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001946 break;
1947 default:
1948 break;
1949 }
1950
1951 /*
1952 * Set Min programmed link rate.
1953 */
1954 switch (phy_info->programmed_link_rate &
1955 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1956 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001957 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001958 break;
1959 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001960 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001961 break;
1962 default:
1963 break;
1964 }
1965
Moore, Erice6b2d762006-03-14 09:14:24 -07001966 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001967
Moore, Erice6b2d762006-03-14 09:14:24 -07001968 error = sas_phy_add(phy);
1969 if (error) {
1970 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001971 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001972 }
1973 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001974 }
1975
Eric Moore547f9a22006-06-27 14:42:12 -06001976 if (!phy_info->attached.handle ||
1977 !phy_info->port_details)
1978 goto out;
1979
1980 port = mptsas_get_port(phy_info);
1981 ioc = phy_to_ioc(phy_info->phy);
1982
1983 if (phy_info->sas_port_add_phy) {
1984
1985 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001986 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001987 if (!port) {
1988 error = -ENOMEM;
1989 goto out;
1990 }
1991 error = sas_port_add(port);
1992 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301993 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06001994 "%s: exit at line=%d\n", ioc->name,
1995 __FUNCTION__, __LINE__));
1996 goto out;
1997 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301998 mptsas_set_port(ioc, phy_info, port);
Eric Moore29dd3602007-09-14 18:46:51 -06001999 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooredc22f162006-07-06 11:23:14 -06002000 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -06002001 ioc->name, port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002002 }
Eric Moore29dd3602007-09-14 18:46:51 -06002003 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
2004 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002005 sas_port_add_phy(port, phy_info->phy);
2006 phy_info->sas_port_add_phy = 0;
2007 }
2008
2009 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002010
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002011 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002012 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002013 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002014
James Bottomley2686de22006-06-30 12:54:02 -05002015 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002016 /*
2017 * Let the hotplug_work thread handle processing
2018 * the adding/removing of devices that occur
2019 * after start of day.
2020 */
2021 if (ioc->sas_discovery_runtime &&
2022 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002023 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002024
James Bottomleyf013db32006-03-18 14:54:36 -06002025 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002026 if (scsi_is_host_device(parent)) {
2027 struct mptsas_portinfo *port_info;
2028 int i;
2029
2030 mutex_lock(&ioc->sas_topology_mutex);
2031 port_info = mptsas_find_portinfo_by_handle(ioc,
2032 ioc->handle);
2033 mutex_unlock(&ioc->sas_topology_mutex);
2034
2035 for (i = 0; i < port_info->num_phys; i++)
2036 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002037 identify.sas_address) {
2038 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002039 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002040 }
James Bottomley2686de22006-06-30 12:54:02 -05002041
2042 } else if (scsi_is_sas_rphy(parent)) {
2043 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2044 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002045 parent_rphy->identify.sas_address) {
2046 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002047 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002048 }
James Bottomley2686de22006-06-30 12:54:02 -05002049 }
2050
James Bottomleyf013db32006-03-18 14:54:36 -06002051 switch (identify.device_type) {
2052 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002053 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002054 break;
2055 case SAS_EDGE_EXPANDER_DEVICE:
2056 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002057 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002058 break;
2059 default:
2060 rphy = NULL;
2061 break;
2062 }
Eric Moore547f9a22006-06-27 14:42:12 -06002063 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302064 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002065 "%s: exit at line=%d\n", ioc->name,
2066 __FUNCTION__, __LINE__));
2067 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002068 }
2069
Eric Moore547f9a22006-06-27 14:42:12 -06002070 rphy->identify = identify;
2071 error = sas_rphy_add(rphy);
2072 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302073 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002074 "%s: exit at line=%d\n", ioc->name,
2075 __FUNCTION__, __LINE__));
2076 sas_rphy_free(rphy);
2077 goto out;
2078 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302079 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002080 }
2081
Eric Moore547f9a22006-06-27 14:42:12 -06002082 out:
2083 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002084}
2085
2086static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002087mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002088{
Moore, Erice6b2d762006-03-14 09:14:24 -07002089 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002090 int error = -ENOMEM, i;
2091
Moore, Erice6b2d762006-03-14 09:14:24 -07002092 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2093 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002094 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002095
Moore, Erice6b2d762006-03-14 09:14:24 -07002096 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002097 if (error)
2098 goto out_free_port_info;
2099
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302100 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002101 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07002102 ioc->handle = hba->phy_info[0].handle;
2103 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07002104 if (!port_info) {
2105 port_info = hba;
2106 list_add_tail(&port_info->list, &ioc->sas_topology);
2107 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002108 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002109 port_info->phy_info[i].negotiated_link_rate =
2110 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002111 port_info->phy_info[i].handle =
2112 hba->phy_info[i].handle;
2113 port_info->phy_info[i].port_id =
2114 hba->phy_info[i].port_id;
2115 }
Eric Moore547f9a22006-06-27 14:42:12 -06002116 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002117 kfree(hba);
2118 hba = NULL;
2119 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002120 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002121 for (i = 0; i < port_info->num_phys; i++) {
2122 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2123 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2124 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2125
2126 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002127 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2128 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2129 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002130 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002131 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002132 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002133 mptsas_sas_device_pg0(ioc,
2134 &port_info->phy_info[i].attached,
2135 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2136 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2137 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002138 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002139
Eric Moore547f9a22006-06-27 14:42:12 -06002140 mptsas_setup_wide_ports(ioc, port_info);
2141
2142 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002143 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002144 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002145
2146 return 0;
2147
2148 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002149 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002150 out:
2151 return error;
2152}
2153
2154static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002155mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002156{
Moore, Erice6b2d762006-03-14 09:14:24 -07002157 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002158 struct device *parent;
2159 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002160 int error = -ENOMEM, i, j;
2161
Moore, Erice6b2d762006-03-14 09:14:24 -07002162 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2163 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002164 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002165
Moore, Erice6b2d762006-03-14 09:14:24 -07002166 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002167 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2168 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002169 if (error)
2170 goto out_free_port_info;
2171
Eric Moore2ecce492007-01-29 09:47:08 -07002172 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002173
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002174 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002175 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2176 if (!port_info) {
2177 port_info = ex;
2178 list_add_tail(&port_info->list, &ioc->sas_topology);
2179 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002180 for (i = 0; i < ex->num_phys; i++) {
2181 port_info->phy_info[i].handle =
2182 ex->phy_info[i].handle;
2183 port_info->phy_info[i].port_id =
2184 ex->phy_info[i].port_id;
2185 }
Eric Moore547f9a22006-06-27 14:42:12 -06002186 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002187 kfree(ex);
2188 ex = NULL;
2189 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002190 mutex_unlock(&ioc->sas_topology_mutex);
2191
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002192 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002193 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2194 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2195 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2196
2197 if (port_info->phy_info[i].identify.handle) {
2198 mptsas_sas_device_pg0(ioc,
2199 &port_info->phy_info[i].identify,
2200 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2201 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2202 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002203 port_info->phy_info[i].identify.phy_id =
2204 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002205 }
2206
2207 if (port_info->phy_info[i].attached.handle) {
2208 mptsas_sas_device_pg0(ioc,
2209 &port_info->phy_info[i].attached,
2210 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2211 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2212 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002213 port_info->phy_info[i].attached.phy_id =
2214 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002215 }
Eric Moore547f9a22006-06-27 14:42:12 -06002216 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002217
Eric Moore547f9a22006-06-27 14:42:12 -06002218 parent = &ioc->sh->shost_gendev;
2219 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002220 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002221 list_for_each_entry(p, &ioc->sas_topology, list) {
2222 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002223 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002224 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002225 continue;
2226 rphy = mptsas_get_rphy(&p->phy_info[j]);
2227 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002228 }
2229 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002230 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002231 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002232
Eric Moore547f9a22006-06-27 14:42:12 -06002233 mptsas_setup_wide_ports(ioc, port_info);
2234
2235 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002236 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002237 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002238
2239 return 0;
2240
2241 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002242 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002243 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002244 kfree(ex);
2245 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002246 out:
2247 return error;
2248}
2249
Moore, Erice6b2d762006-03-14 09:14:24 -07002250/*
2251 * mptsas_delete_expander_phys
2252 *
2253 *
2254 * This will traverse topology, and remove expanders
2255 * that are no longer present
2256 */
2257static void
2258mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2259{
2260 struct mptsas_portinfo buffer;
2261 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002262 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002263 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002264 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002265 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002266
2267 mutex_lock(&ioc->sas_topology_mutex);
2268 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2269
2270 if (port_info->phy_info &&
2271 (!(port_info->phy_info[0].identify.device_info &
2272 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2273 continue;
2274
2275 if (mptsas_sas_expander_pg0(ioc, &buffer,
2276 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002277 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2278 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002279
2280 /*
2281 * Obtain the port_info instance to the parent port
2282 */
2283 parent = mptsas_find_portinfo_by_handle(ioc,
2284 port_info->phy_info[0].identify.handle_parent);
2285
2286 if (!parent)
2287 goto next_port;
2288
Eric Moore547f9a22006-06-27 14:42:12 -06002289 expander_sas_address =
2290 port_info->phy_info[0].identify.sas_address;
2291
Moore, Erice6b2d762006-03-14 09:14:24 -07002292 /*
2293 * Delete rphys in the parent that point
2294 * to this expander. The transport layer will
2295 * cleanup all the children.
2296 */
Eric Moore547f9a22006-06-27 14:42:12 -06002297 phy_info = parent->phy_info;
2298 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2299 port = mptsas_get_port(phy_info);
2300 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002301 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002302 if (phy_info->attached.sas_address !=
2303 expander_sas_address)
2304 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302305 dsaswideprintk(ioc,
Eric Moorec51d0be2007-09-29 10:17:21 -06002306 dev_printk(KERN_DEBUG, &port->dev,
2307 MYIOC_s_FMT "delete port (%d)\n", ioc->name,
2308 port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002309 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302310 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002311 }
2312 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002313
2314 phy_info = port_info->phy_info;
2315 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302316 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002317
Moore, Erice6b2d762006-03-14 09:14:24 -07002318 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002319 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002320 kfree(port_info);
2321 }
2322 /*
2323 * Free this memory allocated from inside
2324 * mptsas_sas_expander_pg0
2325 */
Eric Moore547f9a22006-06-27 14:42:12 -06002326 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002327 }
2328 mutex_unlock(&ioc->sas_topology_mutex);
2329}
2330
2331/*
2332 * Start of day discovery
2333 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002334static void
2335mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2336{
2337 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002338 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002339
Moore, Erice6b2d762006-03-14 09:14:24 -07002340 mutex_lock(&ioc->sas_discovery_mutex);
2341 mptsas_probe_hba_phys(ioc);
2342 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002343 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002344 /*
2345 Reporting RAID volumes.
2346 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002347 if (!ioc->ir_firmware)
2348 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002349 if (!ioc->raid_data.pIocPg2)
2350 goto out;
2351 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2352 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002353 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002354 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002355 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2356 }
2357 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002358 mutex_unlock(&ioc->sas_discovery_mutex);
2359}
2360
2361/*
2362 * Work queue thread to handle Runtime discovery
2363 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002364 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002365 */
2366static void
Eric Moore547f9a22006-06-27 14:42:12 -06002367__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002368{
Moore, Erice6b2d762006-03-14 09:14:24 -07002369 u32 handle = 0xFFFF;
2370
Moore, Erice6b2d762006-03-14 09:14:24 -07002371 ioc->sas_discovery_runtime=1;
2372 mptsas_delete_expander_phys(ioc);
2373 mptsas_probe_hba_phys(ioc);
2374 while (!mptsas_probe_expander_phys(ioc, &handle))
2375 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002376 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002377}
2378
2379/*
2380 * Work queue thread to handle Runtime discovery
2381 * Mere purpose is the hot add/delete of expanders
2382 *(Mutex LOCKED)
2383 */
2384static void
David Howellsc4028952006-11-22 14:57:56 +00002385mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002386{
David Howellsc4028952006-11-22 14:57:56 +00002387 struct mptsas_discovery_event *ev =
2388 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002389 MPT_ADAPTER *ioc = ev->ioc;
2390
2391 mutex_lock(&ioc->sas_discovery_mutex);
2392 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002393 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002394 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002395}
2396
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002397static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002398mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002399{
2400 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002401 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002402 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002403
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002404 mutex_lock(&ioc->sas_topology_mutex);
2405 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2406 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002407 if (!mptsas_is_end_device(
2408 &port_info->phy_info[i].attached))
2409 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002410 if (port_info->phy_info[i].attached.sas_address
2411 != sas_address)
2412 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002413 phy_info = &port_info->phy_info[i];
2414 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002415 }
2416 }
2417 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002418 return phy_info;
2419}
2420
2421static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002422mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002423{
2424 struct mptsas_portinfo *port_info;
2425 struct mptsas_phyinfo *phy_info = NULL;
2426 int i;
2427
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002428 mutex_lock(&ioc->sas_topology_mutex);
2429 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002430 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002431 if (!mptsas_is_end_device(
2432 &port_info->phy_info[i].attached))
2433 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002434 if (port_info->phy_info[i].attached.id != id)
2435 continue;
2436 if (port_info->phy_info[i].attached.channel != channel)
2437 continue;
2438 phy_info = &port_info->phy_info[i];
2439 break;
2440 }
2441 }
2442 mutex_unlock(&ioc->sas_topology_mutex);
2443 return phy_info;
2444}
2445
2446static struct mptsas_phyinfo *
2447mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2448{
2449 struct mptsas_portinfo *port_info;
2450 struct mptsas_phyinfo *phy_info = NULL;
2451 int i;
2452
2453 mutex_lock(&ioc->sas_topology_mutex);
2454 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2455 for (i = 0; i < port_info->num_phys; i++) {
2456 if (!mptsas_is_end_device(
2457 &port_info->phy_info[i].attached))
2458 continue;
2459 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2460 continue;
2461 if (port_info->phy_info[i].attached.phys_disk_num != id)
2462 continue;
2463 if (port_info->phy_info[i].attached.channel != channel)
2464 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002465 phy_info = &port_info->phy_info[i];
2466 break;
2467 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002468 }
2469 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002470 return phy_info;
2471}
2472
Moore, Eric4b766472006-03-14 09:14:12 -07002473/*
2474 * Work queue thread to clear the persitency table
2475 */
2476static void
David Howellsc4028952006-11-22 14:57:56 +00002477mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002478{
David Howellsc4028952006-11-22 14:57:56 +00002479 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002480
2481 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2482}
2483
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002484static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002485mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2486{
Eric Mooref99be432007-01-04 20:46:54 -07002487 int rc;
2488
Moore, Ericf44e5462006-03-14 09:14:21 -07002489 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002490 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002491}
2492
2493static void
2494mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2495{
2496 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2497 mptsas_reprobe_lun);
2498}
2499
Eric Mooreb506ade2007-01-29 09:45:37 -07002500static void
2501mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2502{
2503 CONFIGPARMS cfg;
2504 ConfigPageHeader_t hdr;
2505 dma_addr_t dma_handle;
2506 pRaidVolumePage0_t buffer = NULL;
2507 RaidPhysDiskPage0_t phys_disk;
2508 int i;
2509 struct mptsas_hotplug_event *ev;
2510
2511 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2512 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2513 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2514 cfg.pageAddr = (channel << 8) + id;
2515 cfg.cfghdr.hdr = &hdr;
2516 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2517
2518 if (mpt_config(ioc, &cfg) != 0)
2519 goto out;
2520
2521 if (!hdr.PageLength)
2522 goto out;
2523
2524 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2525 &dma_handle);
2526
2527 if (!buffer)
2528 goto out;
2529
2530 cfg.physAddr = dma_handle;
2531 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2532
2533 if (mpt_config(ioc, &cfg) != 0)
2534 goto out;
2535
2536 if (!(buffer->VolumeStatus.Flags &
2537 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2538 goto out;
2539
2540 if (!buffer->NumPhysDisks)
2541 goto out;
2542
2543 for (i = 0; i < buffer->NumPhysDisks; i++) {
2544
2545 if (mpt_raid_phys_disk_pg0(ioc,
2546 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2547 continue;
2548
2549 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2550 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002551 printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
Eric Mooreb506ade2007-01-29 09:45:37 -07002552 goto out;
2553 }
2554
2555 INIT_WORK(&ev->work, mptsas_hotplug_work);
2556 ev->ioc = ioc;
2557 ev->id = phys_disk.PhysDiskID;
2558 ev->channel = phys_disk.PhysDiskBus;
2559 ev->phys_disk_num_valid = 1;
2560 ev->phys_disk_num = phys_disk.PhysDiskNum;
2561 ev->event_type = MPTSAS_ADD_DEVICE;
2562 schedule_work(&ev->work);
2563 }
2564
2565 out:
2566 if (buffer)
2567 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2568 dma_handle);
2569}
Moore, Erice6b2d762006-03-14 09:14:24 -07002570/*
2571 * Work queue thread to handle SAS hotplug events
2572 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002573static void
David Howellsc4028952006-11-22 14:57:56 +00002574mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002575{
David Howellsc4028952006-11-22 14:57:56 +00002576 struct mptsas_hotplug_event *ev =
2577 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002578
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002579 MPT_ADAPTER *ioc = ev->ioc;
2580 struct mptsas_phyinfo *phy_info;
2581 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002582 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002583 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002584 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002585 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002586 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002587 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002588 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002589 VirtDevice *vdevice;
2590
Moore, Erice6b2d762006-03-14 09:14:24 -07002591 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002592 switch (ev->event_type) {
2593 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002594
Eric Mooreb506ade2007-01-29 09:45:37 -07002595 phy_info = NULL;
2596 if (ev->phys_disk_num_valid) {
2597 if (ev->hidden_raid_component){
2598 if (mptsas_sas_device_pg0(ioc, &sas_device,
2599 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2600 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2601 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302602 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002603 "%s: exit at line=%d\n", ioc->name,
2604 __FUNCTION__, __LINE__));
2605 break;
2606 }
2607 phy_info = mptsas_find_phyinfo_by_sas_address(
2608 ioc, sas_device.sas_address);
2609 }else
2610 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2611 ioc, ev->channel, ev->phys_disk_num);
2612 }
2613
2614 if (!phy_info)
2615 phy_info = mptsas_find_phyinfo_by_target(ioc,
2616 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002617
Moore, Ericf44e5462006-03-14 09:14:21 -07002618 /*
2619 * Sanity checks, for non-existing phys and remote rphys.
2620 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002621 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302622 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002623 "%s: exit at line=%d\n", ioc->name,
2624 __FUNCTION__, __LINE__));
2625 break;
2626 }
2627 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302628 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002629 "%s: exit at line=%d\n", ioc->name,
2630 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002631 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002632 }
2633 rphy = mptsas_get_rphy(phy_info);
2634 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302635 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002636 "%s: exit at line=%d\n", ioc->name,
2637 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002638 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002639 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002640
Eric Moore547f9a22006-06-27 14:42:12 -06002641 port = mptsas_get_port(phy_info);
2642 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302643 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002644 "%s: exit at line=%d\n", ioc->name,
2645 __FUNCTION__, __LINE__));
2646 break;
2647 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002648
Eric Moore547f9a22006-06-27 14:42:12 -06002649 starget = mptsas_get_starget(phy_info);
2650 if (starget) {
2651 vtarget = starget->hostdata;
2652
2653 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302654 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002655 "%s: exit at line=%d\n", ioc->name,
2656 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002657 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002658 }
2659
Moore, Ericf44e5462006-03-14 09:14:21 -07002660 /*
2661 * Handling RAID components
2662 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002663 if (ev->phys_disk_num_valid &&
2664 ev->hidden_raid_component) {
2665 printk(MYIOC_s_INFO_FMT
2666 "RAID Hidding: channel=%d, id=%d, "
2667 "physdsk %d \n", ioc->name, ev->channel,
2668 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002669 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002670 vtarget->tflags |=
2671 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002672 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002673 phy_info->attached.phys_disk_num =
2674 ev->phys_disk_num;
2675 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002676 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002677 }
2678
Eric Mooreb506ade2007-01-29 09:45:37 -07002679 if (phy_info->attached.device_info &
2680 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002681 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002682 if (phy_info->attached.device_info &
2683 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002684 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002685 if (phy_info->attached.device_info &
2686 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002687 ds = "sata";
2688
2689 printk(MYIOC_s_INFO_FMT
2690 "removing %s device, channel %d, id %d, phy %d\n",
2691 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moorec51d0be2007-09-29 10:17:21 -06002692 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002693 "delete port (%d)\n", ioc->name, port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002694 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302695 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002696 break;
2697 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002698
Moore, Ericbd23e942006-04-17 12:43:04 -06002699 if (ev->phys_disk_num_valid)
2700 mpt_findImVolumes(ioc);
2701
Moore, Ericc73787ee2006-01-26 16:20:06 -07002702 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002703 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002704 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002705 if (mptsas_sas_device_pg0(ioc, &sas_device,
2706 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002707 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2708 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302709 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002710 "%s: exit at line=%d\n", ioc->name,
2711 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002712 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002713 }
2714
Eric Moore547f9a22006-06-27 14:42:12 -06002715 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002716
Eric Moore547f9a22006-06-27 14:42:12 -06002717 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2718 sas_device.sas_address);
2719
2720 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302721 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002722 "%s: exit at line=%d\n", ioc->name,
2723 __FUNCTION__, __LINE__));
2724 break;
2725 }
2726
2727 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002728 if (starget && (!ev->hidden_raid_component)){
2729
Eric Moore547f9a22006-06-27 14:42:12 -06002730 vtarget = starget->hostdata;
2731
2732 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302733 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002734 "%s: exit at line=%d\n", ioc->name,
2735 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002736 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002737 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002738 /*
2739 * Handling RAID components
2740 */
2741 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002742 printk(MYIOC_s_INFO_FMT
2743 "RAID Exposing: channel=%d, id=%d, "
2744 "physdsk %d \n", ioc->name, ev->channel,
2745 ev->id, ev->phys_disk_num);
2746 vtarget->tflags &=
2747 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002748 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002749 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002750 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002751 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002752 break;
2753 }
2754
Eric Moore547f9a22006-06-27 14:42:12 -06002755 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302756 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002757 "%s: exit at line=%d\n", ioc->name,
2758 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002759 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002760 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002761 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002762
Eric Moore547f9a22006-06-27 14:42:12 -06002763 port = mptsas_get_port(phy_info);
2764 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302765 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002766 "%s: exit at line=%d\n", ioc->name,
2767 __FUNCTION__, __LINE__));
2768 break;
2769 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002770 memcpy(&phy_info->attached, &sas_device,
2771 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002772
Eric Mooreb506ade2007-01-29 09:45:37 -07002773 if (phy_info->attached.device_info &
2774 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002775 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002776 if (phy_info->attached.device_info &
2777 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002778 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002779 if (phy_info->attached.device_info &
2780 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002781 ds = "sata";
2782
2783 printk(MYIOC_s_INFO_FMT
2784 "attaching %s device, channel %d, id %d, phy %d\n",
2785 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2786
James Bottomleyf013db32006-03-18 14:54:36 -06002787 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002788 rphy = sas_end_device_alloc(port);
2789 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302790 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002791 "%s: exit at line=%d\n", ioc->name,
2792 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002793 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002794 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002795
James Bottomleyf013db32006-03-18 14:54:36 -06002796 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002797 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302798 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002799 "%s: exit at line=%d\n", ioc->name,
2800 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002801 sas_rphy_free(rphy);
2802 break;
2803 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302804 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002805 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002806 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002807 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2808 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002809 if (sdev) {
2810 scsi_device_put(sdev);
2811 break;
2812 }
2813 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002814 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002815 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2816 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002817 mpt_findImVolumes(ioc);
2818 break;
2819 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002820 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002821 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002822 if (!sdev)
2823 break;
2824 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002825 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002826 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002827 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002828 scsi_remove_device(sdev);
2829 scsi_device_put(sdev);
2830 mpt_findImVolumes(ioc);
2831 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002832 case MPTSAS_ADD_INACTIVE_VOLUME:
2833 mptsas_adding_inactive_raid_components(ioc,
2834 ev->channel, ev->id);
2835 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002836 case MPTSAS_IGNORE_EVENT:
2837 default:
2838 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002839 }
2840
Moore, Erice6b2d762006-03-14 09:14:24 -07002841 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002842 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002843}
2844
2845static void
Eric Moore547f9a22006-06-27 14:42:12 -06002846mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002847 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2848{
2849 struct mptsas_hotplug_event *ev;
2850 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2851 __le64 sas_address;
2852
2853 if ((device_info &
2854 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2855 MPI_SAS_DEVICE_INFO_STP_TARGET |
2856 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2857 return;
2858
Moore, Eric4b766472006-03-14 09:14:12 -07002859 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002860 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002861
2862 mptsas_target_reset_queue(ioc, sas_event_data);
2863 break;
2864
2865 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002866 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002867 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002868 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Eric4b766472006-03-14 09:14:12 -07002869 break;
2870 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002871
David Howellsc4028952006-11-22 14:57:56 +00002872 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002873 ev->ioc = ioc;
2874 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2875 ev->parent_handle =
2876 le16_to_cpu(sas_event_data->ParentDevHandle);
2877 ev->channel = sas_event_data->Bus;
2878 ev->id = sas_event_data->TargetID;
2879 ev->phy_id = sas_event_data->PhyNum;
2880 memcpy(&sas_address, &sas_event_data->SASAddress,
2881 sizeof(__le64));
2882 ev->sas_address = le64_to_cpu(sas_address);
2883 ev->device_info = device_info;
2884
2885 if (sas_event_data->ReasonCode &
2886 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2887 ev->event_type = MPTSAS_ADD_DEVICE;
2888 else
2889 ev->event_type = MPTSAS_DEL_DEVICE;
2890 schedule_work(&ev->work);
2891 break;
2892 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2893 /*
2894 * Persistent table is full.
2895 */
Eric Moore547f9a22006-06-27 14:42:12 -06002896 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002897 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002898 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002899 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002900 /*
2901 * TODO, handle other events
2902 */
Moore, Eric4b766472006-03-14 09:14:12 -07002903 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002904 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002905 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002906 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2907 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2908 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2909 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002910 default:
2911 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002912 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002913}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002914static void
Eric Moore547f9a22006-06-27 14:42:12 -06002915mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002916 EVENT_DATA_RAID *raid_event_data)
2917{
2918 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002919 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2920 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002921
2922 if (ioc->bus_type != SAS)
2923 return;
2924
Eric Moore547f9a22006-06-27 14:42:12 -06002925 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002926 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002927 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002928 return;
2929 }
2930
David Howellsc4028952006-11-22 14:57:56 +00002931 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002932 ev->ioc = ioc;
2933 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002934 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002935 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002936
2937 switch (raid_event_data->ReasonCode) {
2938 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002939 ev->phys_disk_num_valid = 1;
2940 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002941 ev->event_type = MPTSAS_ADD_DEVICE;
2942 break;
2943 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002944 ev->phys_disk_num_valid = 1;
2945 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002946 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002947 ev->event_type = MPTSAS_DEL_DEVICE;
2948 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002949 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2950 switch (state) {
2951 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002952 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002953 ev->phys_disk_num_valid = 1;
2954 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002955 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002956 ev->event_type = MPTSAS_ADD_DEVICE;
2957 break;
2958 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002959 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2960 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2961 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002962 ev->phys_disk_num_valid = 1;
2963 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002964 ev->event_type = MPTSAS_DEL_DEVICE;
2965 break;
2966 default:
2967 break;
2968 }
2969 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002970 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2971 ev->event_type = MPTSAS_DEL_RAID;
2972 break;
2973 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2974 ev->event_type = MPTSAS_ADD_RAID;
2975 break;
2976 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002977 switch (state) {
2978 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2979 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2980 ev->event_type = MPTSAS_DEL_RAID;
2981 break;
2982 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2983 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2984 ev->event_type = MPTSAS_ADD_RAID;
2985 break;
2986 default:
2987 break;
2988 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002989 break;
2990 default:
2991 break;
2992 }
2993 schedule_work(&ev->work);
2994}
2995
Moore, Erice6b2d762006-03-14 09:14:24 -07002996static void
Eric Moore547f9a22006-06-27 14:42:12 -06002997mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002998 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2999{
3000 struct mptsas_discovery_event *ev;
3001
3002 /*
3003 * DiscoveryStatus
3004 *
3005 * This flag will be non-zero when firmware
3006 * kicks off discovery, and return to zero
3007 * once its completed.
3008 */
3009 if (discovery_data->DiscoveryStatus)
3010 return;
3011
Eric Moore547f9a22006-06-27 14:42:12 -06003012 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07003013 if (!ev)
3014 return;
David Howellsc4028952006-11-22 14:57:56 +00003015 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07003016 ev->ioc = ioc;
3017 schedule_work(&ev->work);
3018};
3019
Eric Mooreb506ade2007-01-29 09:45:37 -07003020/*
3021 * mptsas_send_ir2_event - handle exposing hidden disk when
3022 * an inactive raid volume is added
3023 *
3024 * @ioc: Pointer to MPT_ADAPTER structure
3025 * @ir2_data
3026 *
3027 */
3028static void
3029mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
3030{
3031 struct mptsas_hotplug_event *ev;
3032
3033 if (ir2_data->ReasonCode !=
3034 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
3035 return;
3036
3037 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
3038 if (!ev)
3039 return;
3040
3041 INIT_WORK(&ev->work, mptsas_hotplug_work);
3042 ev->ioc = ioc;
3043 ev->id = ir2_data->TargetID;
3044 ev->channel = ir2_data->Bus;
3045 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3046
3047 schedule_work(&ev->work);
3048};
Moore, Erice6b2d762006-03-14 09:14:24 -07003049
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003050static int
3051mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3052{
Moore, Ericc73787ee2006-01-26 16:20:06 -07003053 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003054 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3055
3056 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003057 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003058
Moore, Erice6b2d762006-03-14 09:14:24 -07003059 /*
3060 * sas_discovery_ignore_events
3061 *
3062 * This flag is to prevent anymore processing of
3063 * sas events once mptsas_remove function is called.
3064 */
3065 if (ioc->sas_discovery_ignore_events) {
3066 rc = mptscsih_event_process(ioc, reply);
3067 goto out;
3068 }
3069
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003070 switch (event) {
3071 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003072 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003073 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003074 break;
3075 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003076 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003077 (EVENT_DATA_RAID *)reply->Data);
3078 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003079 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003080 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003081 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003082 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003083 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003084 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003085 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003086 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3087 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003088 case MPI_EVENT_IR2:
3089 mptsas_send_ir2_event(ioc,
3090 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3091 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003092 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003093 rc = mptscsih_event_process(ioc, reply);
3094 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003095 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003096 out:
3097
3098 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003099}
3100
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003101static int
3102mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3103{
3104 struct Scsi_Host *sh;
3105 MPT_SCSI_HOST *hd;
3106 MPT_ADAPTER *ioc;
3107 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003108 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003109 int numSGE = 0;
3110 int scale;
3111 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003112 int error=0;
3113 int r;
3114
3115 r = mpt_attach(pdev,id);
3116 if (r)
3117 return r;
3118
3119 ioc = pci_get_drvdata(pdev);
3120 ioc->DoneCtx = mptsasDoneCtx;
3121 ioc->TaskCtx = mptsasTaskCtx;
3122 ioc->InternalCtx = mptsasInternalCtx;
3123
3124 /* Added sanity check on readiness of the MPT adapter.
3125 */
3126 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3127 printk(MYIOC_s_WARN_FMT
3128 "Skipping because it's not operational!\n",
3129 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003130 error = -ENODEV;
3131 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003132 }
3133
3134 if (!ioc->active) {
3135 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3136 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003137 error = -ENODEV;
3138 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003139 }
3140
3141 /* Sanity check - ensure at least 1 port is INITIATOR capable
3142 */
3143 ioc_cap = 0;
3144 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3145 if (ioc->pfacts[ii].ProtocolFlags &
3146 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3147 ioc_cap++;
3148 }
3149
3150 if (!ioc_cap) {
3151 printk(MYIOC_s_WARN_FMT
3152 "Skipping ioc=%p because SCSI Initiator mode "
3153 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003154 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003155 }
3156
3157 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3158 if (!sh) {
3159 printk(MYIOC_s_WARN_FMT
3160 "Unable to register controller with SCSI subsystem\n",
3161 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003162 error = -1;
3163 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003164 }
3165
3166 spin_lock_irqsave(&ioc->FreeQlock, flags);
3167
3168 /* Attach the SCSI Host to the IOC structure
3169 */
3170 ioc->sh = sh;
3171
3172 sh->io_port = 0;
3173 sh->n_io_port = 0;
3174 sh->irq = 0;
3175
3176 /* set 16 byte cdb's */
3177 sh->max_cmd_len = 16;
3178
Eric Moore793955f2007-01-29 09:42:20 -07003179 sh->max_id = ioc->pfacts[0].PortSCSIID;
3180 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003181
3182 sh->transportt = mptsas_transport_template;
3183
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003184 sh->this_id = ioc->pfacts[0].PortSCSIID;
3185
3186 /* Required entry.
3187 */
3188 sh->unique_id = ioc->id;
3189
3190 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003191 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003192 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003193 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003194 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003195
3196 /* Verify that we won't exceed the maximum
3197 * number of chain buffers
3198 * We can optimize: ZZ = req_sz/sizeof(SGE)
3199 * For 32bit SGE's:
3200 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3201 * + (req_sz - 64)/sizeof(SGE)
3202 * A slightly different algorithm is required for
3203 * 64bit SGEs.
3204 */
3205 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3206 if (sizeof(dma_addr_t) == sizeof(u64)) {
3207 numSGE = (scale - 1) *
3208 (ioc->facts.MaxChainDepth-1) + scale +
3209 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3210 sizeof(u32));
3211 } else {
3212 numSGE = 1 + (scale - 1) *
3213 (ioc->facts.MaxChainDepth-1) + scale +
3214 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3215 sizeof(u32));
3216 }
3217
3218 if (numSGE < sh->sg_tablesize) {
3219 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303220 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003221 "Resetting sg_tablesize to %d from %d\n",
3222 ioc->name, numSGE, sh->sg_tablesize));
3223 sh->sg_tablesize = numSGE;
3224 }
3225
Eric Mooree7eae9f2007-09-29 10:15:59 -06003226 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003227 hd->ioc = ioc;
3228
3229 /* SCSI needs scsi_cmnd lookup table!
3230 * (with size equal to req_depth*PtrSz!)
3231 */
Eric Mooree8206382007-09-29 10:16:53 -06003232 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3233 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003234 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06003235 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003236 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003237 }
Eric Mooree8206382007-09-29 10:16:53 -06003238 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003239
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303240 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06003241 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003242
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003243 /* Clear the TM flags
3244 */
3245 hd->tmPending = 0;
3246 hd->tmState = TM_STATE_NONE;
3247 hd->resetPending = 0;
3248 hd->abortSCpnt = NULL;
3249
3250 /* Clear the pointer used to store
3251 * single-threaded commands, i.e., those
3252 * issued during a bus scan, dv and
3253 * configuration pages.
3254 */
3255 hd->cmdPtr = NULL;
3256
3257 /* Initialize this SCSI Hosts' timers
3258 * To use, set the timer expires field
3259 * and add_timer
3260 */
3261 init_timer(&hd->timer);
3262 hd->timer.data = (unsigned long) hd;
3263 hd->timer.function = mptscsih_timer_expired;
3264
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003265 ioc->sas_data.ptClear = mpt_pt_clear;
3266
Eric Mooredf9e0622007-01-29 09:46:21 -07003267 init_waitqueue_head(&hd->scandv_waitq);
3268 hd->scandv_wait_done = 0;
3269 hd->last_queue_full = 0;
3270 INIT_LIST_HEAD(&hd->target_reset_list);
3271 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3272
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003273 if (ioc->sas_data.ptClear==1) {
3274 mptbase_sas_persist_operation(
3275 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3276 }
3277
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003278 error = scsi_add_host(sh, &ioc->pcidev->dev);
3279 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06003280 dprintk(ioc, printk(MYIOC_s_ERR_FMT
3281 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003282 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003283 }
3284
3285 mptsas_scan_sas_topology(ioc);
3286
3287 return 0;
3288
Eric Moore547f9a22006-06-27 14:42:12 -06003289 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003290
3291 mptscsih_remove(pdev);
3292 return error;
3293}
3294
3295static void __devexit mptsas_remove(struct pci_dev *pdev)
3296{
3297 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3298 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003299 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003300
Eric Mooreb506ade2007-01-29 09:45:37 -07003301 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003302 sas_remove_host(ioc->sh);
3303
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003304 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003305 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3306 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003307 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303308 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003309 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003310 kfree(p);
3311 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003312 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003313
3314 mptscsih_remove(pdev);
3315}
3316
3317static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003318 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003319 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003320 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003321 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003322 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003323 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003324 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003325 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003326 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003327 PCI_ANY_ID, PCI_ANY_ID },
3328 {0} /* Terminating entry */
3329};
3330MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3331
3332
3333static struct pci_driver mptsas_driver = {
3334 .name = "mptsas",
3335 .id_table = mptsas_pci_table,
3336 .probe = mptsas_probe,
3337 .remove = __devexit_p(mptsas_remove),
3338 .shutdown = mptscsih_shutdown,
3339#ifdef CONFIG_PM
3340 .suspend = mptscsih_suspend,
3341 .resume = mptscsih_resume,
3342#endif
3343};
3344
3345static int __init
3346mptsas_init(void)
3347{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303348 int error;
3349
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003350 show_mptmod_ver(my_NAME, my_VERSION);
3351
3352 mptsas_transport_template =
3353 sas_attach_transport(&mptsas_transport_functions);
3354 if (!mptsas_transport_template)
3355 return -ENODEV;
3356
3357 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003358 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003359 mptsasInternalCtx =
3360 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003361 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003362
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303363 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3364 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003365
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303366 error = pci_register_driver(&mptsas_driver);
3367 if (error)
3368 sas_release_transport(mptsas_transport_template);
3369
3370 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003371}
3372
3373static void __exit
3374mptsas_exit(void)
3375{
3376 pci_unregister_driver(&mptsas_driver);
3377 sas_release_transport(mptsas_transport_template);
3378
3379 mpt_reset_deregister(mptsasDoneCtx);
3380 mpt_event_deregister(mptsasDoneCtx);
3381
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003382 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003383 mpt_deregister(mptsasInternalCtx);
3384 mpt_deregister(mptsasTaskCtx);
3385 mpt_deregister(mptsasDoneCtx);
3386}
3387
3388module_init(mptsas_init);
3389module_exit(mptsas_exit);