blob: 1dfe7d713aead51e69906f2a905bac859401c8f5 [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)
Eric Moore9f4203b2007-01-04 20:47:47 -07008 * Copyright (c) 2005-2007 Dell
Christoph Hellwig0c33b272005-09-09 16:27:19 +02009 */
10/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
11/*
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; version 2 of the License.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 NO WARRANTY
22 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
23 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
24 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
25 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
26 solely responsible for determining the appropriateness of using and
27 distributing the Program and assumes all risks associated with its
28 exercise of rights under this Agreement, including but not limited to
29 the risks and costs of program errors, damage to or loss of data,
30 programs or equipment, and unavailability or interruption of operations.
31
32 DISCLAIMER OF LIABILITY
33 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
36 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
38 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
39 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
40
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
44*/
45/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
46
47#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/init.h>
50#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080051#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020052#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060053#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020054
Eric Moore547f9a22006-06-27 14:42:12 -060055#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020056#include <scsi/scsi_cmnd.h>
57#include <scsi/scsi_device.h>
58#include <scsi/scsi_host.h>
59#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060060#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020061
62#include "mptbase.h"
63#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053064#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020065
66
67#define my_NAME "Fusion MPT SAS Host driver"
68#define my_VERSION MPT_LINUX_VERSION_COMMON
69#define MYNAM "mptsas"
70
James Bottomleye8bf3942006-07-11 17:49:34 -040071/*
72 * Reserved channel for integrated raid
73 */
74#define MPTSAS_RAID_CHANNEL 1
75
Christoph Hellwig0c33b272005-09-09 16:27:19 +020076MODULE_AUTHOR(MODULEAUTHOR);
77MODULE_DESCRIPTION(my_NAME);
78MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070079MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080
Christoph Hellwig0c33b272005-09-09 16:27:19 +020081static int mpt_pt_clear;
82module_param(mpt_pt_clear, int, 0);
83MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060084 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020085 "(default=MPTSCSIH_PT_CLEAR=0)");
86
Eric Moore793955f2007-01-29 09:42:20 -070087/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
88#define MPTSAS_MAX_LUN (16895)
89static int max_lun = MPTSAS_MAX_LUN;
90module_param(max_lun, int, 0);
91MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
92
Prakash, Sathyaf606f572007-08-14 16:12:53 +053093static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
95static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
96static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020097
Eric Mooreb506ade2007-01-29 09:45:37 -070098static void mptsas_hotplug_work(struct work_struct *work);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020099
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530100static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
101 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200102{
Eric Moore29dd3602007-09-14 18:46:51 -0600103 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
104 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
105 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
106 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
107 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
108 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
109 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
110 ioc->name, phy_data->Port));
111 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
112 ioc->name, phy_data->PortFlags));
113 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
114 ioc->name, phy_data->PhyFlags));
115 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
116 ioc->name, phy_data->NegotiatedLinkRate));
117 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
118 "Controller PHY Device Info=0x%X\n", ioc->name,
119 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
120 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
121 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200122}
123
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530124static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200125{
126 __le64 sas_address;
127
128 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
129
Eric Moore29dd3602007-09-14 18:46:51 -0600130 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
131 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
132 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
133 "Attached Device Handle=0x%X\n", ioc->name,
134 le16_to_cpu(pg0->AttachedDevHandle)));
135 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
136 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
137 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
138 "Attached PHY Identifier=0x%X\n", ioc->name,
139 pg0->AttachedPhyIdentifier));
140 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
141 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
142 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
143 ioc->name, pg0->ProgrammedLinkRate));
144 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
145 ioc->name, pg0->ChangeCount));
146 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
147 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200148}
149
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530150static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200151{
Eric Moore29dd3602007-09-14 18:46:51 -0600152 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
153 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
154 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
155 ioc->name, pg1->InvalidDwordCount));
156 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
157 "Running Disparity Error Count=0x%x\n", ioc->name,
158 pg1->RunningDisparityErrorCount));
159 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
160 "Loss Dword Synch Count=0x%x\n", ioc->name,
161 pg1->LossDwordSynchCount));
162 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
163 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
164 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200165}
166
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530167static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200168{
169 __le64 sas_address;
170
171 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
172
Eric Moore29dd3602007-09-14 18:46:51 -0600173 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
174 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
175 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
176 ioc->name, le16_to_cpu(pg0->DevHandle)));
177 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
178 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
179 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
180 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
181 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
182 ioc->name, le16_to_cpu(pg0->Slot)));
183 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
184 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
185 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
186 ioc->name, pg0->TargetID));
187 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
188 ioc->name, pg0->Bus));
189 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
190 ioc->name, pg0->PhyNum));
191 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
192 ioc->name, le16_to_cpu(pg0->AccessStatus)));
193 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
194 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
195 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
196 ioc->name, le16_to_cpu(pg0->Flags)));
197 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
198 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200199}
200
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530201static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200202{
Eric Moore29dd3602007-09-14 18:46:51 -0600203 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
204 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
205 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
206 ioc->name, pg1->PhysicalPort));
207 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
208 ioc->name, pg1->PhyIdentifier));
209 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
210 ioc->name, pg1->NegotiatedLinkRate));
211 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
212 ioc->name, pg1->ProgrammedLinkRate));
213 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
214 ioc->name, pg1->HwLinkRate));
215 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
216 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
217 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
218 "Attached Device Handle=0x%X\n\n", ioc->name,
219 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200220}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200221
Christoph Hellwige3094442006-02-16 13:25:36 +0100222static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
223{
224 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
225 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
226}
227
228static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
229{
230 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
231 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
232}
233
Moore, Erice6b2d762006-03-14 09:14:24 -0700234/*
235 * mptsas_find_portinfo_by_handle
236 *
237 * This function should be called with the sas_topology_mutex already held
238 */
239static struct mptsas_portinfo *
240mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
241{
242 struct mptsas_portinfo *port_info, *rc=NULL;
243 int i;
244
245 list_for_each_entry(port_info, &ioc->sas_topology, list)
246 for (i = 0; i < port_info->num_phys; i++)
247 if (port_info->phy_info[i].identify.handle == handle) {
248 rc = port_info;
249 goto out;
250 }
251 out:
252 return rc;
253}
254
Moore, Ericbd23e942006-04-17 12:43:04 -0600255/*
256 * Returns true if there is a scsi end device
257 */
258static inline int
259mptsas_is_end_device(struct mptsas_devinfo * attached)
260{
Eric Moore547f9a22006-06-27 14:42:12 -0600261 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600262 (attached->device_info &
263 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
264 ((attached->device_info &
265 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
266 (attached->device_info &
267 MPI_SAS_DEVICE_INFO_STP_TARGET) |
268 (attached->device_info &
269 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
270 return 1;
271 else
272 return 0;
273}
274
Eric Moore547f9a22006-06-27 14:42:12 -0600275/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600276static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530277mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600278{
279 struct mptsas_portinfo *port_info;
280 struct mptsas_phyinfo *phy_info;
281 u8 i;
282
283 if (!port_details)
284 return;
285
286 port_info = port_details->port_info;
287 phy_info = port_info->phy_info;
288
Eric Moore29dd3602007-09-14 18:46:51 -0600289 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
290 "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700291 port_details->num_phys, (unsigned long long)
292 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600293
294 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
295 if(phy_info->port_details != port_details)
296 continue;
297 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
298 phy_info->port_details = NULL;
299 }
300 kfree(port_details);
301}
302
303static inline struct sas_rphy *
304mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
305{
306 if (phy_info->port_details)
307 return phy_info->port_details->rphy;
308 else
309 return NULL;
310}
311
312static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530313mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600314{
315 if (phy_info->port_details) {
316 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600317 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
318 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600319 }
320
Eric Moore547f9a22006-06-27 14:42:12 -0600321 if (rphy) {
Eric Moore29dd3602007-09-14 18:46:51 -0600322 dsaswideprintk(ioc, dev_printk(MYIOC_s_DEBUG_FMT,
323 &rphy->dev, "add:", ioc->name));
324 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
325 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600326 }
Eric Moore547f9a22006-06-27 14:42:12 -0600327}
328
329static inline struct sas_port *
330mptsas_get_port(struct mptsas_phyinfo *phy_info)
331{
332 if (phy_info->port_details)
333 return phy_info->port_details->port;
334 else
335 return NULL;
336}
337
338static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530339mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600340{
341 if (phy_info->port_details)
342 phy_info->port_details->port = port;
343
Eric Moore547f9a22006-06-27 14:42:12 -0600344 if (port) {
Eric Moore29dd3602007-09-14 18:46:51 -0600345 dsaswideprintk(ioc, dev_printk(MYIOC_s_DEBUG_FMT,
346 &port->dev, "add:", ioc->name));
347 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
348 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600349 }
Eric Moore547f9a22006-06-27 14:42:12 -0600350}
351
352static inline struct scsi_target *
353mptsas_get_starget(struct mptsas_phyinfo *phy_info)
354{
355 if (phy_info->port_details)
356 return phy_info->port_details->starget;
357 else
358 return NULL;
359}
360
361static inline void
362mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
363starget)
364{
365 if (phy_info->port_details)
366 phy_info->port_details->starget = starget;
367}
368
369
370/*
371 * mptsas_setup_wide_ports
372 *
373 * Updates for new and existing narrow/wide port configuration
374 * in the sas_topology
375 */
Eric Moore376ac832006-06-29 17:36:26 -0600376static void
Eric Moore547f9a22006-06-27 14:42:12 -0600377mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
378{
379 struct mptsas_portinfo_details * port_details;
380 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
381 u64 sas_address;
382 int i, j;
383
384 mutex_lock(&ioc->sas_topology_mutex);
385
386 phy_info = port_info->phy_info;
387 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
388 if (phy_info->attached.handle)
389 continue;
390 port_details = phy_info->port_details;
391 if (!port_details)
392 continue;
393 if (port_details->num_phys < 2)
394 continue;
395 /*
396 * Removing a phy from a port, letting the last
397 * phy be removed by firmware events.
398 */
Eric Moore29dd3602007-09-14 18:46:51 -0600399 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
400 "%s: [%p]: deleting phy = %d\n",
401 ioc->name, __FUNCTION__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600402 port_details->num_phys--;
403 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
404 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
405 sas_port_delete_phy(port_details->port, phy_info->phy);
406 phy_info->port_details = NULL;
407 }
408
409 /*
410 * Populate and refresh the tree
411 */
412 phy_info = port_info->phy_info;
413 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
414 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600415 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
416 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600417 if (!sas_address)
418 continue;
419 port_details = phy_info->port_details;
420 /*
421 * Forming a port
422 */
423 if (!port_details) {
424 port_details = kzalloc(sizeof(*port_details),
425 GFP_KERNEL);
426 if (!port_details)
427 goto out;
428 port_details->num_phys = 1;
429 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600430 if (phy_info->phy_id < 64 )
431 port_details->phy_bitmask |=
432 (1 << phy_info->phy_id);
433 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600434 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700435 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600436 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600437 phy_info->port_details = port_details;
438 }
439
440 if (i == port_info->num_phys - 1)
441 continue;
442 phy_info_cmp = &port_info->phy_info[i + 1];
443 for (j = i + 1 ; j < port_info->num_phys ; j++,
444 phy_info_cmp++) {
445 if (!phy_info_cmp->attached.sas_address)
446 continue;
447 if (sas_address != phy_info_cmp->attached.sas_address)
448 continue;
449 if (phy_info_cmp->port_details == port_details )
450 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600451 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700452 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600453 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700454 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600455 if (phy_info_cmp->port_details) {
456 port_details->rphy =
457 mptsas_get_rphy(phy_info_cmp);
458 port_details->port =
459 mptsas_get_port(phy_info_cmp);
460 port_details->starget =
461 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600462 port_details->num_phys =
463 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600464 if (!phy_info_cmp->port_details->num_phys)
465 kfree(phy_info_cmp->port_details);
466 } else
467 phy_info_cmp->sas_port_add_phy=1;
468 /*
469 * Adding a phy to a port
470 */
471 phy_info_cmp->port_details = port_details;
472 if (phy_info_cmp->phy_id < 64 )
473 port_details->phy_bitmask |=
474 (1 << phy_info_cmp->phy_id);
475 port_details->num_phys++;
476 }
477 }
478
479 out:
480
Eric Moore547f9a22006-06-27 14:42:12 -0600481 for (i = 0; i < port_info->num_phys; i++) {
482 port_details = port_info->phy_info[i].port_details;
483 if (!port_details)
484 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600485 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700486 "%s: [%p]: phy_id=%02d num_phys=%02d "
Eric Moore29dd3602007-09-14 18:46:51 -0600487 "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
Eric Mooref99be432007-01-04 20:46:54 -0700488 port_details, i, port_details->num_phys,
489 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600490 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
491 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600492 }
Eric Moore29dd3602007-09-14 18:46:51 -0600493 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600494 mutex_unlock(&ioc->sas_topology_mutex);
495}
496
Eric Mooredf9e0622007-01-29 09:46:21 -0700497/**
498 * csmisas_find_vtarget
499 *
500 * @ioc
501 * @volume_id
502 * @volume_bus
503 *
504 **/
505static VirtTarget *
506mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600507{
Eric Mooredf9e0622007-01-29 09:46:21 -0700508 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600509 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700510 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600511
Eric Mooredf9e0622007-01-29 09:46:21 -0700512 shost_for_each_device(sdev, ioc->sh) {
Eric Moorea69de502007-09-14 18:48:19 -0600513 if ((vdevice = sdev->hostdata) == NULL)
Eric Mooredf9e0622007-01-29 09:46:21 -0700514 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600515 if (vdevice->vtarget->id == id &&
516 vdevice->vtarget->channel == channel)
517 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600518 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700519 return vtarget;
520}
521
522/**
523 * mptsas_target_reset
524 *
525 * Issues TARGET_RESET to end device using handshaking method
526 *
527 * @ioc
528 * @channel
529 * @id
530 *
531 * Returns (1) success
532 * (0) failure
533 *
534 **/
535static int
536mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
537{
538 MPT_FRAME_HDR *mf;
539 SCSITaskMgmt_t *pScsiTm;
540
541 if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530542 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700543 ioc->name,__FUNCTION__, __LINE__));
544 return 0;
545 }
546
547 /* Format the Request
548 */
549 pScsiTm = (SCSITaskMgmt_t *) mf;
550 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
551 pScsiTm->TargetID = id;
552 pScsiTm->Bus = channel;
553 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
554 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
555 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
556
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530557 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700558
Prakash, Sathya7a195f42007-08-14 16:08:40 +0530559 mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -0700560
561 return 1;
562}
563
564/**
565 * mptsas_target_reset_queue
566 *
567 * Receive request for TARGET_RESET after recieving an firmware
568 * event NOT_RESPONDING_EVENT, then put command in link list
569 * and queue if task_queue already in use.
570 *
571 * @ioc
572 * @sas_event_data
573 *
574 **/
575static void
576mptsas_target_reset_queue(MPT_ADAPTER *ioc,
577 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
578{
579 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
580 VirtTarget *vtarget = NULL;
581 struct mptsas_target_reset_event *target_reset_list;
582 u8 id, channel;
583
584 id = sas_event_data->TargetID;
585 channel = sas_event_data->Bus;
586
587 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
588 return;
589
590 vtarget->deleted = 1; /* block IO */
591
592 target_reset_list = kzalloc(sizeof(*target_reset_list),
593 GFP_ATOMIC);
594 if (!target_reset_list) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530595 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700596 ioc->name,__FUNCTION__, __LINE__));
597 return;
598 }
599
600 memcpy(&target_reset_list->sas_event_data, sas_event_data,
601 sizeof(*sas_event_data));
602 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
603
604 if (hd->resetPending)
605 return;
606
607 if (mptsas_target_reset(ioc, channel, id)) {
608 target_reset_list->target_reset_issued = 1;
609 hd->resetPending = 1;
610 }
611}
612
613/**
614 * mptsas_dev_reset_complete
615 *
616 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
617 * enable work queue to finish off removing device from upper layers.
618 * then send next TARGET_RESET in the queue.
619 *
620 * @ioc
621 *
622 **/
623static void
624mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
625{
626 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
627 struct list_head *head = &hd->target_reset_list;
628 struct mptsas_target_reset_event *target_reset_list;
629 struct mptsas_hotplug_event *ev;
630 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
631 u8 id, channel;
632 __le64 sas_address;
633
634 if (list_empty(head))
635 return;
636
637 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
638
639 sas_event_data = &target_reset_list->sas_event_data;
640 id = sas_event_data->TargetID;
641 channel = sas_event_data->Bus;
642 hd->resetPending = 0;
643
644 /*
645 * retry target reset
646 */
647 if (!target_reset_list->target_reset_issued) {
648 if (mptsas_target_reset(ioc, channel, id)) {
649 target_reset_list->target_reset_issued = 1;
650 hd->resetPending = 1;
651 }
652 return;
653 }
654
655 /*
656 * enable work queue to remove device from upper layers
657 */
658 list_del(&target_reset_list->list);
659
660 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
661 if (!ev) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530662 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
Eric Mooredf9e0622007-01-29 09:46:21 -0700663 ioc->name,__FUNCTION__, __LINE__));
664 return;
665 }
666
667 INIT_WORK(&ev->work, mptsas_hotplug_work);
668 ev->ioc = ioc;
669 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
670 ev->parent_handle =
671 le16_to_cpu(sas_event_data->ParentDevHandle);
672 ev->channel = channel;
673 ev->id =id;
674 ev->phy_id = sas_event_data->PhyNum;
675 memcpy(&sas_address, &sas_event_data->SASAddress,
676 sizeof(__le64));
677 ev->sas_address = le64_to_cpu(sas_address);
678 ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
679 ev->event_type = MPTSAS_DEL_DEVICE;
680 schedule_work(&ev->work);
681 kfree(target_reset_list);
682
683 /*
684 * issue target reset to next device in the queue
685 */
686
687 head = &hd->target_reset_list;
688 if (list_empty(head))
689 return;
690
691 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
692 list);
693
694 sas_event_data = &target_reset_list->sas_event_data;
695 id = sas_event_data->TargetID;
696 channel = sas_event_data->Bus;
697
698 if (mptsas_target_reset(ioc, channel, id)) {
699 target_reset_list->target_reset_issued = 1;
700 hd->resetPending = 1;
701 }
702}
703
704/**
705 * mptsas_taskmgmt_complete
706 *
707 * @ioc
708 * @mf
709 * @mr
710 *
711 **/
712static int
713mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
714{
715 mptsas_dev_reset_complete(ioc);
716 return mptscsih_taskmgmt_complete(ioc, mf, mr);
717}
718
719/**
720 * mptscsih_ioc_reset
721 *
722 * @ioc
723 * @reset_phase
724 *
725 **/
726static int
727mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
728{
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800729 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -0700730 struct mptsas_target_reset_event *target_reset_list, *n;
731 int rc;
732
733 rc = mptscsih_ioc_reset(ioc, reset_phase);
734
735 if (ioc->bus_type != SAS)
736 goto out;
737
738 if (reset_phase != MPT_IOC_POST_RESET)
739 goto out;
740
Judith Lebzelterba76ef22007-03-09 13:07:44 -0800741 if (!ioc->sh || !ioc->sh->hostdata)
742 goto out;
743 hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
744 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -0700745 goto out;
746
747 if (list_empty(&hd->target_reset_list))
748 goto out;
749
750 /* flush the target_reset_list */
751 list_for_each_entry_safe(target_reset_list, n,
752 &hd->target_reset_list, list) {
753 list_del(&target_reset_list->list);
754 kfree(target_reset_list);
755 }
756
757 out:
758 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -0600759}
760
Christoph Hellwige3094442006-02-16 13:25:36 +0100761static int
Moore, Eric52435432006-03-14 09:14:15 -0700762mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +0100763 u32 form, u32 form_specific)
764{
765 ConfigExtendedPageHeader_t hdr;
766 CONFIGPARMS cfg;
767 SasEnclosurePage0_t *buffer;
768 dma_addr_t dma_handle;
769 int error;
770 __le64 le_identifier;
771
772 memset(&hdr, 0, sizeof(hdr));
773 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
774 hdr.PageNumber = 0;
775 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
776 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
777
778 cfg.cfghdr.ehdr = &hdr;
779 cfg.physAddr = -1;
780 cfg.pageAddr = form + form_specific;
781 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
782 cfg.dir = 0; /* read */
783 cfg.timeout = 10;
784
785 error = mpt_config(ioc, &cfg);
786 if (error)
787 goto out;
788 if (!hdr.ExtPageLength) {
789 error = -ENXIO;
790 goto out;
791 }
792
793 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
794 &dma_handle);
795 if (!buffer) {
796 error = -ENOMEM;
797 goto out;
798 }
799
800 cfg.physAddr = dma_handle;
801 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
802
803 error = mpt_config(ioc, &cfg);
804 if (error)
805 goto out_free_consistent;
806
807 /* save config data */
808 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
809 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
810 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
811 enclosure->flags = le16_to_cpu(buffer->Flags);
812 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
813 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
814 enclosure->start_id = buffer->StartTargetID;
815 enclosure->start_channel = buffer->StartBus;
816 enclosure->sep_id = buffer->SEPTargetID;
817 enclosure->sep_channel = buffer->SEPBus;
818
819 out_free_consistent:
820 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
821 buffer, dma_handle);
822 out:
823 return error;
824}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200825
James Bottomleyf013db32006-03-18 14:54:36 -0600826static int
827mptsas_slave_configure(struct scsi_device *sdev)
828{
Moore, Eric3c0c25b2006-04-13 16:08:17 -0600829
James Bottomleye8bf3942006-07-11 17:49:34 -0400830 if (sdev->channel == MPTSAS_RAID_CHANNEL)
831 goto out;
James Bottomleyf013db32006-03-18 14:54:36 -0600832
James Bottomleye8bf3942006-07-11 17:49:34 -0400833 sas_read_port_mode_page(sdev);
834
835 out:
James Bottomleyf013db32006-03-18 14:54:36 -0600836 return mptscsih_slave_configure(sdev);
837}
838
Eric Moore547f9a22006-06-27 14:42:12 -0600839static int
840mptsas_target_alloc(struct scsi_target *starget)
841{
842 struct Scsi_Host *host = dev_to_shost(&starget->dev);
843 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
844 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -0700845 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -0600846 struct sas_rphy *rphy;
847 struct mptsas_portinfo *p;
848 int i;
849
850 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
851 if (!vtarget)
852 return -ENOMEM;
853
854 vtarget->starget = starget;
855 vtarget->ioc_id = hd->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) {
864 for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
865 if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
866 channel = hd->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);
871 mutex_lock(&hd->ioc->sas_topology_mutex);
872 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
873 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 Moore793955f2007-01-29 09:42:20 -0700884 if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
885 id = mptscsih_raid_id_to_num(hd->ioc,
886 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 }
891 mutex_unlock(&hd->ioc->sas_topology_mutex);
892 goto out;
893 }
894 }
895 mutex_unlock(&hd->ioc->sas_topology_mutex);
896
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);
911 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
912 struct sas_rphy *rphy;
913 struct mptsas_portinfo *p;
914 int i;
915
916 if (!starget->hostdata)
917 return;
918
James Bottomleye8bf3942006-07-11 17:49:34 -0400919 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -0600920 goto out;
921
922 rphy = dev_to_rphy(starget->dev.parent);
923 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
924 for (i = 0; i < p->num_phys; i++) {
925 if (p->phy_info[i].attached.sas_address !=
926 rphy->identify.sas_address)
927 continue;
928 mptsas_set_starget(&p->phy_info[i], NULL);
929 goto out;
930 }
931 }
932
933 out:
934 kfree(starget->hostdata);
935 starget->hostdata = NULL;
936}
937
938
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200939static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700940mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200941{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700942 struct Scsi_Host *host = sdev->host;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200943 MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
944 struct sas_rphy *rphy;
945 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -0600946 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700947 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -0600948 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200949
Eric Moorea69de502007-09-14 18:48:19 -0600950 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
951 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -0600952 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200953 hd->ioc->name, sizeof(VirtDevice));
954 return -ENOMEM;
955 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700956 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -0600957 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200958
James Bottomleye8bf3942006-07-11 17:49:34 -0400959 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -0700960 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -0700961
Moore, Eric Deanc7c82982005-11-16 18:54:25 -0700962 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100963 mutex_lock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200964 list_for_each_entry(p, &hd->ioc->sas_topology, list) {
965 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -0600966 if (p->phy_info[i].attached.sas_address !=
967 rphy->identify.sas_address)
968 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600969 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -0600970 /*
971 * Exposing hidden raid components
972 */
973 if (mptscsih_is_phys_disk(hd->ioc,
Eric Moore793955f2007-01-29 09:42:20 -0700974 p->phy_info[i].attached.channel,
975 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -0600976 sdev->no_uld_attach = 1;
977 mutex_unlock(&hd->ioc->sas_topology_mutex);
978 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200979 }
980 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100981 mutex_unlock(&hd->ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200982
Eric Moorea69de502007-09-14 18:48:19 -0600983 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +0100984 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200985
986 out:
Eric Moorea69de502007-09-14 18:48:19 -0600987 vdevice->vtarget->num_luns++;
988 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200989 return 0;
990}
991
Eric Moore547f9a22006-06-27 14:42:12 -0600992static int
993mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100994{
Eric Moorea69de502007-09-14 18:48:19 -0600995 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +0100996
Eric Moorea69de502007-09-14 18:48:19 -0600997 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -0600998 SCpnt->result = DID_NO_CONNECT << 16;
999 done(SCpnt);
1000 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001001 }
Eric Moore547f9a22006-06-27 14:42:12 -06001002
Eric Moore793955f2007-01-29 09:42:20 -07001003// scsi_print_command(SCpnt);
1004
Eric Moore547f9a22006-06-27 14:42:12 -06001005 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001006}
1007
Eric Moore547f9a22006-06-27 14:42:12 -06001008
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001009static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001010 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001011 .proc_name = "mptsas",
1012 .proc_info = mptscsih_proc_info,
1013 .name = "MPT SPI Host",
1014 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001015 .queuecommand = mptsas_qcmd,
1016 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001017 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001018 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001019 .target_destroy = mptsas_target_destroy,
1020 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001021 .change_queue_depth = mptscsih_change_queue_depth,
1022 .eh_abort_handler = mptscsih_abort,
1023 .eh_device_reset_handler = mptscsih_dev_reset,
1024 .eh_bus_reset_handler = mptscsih_bus_reset,
1025 .eh_host_reset_handler = mptscsih_host_reset,
1026 .bios_param = mptscsih_bios_param,
1027 .can_queue = MPT_FC_CAN_QUEUE,
1028 .this_id = -1,
1029 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1030 .max_sectors = 8192,
1031 .cmd_per_lun = 7,
1032 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301033 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001034};
1035
Christoph Hellwigb5141122005-10-28 22:07:41 +02001036static int mptsas_get_linkerrors(struct sas_phy *phy)
1037{
1038 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1039 ConfigExtendedPageHeader_t hdr;
1040 CONFIGPARMS cfg;
1041 SasPhyPage1_t *buffer;
1042 dma_addr_t dma_handle;
1043 int error;
1044
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001045 /* FIXME: only have link errors on local phys */
1046 if (!scsi_is_sas_phy_local(phy))
1047 return -EINVAL;
1048
Christoph Hellwigb5141122005-10-28 22:07:41 +02001049 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1050 hdr.ExtPageLength = 0;
1051 hdr.PageNumber = 1 /* page number 1*/;
1052 hdr.Reserved1 = 0;
1053 hdr.Reserved2 = 0;
1054 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1055 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1056
1057 cfg.cfghdr.ehdr = &hdr;
1058 cfg.physAddr = -1;
1059 cfg.pageAddr = phy->identify.phy_identifier;
1060 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1061 cfg.dir = 0; /* read */
1062 cfg.timeout = 10;
1063
1064 error = mpt_config(ioc, &cfg);
1065 if (error)
1066 return error;
1067 if (!hdr.ExtPageLength)
1068 return -ENXIO;
1069
1070 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1071 &dma_handle);
1072 if (!buffer)
1073 return -ENOMEM;
1074
1075 cfg.physAddr = dma_handle;
1076 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1077
1078 error = mpt_config(ioc, &cfg);
1079 if (error)
1080 goto out_free_consistent;
1081
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301082 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001083
1084 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1085 phy->running_disparity_error_count =
1086 le32_to_cpu(buffer->RunningDisparityErrorCount);
1087 phy->loss_of_dword_sync_count =
1088 le32_to_cpu(buffer->LossDwordSynchCount);
1089 phy->phy_reset_problem_count =
1090 le32_to_cpu(buffer->PhyResetProblemCount);
1091
1092 out_free_consistent:
1093 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1094 buffer, dma_handle);
1095 return error;
1096}
1097
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001098static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1099 MPT_FRAME_HDR *reply)
1100{
1101 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD;
1102 if (reply != NULL) {
1103 ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID;
1104 memcpy(ioc->sas_mgmt.reply, reply,
1105 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1106 }
1107 complete(&ioc->sas_mgmt.done);
1108 return 1;
1109}
1110
1111static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1112{
1113 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1114 SasIoUnitControlRequest_t *req;
1115 SasIoUnitControlReply_t *reply;
1116 MPT_FRAME_HDR *mf;
1117 MPIHeader_t *hdr;
1118 unsigned long timeleft;
1119 int error = -ERESTARTSYS;
1120
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001121 /* FIXME: fusion doesn't allow non-local phy reset */
1122 if (!scsi_is_sas_phy_local(phy))
1123 return -EINVAL;
1124
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001125 /* not implemented for expanders */
1126 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1127 return -ENXIO;
1128
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001129 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001130 goto out;
1131
1132 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1133 if (!mf) {
1134 error = -ENOMEM;
1135 goto out_unlock;
1136 }
1137
1138 hdr = (MPIHeader_t *) mf;
1139 req = (SasIoUnitControlRequest_t *)mf;
1140 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1141 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1142 req->MsgContext = hdr->MsgContext;
1143 req->Operation = hard_reset ?
1144 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1145 req->PhyNum = phy->identify.phy_identifier;
1146
1147 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1148
1149 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1150 10 * HZ);
1151 if (!timeleft) {
1152 /* On timeout reset the board */
1153 mpt_free_msg_frame(ioc, mf);
1154 mpt_HardResetHandler(ioc, CAN_SLEEP);
1155 error = -ETIMEDOUT;
1156 goto out_unlock;
1157 }
1158
1159 /* a reply frame is expected */
1160 if ((ioc->sas_mgmt.status &
1161 MPT_IOCTL_STATUS_RF_VALID) == 0) {
1162 error = -ENXIO;
1163 goto out_unlock;
1164 }
1165
1166 /* process the completed Reply Message Frame */
1167 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1168 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001169 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
1170 ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001171 error = -ENXIO;
1172 goto out_unlock;
1173 }
1174
1175 error = 0;
1176
1177 out_unlock:
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001178 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001179 out:
1180 return error;
1181}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001182
Christoph Hellwige3094442006-02-16 13:25:36 +01001183static int
1184mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1185{
1186 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1187 int i, error;
1188 struct mptsas_portinfo *p;
1189 struct mptsas_enclosure enclosure_info;
1190 u64 enclosure_handle;
1191
1192 mutex_lock(&ioc->sas_topology_mutex);
1193 list_for_each_entry(p, &ioc->sas_topology, list) {
1194 for (i = 0; i < p->num_phys; i++) {
1195 if (p->phy_info[i].attached.sas_address ==
1196 rphy->identify.sas_address) {
1197 enclosure_handle = p->phy_info[i].
1198 attached.handle_enclosure;
1199 goto found_info;
1200 }
1201 }
1202 }
1203 mutex_unlock(&ioc->sas_topology_mutex);
1204 return -ENXIO;
1205
1206 found_info:
1207 mutex_unlock(&ioc->sas_topology_mutex);
1208 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07001209 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01001210 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
1211 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
1212 if (!error)
1213 *identifier = enclosure_info.enclosure_logical_id;
1214 return error;
1215}
1216
1217static int
1218mptsas_get_bay_identifier(struct sas_rphy *rphy)
1219{
1220 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
1221 struct mptsas_portinfo *p;
1222 int i, rc;
1223
1224 mutex_lock(&ioc->sas_topology_mutex);
1225 list_for_each_entry(p, &ioc->sas_topology, list) {
1226 for (i = 0; i < p->num_phys; i++) {
1227 if (p->phy_info[i].attached.sas_address ==
1228 rphy->identify.sas_address) {
1229 rc = p->phy_info[i].attached.slot;
1230 goto out;
1231 }
1232 }
1233 }
1234 rc = -ENXIO;
1235 out:
1236 mutex_unlock(&ioc->sas_topology_mutex);
1237 return rc;
1238}
1239
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001240static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1241 struct request *req)
1242{
1243 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1244 MPT_FRAME_HDR *mf;
1245 SmpPassthroughRequest_t *smpreq;
1246 struct request *rsp = req->next_rq;
1247 int ret;
1248 int flagsLength;
1249 unsigned long timeleft;
1250 char *psge;
1251 dma_addr_t dma_addr_in = 0;
1252 dma_addr_t dma_addr_out = 0;
1253 u64 sas_address = 0;
1254
1255 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06001256 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
1257 ioc->name, __FUNCTION__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001258 return -EINVAL;
1259 }
1260
1261 /* do we need to support multiple segments? */
1262 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06001263 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
1264 ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len,
1265 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001266 return -EINVAL;
1267 }
1268
1269 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1270 if (ret)
1271 goto out;
1272
1273 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1274 if (!mf) {
1275 ret = -ENOMEM;
1276 goto out_unlock;
1277 }
1278
1279 smpreq = (SmpPassthroughRequest_t *)mf;
1280 memset(smpreq, 0, sizeof(*smpreq));
1281
1282 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1283 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1284
1285 if (rphy)
1286 sas_address = rphy->identify.sas_address;
1287 else {
1288 struct mptsas_portinfo *port_info;
1289
1290 mutex_lock(&ioc->sas_topology_mutex);
1291 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
1292 if (port_info && port_info->phy_info)
1293 sas_address =
1294 port_info->phy_info[0].phy->identify.sas_address;
1295 mutex_unlock(&ioc->sas_topology_mutex);
1296 }
1297
1298 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1299
1300 psge = (char *)
1301 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1302
1303 /* request */
1304 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1305 MPI_SGE_FLAGS_END_OF_BUFFER |
1306 MPI_SGE_FLAGS_DIRECTION |
1307 mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
1308 flagsLength |= (req->data_len - 4);
1309
1310 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1311 req->data_len, PCI_DMA_BIDIRECTIONAL);
1312 if (!dma_addr_out)
1313 goto put_mf;
1314 mpt_add_sge(psge, flagsLength, dma_addr_out);
1315 psge += (sizeof(u32) + sizeof(dma_addr_t));
1316
1317 /* response */
1318 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1319 flagsLength |= rsp->data_len + 4;
1320 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1321 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1322 if (!dma_addr_in)
1323 goto unmap;
1324 mpt_add_sge(psge, flagsLength, dma_addr_in);
1325
1326 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1327
1328 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1329 if (!timeleft) {
Eric Moore29dd3602007-09-14 18:46:51 -06001330 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001331 /* On timeout reset the board */
1332 mpt_HardResetHandler(ioc, CAN_SLEEP);
1333 ret = -ETIMEDOUT;
1334 goto unmap;
1335 }
1336 mf = NULL;
1337
1338 if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
1339 SmpPassthroughReply_t *smprep;
1340
1341 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1342 memcpy(req->sense, smprep, sizeof(*smprep));
1343 req->sense_len = sizeof(*smprep);
1344 } else {
Eric Moore29dd3602007-09-14 18:46:51 -06001345 printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
1346 ioc->name, __FUNCTION__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001347 ret = -ENXIO;
1348 }
1349unmap:
1350 if (dma_addr_out)
1351 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1352 PCI_DMA_BIDIRECTIONAL);
1353 if (dma_addr_in)
1354 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1355 PCI_DMA_BIDIRECTIONAL);
1356put_mf:
1357 if (mf)
1358 mpt_free_msg_frame(ioc, mf);
1359out_unlock:
1360 mutex_unlock(&ioc->sas_mgmt.mutex);
1361out:
1362 return ret;
1363}
1364
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001365static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02001366 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01001367 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1368 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001369 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06001370 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001371};
1372
1373static struct scsi_transport_template *mptsas_transport_template;
1374
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001375static int
1376mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
1377{
1378 ConfigExtendedPageHeader_t hdr;
1379 CONFIGPARMS cfg;
1380 SasIOUnitPage0_t *buffer;
1381 dma_addr_t dma_handle;
1382 int error, i;
1383
1384 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
1385 hdr.ExtPageLength = 0;
1386 hdr.PageNumber = 0;
1387 hdr.Reserved1 = 0;
1388 hdr.Reserved2 = 0;
1389 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1390 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1391
1392 cfg.cfghdr.ehdr = &hdr;
1393 cfg.physAddr = -1;
1394 cfg.pageAddr = 0;
1395 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1396 cfg.dir = 0; /* read */
1397 cfg.timeout = 10;
1398
1399 error = mpt_config(ioc, &cfg);
1400 if (error)
1401 goto out;
1402 if (!hdr.ExtPageLength) {
1403 error = -ENXIO;
1404 goto out;
1405 }
1406
1407 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1408 &dma_handle);
1409 if (!buffer) {
1410 error = -ENOMEM;
1411 goto out;
1412 }
1413
1414 cfg.physAddr = dma_handle;
1415 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1416
1417 error = mpt_config(ioc, &cfg);
1418 if (error)
1419 goto out_free_consistent;
1420
1421 port_info->num_phys = buffer->NumPhys;
1422 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001423 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001424 if (!port_info->phy_info) {
1425 error = -ENOMEM;
1426 goto out_free_consistent;
1427 }
1428
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301429 ioc->nvdata_version_persistent =
1430 le16_to_cpu(buffer->NvdataVersionPersistent);
1431 ioc->nvdata_version_default =
1432 le16_to_cpu(buffer->NvdataVersionDefault);
1433
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001434 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301435 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001436 port_info->phy_info[i].phy_id = i;
1437 port_info->phy_info[i].port_id =
1438 buffer->PhyData[i].Port;
1439 port_info->phy_info[i].negotiated_link_rate =
1440 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06001441 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001442 port_info->phy_info[i].handle =
1443 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001444 }
1445
1446 out_free_consistent:
1447 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1448 buffer, dma_handle);
1449 out:
1450 return error;
1451}
1452
1453static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301454mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
1455{
1456 ConfigExtendedPageHeader_t hdr;
1457 CONFIGPARMS cfg;
1458 SasIOUnitPage1_t *buffer;
1459 dma_addr_t dma_handle;
1460 int error;
1461 u16 device_missing_delay;
1462
1463 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
1464 memset(&cfg, 0, sizeof(CONFIGPARMS));
1465
1466 cfg.cfghdr.ehdr = &hdr;
1467 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1468 cfg.timeout = 10;
1469 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1470 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
1471 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
1472 cfg.cfghdr.ehdr->PageNumber = 1;
1473
1474 error = mpt_config(ioc, &cfg);
1475 if (error)
1476 goto out;
1477 if (!hdr.ExtPageLength) {
1478 error = -ENXIO;
1479 goto out;
1480 }
1481
1482 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1483 &dma_handle);
1484 if (!buffer) {
1485 error = -ENOMEM;
1486 goto out;
1487 }
1488
1489 cfg.physAddr = dma_handle;
1490 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1491
1492 error = mpt_config(ioc, &cfg);
1493 if (error)
1494 goto out_free_consistent;
1495
1496 ioc->io_missing_delay =
1497 le16_to_cpu(buffer->IODeviceMissingDelay);
1498 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
1499 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
1500 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
1501 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
1502
1503 out_free_consistent:
1504 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1505 buffer, dma_handle);
1506 out:
1507 return error;
1508}
1509
1510static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001511mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1512 u32 form, u32 form_specific)
1513{
1514 ConfigExtendedPageHeader_t hdr;
1515 CONFIGPARMS cfg;
1516 SasPhyPage0_t *buffer;
1517 dma_addr_t dma_handle;
1518 int error;
1519
1520 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
1521 hdr.ExtPageLength = 0;
1522 hdr.PageNumber = 0;
1523 hdr.Reserved1 = 0;
1524 hdr.Reserved2 = 0;
1525 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1526 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1527
1528 cfg.cfghdr.ehdr = &hdr;
1529 cfg.dir = 0; /* read */
1530 cfg.timeout = 10;
1531
1532 /* Get Phy Pg 0 for each Phy. */
1533 cfg.physAddr = -1;
1534 cfg.pageAddr = form + form_specific;
1535 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1536
1537 error = mpt_config(ioc, &cfg);
1538 if (error)
1539 goto out;
1540
1541 if (!hdr.ExtPageLength) {
1542 error = -ENXIO;
1543 goto out;
1544 }
1545
1546 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1547 &dma_handle);
1548 if (!buffer) {
1549 error = -ENOMEM;
1550 goto out;
1551 }
1552
1553 cfg.physAddr = dma_handle;
1554 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1555
1556 error = mpt_config(ioc, &cfg);
1557 if (error)
1558 goto out_free_consistent;
1559
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301560 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001561
1562 phy_info->hw_link_rate = buffer->HwLinkRate;
1563 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1564 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1565 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1566
1567 out_free_consistent:
1568 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1569 buffer, dma_handle);
1570 out:
1571 return error;
1572}
1573
1574static int
1575mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
1576 u32 form, u32 form_specific)
1577{
1578 ConfigExtendedPageHeader_t hdr;
1579 CONFIGPARMS cfg;
1580 SasDevicePage0_t *buffer;
1581 dma_addr_t dma_handle;
1582 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06001583 int error=0;
1584
1585 if (ioc->sas_discovery_runtime &&
1586 mptsas_is_end_device(device_info))
1587 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001588
1589 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
1590 hdr.ExtPageLength = 0;
1591 hdr.PageNumber = 0;
1592 hdr.Reserved1 = 0;
1593 hdr.Reserved2 = 0;
1594 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1595 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
1596
1597 cfg.cfghdr.ehdr = &hdr;
1598 cfg.pageAddr = form + form_specific;
1599 cfg.physAddr = -1;
1600 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1601 cfg.dir = 0; /* read */
1602 cfg.timeout = 10;
1603
Moore, Ericdb9c9172006-03-14 09:14:18 -07001604 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001605 error = mpt_config(ioc, &cfg);
1606 if (error)
1607 goto out;
1608 if (!hdr.ExtPageLength) {
1609 error = -ENXIO;
1610 goto out;
1611 }
1612
1613 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1614 &dma_handle);
1615 if (!buffer) {
1616 error = -ENOMEM;
1617 goto out;
1618 }
1619
1620 cfg.physAddr = dma_handle;
1621 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1622
1623 error = mpt_config(ioc, &cfg);
1624 if (error)
1625 goto out_free_consistent;
1626
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301627 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001628
1629 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07001630 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01001631 device_info->handle_enclosure =
1632 le16_to_cpu(buffer->EnclosureHandle);
1633 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001634 device_info->phy_id = buffer->PhyNum;
1635 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001636 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07001637 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001638 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001639 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
1640 device_info->sas_address = le64_to_cpu(sas_address);
1641 device_info->device_info =
1642 le32_to_cpu(buffer->DeviceInfo);
1643
1644 out_free_consistent:
1645 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1646 buffer, dma_handle);
1647 out:
1648 return error;
1649}
1650
1651static int
1652mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
1653 u32 form, u32 form_specific)
1654{
1655 ConfigExtendedPageHeader_t hdr;
1656 CONFIGPARMS cfg;
1657 SasExpanderPage0_t *buffer;
1658 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06001659 int i, error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001660
1661 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1662 hdr.ExtPageLength = 0;
1663 hdr.PageNumber = 0;
1664 hdr.Reserved1 = 0;
1665 hdr.Reserved2 = 0;
1666 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1667 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1668
1669 cfg.cfghdr.ehdr = &hdr;
1670 cfg.physAddr = -1;
1671 cfg.pageAddr = form + form_specific;
1672 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1673 cfg.dir = 0; /* read */
1674 cfg.timeout = 10;
1675
Moore, Ericdb9c9172006-03-14 09:14:18 -07001676 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001677 error = mpt_config(ioc, &cfg);
1678 if (error)
1679 goto out;
1680
1681 if (!hdr.ExtPageLength) {
1682 error = -ENXIO;
1683 goto out;
1684 }
1685
1686 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1687 &dma_handle);
1688 if (!buffer) {
1689 error = -ENOMEM;
1690 goto out;
1691 }
1692
1693 cfg.physAddr = dma_handle;
1694 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1695
1696 error = mpt_config(ioc, &cfg);
1697 if (error)
1698 goto out_free_consistent;
1699
1700 /* save config data */
1701 port_info->num_phys = buffer->NumPhys;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001702 port_info->phy_info = kcalloc(port_info->num_phys,
Eric Moore547f9a22006-06-27 14:42:12 -06001703 sizeof(*port_info->phy_info),GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001704 if (!port_info->phy_info) {
1705 error = -ENOMEM;
1706 goto out_free_consistent;
1707 }
1708
Eric Moore2ecce492007-01-29 09:47:08 -07001709 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001710 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07001711 port_info->phy_info[i].handle =
1712 le16_to_cpu(buffer->DevHandle);
1713 }
Eric Moore547f9a22006-06-27 14:42:12 -06001714
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001715 out_free_consistent:
1716 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1717 buffer, dma_handle);
1718 out:
1719 return error;
1720}
1721
1722static int
1723mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
1724 u32 form, u32 form_specific)
1725{
1726 ConfigExtendedPageHeader_t hdr;
1727 CONFIGPARMS cfg;
1728 SasExpanderPage1_t *buffer;
1729 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06001730 int error=0;
1731
1732 if (ioc->sas_discovery_runtime &&
1733 mptsas_is_end_device(&phy_info->attached))
1734 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001735
1736 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
1737 hdr.ExtPageLength = 0;
1738 hdr.PageNumber = 1;
1739 hdr.Reserved1 = 0;
1740 hdr.Reserved2 = 0;
1741 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1742 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
1743
1744 cfg.cfghdr.ehdr = &hdr;
1745 cfg.physAddr = -1;
1746 cfg.pageAddr = form + form_specific;
1747 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1748 cfg.dir = 0; /* read */
1749 cfg.timeout = 10;
1750
1751 error = mpt_config(ioc, &cfg);
1752 if (error)
1753 goto out;
1754
1755 if (!hdr.ExtPageLength) {
1756 error = -ENXIO;
1757 goto out;
1758 }
1759
1760 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1761 &dma_handle);
1762 if (!buffer) {
1763 error = -ENOMEM;
1764 goto out;
1765 }
1766
1767 cfg.physAddr = dma_handle;
1768 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1769
1770 error = mpt_config(ioc, &cfg);
1771 if (error)
1772 goto out_free_consistent;
1773
1774
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301775 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001776
1777 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02001778 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001779 phy_info->port_id = buffer->PhysicalPort;
1780 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
1781 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
1782 phy_info->hw_link_rate = buffer->HwLinkRate;
1783 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
1784 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
1785
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001786 out_free_consistent:
1787 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1788 buffer, dma_handle);
1789 out:
1790 return error;
1791}
1792
1793static void
1794mptsas_parse_device_info(struct sas_identify *identify,
1795 struct mptsas_devinfo *device_info)
1796{
1797 u16 protocols;
1798
1799 identify->sas_address = device_info->sas_address;
1800 identify->phy_identifier = device_info->phy_id;
1801
1802 /*
1803 * Fill in Phy Initiator Port Protocol.
1804 * Bits 6:3, more than one bit can be set, fall through cases.
1805 */
1806 protocols = device_info->device_info & 0x78;
1807 identify->initiator_port_protocols = 0;
1808 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
1809 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
1810 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1811 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
1812 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
1813 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
1814 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
1815 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
1816
1817 /*
1818 * Fill in Phy Target Port Protocol.
1819 * Bits 10:7, more than one bit can be set, fall through cases.
1820 */
1821 protocols = device_info->device_info & 0x780;
1822 identify->target_port_protocols = 0;
1823 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
1824 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
1825 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
1826 identify->target_port_protocols |= SAS_PROTOCOL_STP;
1827 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
1828 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
1829 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1830 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
1831
1832 /*
1833 * Fill in Attached device type.
1834 */
1835 switch (device_info->device_info &
1836 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
1837 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
1838 identify->device_type = SAS_PHY_UNUSED;
1839 break;
1840 case MPI_SAS_DEVICE_INFO_END_DEVICE:
1841 identify->device_type = SAS_END_DEVICE;
1842 break;
1843 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
1844 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
1845 break;
1846 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
1847 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
1848 break;
1849 }
1850}
1851
1852static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001853 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001854{
Moore, Erice6b2d762006-03-14 09:14:24 -07001855 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001856 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06001857 struct sas_port *port;
1858 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001859
Eric Moore547f9a22006-06-27 14:42:12 -06001860 if (!dev) {
1861 error = -ENODEV;
1862 goto out;
1863 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001864
1865 if (!phy_info->phy) {
1866 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06001867 if (!phy) {
1868 error = -ENOMEM;
1869 goto out;
1870 }
Moore, Erice6b2d762006-03-14 09:14:24 -07001871 } else
1872 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001873
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001874 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001875
1876 /*
1877 * Set Negotiated link rate.
1878 */
1879 switch (phy_info->negotiated_link_rate) {
1880 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001881 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001882 break;
1883 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001884 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001885 break;
1886 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001887 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001888 break;
1889 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001890 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001891 break;
1892 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
1893 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
1894 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001895 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001896 break;
1897 }
1898
1899 /*
1900 * Set Max hardware link rate.
1901 */
1902 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1903 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001904 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001905 break;
1906 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001907 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001908 break;
1909 default:
1910 break;
1911 }
1912
1913 /*
1914 * Set Max programmed link rate.
1915 */
1916 switch (phy_info->programmed_link_rate &
1917 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
1918 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001919 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001920 break;
1921 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001922 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001923 break;
1924 default:
1925 break;
1926 }
1927
1928 /*
1929 * Set Min hardware link rate.
1930 */
1931 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
1932 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001933 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001934 break;
1935 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001936 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001937 break;
1938 default:
1939 break;
1940 }
1941
1942 /*
1943 * Set Min programmed link rate.
1944 */
1945 switch (phy_info->programmed_link_rate &
1946 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
1947 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001948 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001949 break;
1950 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001951 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001952 break;
1953 default:
1954 break;
1955 }
1956
Moore, Erice6b2d762006-03-14 09:14:24 -07001957 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02001958
Moore, Erice6b2d762006-03-14 09:14:24 -07001959 error = sas_phy_add(phy);
1960 if (error) {
1961 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06001962 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07001963 }
1964 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001965 }
1966
Eric Moore547f9a22006-06-27 14:42:12 -06001967 if (!phy_info->attached.handle ||
1968 !phy_info->port_details)
1969 goto out;
1970
1971 port = mptsas_get_port(phy_info);
1972 ioc = phy_to_ioc(phy_info->phy);
1973
1974 if (phy_info->sas_port_add_phy) {
1975
1976 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06001977 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06001978 if (!port) {
1979 error = -ENOMEM;
1980 goto out;
1981 }
1982 error = sas_port_add(port);
1983 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301984 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06001985 "%s: exit at line=%d\n", ioc->name,
1986 __FUNCTION__, __LINE__));
1987 goto out;
1988 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301989 mptsas_set_port(ioc, phy_info, port);
Eric Moore29dd3602007-09-14 18:46:51 -06001990 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooredc22f162006-07-06 11:23:14 -06001991 "sas_port_alloc: port=%p dev=%p port_id=%d\n",
Eric Moore29dd3602007-09-14 18:46:51 -06001992 ioc->name, port, dev, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06001993 }
Eric Moore29dd3602007-09-14 18:46:51 -06001994 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
1995 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06001996 sas_port_add_phy(port, phy_info->phy);
1997 phy_info->sas_port_add_phy = 0;
1998 }
1999
2000 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002001
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002002 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002003 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002004 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002005
James Bottomley2686de22006-06-30 12:54:02 -05002006 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002007 /*
2008 * Let the hotplug_work thread handle processing
2009 * the adding/removing of devices that occur
2010 * after start of day.
2011 */
2012 if (ioc->sas_discovery_runtime &&
2013 mptsas_is_end_device(&phy_info->attached))
Eric Moore547f9a22006-06-27 14:42:12 -06002014 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002015
James Bottomleyf013db32006-03-18 14:54:36 -06002016 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002017 if (scsi_is_host_device(parent)) {
2018 struct mptsas_portinfo *port_info;
2019 int i;
2020
2021 mutex_lock(&ioc->sas_topology_mutex);
2022 port_info = mptsas_find_portinfo_by_handle(ioc,
2023 ioc->handle);
2024 mutex_unlock(&ioc->sas_topology_mutex);
2025
2026 for (i = 0; i < port_info->num_phys; i++)
2027 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002028 identify.sas_address) {
2029 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002030 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002031 }
James Bottomley2686de22006-06-30 12:54:02 -05002032
2033 } else if (scsi_is_sas_rphy(parent)) {
2034 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2035 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002036 parent_rphy->identify.sas_address) {
2037 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002038 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002039 }
James Bottomley2686de22006-06-30 12:54:02 -05002040 }
2041
James Bottomleyf013db32006-03-18 14:54:36 -06002042 switch (identify.device_type) {
2043 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002044 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002045 break;
2046 case SAS_EDGE_EXPANDER_DEVICE:
2047 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002048 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002049 break;
2050 default:
2051 rphy = NULL;
2052 break;
2053 }
Eric Moore547f9a22006-06-27 14:42:12 -06002054 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302055 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002056 "%s: exit at line=%d\n", ioc->name,
2057 __FUNCTION__, __LINE__));
2058 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002059 }
2060
Eric Moore547f9a22006-06-27 14:42:12 -06002061 rphy->identify = identify;
2062 error = sas_rphy_add(rphy);
2063 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302064 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002065 "%s: exit at line=%d\n", ioc->name,
2066 __FUNCTION__, __LINE__));
2067 sas_rphy_free(rphy);
2068 goto out;
2069 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302070 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002071 }
2072
Eric Moore547f9a22006-06-27 14:42:12 -06002073 out:
2074 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002075}
2076
2077static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002078mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002079{
Moore, Erice6b2d762006-03-14 09:14:24 -07002080 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002081 int error = -ENOMEM, i;
2082
Moore, Erice6b2d762006-03-14 09:14:24 -07002083 hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
2084 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002085 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002086
Moore, Erice6b2d762006-03-14 09:14:24 -07002087 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002088 if (error)
2089 goto out_free_port_info;
2090
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302091 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002092 mutex_lock(&ioc->sas_topology_mutex);
Eric Moore2ecce492007-01-29 09:47:08 -07002093 ioc->handle = hba->phy_info[0].handle;
2094 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
Moore, Erice6b2d762006-03-14 09:14:24 -07002095 if (!port_info) {
2096 port_info = hba;
2097 list_add_tail(&port_info->list, &ioc->sas_topology);
2098 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002099 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002100 port_info->phy_info[i].negotiated_link_rate =
2101 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002102 port_info->phy_info[i].handle =
2103 hba->phy_info[i].handle;
2104 port_info->phy_info[i].port_id =
2105 hba->phy_info[i].port_id;
2106 }
Eric Moore547f9a22006-06-27 14:42:12 -06002107 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002108 kfree(hba);
2109 hba = NULL;
2110 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002111 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002112 for (i = 0; i < port_info->num_phys; i++) {
2113 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2114 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2115 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
2116
2117 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002118 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2119 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2120 port_info->phy_info[i].handle);
Eric Moore024358e2005-10-21 20:56:36 +02002121 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002122 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002123 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002124 mptsas_sas_device_pg0(ioc,
2125 &port_info->phy_info[i].attached,
2126 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2127 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2128 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002129 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002130
Eric Moore547f9a22006-06-27 14:42:12 -06002131 mptsas_setup_wide_ports(ioc, port_info);
2132
2133 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002134 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002135 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002136
2137 return 0;
2138
2139 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002140 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002141 out:
2142 return error;
2143}
2144
2145static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002146mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002147{
Moore, Erice6b2d762006-03-14 09:14:24 -07002148 struct mptsas_portinfo *port_info, *p, *ex;
Eric Moore547f9a22006-06-27 14:42:12 -06002149 struct device *parent;
2150 struct sas_rphy *rphy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002151 int error = -ENOMEM, i, j;
2152
Moore, Erice6b2d762006-03-14 09:14:24 -07002153 ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
2154 if (!ex)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002155 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002156
Moore, Erice6b2d762006-03-14 09:14:24 -07002157 error = mptsas_sas_expander_pg0(ioc, ex,
Eric Moore2ecce492007-01-29 09:47:08 -07002158 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
2159 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002160 if (error)
2161 goto out_free_port_info;
2162
Eric Moore2ecce492007-01-29 09:47:08 -07002163 *handle = ex->phy_info[0].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002164
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002165 mutex_lock(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07002166 port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
2167 if (!port_info) {
2168 port_info = ex;
2169 list_add_tail(&port_info->list, &ioc->sas_topology);
2170 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002171 for (i = 0; i < ex->num_phys; i++) {
2172 port_info->phy_info[i].handle =
2173 ex->phy_info[i].handle;
2174 port_info->phy_info[i].port_id =
2175 ex->phy_info[i].port_id;
2176 }
Eric Moore547f9a22006-06-27 14:42:12 -06002177 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002178 kfree(ex);
2179 ex = NULL;
2180 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002181 mutex_unlock(&ioc->sas_topology_mutex);
2182
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002183 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002184 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
2185 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
2186 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
2187
2188 if (port_info->phy_info[i].identify.handle) {
2189 mptsas_sas_device_pg0(ioc,
2190 &port_info->phy_info[i].identify,
2191 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2192 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2193 port_info->phy_info[i].identify.handle);
Eric Moore024358e2005-10-21 20:56:36 +02002194 port_info->phy_info[i].identify.phy_id =
2195 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002196 }
2197
2198 if (port_info->phy_info[i].attached.handle) {
2199 mptsas_sas_device_pg0(ioc,
2200 &port_info->phy_info[i].attached,
2201 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2202 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2203 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07002204 port_info->phy_info[i].attached.phy_id =
2205 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002206 }
Eric Moore547f9a22006-06-27 14:42:12 -06002207 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002208
Eric Moore547f9a22006-06-27 14:42:12 -06002209 parent = &ioc->sh->shost_gendev;
2210 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002211 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002212 list_for_each_entry(p, &ioc->sas_topology, list) {
2213 for (j = 0; j < p->num_phys; j++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002214 if (port_info->phy_info[i].identify.handle !=
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002215 p->phy_info[j].attached.handle)
Eric Moore547f9a22006-06-27 14:42:12 -06002216 continue;
2217 rphy = mptsas_get_rphy(&p->phy_info[j]);
2218 parent = &rphy->dev;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002219 }
2220 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002221 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002222 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002223
Eric Moore547f9a22006-06-27 14:42:12 -06002224 mptsas_setup_wide_ports(ioc, port_info);
2225
2226 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002227 mptsas_probe_one_phy(parent, &port_info->phy_info[i],
Moore, Erice6b2d762006-03-14 09:14:24 -07002228 ioc->sas_index, 0);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002229
2230 return 0;
2231
2232 out_free_port_info:
Moore, Erice6b2d762006-03-14 09:14:24 -07002233 if (ex) {
Eric Moore547f9a22006-06-27 14:42:12 -06002234 kfree(ex->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002235 kfree(ex);
2236 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002237 out:
2238 return error;
2239}
2240
Moore, Erice6b2d762006-03-14 09:14:24 -07002241/*
2242 * mptsas_delete_expander_phys
2243 *
2244 *
2245 * This will traverse topology, and remove expanders
2246 * that are no longer present
2247 */
2248static void
2249mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
2250{
2251 struct mptsas_portinfo buffer;
2252 struct mptsas_portinfo *port_info, *n, *parent;
Eric Moore547f9a22006-06-27 14:42:12 -06002253 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06002254 struct sas_port * port;
Moore, Erice6b2d762006-03-14 09:14:24 -07002255 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06002256 u64 expander_sas_address;
Moore, Erice6b2d762006-03-14 09:14:24 -07002257
2258 mutex_lock(&ioc->sas_topology_mutex);
2259 list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
2260
2261 if (port_info->phy_info &&
2262 (!(port_info->phy_info[0].identify.device_info &
2263 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
2264 continue;
2265
2266 if (mptsas_sas_expander_pg0(ioc, &buffer,
2267 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
Eric Moore2ecce492007-01-29 09:47:08 -07002268 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
2269 port_info->phy_info[0].handle)) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002270
2271 /*
2272 * Obtain the port_info instance to the parent port
2273 */
2274 parent = mptsas_find_portinfo_by_handle(ioc,
2275 port_info->phy_info[0].identify.handle_parent);
2276
2277 if (!parent)
2278 goto next_port;
2279
Eric Moore547f9a22006-06-27 14:42:12 -06002280 expander_sas_address =
2281 port_info->phy_info[0].identify.sas_address;
2282
Moore, Erice6b2d762006-03-14 09:14:24 -07002283 /*
2284 * Delete rphys in the parent that point
2285 * to this expander. The transport layer will
2286 * cleanup all the children.
2287 */
Eric Moore547f9a22006-06-27 14:42:12 -06002288 phy_info = parent->phy_info;
2289 for (i = 0; i < parent->num_phys; i++, phy_info++) {
2290 port = mptsas_get_port(phy_info);
2291 if (!port)
Moore, Erice6b2d762006-03-14 09:14:24 -07002292 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002293 if (phy_info->attached.sas_address !=
2294 expander_sas_address)
2295 continue;
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302296 dsaswideprintk(ioc,
Eric Moore29dd3602007-09-14 18:46:51 -06002297 dev_printk(MYIOC_s_DEBUG_FMT, &port->dev,
2298 "delete port (%d)\n", ioc->name, port->port_identifier));
Eric Moore547f9a22006-06-27 14:42:12 -06002299 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302300 mptsas_port_delete(ioc, phy_info->port_details);
Moore, Erice6b2d762006-03-14 09:14:24 -07002301 }
2302 next_port:
Eric Moore547f9a22006-06-27 14:42:12 -06002303
2304 phy_info = port_info->phy_info;
2305 for (i = 0; i < port_info->num_phys; i++, phy_info++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302306 mptsas_port_delete(ioc, phy_info->port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06002307
Moore, Erice6b2d762006-03-14 09:14:24 -07002308 list_del(&port_info->list);
Eric Moore547f9a22006-06-27 14:42:12 -06002309 kfree(port_info->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002310 kfree(port_info);
2311 }
2312 /*
2313 * Free this memory allocated from inside
2314 * mptsas_sas_expander_pg0
2315 */
Eric Moore547f9a22006-06-27 14:42:12 -06002316 kfree(buffer.phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002317 }
2318 mutex_unlock(&ioc->sas_topology_mutex);
2319}
2320
2321/*
2322 * Start of day discovery
2323 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002324static void
2325mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
2326{
2327 u32 handle = 0xFFFF;
Moore, Ericf44e5462006-03-14 09:14:21 -07002328 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002329
Moore, Erice6b2d762006-03-14 09:14:24 -07002330 mutex_lock(&ioc->sas_discovery_mutex);
2331 mptsas_probe_hba_phys(ioc);
2332 while (!mptsas_probe_expander_phys(ioc, &handle))
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002333 ;
Moore, Ericf44e5462006-03-14 09:14:21 -07002334 /*
2335 Reporting RAID volumes.
2336 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002337 if (!ioc->ir_firmware)
2338 goto out;
Moore, Ericf44e5462006-03-14 09:14:21 -07002339 if (!ioc->raid_data.pIocPg2)
2340 goto out;
2341 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
2342 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07002343 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
James Bottomleye8bf3942006-07-11 17:49:34 -04002344 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07002345 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
2346 }
2347 out:
Moore, Erice6b2d762006-03-14 09:14:24 -07002348 mutex_unlock(&ioc->sas_discovery_mutex);
2349}
2350
2351/*
2352 * Work queue thread to handle Runtime discovery
2353 * Mere purpose is the hot add/delete of expanders
Eric Moore547f9a22006-06-27 14:42:12 -06002354 *(Mutex UNLOCKED)
Moore, Erice6b2d762006-03-14 09:14:24 -07002355 */
2356static void
Eric Moore547f9a22006-06-27 14:42:12 -06002357__mptsas_discovery_work(MPT_ADAPTER *ioc)
Moore, Erice6b2d762006-03-14 09:14:24 -07002358{
Moore, Erice6b2d762006-03-14 09:14:24 -07002359 u32 handle = 0xFFFF;
2360
Moore, Erice6b2d762006-03-14 09:14:24 -07002361 ioc->sas_discovery_runtime=1;
2362 mptsas_delete_expander_phys(ioc);
2363 mptsas_probe_hba_phys(ioc);
2364 while (!mptsas_probe_expander_phys(ioc, &handle))
2365 ;
Moore, Erice6b2d762006-03-14 09:14:24 -07002366 ioc->sas_discovery_runtime=0;
Eric Moore547f9a22006-06-27 14:42:12 -06002367}
2368
2369/*
2370 * Work queue thread to handle Runtime discovery
2371 * Mere purpose is the hot add/delete of expanders
2372 *(Mutex LOCKED)
2373 */
2374static void
David Howellsc4028952006-11-22 14:57:56 +00002375mptsas_discovery_work(struct work_struct *work)
Eric Moore547f9a22006-06-27 14:42:12 -06002376{
David Howellsc4028952006-11-22 14:57:56 +00002377 struct mptsas_discovery_event *ev =
2378 container_of(work, struct mptsas_discovery_event, work);
Eric Moore547f9a22006-06-27 14:42:12 -06002379 MPT_ADAPTER *ioc = ev->ioc;
2380
2381 mutex_lock(&ioc->sas_discovery_mutex);
2382 __mptsas_discovery_work(ioc);
Moore, Erice6b2d762006-03-14 09:14:24 -07002383 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002384 kfree(ev);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002385}
2386
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002387static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06002388mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002389{
2390 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002391 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06002392 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002393
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002394 mutex_lock(&ioc->sas_topology_mutex);
2395 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2396 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002397 if (!mptsas_is_end_device(
2398 &port_info->phy_info[i].attached))
2399 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002400 if (port_info->phy_info[i].attached.sas_address
2401 != sas_address)
2402 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002403 phy_info = &port_info->phy_info[i];
2404 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002405 }
2406 }
2407 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002408 return phy_info;
2409}
2410
2411static struct mptsas_phyinfo *
Eric Mooreb506ade2007-01-29 09:45:37 -07002412mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002413{
2414 struct mptsas_portinfo *port_info;
2415 struct mptsas_phyinfo *phy_info = NULL;
2416 int i;
2417
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002418 mutex_lock(&ioc->sas_topology_mutex);
2419 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06002420 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002421 if (!mptsas_is_end_device(
2422 &port_info->phy_info[i].attached))
2423 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07002424 if (port_info->phy_info[i].attached.id != id)
2425 continue;
2426 if (port_info->phy_info[i].attached.channel != channel)
2427 continue;
2428 phy_info = &port_info->phy_info[i];
2429 break;
2430 }
2431 }
2432 mutex_unlock(&ioc->sas_topology_mutex);
2433 return phy_info;
2434}
2435
2436static struct mptsas_phyinfo *
2437mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
2438{
2439 struct mptsas_portinfo *port_info;
2440 struct mptsas_phyinfo *phy_info = NULL;
2441 int i;
2442
2443 mutex_lock(&ioc->sas_topology_mutex);
2444 list_for_each_entry(port_info, &ioc->sas_topology, list) {
2445 for (i = 0; i < port_info->num_phys; i++) {
2446 if (!mptsas_is_end_device(
2447 &port_info->phy_info[i].attached))
2448 continue;
2449 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
2450 continue;
2451 if (port_info->phy_info[i].attached.phys_disk_num != id)
2452 continue;
2453 if (port_info->phy_info[i].attached.channel != channel)
2454 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06002455 phy_info = &port_info->phy_info[i];
2456 break;
2457 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002458 }
2459 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002460 return phy_info;
2461}
2462
Moore, Eric4b766472006-03-14 09:14:12 -07002463/*
2464 * Work queue thread to clear the persitency table
2465 */
2466static void
David Howellsc4028952006-11-22 14:57:56 +00002467mptsas_persist_clear_table(struct work_struct *work)
Moore, Eric4b766472006-03-14 09:14:12 -07002468{
David Howellsc4028952006-11-22 14:57:56 +00002469 MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002470
2471 mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
2472}
2473
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002474static void
Moore, Ericf44e5462006-03-14 09:14:21 -07002475mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
2476{
Eric Mooref99be432007-01-04 20:46:54 -07002477 int rc;
2478
Moore, Ericf44e5462006-03-14 09:14:21 -07002479 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07002480 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07002481}
2482
2483static void
2484mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
2485{
2486 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
2487 mptsas_reprobe_lun);
2488}
2489
Eric Mooreb506ade2007-01-29 09:45:37 -07002490static void
2491mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
2492{
2493 CONFIGPARMS cfg;
2494 ConfigPageHeader_t hdr;
2495 dma_addr_t dma_handle;
2496 pRaidVolumePage0_t buffer = NULL;
2497 RaidPhysDiskPage0_t phys_disk;
2498 int i;
2499 struct mptsas_hotplug_event *ev;
2500
2501 memset(&cfg, 0 , sizeof(CONFIGPARMS));
2502 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
2503 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
2504 cfg.pageAddr = (channel << 8) + id;
2505 cfg.cfghdr.hdr = &hdr;
2506 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2507
2508 if (mpt_config(ioc, &cfg) != 0)
2509 goto out;
2510
2511 if (!hdr.PageLength)
2512 goto out;
2513
2514 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
2515 &dma_handle);
2516
2517 if (!buffer)
2518 goto out;
2519
2520 cfg.physAddr = dma_handle;
2521 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2522
2523 if (mpt_config(ioc, &cfg) != 0)
2524 goto out;
2525
2526 if (!(buffer->VolumeStatus.Flags &
2527 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
2528 goto out;
2529
2530 if (!buffer->NumPhysDisks)
2531 goto out;
2532
2533 for (i = 0; i < buffer->NumPhysDisks; i++) {
2534
2535 if (mpt_raid_phys_disk_pg0(ioc,
2536 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
2537 continue;
2538
2539 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
2540 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002541 printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
Eric Mooreb506ade2007-01-29 09:45:37 -07002542 goto out;
2543 }
2544
2545 INIT_WORK(&ev->work, mptsas_hotplug_work);
2546 ev->ioc = ioc;
2547 ev->id = phys_disk.PhysDiskID;
2548 ev->channel = phys_disk.PhysDiskBus;
2549 ev->phys_disk_num_valid = 1;
2550 ev->phys_disk_num = phys_disk.PhysDiskNum;
2551 ev->event_type = MPTSAS_ADD_DEVICE;
2552 schedule_work(&ev->work);
2553 }
2554
2555 out:
2556 if (buffer)
2557 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
2558 dma_handle);
2559}
Moore, Erice6b2d762006-03-14 09:14:24 -07002560/*
2561 * Work queue thread to handle SAS hotplug events
2562 */
Moore, Ericf44e5462006-03-14 09:14:21 -07002563static void
David Howellsc4028952006-11-22 14:57:56 +00002564mptsas_hotplug_work(struct work_struct *work)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002565{
David Howellsc4028952006-11-22 14:57:56 +00002566 struct mptsas_hotplug_event *ev =
2567 container_of(work, struct mptsas_hotplug_event, work);
Eric Mooreb506ade2007-01-29 09:45:37 -07002568
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002569 MPT_ADAPTER *ioc = ev->ioc;
2570 struct mptsas_phyinfo *phy_info;
2571 struct sas_rphy *rphy;
Eric Moore547f9a22006-06-27 14:42:12 -06002572 struct sas_port *port;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002573 struct scsi_device *sdev;
Eric Moore547f9a22006-06-27 14:42:12 -06002574 struct scsi_target * starget;
James Bottomleyf013db32006-03-18 14:54:36 -06002575 struct sas_identify identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002576 char *ds = NULL;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002577 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07002578 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06002579 VirtDevice *vdevice;
2580
Moore, Erice6b2d762006-03-14 09:14:24 -07002581 mutex_lock(&ioc->sas_discovery_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002582 switch (ev->event_type) {
2583 case MPTSAS_DEL_DEVICE:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002584
Eric Mooreb506ade2007-01-29 09:45:37 -07002585 phy_info = NULL;
2586 if (ev->phys_disk_num_valid) {
2587 if (ev->hidden_raid_component){
2588 if (mptsas_sas_device_pg0(ioc, &sas_device,
2589 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
2590 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2591 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302592 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002593 "%s: exit at line=%d\n", ioc->name,
2594 __FUNCTION__, __LINE__));
2595 break;
2596 }
2597 phy_info = mptsas_find_phyinfo_by_sas_address(
2598 ioc, sas_device.sas_address);
2599 }else
2600 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
2601 ioc, ev->channel, ev->phys_disk_num);
2602 }
2603
2604 if (!phy_info)
2605 phy_info = mptsas_find_phyinfo_by_target(ioc,
2606 ev->channel, ev->id);
Moore, Erice6b2d762006-03-14 09:14:24 -07002607
Moore, Ericf44e5462006-03-14 09:14:21 -07002608 /*
2609 * Sanity checks, for non-existing phys and remote rphys.
2610 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002611 if (!phy_info){
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302612 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Mooreb506ade2007-01-29 09:45:37 -07002613 "%s: exit at line=%d\n", ioc->name,
2614 __FUNCTION__, __LINE__));
2615 break;
2616 }
2617 if (!phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302618 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002619 "%s: exit at line=%d\n", ioc->name,
2620 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002621 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002622 }
2623 rphy = mptsas_get_rphy(phy_info);
2624 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302625 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002626 "%s: exit at line=%d\n", ioc->name,
2627 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002628 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002629 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002630
Eric Moore547f9a22006-06-27 14:42:12 -06002631 port = mptsas_get_port(phy_info);
2632 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302633 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002634 "%s: exit at line=%d\n", ioc->name,
2635 __FUNCTION__, __LINE__));
2636 break;
2637 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002638
Eric Moore547f9a22006-06-27 14:42:12 -06002639 starget = mptsas_get_starget(phy_info);
2640 if (starget) {
2641 vtarget = starget->hostdata;
2642
2643 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302644 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002645 "%s: exit at line=%d\n", ioc->name,
2646 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002647 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002648 }
2649
Moore, Ericf44e5462006-03-14 09:14:21 -07002650 /*
2651 * Handling RAID components
2652 */
Eric Mooreb506ade2007-01-29 09:45:37 -07002653 if (ev->phys_disk_num_valid &&
2654 ev->hidden_raid_component) {
2655 printk(MYIOC_s_INFO_FMT
2656 "RAID Hidding: channel=%d, id=%d, "
2657 "physdsk %d \n", ioc->name, ev->channel,
2658 ev->id, ev->phys_disk_num);
Eric Moore793955f2007-01-29 09:42:20 -07002659 vtarget->id = ev->phys_disk_num;
Eric Mooreb506ade2007-01-29 09:45:37 -07002660 vtarget->tflags |=
2661 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore547f9a22006-06-27 14:42:12 -06002662 mptsas_reprobe_target(starget, 1);
Eric Mooreb506ade2007-01-29 09:45:37 -07002663 phy_info->attached.phys_disk_num =
2664 ev->phys_disk_num;
2665 break;
Moore, Ericf44e5462006-03-14 09:14:21 -07002666 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002667 }
2668
Eric Mooreb506ade2007-01-29 09:45:37 -07002669 if (phy_info->attached.device_info &
2670 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002671 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002672 if (phy_info->attached.device_info &
2673 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002674 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002675 if (phy_info->attached.device_info &
2676 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002677 ds = "sata";
2678
2679 printk(MYIOC_s_INFO_FMT
2680 "removing %s device, channel %d, id %d, phy %d\n",
2681 ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
Eric Moore29dd3602007-09-14 18:46:51 -06002682 dev_printk(MYIOC_s_DEBUG_FMT, &port->dev,
2683 "delete port (%d)\n", ioc->name, port->port_identifier);
Eric Moore547f9a22006-06-27 14:42:12 -06002684 sas_port_delete(port);
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302685 mptsas_port_delete(ioc, phy_info->port_details);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002686 break;
2687 case MPTSAS_ADD_DEVICE:
Moore, Ericc73787ee2006-01-26 16:20:06 -07002688
Moore, Ericbd23e942006-04-17 12:43:04 -06002689 if (ev->phys_disk_num_valid)
2690 mpt_findImVolumes(ioc);
2691
Moore, Ericc73787ee2006-01-26 16:20:06 -07002692 /*
Christoph Hellwige3094442006-02-16 13:25:36 +01002693 * Refresh sas device pg0 data
Moore, Ericc73787ee2006-01-26 16:20:06 -07002694 */
Christoph Hellwige3094442006-02-16 13:25:36 +01002695 if (mptsas_sas_device_pg0(ioc, &sas_device,
2696 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07002697 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2698 (ev->channel << 8) + ev->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302699 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002700 "%s: exit at line=%d\n", ioc->name,
2701 __FUNCTION__, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01002702 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07002703 }
2704
Eric Moore547f9a22006-06-27 14:42:12 -06002705 __mptsas_discovery_work(ioc);
Moore, Ericf44e5462006-03-14 09:14:21 -07002706
Eric Moore547f9a22006-06-27 14:42:12 -06002707 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
2708 sas_device.sas_address);
2709
2710 if (!phy_info || !phy_info->port_details) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302711 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002712 "%s: exit at line=%d\n", ioc->name,
2713 __FUNCTION__, __LINE__));
2714 break;
2715 }
2716
2717 starget = mptsas_get_starget(phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07002718 if (starget && (!ev->hidden_raid_component)){
2719
Eric Moore547f9a22006-06-27 14:42:12 -06002720 vtarget = starget->hostdata;
2721
2722 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302723 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore29dd3602007-09-14 18:46:51 -06002724 "%s: exit at line=%d\n", ioc->name,
2725 __FUNCTION__, __LINE__));
Moore, Ericf44e5462006-03-14 09:14:21 -07002726 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002727 }
Moore, Ericf44e5462006-03-14 09:14:21 -07002728 /*
2729 * Handling RAID components
2730 */
2731 if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
Eric Mooreb506ade2007-01-29 09:45:37 -07002732 printk(MYIOC_s_INFO_FMT
2733 "RAID Exposing: channel=%d, id=%d, "
2734 "physdsk %d \n", ioc->name, ev->channel,
2735 ev->id, ev->phys_disk_num);
2736 vtarget->tflags &=
2737 ~MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Moore793955f2007-01-29 09:42:20 -07002738 vtarget->id = ev->id;
Eric Moore547f9a22006-06-27 14:42:12 -06002739 mptsas_reprobe_target(starget, 0);
Eric Mooreb506ade2007-01-29 09:45:37 -07002740 phy_info->attached.phys_disk_num = ~0;
Moore, Ericf44e5462006-03-14 09:14:21 -07002741 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002742 break;
2743 }
2744
Eric Moore547f9a22006-06-27 14:42:12 -06002745 if (mptsas_get_rphy(phy_info)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302746 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002747 "%s: exit at line=%d\n", ioc->name,
2748 __FUNCTION__, __LINE__));
Eric Mooreb506ade2007-01-29 09:45:37 -07002749 if (ev->channel) printk("%d\n", __LINE__);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002750 break;
Eric Moore547f9a22006-06-27 14:42:12 -06002751 }
Eric Mooreb506ade2007-01-29 09:45:37 -07002752
Eric Moore547f9a22006-06-27 14:42:12 -06002753 port = mptsas_get_port(phy_info);
2754 if (!port) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302755 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002756 "%s: exit at line=%d\n", ioc->name,
2757 __FUNCTION__, __LINE__));
2758 break;
2759 }
Christoph Hellwige3094442006-02-16 13:25:36 +01002760 memcpy(&phy_info->attached, &sas_device,
2761 sizeof(struct mptsas_devinfo));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002762
Eric Mooreb506ade2007-01-29 09:45:37 -07002763 if (phy_info->attached.device_info &
2764 MPI_SAS_DEVICE_INFO_SSP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002765 ds = "ssp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002766 if (phy_info->attached.device_info &
2767 MPI_SAS_DEVICE_INFO_STP_TARGET)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002768 ds = "stp";
Eric Mooreb506ade2007-01-29 09:45:37 -07002769 if (phy_info->attached.device_info &
2770 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
Moore, Ericc73787ee2006-01-26 16:20:06 -07002771 ds = "sata";
2772
2773 printk(MYIOC_s_INFO_FMT
2774 "attaching %s device, channel %d, id %d, phy %d\n",
2775 ioc->name, ds, ev->channel, ev->id, ev->phy_id);
2776
James Bottomleyf013db32006-03-18 14:54:36 -06002777 mptsas_parse_device_info(&identify, &phy_info->attached);
Eric Moore547f9a22006-06-27 14:42:12 -06002778 rphy = sas_end_device_alloc(port);
2779 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302780 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002781 "%s: exit at line=%d\n", ioc->name,
2782 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002783 break; /* non-fatal: an rphy can be added later */
Eric Moore547f9a22006-06-27 14:42:12 -06002784 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002785
James Bottomleyf013db32006-03-18 14:54:36 -06002786 rphy->identify = identify;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002787 if (sas_rphy_add(rphy)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302788 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002789 "%s: exit at line=%d\n", ioc->name,
2790 __FUNCTION__, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002791 sas_rphy_free(rphy);
2792 break;
2793 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302794 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002795 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002796 case MPTSAS_ADD_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002797 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
2798 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002799 if (sdev) {
2800 scsi_device_put(sdev);
2801 break;
2802 }
2803 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002804 "attaching raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002805 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
2806 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002807 mpt_findImVolumes(ioc);
2808 break;
2809 case MPTSAS_DEL_RAID:
James Bottomleye8bf3942006-07-11 17:49:34 -04002810 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
Eric Mooreb506ade2007-01-29 09:45:37 -07002811 ev->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002812 if (!sdev)
2813 break;
2814 printk(MYIOC_s_INFO_FMT
Moore, Eric4b766472006-03-14 09:14:12 -07002815 "removing raid volume, channel %d, id %d\n",
James Bottomleye8bf3942006-07-11 17:49:34 -04002816 ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07002817 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002818 scsi_remove_device(sdev);
2819 scsi_device_put(sdev);
2820 mpt_findImVolumes(ioc);
2821 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002822 case MPTSAS_ADD_INACTIVE_VOLUME:
2823 mptsas_adding_inactive_raid_components(ioc,
2824 ev->channel, ev->id);
2825 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002826 case MPTSAS_IGNORE_EVENT:
2827 default:
2828 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002829 }
2830
Moore, Erice6b2d762006-03-14 09:14:24 -07002831 mutex_unlock(&ioc->sas_discovery_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06002832 kfree(ev);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002833}
2834
2835static void
Eric Moore547f9a22006-06-27 14:42:12 -06002836mptsas_send_sas_event(MPT_ADAPTER *ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002837 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
2838{
2839 struct mptsas_hotplug_event *ev;
2840 u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
2841 __le64 sas_address;
2842
2843 if ((device_info &
2844 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
2845 MPI_SAS_DEVICE_INFO_STP_TARGET |
2846 MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
2847 return;
2848
Moore, Eric4b766472006-03-14 09:14:12 -07002849 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07002850 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07002851
2852 mptsas_target_reset_queue(ioc, sas_event_data);
2853 break;
2854
2855 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Eric Moore547f9a22006-06-27 14:42:12 -06002856 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Eric4b766472006-03-14 09:14:12 -07002857 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002858 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Eric4b766472006-03-14 09:14:12 -07002859 break;
2860 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002861
David Howellsc4028952006-11-22 14:57:56 +00002862 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Eric4b766472006-03-14 09:14:12 -07002863 ev->ioc = ioc;
2864 ev->handle = le16_to_cpu(sas_event_data->DevHandle);
2865 ev->parent_handle =
2866 le16_to_cpu(sas_event_data->ParentDevHandle);
2867 ev->channel = sas_event_data->Bus;
2868 ev->id = sas_event_data->TargetID;
2869 ev->phy_id = sas_event_data->PhyNum;
2870 memcpy(&sas_address, &sas_event_data->SASAddress,
2871 sizeof(__le64));
2872 ev->sas_address = le64_to_cpu(sas_address);
2873 ev->device_info = device_info;
2874
2875 if (sas_event_data->ReasonCode &
2876 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
2877 ev->event_type = MPTSAS_ADD_DEVICE;
2878 else
2879 ev->event_type = MPTSAS_DEL_DEVICE;
2880 schedule_work(&ev->work);
2881 break;
2882 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
2883 /*
2884 * Persistent table is full.
2885 */
Eric Moore547f9a22006-06-27 14:42:12 -06002886 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00002887 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06002888 schedule_work(&ioc->sas_persist_task);
Moore, Eric4b766472006-03-14 09:14:12 -07002889 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07002890 /*
2891 * TODO, handle other events
2892 */
Moore, Eric4b766472006-03-14 09:14:12 -07002893 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Eric Mooreb506ade2007-01-29 09:45:37 -07002894 case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
Moore, Eric4b766472006-03-14 09:14:12 -07002895 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Eric Mooreb506ade2007-01-29 09:45:37 -07002896 case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
2897 case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
2898 case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
2899 case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
Moore, Eric4b766472006-03-14 09:14:12 -07002900 default:
2901 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002902 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002903}
Moore, Ericc73787ee2006-01-26 16:20:06 -07002904static void
Eric Moore547f9a22006-06-27 14:42:12 -06002905mptsas_send_raid_event(MPT_ADAPTER *ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07002906 EVENT_DATA_RAID *raid_event_data)
2907{
2908 struct mptsas_hotplug_event *ev;
Moore, Ericbd23e942006-04-17 12:43:04 -06002909 int status = le32_to_cpu(raid_event_data->SettingsStatus);
2910 int state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002911
2912 if (ioc->bus_type != SAS)
2913 return;
2914
Eric Moore547f9a22006-06-27 14:42:12 -06002915 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002916 if (!ev) {
Eric Moore29dd3602007-09-14 18:46:51 -06002917 printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002918 return;
2919 }
2920
David Howellsc4028952006-11-22 14:57:56 +00002921 INIT_WORK(&ev->work, mptsas_hotplug_work);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002922 ev->ioc = ioc;
2923 ev->id = raid_event_data->VolumeID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002924 ev->channel = raid_event_data->VolumeBus;
Moore, Ericbd23e942006-04-17 12:43:04 -06002925 ev->event_type = MPTSAS_IGNORE_EVENT;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002926
2927 switch (raid_event_data->ReasonCode) {
2928 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Eric Mooreb506ade2007-01-29 09:45:37 -07002929 ev->phys_disk_num_valid = 1;
2930 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002931 ev->event_type = MPTSAS_ADD_DEVICE;
2932 break;
2933 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Moore, Ericf44e5462006-03-14 09:14:21 -07002934 ev->phys_disk_num_valid = 1;
2935 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002936 ev->hidden_raid_component = 1;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002937 ev->event_type = MPTSAS_DEL_DEVICE;
2938 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06002939 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
2940 switch (state) {
2941 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07002942 case MPI_PD_STATE_NOT_COMPATIBLE:
Moore, Ericbd23e942006-04-17 12:43:04 -06002943 ev->phys_disk_num_valid = 1;
2944 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Eric Mooreb506ade2007-01-29 09:45:37 -07002945 ev->hidden_raid_component = 1;
Moore, Ericbd23e942006-04-17 12:43:04 -06002946 ev->event_type = MPTSAS_ADD_DEVICE;
2947 break;
2948 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06002949 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
2950 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
2951 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Eric Mooreb506ade2007-01-29 09:45:37 -07002952 ev->phys_disk_num_valid = 1;
2953 ev->phys_disk_num = raid_event_data->PhysDiskNum;
Moore, Ericbd23e942006-04-17 12:43:04 -06002954 ev->event_type = MPTSAS_DEL_DEVICE;
2955 break;
2956 default:
2957 break;
2958 }
2959 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07002960 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
2961 ev->event_type = MPTSAS_DEL_RAID;
2962 break;
2963 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
2964 ev->event_type = MPTSAS_ADD_RAID;
2965 break;
2966 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Moore, Ericbd23e942006-04-17 12:43:04 -06002967 switch (state) {
2968 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
2969 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
2970 ev->event_type = MPTSAS_DEL_RAID;
2971 break;
2972 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
2973 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
2974 ev->event_type = MPTSAS_ADD_RAID;
2975 break;
2976 default:
2977 break;
2978 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07002979 break;
2980 default:
2981 break;
2982 }
2983 schedule_work(&ev->work);
2984}
2985
Moore, Erice6b2d762006-03-14 09:14:24 -07002986static void
Eric Moore547f9a22006-06-27 14:42:12 -06002987mptsas_send_discovery_event(MPT_ADAPTER *ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07002988 EVENT_DATA_SAS_DISCOVERY *discovery_data)
2989{
2990 struct mptsas_discovery_event *ev;
2991
2992 /*
2993 * DiscoveryStatus
2994 *
2995 * This flag will be non-zero when firmware
2996 * kicks off discovery, and return to zero
2997 * once its completed.
2998 */
2999 if (discovery_data->DiscoveryStatus)
3000 return;
3001
Eric Moore547f9a22006-06-27 14:42:12 -06003002 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
Moore, Erice6b2d762006-03-14 09:14:24 -07003003 if (!ev)
3004 return;
David Howellsc4028952006-11-22 14:57:56 +00003005 INIT_WORK(&ev->work, mptsas_discovery_work);
Moore, Erice6b2d762006-03-14 09:14:24 -07003006 ev->ioc = ioc;
3007 schedule_work(&ev->work);
3008};
3009
Eric Mooreb506ade2007-01-29 09:45:37 -07003010/*
3011 * mptsas_send_ir2_event - handle exposing hidden disk when
3012 * an inactive raid volume is added
3013 *
3014 * @ioc: Pointer to MPT_ADAPTER structure
3015 * @ir2_data
3016 *
3017 */
3018static void
3019mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
3020{
3021 struct mptsas_hotplug_event *ev;
3022
3023 if (ir2_data->ReasonCode !=
3024 MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
3025 return;
3026
3027 ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
3028 if (!ev)
3029 return;
3030
3031 INIT_WORK(&ev->work, mptsas_hotplug_work);
3032 ev->ioc = ioc;
3033 ev->id = ir2_data->TargetID;
3034 ev->channel = ir2_data->Bus;
3035 ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
3036
3037 schedule_work(&ev->work);
3038};
Moore, Erice6b2d762006-03-14 09:14:24 -07003039
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003040static int
3041mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
3042{
Moore, Ericc73787ee2006-01-26 16:20:06 -07003043 int rc=1;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003044 u8 event = le32_to_cpu(reply->Event) & 0xFF;
3045
3046 if (!ioc->sh)
Moore, Ericc73787ee2006-01-26 16:20:06 -07003047 goto out;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003048
Moore, Erice6b2d762006-03-14 09:14:24 -07003049 /*
3050 * sas_discovery_ignore_events
3051 *
3052 * This flag is to prevent anymore processing of
3053 * sas events once mptsas_remove function is called.
3054 */
3055 if (ioc->sas_discovery_ignore_events) {
3056 rc = mptscsih_event_process(ioc, reply);
3057 goto out;
3058 }
3059
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003060 switch (event) {
3061 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Eric Moore547f9a22006-06-27 14:42:12 -06003062 mptsas_send_sas_event(ioc,
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003063 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003064 break;
3065 case MPI_EVENT_INTEGRATED_RAID:
Eric Moore547f9a22006-06-27 14:42:12 -06003066 mptsas_send_raid_event(ioc,
Moore, Ericc73787ee2006-01-26 16:20:06 -07003067 (EVENT_DATA_RAID *)reply->Data);
3068 break;
Moore, Eric79de2782006-01-25 18:05:15 -07003069 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Moore547f9a22006-06-27 14:42:12 -06003070 INIT_WORK(&ioc->sas_persist_task,
David Howellsc4028952006-11-22 14:57:56 +00003071 mptsas_persist_clear_table);
Eric Moore547f9a22006-06-27 14:42:12 -06003072 schedule_work(&ioc->sas_persist_task);
Moore, Eric79de2782006-01-25 18:05:15 -07003073 break;
Moore, Eric4b766472006-03-14 09:14:12 -07003074 case MPI_EVENT_SAS_DISCOVERY:
Eric Moore547f9a22006-06-27 14:42:12 -06003075 mptsas_send_discovery_event(ioc,
Moore, Erice6b2d762006-03-14 09:14:24 -07003076 (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
3077 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003078 case MPI_EVENT_IR2:
3079 mptsas_send_ir2_event(ioc,
3080 (PTR_MPI_EVENT_DATA_IR2)reply->Data);
3081 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003082 default:
Moore, Ericc73787ee2006-01-26 16:20:06 -07003083 rc = mptscsih_event_process(ioc, reply);
3084 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003085 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07003086 out:
3087
3088 return rc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003089}
3090
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003091static int
3092mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
3093{
3094 struct Scsi_Host *sh;
3095 MPT_SCSI_HOST *hd;
3096 MPT_ADAPTER *ioc;
3097 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003098 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003099 int numSGE = 0;
3100 int scale;
3101 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003102 int error=0;
3103 int r;
3104
3105 r = mpt_attach(pdev,id);
3106 if (r)
3107 return r;
3108
3109 ioc = pci_get_drvdata(pdev);
3110 ioc->DoneCtx = mptsasDoneCtx;
3111 ioc->TaskCtx = mptsasTaskCtx;
3112 ioc->InternalCtx = mptsasInternalCtx;
3113
3114 /* Added sanity check on readiness of the MPT adapter.
3115 */
3116 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
3117 printk(MYIOC_s_WARN_FMT
3118 "Skipping because it's not operational!\n",
3119 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003120 error = -ENODEV;
3121 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003122 }
3123
3124 if (!ioc->active) {
3125 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
3126 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003127 error = -ENODEV;
3128 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003129 }
3130
3131 /* Sanity check - ensure at least 1 port is INITIATOR capable
3132 */
3133 ioc_cap = 0;
3134 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
3135 if (ioc->pfacts[ii].ProtocolFlags &
3136 MPI_PORTFACTS_PROTOCOL_INITIATOR)
3137 ioc_cap++;
3138 }
3139
3140 if (!ioc_cap) {
3141 printk(MYIOC_s_WARN_FMT
3142 "Skipping ioc=%p because SCSI Initiator mode "
3143 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06003144 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003145 }
3146
3147 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
3148 if (!sh) {
3149 printk(MYIOC_s_WARN_FMT
3150 "Unable to register controller with SCSI subsystem\n",
3151 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003152 error = -1;
3153 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003154 }
3155
3156 spin_lock_irqsave(&ioc->FreeQlock, flags);
3157
3158 /* Attach the SCSI Host to the IOC structure
3159 */
3160 ioc->sh = sh;
3161
3162 sh->io_port = 0;
3163 sh->n_io_port = 0;
3164 sh->irq = 0;
3165
3166 /* set 16 byte cdb's */
3167 sh->max_cmd_len = 16;
3168
Eric Moore793955f2007-01-29 09:42:20 -07003169 sh->max_id = ioc->pfacts[0].PortSCSIID;
3170 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003171
3172 sh->transportt = mptsas_transport_template;
3173
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003174 sh->this_id = ioc->pfacts[0].PortSCSIID;
3175
3176 /* Required entry.
3177 */
3178 sh->unique_id = ioc->id;
3179
3180 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003181 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07003182 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01003183 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003184 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003185
3186 /* Verify that we won't exceed the maximum
3187 * number of chain buffers
3188 * We can optimize: ZZ = req_sz/sizeof(SGE)
3189 * For 32bit SGE's:
3190 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
3191 * + (req_sz - 64)/sizeof(SGE)
3192 * A slightly different algorithm is required for
3193 * 64bit SGEs.
3194 */
3195 scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
3196 if (sizeof(dma_addr_t) == sizeof(u64)) {
3197 numSGE = (scale - 1) *
3198 (ioc->facts.MaxChainDepth-1) + scale +
3199 (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
3200 sizeof(u32));
3201 } else {
3202 numSGE = 1 + (scale - 1) *
3203 (ioc->facts.MaxChainDepth-1) + scale +
3204 (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
3205 sizeof(u32));
3206 }
3207
3208 if (numSGE < sh->sg_tablesize) {
3209 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303210 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003211 "Resetting sg_tablesize to %d from %d\n",
3212 ioc->name, numSGE, sh->sg_tablesize));
3213 sh->sg_tablesize = numSGE;
3214 }
3215
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003216 hd = (MPT_SCSI_HOST *) sh->hostdata;
3217 hd->ioc = ioc;
3218
3219 /* SCSI needs scsi_cmnd lookup table!
3220 * (with size equal to req_depth*PtrSz!)
3221 */
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003222 hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
3223 if (!hd->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003224 error = -ENOMEM;
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003225 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003226 }
3227
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303228 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01003229 ioc->name, hd->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003230
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003231 /* Clear the TM flags
3232 */
3233 hd->tmPending = 0;
3234 hd->tmState = TM_STATE_NONE;
3235 hd->resetPending = 0;
3236 hd->abortSCpnt = NULL;
3237
3238 /* Clear the pointer used to store
3239 * single-threaded commands, i.e., those
3240 * issued during a bus scan, dv and
3241 * configuration pages.
3242 */
3243 hd->cmdPtr = NULL;
3244
3245 /* Initialize this SCSI Hosts' timers
3246 * To use, set the timer expires field
3247 * and add_timer
3248 */
3249 init_timer(&hd->timer);
3250 hd->timer.data = (unsigned long) hd;
3251 hd->timer.function = mptscsih_timer_expired;
3252
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003253 ioc->sas_data.ptClear = mpt_pt_clear;
3254
Eric Mooredf9e0622007-01-29 09:46:21 -07003255 init_waitqueue_head(&hd->scandv_waitq);
3256 hd->scandv_wait_done = 0;
3257 hd->last_queue_full = 0;
3258 INIT_LIST_HEAD(&hd->target_reset_list);
3259 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
3260
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003261 if (ioc->sas_data.ptClear==1) {
3262 mptbase_sas_persist_operation(
3263 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
3264 }
3265
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003266 error = scsi_add_host(sh, &ioc->pcidev->dev);
3267 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06003268 dprintk(ioc, printk(MYIOC_s_ERR_FMT
3269 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07003270 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003271 }
3272
3273 mptsas_scan_sas_topology(ioc);
3274
3275 return 0;
3276
Eric Moore547f9a22006-06-27 14:42:12 -06003277 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003278
3279 mptscsih_remove(pdev);
3280 return error;
3281}
3282
3283static void __devexit mptsas_remove(struct pci_dev *pdev)
3284{
3285 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
3286 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06003287 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003288
Eric Mooreb506ade2007-01-29 09:45:37 -07003289 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003290 sas_remove_host(ioc->sh);
3291
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003292 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003293 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
3294 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06003295 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303296 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Eric Moore547f9a22006-06-27 14:42:12 -06003297 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003298 kfree(p);
3299 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003300 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003301
3302 mptscsih_remove(pdev);
3303}
3304
3305static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06003306 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003307 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003308 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003309 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003310 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003311 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003312 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003313 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06003314 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003315 PCI_ANY_ID, PCI_ANY_ID },
3316 {0} /* Terminating entry */
3317};
3318MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
3319
3320
3321static struct pci_driver mptsas_driver = {
3322 .name = "mptsas",
3323 .id_table = mptsas_pci_table,
3324 .probe = mptsas_probe,
3325 .remove = __devexit_p(mptsas_remove),
3326 .shutdown = mptscsih_shutdown,
3327#ifdef CONFIG_PM
3328 .suspend = mptscsih_suspend,
3329 .resume = mptscsih_resume,
3330#endif
3331};
3332
3333static int __init
3334mptsas_init(void)
3335{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303336 int error;
3337
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003338 show_mptmod_ver(my_NAME, my_VERSION);
3339
3340 mptsas_transport_template =
3341 sas_attach_transport(&mptsas_transport_functions);
3342 if (!mptsas_transport_template)
3343 return -ENODEV;
3344
3345 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Eric Mooredf9e0622007-01-29 09:46:21 -07003346 mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003347 mptsasInternalCtx =
3348 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003349 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003350
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303351 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
3352 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003353
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05303354 error = pci_register_driver(&mptsas_driver);
3355 if (error)
3356 sas_release_transport(mptsas_transport_template);
3357
3358 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003359}
3360
3361static void __exit
3362mptsas_exit(void)
3363{
3364 pci_unregister_driver(&mptsas_driver);
3365 sas_release_transport(mptsas_transport_template);
3366
3367 mpt_reset_deregister(mptsasDoneCtx);
3368 mpt_event_deregister(mptsasDoneCtx);
3369
Christoph Hellwigda4fa652005-10-19 20:01:42 +02003370 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003371 mpt_deregister(mptsasInternalCtx);
3372 mpt_deregister(mptsasTaskCtx);
3373 mpt_deregister(mptsasDoneCtx);
3374}
3375
3376module_init(mptsas_init);
3377module_exit(mptsas_exit);