blob: e4c94f93de16a98462518419c923bb24f24d9414 [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);
1346 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001347 printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
1348 ioc->name, __FUNCTION__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001349 ret = -ENXIO;
1350 }
1351unmap:
1352 if (dma_addr_out)
1353 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1354 PCI_DMA_BIDIRECTIONAL);
1355 if (dma_addr_in)
1356 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1357 PCI_DMA_BIDIRECTIONAL);
1358put_mf:
1359 if (mf)
1360 mpt_free_msg_frame(ioc, mf);
1361out_unlock:
1362 mutex_unlock(&ioc->sas_mgmt.mutex);
1363out:
1364 return ret;
1365}
1366
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001367static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001368 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001369 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1370 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001371 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001372 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001373};
1374
1375static struct scsi_transport_template *mptsas_transport_template;
1376
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001377static int
1378mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1379{
1380 ConfigExtendedPageHeader_t hdr;
1381 CONFIGPARMS cfg;
1382 SasIOUnitPage0_t *buffer;
1383 dma_addr_t dma_handle;
1384 int error, i;
1385
1386 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1387 hdr.ExtPageLength = 0;
1388 hdr.PageNumber = 0;
1389 hdr.Reserved1 = 0;
1390 hdr.Reserved2 = 0;
1391 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1392 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1393
1394 cfg.cfghdr.ehdr = &hdr;
1395 cfg.physAddr = -1;
1396 cfg.pageAddr = 0;
1397 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1398 cfg.dir = 0; /* read */
1399 cfg.timeout = 10;
1400
1401 error = mpt_config(ioc, &cfg);
1402 if (error)
1403 goto out;
1404 if (!hdr.ExtPageLength) {
1405 error = -ENXIO;
1406 goto out;
1407 }
1408
1409 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1410 &dma_handle);
1411 if (!buffer) {
1412 error = -ENOMEM;
1413 goto out;
1414 }
1415
1416 cfg.physAddr = dma_handle;
1417 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1418
1419 error = mpt_config(ioc, &cfg);
1420 if (error)
1421 goto out_free_consistent;
1422
1423 port_info->num_phys = buffer->NumPhys;
1424 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001425 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001426 if (!port_info->phy_info) {
1427 error = -ENOMEM;
1428 goto out_free_consistent;
1429 }
1430
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301431 ioc->nvdata_version_persistent =
1432 le16_to_cpu(buffer->NvdataVersionPersistent);
1433 ioc->nvdata_version_default =
1434 le16_to_cpu(buffer->NvdataVersionDefault);
1435
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001436 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301437 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001438 port_info->phy_info[i].phy_id = i;
1439 port_info->phy_info[i].port_id =
1440 buffer->PhyData[i].Port;
1441 port_info->phy_info[i].negotiated_link_rate =
1442 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001443 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001444 port_info->phy_info[i].handle =
1445 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001446 }
1447
1448 out_free_consistent:
1449 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1450 buffer, dma_handle);
1451 out:
1452 return error;
1453}
1454
1455static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301456mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1457{
1458 ConfigExtendedPageHeader_t hdr;
1459 CONFIGPARMS cfg;
1460 SasIOUnitPage1_t *buffer;
1461 dma_addr_t dma_handle;
1462 int error;
1463 u16 device_missing_delay;
1464
1465 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1466 memset(&cfg, 0, sizeof(CONFIGPARMS));
1467
1468 cfg.cfghdr.ehdr = &hdr;
1469 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1470 cfg.timeout = 10;
1471 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1472 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1473 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1474 cfg.cfghdr.ehdr->PageNumber = 1;
1475
1476 error = mpt_config(ioc, &cfg);
1477 if (error)
1478 goto out;
1479 if (!hdr.ExtPageLength) {
1480 error = -ENXIO;
1481 goto out;
1482 }
1483
1484 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1485 &dma_handle);
1486 if (!buffer) {
1487 error = -ENOMEM;
1488 goto out;
1489 }
1490
1491 cfg.physAddr = dma_handle;
1492 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1493
1494 error = mpt_config(ioc, &cfg);
1495 if (error)
1496 goto out_free_consistent;
1497
1498 ioc->io_missing_delay =
1499 le16_to_cpu(buffer->IODeviceMissingDelay);
1500 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1501 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1502 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1503 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1504
1505 out_free_consistent:
1506 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1507 buffer, dma_handle);
1508 out:
1509 return error;
1510}
1511
1512static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001513mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1514 u32 form, u32 form_specific)
1515{
1516 ConfigExtendedPageHeader_t hdr;
1517 CONFIGPARMS cfg;
1518 SasPhyPage0_t *buffer;
1519 dma_addr_t dma_handle;
1520 int error;
1521
1522 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1523 hdr.ExtPageLength = 0;
1524 hdr.PageNumber = 0;
1525 hdr.Reserved1 = 0;
1526 hdr.Reserved2 = 0;
1527 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1528 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1529
1530 cfg.cfghdr.ehdr = &hdr;
1531 cfg.dir = 0; /* read */
1532 cfg.timeout = 10;
1533
1534 /* Get Phy Pg 0 for each Phy. */
1535 cfg.physAddr = -1;
1536 cfg.pageAddr = form + form_specific;
1537 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1538
1539 error = mpt_config(ioc, &cfg);
1540 if (error)
1541 goto out;
1542
1543 if (!hdr.ExtPageLength) {
1544 error = -ENXIO;
1545 goto out;
1546 }
1547
1548 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1549 &dma_handle);
1550 if (!buffer) {
1551 error = -ENOMEM;
1552 goto out;
1553 }
1554
1555 cfg.physAddr = dma_handle;
1556 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1557
1558 error = mpt_config(ioc, &cfg);
1559 if (error)
1560 goto out_free_consistent;
1561
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301562 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001563
1564 phy_info->hw_link_rate = buffer->HwLinkRate;
1565 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1566 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1567 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1568
1569 out_free_consistent:
1570 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1571 buffer, dma_handle);
1572 out:
1573 return error;
1574}
1575
1576static int
1577mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1578 u32 form, u32 form_specific)
1579{
1580 ConfigExtendedPageHeader_t hdr;
1581 CONFIGPARMS cfg;
1582 SasDevicePage0_t *buffer;
1583 dma_addr_t dma_handle;
1584 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001585 int error=0;
1586
1587 if (ioc->sas_discovery_runtime &&
1588 mptsas_is_end_device(device_info))
1589 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001590
1591 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1592 hdr.ExtPageLength = 0;
1593 hdr.PageNumber = 0;
1594 hdr.Reserved1 = 0;
1595 hdr.Reserved2 = 0;
1596 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1597 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1598
1599 cfg.cfghdr.ehdr = &hdr;
1600 cfg.pageAddr = form + form_specific;
1601 cfg.physAddr = -1;
1602 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1603 cfg.dir = 0; /* read */
1604 cfg.timeout = 10;
1605
Moore, Ericdb9c9172006-03-14 09:14:18 -07001606 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001607 error = mpt_config(ioc, &cfg);
1608 if (error)
1609 goto out;
1610 if (!hdr.ExtPageLength) {
1611 error = -ENXIO;
1612 goto out;
1613 }
1614
1615 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1616 &dma_handle);
1617 if (!buffer) {
1618 error = -ENOMEM;
1619 goto out;
1620 }
1621
1622 cfg.physAddr = dma_handle;
1623 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1624
1625 error = mpt_config(ioc, &cfg);
1626 if (error)
1627 goto out_free_consistent;
1628
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301629 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001630
1631 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001632 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001633 device_info->handle_enclosure =
1634 le16_to_cpu(buffer->EnclosureHandle);
1635 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001636 device_info->phy_id = buffer->PhyNum;
1637 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001638 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001639 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001640 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001641 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1642 device_info->sas_address = le64_to_cpu(sas_address);
1643 device_info->device_info =
1644 le32_to_cpu(buffer->DeviceInfo);
1645
1646 out_free_consistent:
1647 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1648 buffer, dma_handle);
1649 out:
1650 return error;
1651}
1652
1653static int
1654mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1655 u32 form, u32 form_specific)
1656{
1657 ConfigExtendedPageHeader_t hdr;
1658 CONFIGPARMS cfg;
1659 SasExpanderPage0_t *buffer;
1660 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001661 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001662
1663 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1664 hdr.ExtPageLength = 0;
1665 hdr.PageNumber = 0;
1666 hdr.Reserved1 = 0;
1667 hdr.Reserved2 = 0;
1668 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1669 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1670
1671 cfg.cfghdr.ehdr = &hdr;
1672 cfg.physAddr = -1;
1673 cfg.pageAddr = form + form_specific;
1674 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1675 cfg.dir = 0; /* read */
1676 cfg.timeout = 10;
1677
Moore, Ericdb9c9172006-03-14 09:14:18 -07001678 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001679 error = mpt_config(ioc, &cfg);
1680 if (error)
1681 goto out;
1682
1683 if (!hdr.ExtPageLength) {
1684 error = -ENXIO;
1685 goto out;
1686 }
1687
1688 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1689 &dma_handle);
1690 if (!buffer) {
1691 error = -ENOMEM;
1692 goto out;
1693 }
1694
1695 cfg.physAddr = dma_handle;
1696 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1697
1698 error = mpt_config(ioc, &cfg);
1699 if (error)
1700 goto out_free_consistent;
1701
1702 /* save config data */
1703 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001704 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001705 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001706 if (!port_info->phy_info) {
1707 error = -ENOMEM;
1708 goto out_free_consistent;
1709 }
1710
Eric Moore2ecce492007-01-29 09:47:08 -07001711 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001712 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001713 port_info->phy_info[i].handle =
1714 le16_to_cpu(buffer->DevHandle);
1715 }
Eric Moore547f9a22006-06-27 14:42:12 -06001716
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001717 out_free_consistent:
1718 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1719 buffer, dma_handle);
1720 out:
1721 return error;
1722}
1723
1724static int
1725mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1726 u32 form, u32 form_specific)
1727{
1728 ConfigExtendedPageHeader_t hdr;
1729 CONFIGPARMS cfg;
1730 SasExpanderPage1_t *buffer;
1731 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001732 int error=0;
1733
1734 if (ioc->sas_discovery_runtime &&
1735 mptsas_is_end_device(&phy_info->attached))
1736 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001737
1738 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1739 hdr.ExtPageLength = 0;
1740 hdr.PageNumber = 1;
1741 hdr.Reserved1 = 0;
1742 hdr.Reserved2 = 0;
1743 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1744 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1745
1746 cfg.cfghdr.ehdr = &hdr;
1747 cfg.physAddr = -1;
1748 cfg.pageAddr = form + form_specific;
1749 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1750 cfg.dir = 0; /* read */
1751 cfg.timeout = 10;
1752
1753 error = mpt_config(ioc, &cfg);
1754 if (error)
1755 goto out;
1756
1757 if (!hdr.ExtPageLength) {
1758 error = -ENXIO;
1759 goto out;
1760 }
1761
1762 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1763 &dma_handle);
1764 if (!buffer) {
1765 error = -ENOMEM;
1766 goto out;
1767 }
1768
1769 cfg.physAddr = dma_handle;
1770 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1771
1772 error = mpt_config(ioc, &cfg);
1773 if (error)
1774 goto out_free_consistent;
1775
1776
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301777 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001778
1779 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001780 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001781 phy_info->port_id = buffer->PhysicalPort;
1782 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1783 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1784 phy_info->hw_link_rate = buffer->HwLinkRate;
1785 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1786 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1787
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001788 out_free_consistent:
1789 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1790 buffer, dma_handle);
1791 out:
1792 return error;
1793}
1794
1795static void
1796mptsas_parse_device_info(struct sas_identify *identify,
1797 struct mptsas_devinfo *device_info)
1798{
1799 u16 protocols;
1800
1801 identify->sas_address = device_info->sas_address;
1802 identify->phy_identifier = device_info->phy_id;
1803
1804 /*
1805 * Fill in Phy Initiator Port Protocol.
1806 * Bits 6:3, more than one bit can be set, fall through cases.
1807 */
1808 protocols = device_info->device_info & 0x78;
1809 identify->initiator_port_protocols = 0;
1810 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1811 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1812 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1813 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1814 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1815 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1816 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1817 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1818
1819 /*
1820 * Fill in Phy Target Port Protocol.
1821 * Bits 10:7, more than one bit can be set, fall through cases.
1822 */
1823 protocols = device_info->device_info & 0x780;
1824 identify->target_port_protocols = 0;
1825 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1826 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1827 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1828 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1829 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1830 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1831 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1832 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1833
1834 /*
1835 * Fill in Attached device type.
1836 */
1837 switch (device_info->device_info &
1838 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1839 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1840 identify->device_type = SAS_PHY_UNUSED;
1841 break;
1842 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1843 identify->device_type = SAS_END_DEVICE;
1844 break;
1845 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1846 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1847 break;
1848 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1849 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1850 break;
1851 }
1852}
1853
1854static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001855 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001856{
Moore, Erice6b2d762006-03-14 09:14:24 -07001857 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001858 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001859 struct sas_port *port;
1860 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001861
Eric Moore547f9a22006-06-27 14:42:12 -06001862 if (!dev) {
1863 error = -ENODEV;
1864 goto out;
1865 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001866
1867 if (!phy_info->phy) {
1868 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001869 if (!phy) {
1870 error = -ENOMEM;
1871 goto out;
1872 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001873 } else
1874 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001875
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001876 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001877
1878 /*
1879 * Set Negotiated link rate.
1880 */
1881 switch (phy_info->negotiated_link_rate) {
1882 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001883 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001884 break;
1885 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001886 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001887 break;
1888 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001889 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001890 break;
1891 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001892 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001893 break;
1894 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1895 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1896 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001897 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001898 break;
1899 }
1900
1901 /*
1902 * Set Max hardware link rate.
1903 */
1904 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1905 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001906 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001907 break;
1908 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001909 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001910 break;
1911 default:
1912 break;
1913 }
1914
1915 /*
1916 * Set Max programmed link rate.
1917 */
1918 switch (phy_info->programmed_link_rate &
1919 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1920 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001921 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001922 break;
1923 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001924 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001925 break;
1926 default:
1927 break;
1928 }
1929
1930 /*
1931 * Set Min hardware link rate.
1932 */
1933 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1934 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001935 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001936 break;
1937 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001938 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001939 break;
1940 default:
1941 break;
1942 }
1943
1944 /*
1945 * Set Min programmed link rate.
1946 */
1947 switch (phy_info->programmed_link_rate &
1948 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1949 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001950 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001951 break;
1952 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001953 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001954 break;
1955 default:
1956 break;
1957 }
1958
Moore, Erice6b2d762006-03-14 09:14:24 -07001959 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001960
Moore, Erice6b2d762006-03-14 09:14:24 -07001961 error = sas_phy_add(phy);
1962 if (error) {
1963 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001964 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001965 }
1966 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001967 }
1968
Eric Moore547f9a22006-06-27 14:42:12 -06001969 if (!phy_info->attached.handle ||
1970 !phy_info->port_details)
1971 goto out;
1972
1973 port = mptsas_get_port(phy_info);
1974 ioc = phy_to_ioc(phy_info->phy);
1975
1976 if (phy_info->sas_port_add_phy) {
1977
1978 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001979 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001980 if (!port) {
1981 error = -ENOMEM;
1982 goto out;
1983 }
1984 error = sas_port_add(port);
1985 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301986 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06001987 "%s: exit at line=%d\n", ioc->name,
1988 __FUNCTION__, __LINE__));
1989 goto out;
1990 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301991 mptsas_set_port(ioc, phy_info, port);
Eric Moore29dd3602007-09-14 18:46:51 -06001992 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooredc22f162006-07-06 11:23:14 -06001993 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001994 ioc->name, port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06001995 }
Eric Moore29dd3602007-09-14 18:46:51 -06001996 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
1997 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06001998 sas_port_add_phy(port, phy_info->phy);
1999 phy_info->sas_port_add_phy = 0;
2000 }
2001
2002 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002003
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002004 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002005 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002006 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002007
James Bottomley2686de22006-06-30 12:54:02 -05002008 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002009 /*
2010 * Let the hotplug_work thread handle processing
2011 * the adding/removing of devices that occur
2012 * after start of day.
2013 */
2014 if (ioc->sas_discovery_runtime &&
2015 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002016 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002017
James Bottomleyf013db32006-03-18 14:54:36 -06002018 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002019 if (scsi_is_host_device(parent)) {
2020 struct mptsas_portinfo *port_info;
2021 int i;
2022
2023 mutex_lock(&ioc->sas_topology_mutex);
2024 port_info = mptsas_find_portinfo_by_handle(ioc,
2025 ioc->handle);
2026 mutex_unlock(&ioc->sas_topology_mutex);
2027
2028 for (i = 0; i < port_info->num_phys; i++)
2029 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002030 identify.sas_address) {
2031 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002032 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002033 }
James Bottomley2686de22006-06-30 12:54:02 -05002034
2035 } else if (scsi_is_sas_rphy(parent)) {
2036 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2037 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002038 parent_rphy->identify.sas_address) {
2039 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002040 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002041 }
James Bottomley2686de22006-06-30 12:54:02 -05002042 }
2043
James Bottomleyf013db32006-03-18 14:54:36 -06002044 switch (identify.device_type) {
2045 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002046 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002047 break;
2048 case SAS_EDGE_EXPANDER_DEVICE:
2049 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002050 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002051 break;
2052 default:
2053 rphy = NULL;
2054 break;
2055 }
Eric Moore547f9a22006-06-27 14:42:12 -06002056 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302057 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002058 "%s: exit at line=%d\n", ioc->name,
2059 __FUNCTION__, __LINE__));
2060 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002061 }
2062
Eric Moore547f9a22006-06-27 14:42:12 -06002063 rphy->identify = identify;
2064 error = sas_rphy_add(rphy);
2065 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302066 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002067 "%s: exit at line=%d\n", ioc->name,
2068 __FUNCTION__, __LINE__));
2069 sas_rphy_free(rphy);
2070 goto out;
2071 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302072 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002073 }
2074
Eric Moore547f9a22006-06-27 14:42:12 -06002075 out:
2076 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002077}
2078
2079static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002080mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002081{
Moore, Erice6b2d762006-03-14 09:14:24 -07002082 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002083 int error = -ENOMEM, i;
2084
Moore, Erice6b2d762006-03-14 09:14:24 -07002085 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2086 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002087 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002088
Moore, Erice6b2d762006-03-14 09:14:24 -07002089 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002090 if (error)
2091 goto out_free_port_info;
2092
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302093 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002094 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07002095 ioc->handle = hba->phy_info[0].handle;
2096 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07002097 if (!port_info) {
2098 port_info = hba;
2099 list_add_tail(&port_info->list, &ioc->sas_topology);
2100 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002101 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002102 port_info->phy_info[i].negotiated_link_rate =
2103 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002104 port_info->phy_info[i].handle =
2105 hba->phy_info[i].handle;
2106 port_info->phy_info[i].port_id =
2107 hba->phy_info[i].port_id;
2108 }
Eric Moore547f9a22006-06-27 14:42:12 -06002109 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002110 kfree(hba);
2111 hba = NULL;
2112 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002113 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002114 for (i = 0; i < port_info->num_phys; i++) {
2115 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2116 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2117 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2118
2119 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002120 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2121 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2122 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002123 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002124 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002125 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002126 mptsas_sas_device_pg0(ioc,
2127 &port_info->phy_info[i].attached,
2128 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2129 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2130 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002131 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002132
Eric Moore547f9a22006-06-27 14:42:12 -06002133 mptsas_setup_wide_ports(ioc, port_info);
2134
2135 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002136 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002137 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002138
2139 return 0;
2140
2141 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002142 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002143 out:
2144 return error;
2145}
2146
2147static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002148mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002149{
Moore, Erice6b2d762006-03-14 09:14:24 -07002150 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002151 struct device *parent;
2152 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002153 int error = -ENOMEM, i, j;
2154
Moore, Erice6b2d762006-03-14 09:14:24 -07002155 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2156 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002157 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002158
Moore, Erice6b2d762006-03-14 09:14:24 -07002159 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002160 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2161 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002162 if (error)
2163 goto out_free_port_info;
2164
Eric Moore2ecce492007-01-29 09:47:08 -07002165 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002166
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002167 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002168 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2169 if (!port_info) {
2170 port_info = ex;
2171 list_add_tail(&port_info->list, &ioc->sas_topology);
2172 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002173 for (i = 0; i < ex->num_phys; i++) {
2174 port_info->phy_info[i].handle =
2175 ex->phy_info[i].handle;
2176 port_info->phy_info[i].port_id =
2177 ex->phy_info[i].port_id;
2178 }
Eric Moore547f9a22006-06-27 14:42:12 -06002179 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002180 kfree(ex);
2181 ex = NULL;
2182 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002183 mutex_unlock(&ioc->sas_topology_mutex);
2184
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002185 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002186 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2187 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2188 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2189
2190 if (port_info->phy_info[i].identify.handle) {
2191 mptsas_sas_device_pg0(ioc,
2192 &port_info->phy_info[i].identify,
2193 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2194 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2195 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002196 port_info->phy_info[i].identify.phy_id =
2197 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002198 }
2199
2200 if (port_info->phy_info[i].attached.handle) {
2201 mptsas_sas_device_pg0(ioc,
2202 &port_info->phy_info[i].attached,
2203 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2204 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2205 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002206 port_info->phy_info[i].attached.phy_id =
2207 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002208 }
Eric Moore547f9a22006-06-27 14:42:12 -06002209 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002210
Eric Moore547f9a22006-06-27 14:42:12 -06002211 parent = &ioc->sh->shost_gendev;
2212 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002213 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002214 list_for_each_entry(p, &ioc->sas_topology, list) {
2215 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002216 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002217 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002218 continue;
2219 rphy = mptsas_get_rphy(&p->phy_info[j]);
2220 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002221 }
2222 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002223 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002224 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002225
Eric Moore547f9a22006-06-27 14:42:12 -06002226 mptsas_setup_wide_ports(ioc, port_info);
2227
2228 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002229 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002230 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002231
2232 return 0;
2233
2234 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002235 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002236 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002237 kfree(ex);
2238 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002239 out:
2240 return error;
2241}
2242
Moore, Erice6b2d762006-03-14 09:14:24 -07002243/*
2244 * mptsas_delete_expander_phys
2245 *
2246 *
2247 * This will traverse topology, and remove expanders
2248 * that are no longer present
2249 */
2250static void
2251mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2252{
2253 struct mptsas_portinfo buffer;
2254 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002255 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002256 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002257 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002258 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002259
2260 mutex_lock(&ioc->sas_topology_mutex);
2261 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2262
2263 if (port_info->phy_info &&
2264 (!(port_info->phy_info[0].identify.device_info &
2265 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2266 continue;
2267
2268 if (mptsas_sas_expander_pg0(ioc, &buffer,
2269 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002270 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2271 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002272
2273 /*
2274 * Obtain the port_info instance to the parent port
2275 */
2276 parent = mptsas_find_portinfo_by_handle(ioc,
2277 port_info->phy_info[0].identify.handle_parent);
2278
2279 if (!parent)
2280 goto next_port;
2281
Eric Moore547f9a22006-06-27 14:42:12 -06002282 expander_sas_address =
2283 port_info->phy_info[0].identify.sas_address;
2284
Moore, Erice6b2d762006-03-14 09:14:24 -07002285 /*
2286 * Delete rphys in the parent that point
2287 * to this expander. The transport layer will
2288 * cleanup all the children.
2289 */
Eric Moore547f9a22006-06-27 14:42:12 -06002290 phy_info = parent->phy_info;
2291 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2292 port = mptsas_get_port(phy_info);
2293 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002294 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002295 if (phy_info->attached.sas_address !=
2296 expander_sas_address)
2297 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302298 dsaswideprintk(ioc,
Eric Moorec51d0be2007-09-29 10:17:21 -06002299 dev_printk(KERN_DEBUG, &port->dev,
2300 MYIOC_s_FMT "delete port (%d)\n", ioc->name,
2301 port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002302 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302303 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002304 }
2305 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002306
2307 phy_info = port_info->phy_info;
2308 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302309 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002310
Moore, Erice6b2d762006-03-14 09:14:24 -07002311 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002312 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002313 kfree(port_info);
2314 }
2315 /*
2316 * Free this memory allocated from inside
2317 * mptsas_sas_expander_pg0
2318 */
Eric Moore547f9a22006-06-27 14:42:12 -06002319 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002320 }
2321 mutex_unlock(&ioc->sas_topology_mutex);
2322}
2323
2324/*
2325 * Start of day discovery
2326 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002327static void
2328mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2329{
2330 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002331 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002332
Moore, Erice6b2d762006-03-14 09:14:24 -07002333 mutex_lock(&ioc->sas_discovery_mutex);
2334 mptsas_probe_hba_phys(ioc);
2335 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002336 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002337 /*
2338 Reporting RAID volumes.
2339 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002340 if (!ioc->ir_firmware)
2341 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002342 if (!ioc->raid_data.pIocPg2)
2343 goto out;
2344 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2345 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002346 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002347 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002348 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2349 }
2350 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002351 mutex_unlock(&ioc->sas_discovery_mutex);
2352}
2353
2354/*
2355 * Work queue thread to handle Runtime discovery
2356 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002357 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002358 */
2359static void
Eric Moore547f9a22006-06-27 14:42:12 -06002360__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002361{
Moore, Erice6b2d762006-03-14 09:14:24 -07002362 u32 handle = 0xFFFF;
2363
Moore, Erice6b2d762006-03-14 09:14:24 -07002364 ioc->sas_discovery_runtime=1;
2365 mptsas_delete_expander_phys(ioc);
2366 mptsas_probe_hba_phys(ioc);
2367 while (!mptsas_probe_expander_phys(ioc, &handle))
2368 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002369 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002370}
2371
2372/*
2373 * Work queue thread to handle Runtime discovery
2374 * Mere purpose is the hot add/delete of expanders
2375 *(Mutex LOCKED)
2376 */
2377static void
David Howellsc4028952006-11-22 14:57:56 +00002378mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002379{
David Howellsc4028952006-11-22 14:57:56 +00002380 struct mptsas_discovery_event *ev =
2381 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002382 MPT_ADAPTER *ioc = ev->ioc;
2383
2384 mutex_lock(&ioc->sas_discovery_mutex);
2385 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002386 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002387 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002388}
2389
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002390static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002391mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002392{
2393 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002394 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002395 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002396
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002397 mutex_lock(&ioc->sas_topology_mutex);
2398 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2399 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002400 if (!mptsas_is_end_device(
2401 &port_info->phy_info[i].attached))
2402 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002403 if (port_info->phy_info[i].attached.sas_address
2404 != sas_address)
2405 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002406 phy_info = &port_info->phy_info[i];
2407 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002408 }
2409 }
2410 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002411 return phy_info;
2412}
2413
2414static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002415mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002416{
2417 struct mptsas_portinfo *port_info;
2418 struct mptsas_phyinfo *phy_info = NULL;
2419 int i;
2420
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002421 mutex_lock(&ioc->sas_topology_mutex);
2422 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002423 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002424 if (!mptsas_is_end_device(
2425 &port_info->phy_info[i].attached))
2426 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002427 if (port_info->phy_info[i].attached.id != id)
2428 continue;
2429 if (port_info->phy_info[i].attached.channel != channel)
2430 continue;
2431 phy_info = &port_info->phy_info[i];
2432 break;
2433 }
2434 }
2435 mutex_unlock(&ioc->sas_topology_mutex);
2436 return phy_info;
2437}
2438
2439static struct mptsas_phyinfo *
2440mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2441{
2442 struct mptsas_portinfo *port_info;
2443 struct mptsas_phyinfo *phy_info = NULL;
2444 int i;
2445
2446 mutex_lock(&ioc->sas_topology_mutex);
2447 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2448 for (i = 0; i < port_info->num_phys; i++) {
2449 if (!mptsas_is_end_device(
2450 &port_info->phy_info[i].attached))
2451 continue;
2452 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2453 continue;
2454 if (port_info->phy_info[i].attached.phys_disk_num != id)
2455 continue;
2456 if (port_info->phy_info[i].attached.channel != channel)
2457 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002458 phy_info = &port_info->phy_info[i];
2459 break;
2460 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002461 }
2462 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002463 return phy_info;
2464}
2465
Moore, Eric4b766472006-03-14 09:14:12 -07002466/*
2467 * Work queue thread to clear the persitency table
2468 */
2469static void
David Howellsc4028952006-11-22 14:57:56 +00002470mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002471{
David Howellsc4028952006-11-22 14:57:56 +00002472 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002473
2474 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2475}
2476
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002477static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002478mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2479{
Eric Mooref99be432007-01-04 20:46:54 -07002480 int rc;
2481
Moore, Ericf44e5462006-03-14 09:14:21 -07002482 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002483 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002484}
2485
2486static void
2487mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2488{
2489 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2490 mptsas_reprobe_lun);
2491}
2492
Eric Mooreb506ade2007-01-29 09:45:37 -07002493static void
2494mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2495{
2496 CONFIGPARMS cfg;
2497 ConfigPageHeader_t hdr;
2498 dma_addr_t dma_handle;
2499 pRaidVolumePage0_t buffer = NULL;
2500 RaidPhysDiskPage0_t phys_disk;
2501 int i;
2502 struct mptsas_hotplug_event *ev;
2503
2504 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2505 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2506 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2507 cfg.pageAddr = (channel << 8) + id;
2508 cfg.cfghdr.hdr = &hdr;
2509 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2510
2511 if (mpt_config(ioc, &cfg) != 0)
2512 goto out;
2513
2514 if (!hdr.PageLength)
2515 goto out;
2516
2517 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2518 &dma_handle);
2519
2520 if (!buffer)
2521 goto out;
2522
2523 cfg.physAddr = dma_handle;
2524 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2525
2526 if (mpt_config(ioc, &cfg) != 0)
2527 goto out;
2528
2529 if (!(buffer->VolumeStatus.Flags &
2530 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2531 goto out;
2532
2533 if (!buffer->NumPhysDisks)
2534 goto out;
2535
2536 for (i = 0; i < buffer->NumPhysDisks; i++) {
2537
2538 if (mpt_raid_phys_disk_pg0(ioc,
2539 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2540 continue;
2541
2542 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2543 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002544 printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
Eric Mooreb506ade2007-01-29 09:45:37 -07002545 goto out;
2546 }
2547
2548 INIT_WORK(&ev->work, mptsas_hotplug_work);
2549 ev->ioc = ioc;
2550 ev->id = phys_disk.PhysDiskID;
2551 ev->channel = phys_disk.PhysDiskBus;
2552 ev->phys_disk_num_valid = 1;
2553 ev->phys_disk_num = phys_disk.PhysDiskNum;
2554 ev->event_type = MPTSAS_ADD_DEVICE;
2555 schedule_work(&ev->work);
2556 }
2557
2558 out:
2559 if (buffer)
2560 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2561 dma_handle);
2562}
Moore, Erice6b2d762006-03-14 09:14:24 -07002563/*
2564 * Work queue thread to handle SAS hotplug events
2565 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002566static void
David Howellsc4028952006-11-22 14:57:56 +00002567mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002568{
David Howellsc4028952006-11-22 14:57:56 +00002569 struct mptsas_hotplug_event *ev =
2570 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002571
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002572 MPT_ADAPTER *ioc = ev->ioc;
2573 struct mptsas_phyinfo *phy_info;
2574 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002575 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002576 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002577 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002578 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002579 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002580 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002581 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002582 VirtDevice *vdevice;
2583
Moore, Erice6b2d762006-03-14 09:14:24 -07002584 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002585 switch (ev->event_type) {
2586 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002587
Eric Mooreb506ade2007-01-29 09:45:37 -07002588 phy_info = NULL;
2589 if (ev->phys_disk_num_valid) {
2590 if (ev->hidden_raid_component){
2591 if (mptsas_sas_device_pg0(ioc, &sas_device,
2592 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2593 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2594 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302595 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002596 "%s: exit at line=%d\n", ioc->name,
2597 __FUNCTION__, __LINE__));
2598 break;
2599 }
2600 phy_info = mptsas_find_phyinfo_by_sas_address(
2601 ioc, sas_device.sas_address);
2602 }else
2603 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2604 ioc, ev->channel, ev->phys_disk_num);
2605 }
2606
2607 if (!phy_info)
2608 phy_info = mptsas_find_phyinfo_by_target(ioc,
2609 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002610
Moore, Ericf44e5462006-03-14 09:14:21 -07002611 /*
2612 * Sanity checks, for non-existing phys and remote rphys.
2613 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002614 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302615 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002616 "%s: exit at line=%d\n", ioc->name,
2617 __FUNCTION__, __LINE__));
2618 break;
2619 }
2620 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302621 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002622 "%s: exit at line=%d\n", ioc->name,
2623 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002624 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002625 }
2626 rphy = mptsas_get_rphy(phy_info);
2627 if (!rphy) {
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__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002631 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002632 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002633
Eric Moore547f9a22006-06-27 14:42:12 -06002634 port = mptsas_get_port(phy_info);
2635 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302636 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002637 "%s: exit at line=%d\n", ioc->name,
2638 __FUNCTION__, __LINE__));
2639 break;
2640 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002641
Eric Moore547f9a22006-06-27 14:42:12 -06002642 starget = mptsas_get_starget(phy_info);
2643 if (starget) {
2644 vtarget = starget->hostdata;
2645
2646 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302647 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002648 "%s: exit at line=%d\n", ioc->name,
2649 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002650 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002651 }
2652
Moore, Ericf44e5462006-03-14 09:14:21 -07002653 /*
2654 * Handling RAID components
2655 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002656 if (ev->phys_disk_num_valid &&
2657 ev->hidden_raid_component) {
2658 printk(MYIOC_s_INFO_FMT
2659 "RAID Hidding: channel=%d, id=%d, "
2660 "physdsk %d \n", ioc->name, ev->channel,
2661 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002662 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002663 vtarget->tflags |=
2664 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002665 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002666 phy_info->attached.phys_disk_num =
2667 ev->phys_disk_num;
2668 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002669 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002670 }
2671
Eric Mooreb506ade2007-01-29 09:45:37 -07002672 if (phy_info->attached.device_info &
2673 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002674 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002675 if (phy_info->attached.device_info &
2676 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002677 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002678 if (phy_info->attached.device_info &
2679 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002680 ds = "sata";
2681
2682 printk(MYIOC_s_INFO_FMT
2683 "removing %s device, channel %d, id %d, phy %d\n",
2684 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moorec51d0be2007-09-29 10:17:21 -06002685 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002686 "delete port (%d)\n", ioc->name, port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002687 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302688 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002689 break;
2690 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002691
Moore, Ericbd23e942006-04-17 12:43:04 -06002692 if (ev->phys_disk_num_valid)
2693 mpt_findImVolumes(ioc);
2694
Moore, Ericc73787ee2006-01-26 16:20:06 -07002695 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002696 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002697 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002698 if (mptsas_sas_device_pg0(ioc, &sas_device,
2699 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002700 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2701 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302702 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002703 "%s: exit at line=%d\n", ioc->name,
2704 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002705 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002706 }
2707
Eric Moore547f9a22006-06-27 14:42:12 -06002708 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002709
Eric Moore547f9a22006-06-27 14:42:12 -06002710 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2711 sas_device.sas_address);
2712
2713 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302714 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002715 "%s: exit at line=%d\n", ioc->name,
2716 __FUNCTION__, __LINE__));
2717 break;
2718 }
2719
2720 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002721 if (starget && (!ev->hidden_raid_component)){
2722
Eric Moore547f9a22006-06-27 14:42:12 -06002723 vtarget = starget->hostdata;
2724
2725 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302726 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002727 "%s: exit at line=%d\n", ioc->name,
2728 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002729 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002730 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002731 /*
2732 * Handling RAID components
2733 */
2734 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002735 printk(MYIOC_s_INFO_FMT
2736 "RAID Exposing: channel=%d, id=%d, "
2737 "physdsk %d \n", ioc->name, ev->channel,
2738 ev->id, ev->phys_disk_num);
2739 vtarget->tflags &=
2740 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002741 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002742 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002743 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002744 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002745 break;
2746 }
2747
Eric Moore547f9a22006-06-27 14:42:12 -06002748 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302749 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002750 "%s: exit at line=%d\n", ioc->name,
2751 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002752 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002753 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002754 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002755
Eric Moore547f9a22006-06-27 14:42:12 -06002756 port = mptsas_get_port(phy_info);
2757 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302758 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002759 "%s: exit at line=%d\n", ioc->name,
2760 __FUNCTION__, __LINE__));
2761 break;
2762 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002763 memcpy(&phy_info->attached, &sas_device,
2764 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002765
Eric Mooreb506ade2007-01-29 09:45:37 -07002766 if (phy_info->attached.device_info &
2767 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002768 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002769 if (phy_info->attached.device_info &
2770 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002771 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002772 if (phy_info->attached.device_info &
2773 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002774 ds = "sata";
2775
2776 printk(MYIOC_s_INFO_FMT
2777 "attaching %s device, channel %d, id %d, phy %d\n",
2778 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2779
James Bottomleyf013db32006-03-18 14:54:36 -06002780 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002781 rphy = sas_end_device_alloc(port);
2782 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302783 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002784 "%s: exit at line=%d\n", ioc->name,
2785 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002786 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002787 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002788
James Bottomleyf013db32006-03-18 14:54:36 -06002789 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002790 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302791 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002792 "%s: exit at line=%d\n", ioc->name,
2793 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002794 sas_rphy_free(rphy);
2795 break;
2796 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302797 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002798 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002799 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002800 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2801 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002802 if (sdev) {
2803 scsi_device_put(sdev);
2804 break;
2805 }
2806 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002807 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002808 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2809 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002810 mpt_findImVolumes(ioc);
2811 break;
2812 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002813 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002814 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002815 if (!sdev)
2816 break;
2817 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002818 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002819 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002820 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002821 scsi_remove_device(sdev);
2822 scsi_device_put(sdev);
2823 mpt_findImVolumes(ioc);
2824 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002825 case MPTSAS_ADD_INACTIVE_VOLUME:
2826 mptsas_adding_inactive_raid_components(ioc,
2827 ev->channel, ev->id);
2828 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002829 case MPTSAS_IGNORE_EVENT:
2830 default:
2831 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002832 }
2833
Moore, Erice6b2d762006-03-14 09:14:24 -07002834 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002835 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002836}
2837
2838static void
Eric Moore547f9a22006-06-27 14:42:12 -06002839mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002840 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2841{
2842 struct mptsas_hotplug_event *ev;
2843 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2844 __le64 sas_address;
2845
2846 if ((device_info &
2847 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2848 MPI_SAS_DEVICE_INFO_STP_TARGET |
2849 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2850 return;
2851
Moore, Eric4b766472006-03-14 09:14:12 -07002852 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002853 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002854
2855 mptsas_target_reset_queue(ioc, sas_event_data);
2856 break;
2857
2858 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002859 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002860 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002861 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Eric4b766472006-03-14 09:14:12 -07002862 break;
2863 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002864
David Howellsc4028952006-11-22 14:57:56 +00002865 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002866 ev->ioc = ioc;
2867 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2868 ev->parent_handle =
2869 le16_to_cpu(sas_event_data->ParentDevHandle);
2870 ev->channel = sas_event_data->Bus;
2871 ev->id = sas_event_data->TargetID;
2872 ev->phy_id = sas_event_data->PhyNum;
2873 memcpy(&sas_address, &sas_event_data->SASAddress,
2874 sizeof(__le64));
2875 ev->sas_address = le64_to_cpu(sas_address);
2876 ev->device_info = device_info;
2877
2878 if (sas_event_data->ReasonCode &
2879 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2880 ev->event_type = MPTSAS_ADD_DEVICE;
2881 else
2882 ev->event_type = MPTSAS_DEL_DEVICE;
2883 schedule_work(&ev->work);
2884 break;
2885 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2886 /*
2887 * Persistent table is full.
2888 */
Eric Moore547f9a22006-06-27 14:42:12 -06002889 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002890 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002891 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002892 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002893 /*
2894 * TODO, handle other events
2895 */
Moore, Eric4b766472006-03-14 09:14:12 -07002896 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002897 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002898 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002899 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2900 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2901 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2902 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002903 default:
2904 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002905 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002906}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002907static void
Eric Moore547f9a22006-06-27 14:42:12 -06002908mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002909 EVENT_DATA_RAID *raid_event_data)
2910{
2911 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002912 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2913 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002914
2915 if (ioc->bus_type != SAS)
2916 return;
2917
Eric Moore547f9a22006-06-27 14:42:12 -06002918 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002919 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002920 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002921 return;
2922 }
2923
David Howellsc4028952006-11-22 14:57:56 +00002924 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002925 ev->ioc = ioc;
2926 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002927 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002928 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002929
2930 switch (raid_event_data->ReasonCode) {
2931 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002932 ev->phys_disk_num_valid = 1;
2933 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002934 ev->event_type = MPTSAS_ADD_DEVICE;
2935 break;
2936 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002937 ev->phys_disk_num_valid = 1;
2938 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002939 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002940 ev->event_type = MPTSAS_DEL_DEVICE;
2941 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002942 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2943 switch (state) {
2944 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002945 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002946 ev->phys_disk_num_valid = 1;
2947 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002948 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002949 ev->event_type = MPTSAS_ADD_DEVICE;
2950 break;
2951 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002952 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2953 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2954 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002955 ev->phys_disk_num_valid = 1;
2956 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002957 ev->event_type = MPTSAS_DEL_DEVICE;
2958 break;
2959 default:
2960 break;
2961 }
2962 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002963 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2964 ev->event_type = MPTSAS_DEL_RAID;
2965 break;
2966 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2967 ev->event_type = MPTSAS_ADD_RAID;
2968 break;
2969 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002970 switch (state) {
2971 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2972 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2973 ev->event_type = MPTSAS_DEL_RAID;
2974 break;
2975 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2976 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2977 ev->event_type = MPTSAS_ADD_RAID;
2978 break;
2979 default:
2980 break;
2981 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002982 break;
2983 default:
2984 break;
2985 }
2986 schedule_work(&ev->work);
2987}
2988
Moore, Erice6b2d762006-03-14 09:14:24 -07002989static void
Eric Moore547f9a22006-06-27 14:42:12 -06002990mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002991 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2992{
2993 struct mptsas_discovery_event *ev;
2994
2995 /*
2996 * DiscoveryStatus
2997 *
2998 * This flag will be non-zero when firmware
2999 * kicks off discovery, and return to zero
3000 * once its completed.
3001 */
3002 if (discovery_data->DiscoveryStatus)
3003 return;
3004
Eric Moore547f9a22006-06-27 14:42:12 -06003005 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07003006 if (!ev)
3007 return;
David Howellsc4028952006-11-22 14:57:56 +00003008 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07003009 ev->ioc = ioc;
3010 schedule_work(&ev->work);
3011};
3012
Eric Mooreb506ade2007-01-29 09:45:37 -07003013/*
3014 * mptsas_send_ir2_event - handle exposing hidden disk when
3015 * an inactive raid volume is added
3016 *
3017 * @ioc: Pointer to MPT_ADAPTER structure
3018 * @ir2_data
3019 *
3020 */
3021static void
3022mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
3023{
3024 struct mptsas_hotplug_event *ev;
3025
3026 if (ir2_data->ReasonCode !=
3027 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
3028 return;
3029
3030 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
3031 if (!ev)
3032 return;
3033
3034 INIT_WORK(&ev->work, mptsas_hotplug_work);
3035 ev->ioc = ioc;
3036 ev->id = ir2_data->TargetID;
3037 ev->channel = ir2_data->Bus;
3038 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3039
3040 schedule_work(&ev->work);
3041};
Moore, Erice6b2d762006-03-14 09:14:24 -07003042
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003043static int
3044mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3045{
Moore, Ericc73787ee2006-01-26 16:20:06 -07003046 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003047 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3048
3049 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003050 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003051
Moore, Erice6b2d762006-03-14 09:14:24 -07003052 /*
3053 * sas_discovery_ignore_events
3054 *
3055 * This flag is to prevent anymore processing of
3056 * sas events once mptsas_remove function is called.
3057 */
3058 if (ioc->sas_discovery_ignore_events) {
3059 rc = mptscsih_event_process(ioc, reply);
3060 goto out;
3061 }
3062
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003063 switch (event) {
3064 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003065 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003066 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003067 break;
3068 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003069 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003070 (EVENT_DATA_RAID *)reply->Data);
3071 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003072 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003073 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003074 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003075 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003076 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003077 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003078 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003079 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3080 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003081 case MPI_EVENT_IR2:
3082 mptsas_send_ir2_event(ioc,
3083 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3084 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003085 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003086 rc = mptscsih_event_process(ioc, reply);
3087 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003088 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003089 out:
3090
3091 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003092}
3093
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003094static int
3095mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3096{
3097 struct Scsi_Host *sh;
3098 MPT_SCSI_HOST *hd;
3099 MPT_ADAPTER *ioc;
3100 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003101 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003102 int numSGE = 0;
3103 int scale;
3104 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003105 int error=0;
3106 int r;
3107
3108 r = mpt_attach(pdev,id);
3109 if (r)
3110 return r;
3111
3112 ioc = pci_get_drvdata(pdev);
3113 ioc->DoneCtx = mptsasDoneCtx;
3114 ioc->TaskCtx = mptsasTaskCtx;
3115 ioc->InternalCtx = mptsasInternalCtx;
3116
3117 /* Added sanity check on readiness of the MPT adapter.
3118 */
3119 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3120 printk(MYIOC_s_WARN_FMT
3121 "Skipping because it's not operational!\n",
3122 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003123 error = -ENODEV;
3124 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003125 }
3126
3127 if (!ioc->active) {
3128 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\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 /* Sanity check - ensure at least 1 port is INITIATOR capable
3135 */
3136 ioc_cap = 0;
3137 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3138 if (ioc->pfacts[ii].ProtocolFlags &
3139 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3140 ioc_cap++;
3141 }
3142
3143 if (!ioc_cap) {
3144 printk(MYIOC_s_WARN_FMT
3145 "Skipping ioc=%p because SCSI Initiator mode "
3146 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003147 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003148 }
3149
3150 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3151 if (!sh) {
3152 printk(MYIOC_s_WARN_FMT
3153 "Unable to register controller with SCSI subsystem\n",
3154 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003155 error = -1;
3156 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003157 }
3158
3159 spin_lock_irqsave(&ioc->FreeQlock, flags);
3160
3161 /* Attach the SCSI Host to the IOC structure
3162 */
3163 ioc->sh = sh;
3164
3165 sh->io_port = 0;
3166 sh->n_io_port = 0;
3167 sh->irq = 0;
3168
3169 /* set 16 byte cdb's */
3170 sh->max_cmd_len = 16;
3171
Eric Moore793955f2007-01-29 09:42:20 -07003172 sh->max_id = ioc->pfacts[0].PortSCSIID;
3173 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003174
3175 sh->transportt = mptsas_transport_template;
3176
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003177 sh->this_id = ioc->pfacts[0].PortSCSIID;
3178
3179 /* Required entry.
3180 */
3181 sh->unique_id = ioc->id;
3182
3183 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003184 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003185 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003186 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003187 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003188
3189 /* Verify that we won't exceed the maximum
3190 * number of chain buffers
3191 * We can optimize: ZZ = req_sz/sizeof(SGE)
3192 * For 32bit SGE's:
3193 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3194 * + (req_sz - 64)/sizeof(SGE)
3195 * A slightly different algorithm is required for
3196 * 64bit SGEs.
3197 */
3198 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3199 if (sizeof(dma_addr_t) == sizeof(u64)) {
3200 numSGE = (scale - 1) *
3201 (ioc->facts.MaxChainDepth-1) + scale +
3202 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3203 sizeof(u32));
3204 } else {
3205 numSGE = 1 + (scale - 1) *
3206 (ioc->facts.MaxChainDepth-1) + scale +
3207 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3208 sizeof(u32));
3209 }
3210
3211 if (numSGE < sh->sg_tablesize) {
3212 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303213 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003214 "Resetting sg_tablesize to %d from %d\n",
3215 ioc->name, numSGE, sh->sg_tablesize));
3216 sh->sg_tablesize = numSGE;
3217 }
3218
Eric Mooree7eae9f2007-09-29 10:15:59 -06003219 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003220 hd->ioc = ioc;
3221
3222 /* SCSI needs scsi_cmnd lookup table!
3223 * (with size equal to req_depth*PtrSz!)
3224 */
Eric Mooree8206382007-09-29 10:16:53 -06003225 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3226 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003227 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06003228 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003229 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003230 }
Eric Mooree8206382007-09-29 10:16:53 -06003231 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003232
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303233 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06003234 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003235
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003236 /* Clear the TM flags
3237 */
3238 hd->tmPending = 0;
3239 hd->tmState = TM_STATE_NONE;
3240 hd->resetPending = 0;
3241 hd->abortSCpnt = NULL;
3242
3243 /* Clear the pointer used to store
3244 * single-threaded commands, i.e., those
3245 * issued during a bus scan, dv and
3246 * configuration pages.
3247 */
3248 hd->cmdPtr = NULL;
3249
3250 /* Initialize this SCSI Hosts' timers
3251 * To use, set the timer expires field
3252 * and add_timer
3253 */
3254 init_timer(&hd->timer);
3255 hd->timer.data = (unsigned long) hd;
3256 hd->timer.function = mptscsih_timer_expired;
3257
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003258 ioc->sas_data.ptClear = mpt_pt_clear;
3259
Eric Mooredf9e0622007-01-29 09:46:21 -07003260 init_waitqueue_head(&hd->scandv_waitq);
3261 hd->scandv_wait_done = 0;
3262 hd->last_queue_full = 0;
3263 INIT_LIST_HEAD(&hd->target_reset_list);
3264 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3265
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003266 if (ioc->sas_data.ptClear==1) {
3267 mptbase_sas_persist_operation(
3268 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3269 }
3270
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003271 error = scsi_add_host(sh, &ioc->pcidev->dev);
3272 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06003273 dprintk(ioc, printk(MYIOC_s_ERR_FMT
3274 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003275 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003276 }
3277
3278 mptsas_scan_sas_topology(ioc);
3279
3280 return 0;
3281
Eric Moore547f9a22006-06-27 14:42:12 -06003282 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003283
3284 mptscsih_remove(pdev);
3285 return error;
3286}
3287
3288static void __devexit mptsas_remove(struct pci_dev *pdev)
3289{
3290 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3291 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003292 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003293
Eric Mooreb506ade2007-01-29 09:45:37 -07003294 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003295 sas_remove_host(ioc->sh);
3296
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003297 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003298 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3299 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003300 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303301 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003302 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003303 kfree(p);
3304 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003305 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003306
3307 mptscsih_remove(pdev);
3308}
3309
3310static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003311 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003312 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003313 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003314 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003315 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003316 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003317 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003318 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003319 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003320 PCI_ANY_ID, PCI_ANY_ID },
3321 {0} /* Terminating entry */
3322};
3323MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3324
3325
3326static struct pci_driver mptsas_driver = {
3327 .name = "mptsas",
3328 .id_table = mptsas_pci_table,
3329 .probe = mptsas_probe,
3330 .remove = __devexit_p(mptsas_remove),
3331 .shutdown = mptscsih_shutdown,
3332#ifdef CONFIG_PM
3333 .suspend = mptscsih_suspend,
3334 .resume = mptscsih_resume,
3335#endif
3336};
3337
3338static int __init
3339mptsas_init(void)
3340{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303341 int error;
3342
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003343 show_mptmod_ver(my_NAME, my_VERSION);
3344
3345 mptsas_transport_template =
3346 sas_attach_transport(&mptsas_transport_functions);
3347 if (!mptsas_transport_template)
3348 return -ENODEV;
3349
3350 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003351 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003352 mptsasInternalCtx =
3353 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003354 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003355
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303356 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3357 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003358
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303359 error = pci_register_driver(&mptsas_driver);
3360 if (error)
3361 sas_release_transport(mptsas_transport_template);
3362
3363 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003364}
3365
3366static void __exit
3367mptsas_exit(void)
3368{
3369 pci_unregister_driver(&mptsas_driver);
3370 sas_release_transport(mptsas_transport_template);
3371
3372 mpt_reset_deregister(mptsasDoneCtx);
3373 mpt_event_deregister(mptsasDoneCtx);
3374
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003375 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003376 mpt_deregister(mptsasInternalCtx);
3377 mpt_deregister(mptsasTaskCtx);
3378 mpt_deregister(mptsasDoneCtx);
3379}
3380
3381module_init(mptsas_init);
3382module_exit(mptsas_exit);